Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7018 Articles
article-image-how-does-ocs-inventory-ng-meet-our-needs
Packt
12 May 2010
8 min read
Save for later

How does OCS Inventory NG meet our needs?

Packt
12 May 2010
8 min read
OCS Inventory NG stands for Open Computer and Software Inventory Next Generation , and it is the name of an open source project that was started back in late 2005. The project matured into the first final release in the beginning of year 2007. It's an undertaking that is still actively maintained, fully documented, and has support forums. It has all of the requirements that an open source application should have in order to be competitive. There is a tricky part when it comes to open source solutions. Proposing them and getting them accepted by the management requires quite a bit of research. One side of the coin is that it is always favorable, everyone appreciates cutting down licensing costs. The problem with such a solution is that you cannot always take for granted their future support. In order to take an educated guess on whether an open source solution could be beneficial for the company, we need to look at the following criteria: how frequently is the project updated, check the download count, what is the feedback of the community, whether the application is thoroughly documented, and the existence of active community support. OCS-NG occupies a dominant position when it comes to open source projects on the area of inventorying computers and software. Brief overview on OCS Inventory NG's architecture The architecture of OCS-NG is based on the client-server model. The client program is called a network agent. These agents need to be deployed on the client computers that we want to include in our inventory. The management server is composed of four individual server roles: database server, communication server, deployment server, and the administration console server. More often than not, these can be run from the same machine. OCS Inventory NG is cross-platform and supports most Unices, BSD derivates (including Mac OS X), and all kinds of Windows-based operating systems. The server can be also be run on either platform. As it is an open source project, it's based on the popular LAMP or WAMP solution stack. This means that the main server-side prerequisites are Apache web server, MySQL database server, and PHP server. These are also the viable components of a fully functional web server. The network agents communicate with the management server under standardized HTTP protocols. The data that is exchanged is formatted under XML conventions. The screenshot below describes a general overview on the way clients communicate with the management server's sub-server components. Rough performance evaluation of OCS-NG The data that is collected in case of a fully - inventoried computer sums up to something around 5KB. That is a small amount and it will neither overload the server nor create network congestion. It is often said that around one million systems can be inventoried daily on a 3GHz bi-Xeon processor based server with 4 GB of RAM without any issues. Any modest old-generation server should suffice for the inventory of few thousand systems. When scalability is necessary such as over 10,000-20,000 inventoried systems, it is recommended to split those 4 server-role components on two individual servers. Should this be the case, the database server needs to be installed on the same machine with the communication server, and on another system with the administration server and the deployment server with a database replica. Any other combination is also possible. Although distributing the server components is possible, very rarely do we really need to do that. In this day and age, we can seamlessly virtualize up to four or more servers on any dual or quad-core new generation computer. OCS-NG's management server can be one of those VMs. If necessary, distributing server components in the future is possible. Meeting our inventory demands First and foremost, OCS Inventory NG network agents are able to collect all of the must-have attributes of a client computer and many more. Let's do a quick checkup on these: BIOS: System serial number, manufacturer, and model Bios manufacturer, version, and date Processors: Type, count (how many of them), manufacturer, speed, and cache Memory: Physical memory type, manufacturer, capacity, and slot number Total physical memory Total swap/paging memory Video: Video adapter: Chipset/model, manufacturer, memory size, speed, and screen resolution Display monitor: Manufacturer, description, refresh rate, type, serial number, and caption Storage/removable devices: Manufacturer, model, size, type, speed( all when applicable) Drive letter, filesystem type, partition/volume size, free space Network adapters/telephony: Manufacturer, model, type, speed, and description MAC and IP address, mask and IP gateway, DHCP server used Miscellaneous hardware Input devices: Keyboard, mouse, and pointing device Sound devices: Manufacturer name, type, and description System slots: Name, type, and designation System ports: Type, name, caption, and description Software Information: Operating system: Name, version, comments, and registration info Installed software: Name, publisher, version (from Add / Remove software or Programs and Features menu) Custom-specified registry queries (applicable to Windows OS) Not only computers but also networking components can be used for inventorying. OCS Inventory NG detects and collects network-specific information about these (such as MAC address and IP address, subnet mask, and so on.). Later on we can set labels and organize them appropriately. The place where OCS-NG comes as a surprise is its unique capability to make an inventory of hosts that are not on the network. The network agent can be run manually on these offline hosts and are then imported into the centralized management server. One of its features include intelligent auto-discovering functionalities and its ability to detect hosts that have not been inventoried. It is based on popular network diagnosing and auditing tools such as the nmap . The algorithm can decide whether it's an actual workstation computer or rather just a printer. If it's the former, the agent needs to be deployed. The network scanning is not done by the management server. It is delegated to network agents. This way the network is never overcrowded or congested. If the management server itself scans for populated networks spanning throughout different subnets, the process would be disastrous. This way the process is seamless and simply practical. Another interesting part is the election mechanism based on which the server is able to decide the most suited client to carry out the discovery. A rough sketch of this in action can be seen in the next figure. Set of functions and what it brings to the table At this moment, we're fully aware that the kind information that the network agents are getting into the database are relevant and more than enough for our inventorying needs. Nevertheless, we won't stop here. It's time to analyze and present its web interface. We will also shed a bit of light on the set of features it supports out of the box without any plugins or other mods yet. There will be a time for those too. Taking a glance at the OCS-NG web interface The web interface of OCS Inventory NG is slightly old-fashioned. One direct advantage of this is that the interface is really snappy. Queries are displayed quickly, and the UI won't lag. The other side of the coin is that intuitiveness is not the interface's strongest point. Getting used to it might take a while. At least it does not make you feel that the interface is overcrowded. However, the location and naming of buttons leaves plenty of room for improvement. Some people might prefer to see captions below the shortcuts as the meaning of the icons is not always obvious. After the first few minutes, we will easily get used to them. A picture is worth thousands of words, so let's exemplify our claims. The buttons that appear in the previous screenshot from left to right are the following: All computers Tag/Number of PC repartition Groups All softwares Search with various criteria In the same fashion, in this case the buttons in the previous screenshot stand for the following features: Deployment Security Dictionary Agent Configuration (this one is intuitive!) Registry (self-explanatory) Admin Info Duplicates Users Local Import Help When you click on the name of the specific icon, the drop-down menu appears right below on the cursor All in all, the web interface is not that bad after all. We must accept that the strongestpoint lies in its snappiness, and the wealth of information that is presented in a fraction of a second rather than its design or intuitiveness. We appreciate its overall simplicity and its quick response time. We are often struggling with new generation Java-based and AJAX-based overcrowded interfaces of network equipment that seem slow as hell. So, we'll choose OCS Inventory NG's UI over those anytime!
Read more
  • 0
  • 0
  • 9904

article-image-creating-customizing-and-assigning-portlets-automatically-plone-33
Packt
12 May 2010
5 min read
Save for later

Creating, Customizing, and Assigning Portlets Automatically for Plone 3.3

Packt
12 May 2010
5 min read
(For more resources on Plone, see here.) Introduction One of the major changes from Plone 2.5 to Plone 3.0 was the complete refactoring of its portlets engine. In Plone 2.5, left and right side portlets were managed from Zope Management Interface (ZMI) by setting two special properties: left_slots and right_slots. This was not so hard but was cumbersome. Any TALES path expression—ZPT macros typically—could be manually inserted in the above two properties and would be displayed as a bit of HTML to the final user. The major drawback for site managers with the old-style approach was not just the uncomfortable way of setting which portlets to display, but the lack of any configuration options for them. For example, if we wanted to present the latest published news items, we wouldn't have any means of telling how many of them to show, unless the portlet itself were intelligent enough to get that value from some other contextual property. But again, we were still stuck in the ZMI. Fortunately, this has changed enormously in Plone 3.x: Portlets can now be configured and their settings are mantained in ZODB. Portlets are now managed via a user-friendly, Plone-like interface. Just click on the Manage portlets link below each of the portlets columns (see the following screenshot). In the above screen, if we click on the News portlet link, we are presented with a special configuration form to choose the Number of items to display and the Workflow state(s) we want to consider when showing news items. If you have read previous chapters, you might be correctly guessing that Zope 3 components (zope.formlib mainly) are behind the portlets configuration forms. In the next sections, we'll look again at the customer's requirements: Advertisement banners will be located in several areas of every page Advertisement banners may vary according to the section of the website Creating a portlet package Once again, paster comes to the rescue. As in Creating a product package structure and Creating an Archetypes product with paster, we will use the paster command here to create all the necessary boilerplate (and even more) to get a fully working portlet. Getting ready As we are still at the development stage, we should run the following commands in our buildout's src folder: cd ./src How to do it... Run the paster command: We are going to create a new egg called pox.portlet.banner. The pox prefix is from PloneOpenX (the website we are working on) and it will be the namespace of our product. Portlets eggs usually have a nested portlet namespace as in plone.portlet.collection or plone.portlet.static. We have chosen the pox main namespace as in the previous eggs we have created, and the banner suffix corresponds to the portlet name. For more information about eggs and packages names read http://www.martinaspeli.net/articles/the-naming-ofthings-package-names-and-namespaces.If you want to add portlets to an existing package instead of creating a new one, the steps covered in this chapter should tell you all you need to know (the use of paster addcontent portlet local command will be of great help). In your src folder, run the following command: paster create -t plone3_portlet This paster command creates a product using the plone3_portlet template. When run, it will output some informative text, and then a short wizard will be started to select options for the package: Option Value Enter project name pox.portlet.banner Expert Mode? easy Version 1.0 Description Portlet to show banners Portlet Name Banner portlet Portlet Type BannerPortlet After selecting the last option, you'll get an output like this (a little longer actually): Creating directory ./pox.portlet.banner ... Recursing into +namespace_package+ Recursing into +namespace_package2+ Recursing into +package+ Recursing into profiles Creating ./pox.portlet.banner/pox/portlet/banner/profiles/ Recursing into default Creating ./pox.portlet.banner/pox/portlet/banner/profiles/default/ Copying metadata.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/metadata.xml Copying portlets.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/portlets.xml This tells us that even the GenericSetup extension profile has also been created by paster. This means that we can install the new Banner portlet product (as entered in the portlet_name option above). Install the product: To tell our Zope instance about the new product, we must update the buildout.cfg file as follows: [buildout]...eggs =... pox.portlet.banner...develop = src/pox.portlet.banner We can automatically install the product during buildout. Add a pox.portlet.banner line inside the products parameter of the [plonesite] part: [plonesite]recipe = collective.recipe.plonesite...products =... pox.portlet.banner Build your instance and, if you want to, launch it to see the new empty Banner portlet: ./bin/buildout./bin/instance fg Check the new portlet: After implementing the changes above, if you click on the Manage portlets link in the site's home page (or anywhere in the Plone site), you will see a new Banner portlet option in the drop-down menu. A new box in the portlet column will then be shown. The Header/Body text/Footer box shown above matches the template definition in the bannerportlet.pt file the way paster created it.
Read more
  • 0
  • 0
  • 4652

article-image-introduction-it-inventory-and-resource-management
Packt
12 May 2010
8 min read
Save for later

Introduction to IT Inventory and Resource Management

Packt
12 May 2010
8 min read
For the past decade or so we have begun to realize that computers are an indispensable necessity. They're around us everywhere, starting from our comfortable households to rovers from other planets. Currently, it is not uncommon at all to have more than a few dozen of office computers and other IT equipment in the infrastructure of a small company that does nothing directly related to that specific area. It should not surprise anyone that in case of business environments there has to be some streamlined inventory. Especially, when we consider that the network might have a total of several hundreds, if not thousands, of workstation computers, servers, portable devices, other office equipment such as printers, scanners, and other networking components. Resource management, in its essence, when viewed from an IT perspective, is providing a method to gather and store all kinds of information about items in our infrastructure. Later on supporting means to further maintain the said inventory. Also, performing routine tasks based on the collected data such as generating reports, locating relevant information easily (like where is a specific memory module with the model number you're looking for), auditing type of software installed on workstation computers, and more. Our plan of action is going to be pretty straightforward; we analyze the IT inventorying needs and some general requisites when it comes to managing those assets. What's more we'll be presenting the client-sever model that is the underlying foundation on which most centralized management solutions are working. This is when OCS Inventory NG pops into the picture saving the day. Soon we will see why. We will get to know more about OCS Inventory NG soon, for now it's enough to realize that it's an open source project. No matter how successful a company is, open source solutions are always appreciated by the IT staff and management. As long as the project is actively developed, it's fairly popular, well documented, provides community support, and meets their needs. Among others, open source projects end up modular and flexible. Inventorying requirements in the real world One of the general requirements of an IT inventory is to be efficient and practical. The entire process should be seamless to the clients and requires limited (or none at all) user interaction. Once set up, it just needs to be automated to update the inventory database based on the latest changes without manually being required to do so. Thereafter, the collage of data gathered is ought to be organized and labeled the way we want. Businesses everywhere have come to realize that process integration is the best method for querying, standardizing, and organizing information about the infrastructure. The age of hi-tech computing made this possible by speeding up routine tasks and saving up employee time, eliminating bureaucracy and unnecessary filing of papers that all lead to frustration and waste of resources. Implementing integrated processes can change the structure and behavior of an organization. But finding the correct integration often becomes a dilemma. Feasible solution to avoid inevitable havoc Drifting back to the case of IT department, the necessity of having an integrated and centralized solution to manage numerous systems and other hardware equipment becomes obvious. The higher the number of systems, the bigger the volume to be managed, the easier the situation can get out of control, thus leading to crisis. Everyone runs around in panic like headless zombies trying to figure out who can be held responsible and what's there to do in order to avoid such scenarios. Taking a rational approach soon enough can improve the stability of entire organizations. Chances are you already know this, but usually system administrators tend to dislike working with papers. Filling in forms, storing them purely for archiving needs, and then when they least expect it, finding relevant information. A system like that won't make anyone happy. A centralized repository in some shape or form of a database gives almost instant access to results whenever such a query happens. Its actual state of always being up-to-date and reflecting the actual state of the infrastructure can be guaranteed by implementing updating mechanism. Later on, once the database is in healthy state and the process is integrated, tried and proven, it won't make any significant difference between managing dozens of computers or thousands. A well-designed integrated process is future proof and scalable. This way it won't become a setback if and when the company decides to expand. Streamlining software auditing and license management As mentioned earlier, it is important to understand that auditing workstation machines cannot be neglected. In certain environments, the users or employees have limited access and work within a sort of enclosed program area and they can do little to nothing outside of their specialization. But there are situations when the employees are supposed to have administrative access and full permissions. It is for the good of both the user and company to monitor and pay attention to what happens within each and every computer. Having an up to par auditing mechanism can integrate the system of license management as well. The persons responsible for this can track the total amount of licenses used and owned by the company, can calculate balance, notify when this number is about to run out, and so forth. It isn't all that uncommon to automate the purchasing of licenses either. The license management process description varies from firm to firm, but usually it's something similar to the following: user requests for a license, supervisor agrees, and the request arrives to the relevant IT staff. After this step, the license request gets analyzed and based on the result it is either handed out or ordered/acquired if necessary. If the process is not automated, all this would involve paperwork. And soon you will see frustrated employees running back-and-forth through departments asking who else needs to sign this paper. The process of automating and printing the end result is elegant and takes no trouble. The responsible department can then store the printed document for archiving purposes, if required. But the key of the process lies in integration. Inventorying can help here too. More uses of an integrated IT inventory solution The count of office consumables can also be tracked and maintained. This is a trickier process because it cannot be made unattended totally. Unless by installing some sort of sensor to track the count of printer cartridges inside an office furniture or the warehouse. However, you can update this field each time the said item gets restocked. A centralized method for consumables means the responsible parties can get notified before running out of stock. Once again, this step eliminates unexpected scenarios and unnecessary tasks. The beauty of centralized management solutions in the IT world is that if it is done right, they can open doors to numerous other activities as well. For example, in case of workstation PCs, the integrated process can be expanded into providing remote administration and similar other activities to be carried out remotely on the client machine. Package deployment and execution of scripts are just few distinctive examples. Think of it like, license is granted, the package is deployed, and the script is run to ensure proper registration of the application, if required. System administrators can usually help fixing common issues of employees via remote execution of scripts. Surely there are other means to administer the machines, but we're focusing on all-in-one integrated solutions. Another possibility is integrating the help-desk and ticketing system within the centralized inventory's management control panel as well. This way when an employee asks for help or reports a hardware issue, the system administrator can take a look at what's inside that system (hardware specifications, software installed, and so on.).Therefore, the system administrator gets to know the situation beforehand and thus use the right tools to troubleshoot the said issue. Gathering relevant inventory information We can conclude that in order to have a complete inventory on top of which we can build and implement other IT-related and administrative tasks, we need at least the following: Collecting relevant hardware information in case of workstation computers Manufacturer, serial number, model number of every component When applicable,some of the following: revision number, size, speed, memory, type, description, designation, connection port, interface, slot number, driver, MAC and IP address, and so on Collecting installed software/OS (licensing) information Operating system: Name, version, and registration information Application name, publisher, version, location Custom-queries from the Windows registry (if applicable) Collecting information about networking equipment and office peripherals Manufacturer, serial number, model, type of component, and so on MAC and IP address When applicable: revision number, firmware, total uptime, and so on
Read more
  • 0
  • 0
  • 1857

article-image-securing-our-applications-using-opensso-glassfish-security
Packt
12 May 2010
8 min read
Save for later

Securing our Applications using OpenSSO in GlassFish Security

Packt
12 May 2010
8 min read
An example of such system is integration between an online shopping system, the product provider who actually produces the goods, the insurance company that provides insurance on purchases, and finally the shipping company that delivers the goods to the consumers' hand. All of these systems access some parts of the data, which flows into the other software to perform its job in an efficient way. All the employees can benefit from a single sign-on solution, which keeps them free from having to authenticate themselves multiple times during the working day. Another example can be a travel portal, whose clients need to communicate with many other systems to plan their traveling. Integration between an in-house system and external partners can happen in different levels, from communication protocol and data format to security policies, authentication, and authorization. Because of the variety of communication models, policies, and client types that each partner may use, unifying the security model is almost impossible and the urge for some kind of integration mechanism shows itself bolder and bolder. SSO as a concept and OpenSSO as a product address this urge for integrating the systems' security together. OpenSSO provides developers with several client interfaces to interact with OpenSSO to perform authentication, authorization, session and identity management, and audition. These interfaces include Client SDK for different programming languages and using standards including: Liberty Alliance Project and Security Assertion Markup Language (SAML) for authentication and single sign-on (SSO) XML Access Control Markup Language (XACML) for authorization functions Service Provisioning Markup Language (SPML) for identity management functions. Using the client SDKs and standards mentioned above are suitable when we are developing custom solutions or integrating our system with partners, which are already using them in their security infrastructure. For any other scenario these methods are overkill for developers. To make it easier for the developers to interact with OpenSSO core services the Identity Web Services are provided. We discussed IWS briefly in OpenSSO functionalities section. The IWS are included in OpenSSO to perform the tasks included in the following table. Task Description Authentication and Single sign-on Verifying the user credentials or its authentication token. Authorization Checking the authenticated user's permissions for accessing a resource. Provisioning Creating, deleting, searching, and editing users. Logging Ability to audit and record operations. IWS are exposed in two models—the first model is the WS-* compliant SOAP-based Web Services and the second model is a very simple but elegant RESTful set of services based on HTTP and REST principles. Finally, the third way of using OpenSSO is deploying the policy agents to protect the resources available in a container. In the following section we will use RESTful interface to perform authentication, authorization, and SSO. Authenticating users by the RESTful interface Performing authentication using the RESTful Web Services interface is very simple as it is just like performing a pure HTTP communication with an HTTP server. For each type of operation there is one URL, which may have some required parameters and the output is what we can expect from that operation. The URL for authentication operation along with its parameters is as follows: Operation: Authentication Operation URL: http://host:port/OpenSSOContext/identity/authenticate Parameters: username, password, uri Output: subjectid The Operation URL specifies the address of a Servlet which will receive the required parameters, perform the operation, and write back the result. In the template included above we have the host, port, and OpenSSOContext which are things we already know. After the context we have the path to the RESTful service we want to invoke. The path includes the task type, which can be one of the tasks included in the IWS task lists table and the operation we want to invoke. All parameters are self-descriptive except the uri. We pass a URL to have our users redirected to it after the authentication is performed. This URL can include information related to the user or the original resource which the user has requested. In the case of successful authentication we will receive a subjectid, which we can use in any other RESTful operation like authorization, to log in, log out, and so on. If you remember session ID from your web development experience, subjected is the same as session ID. You can view all sessions along with related information from the OpenSSO administration console homepage under the Sessions tab. The following listing shows a sample JSP page which performs a RESTful call over OpenSSO to authenticate a user and obtain a session ID for the user if they get authenticated. <%try {String operationURL ="http://gfbook.pcname.com:8080/opensso/identity/authenticate";String username = "james";String password = "james";username = java.net.URLEncoder.encode(username, "UTF-8");password = java.net.URLEncoder.encode(password, "UTF-8");String operationString = operationURL + "?username=" +username +"&password=" + password;java.net.URL Operation = new java.net.URL(operationString);java.net.HttpURLConnection connection =(java.net.HttpURLConnection)Operation.openConnection();int responseCode = connection.getResponseCode();if (responseCode == java.net.HttpURLConnection.HTTP_OK) {java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader((java.io.InputStream) connection.getContent()));out.println("<h2>Subject ID</h2>");String line = reader.readLine();out.println(line);}} catch (Exception e) {e.printStackTrace();}%> REST made straightforward tasks easier than ever. Without using REST we would have dealt with complexity of SOAP and WSDL and so on but with REST you can understand the whole code with the first scan. Beginning from the top, we define the REST operation URL, which is assembled using the operation URL and appending the required parameters using the parameters name and the parameters value. The URL that we will connect to it will be something like: http://gfbook.pcname.com:8080/opensso/identity/authenticate?username=james&password=james After assembling the URL we open a network connection to authenticate it. After opening the connection we can check to see whether we received an HTTP_OK response from the server or not. Receiving the HTTP_OK means that the authentication was successful and we can read the subjectid from the socket. The connection may result in other response codes like HTTP_UNAUTHORIZED (HTTP Error code 401) when the credentials are not valid. A complete list of possible return values can be found at http://java.sun.com/javase/6/docs/api/java/net/HttpURLConnection.html. Authorizing using REST If you remember in Configuring OpenSSO for authentication and authorization section we defined a rule that was set to police http://gfbook.pcname.com:8080/ URL for us. And later on we applied the policy rule to a group of users that we created; now we want to check and see how our policy works. In every security system, before any authorization process, an authentication process should compete with a positive result. In our case the result for the authentication is subjectid, which the authorization process will use to check whether the authenticated entity is allowed to perform the action or not. The URL for the authorization operation along with its parameters is as follows: Operation: Authorization Operation URL: http://host:port/OpenSSOContext/identity/authorize Parameters: uri, action, subjectid Output: True or false based on the permission of subject over the entity and given action The combination of uri, action, and subjectid specifies that we want to check our client, identified by subjectid, permission for performing the specified action on the resource identified by the uri. The output of the service invocation is either true or false. The following listing shows how we can check whether an authenticated user has access to a certain resource or not. In the sample code we are checking james, identified by his subjectid we acquired by executing the previous code snippet, against the localhost Protector rule we defined earlier. <%try {String operationURL ="http://gfbook.pcname.com:8080/opensso/identity/authorize";String protectecUrl = " http://127.0.0.1:38080/Conversion-war/";String subjectId ="AQIC5wM2LY4SfcyemVIZX6qBGdyH7b8C5KFJjuuMbw4oj24=@AAJTSQACMDE=#";String action = "POST";protectecUrl = java.net.URLEncoder.encode(protectecUrl, "UTF-8");subjectId = java.net.URLEncoder.encode(subjectId, "UTF-8");String operationString = operationURL + "?uri=" + protectecUrl +"&action=" + action + "&subjectid=" + subjectId;java.net.URL Operation = new java.net.URL(operationString);java.net.HttpURLConnection connection =(java.net.HttpURLConnection) Operation.openConnection();int responseCode = connection.getResponseCode();if (responseCode == java.net.HttpURLConnection.HTTP_OK) {java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader((java.io.InputStream) connection.getContent()));out.println("<h2>authorization Result</h2>");String line = reader.readLine();out.println(line);}} catch (Exception e) {e.printStackTrace();}%> For this listing everything is the same as the authentication process in terms of initializing objects and calling methods, except that in the beginning we define the protected URL string, then we include the subjectid, which is result of our previous authentication. Later on we define the action that we need to check the permission of our authenticated user over it and finally we read the result of authorization. The complete operation after including all parameters is similar to the following snippet: http://gfbook.pcname.com:8080/opensso/identity/authorize?uri=http://127.0.0.1:38080/Conversion-war/&action=POST&subjectid=subjectId Pay attention that two subjectid elements cannot be similar even for the same user on the same machine and same OpenSSO installation. So, before running this code, make sure that you perform the authentication process and include the subjectid resulted from your authentication with the subjectid we specified previously.
Read more
  • 0
  • 0
  • 4095

article-image-creating-your-first-complete-moodle-theme
Packt
11 May 2010
11 min read
Save for later

Creating your First Complete Moodle Theme

Packt
11 May 2010
11 min read
So let's crack on... Creating a new theme Finding a base theme to create your Moodle theme on is the first thing that you need to do.There are, however, various ways to do this; you can make a copy of the standard themeand rename it as you did in part of this article, or you can use a parent theme that isalso based on the standard theme. The important point here is that the standard theme that comes with Moodle is the cornerstone of the Moodle theming process. Every other Moodle theme should be based upon this theme, and would normally describe the differences from the standard theme. Although this method does work and is a simple way to get started with Moodle theming, it does cause problems as new features could get added to Moodle that might cause your theme to display or function incorrectly. The standard theme will always be updated before a new release of Moodle is launched. So if you do choose to make a copy of the standard theme and change its styles, it would be best to make sure that you use a parent theme as well. In this way, the parent theme will be your base theme along with the changes that you make to your copy of the standard theme. However, there is another way of creating your first theme, and that is to create a copy of a theme that is very close to the standard theme, such as standardwhite, and use this as your theme. Moodle will then use the standard theme as its base theme and apply any changes that you make to the standardwhite theme on the top (parent). All we are doing is describing the differences between the standard and the standardwhite themes. This is better because Moodle developers will sometimes make changes to the standard theme to be up-to-date with new Moodle features. This means that on each Moodle update, your standard theme, folder will be updated automatically, thus avoiding any nasty display problems being caused by Moodle updates. The way by which you configure Moodle themes is completely up to you. If you see a theme that is nearly what you want and there aren't really many changes needed, then using a parent theme makes sense, as most of the styles that you require have already been written. However, if you want to create a theme that is completely different from any other theme or wish to really get into Moodle theming, then using a copy of one of the standard sheets would be best. So let's get on and see what the differences are when using different theme setups, and see what effect these different methods have on the theming process. Time for action – copying the standard theme Browse to your theme folder in C:Program FilesApache Software FoundationApache 2.2htdocstheme. Copy the standard theme by right-clicking on the theme's folder and choosing Copy. Paste the copied theme into the theme directory (the same directory that you arecurrently in). Rename the copy of standard folder to blackandblue or any other name that you wish to choose (remember not to use capitals or spaces). Open your Moodle site and navigate to Site Administration Appearance | Themes | Theme Selector|, and choose the blackandblue theme that you have just created. Y ou might have noticed that the theme shown in the preceding screenshot has a header that says Black and Blue theme. This is because I have added this to the Full site name in the Front Page settings page. Time for action – setting a parent theme Open your web browser and navigate to your Moodle site and log in as the administrator. Go to Site Administration | Appearance | Themes | Theme Selector and choose your blackandblue theme if it is not already selected. Browse to the root of your blackandblue folder, right-click on the config.php file, and choose Open with | WordPad. You need to make four changes to this file so that you can use this theme and a parent theme while ensuring that you still use the default standard theme as your base. Here are the changes: $THEME->sheets = array('user_styles');$THEME->standardsheets = true;$THEME->parent = 'autumn';$THEME->parentsheets = array('styles'); Let's look at each of these statements, in turn. $THEME->sheets = array('user_styles'); This contains the names of all of the stylesheet files that you want to include in this for your blackandblue theme, namely user_styles. $THEME->standardsheets = true; This parameter is used to include the standard theme's stylesheets. If it is set to True, it will use all of the stylesheets in the standard theme. Alternatively, it can be set as an array in order to load individual stylesheets in whatever order is required. We have set this to True, so we will use all of the stylesheets of the standard theme. $THEME->parent = 'autumn'; This variable can be set to use a theme as the parent theme, which is included before the current theme. This will make it easier to make changes to another theme without having to change the actual files. $THEME->parentsheets = array('styles'); This variable can be used to choose either all of the parent theme's stylesheets or individual files. It has been set to include the styles.css file from the parent theme, namely autumn. Because there is only one stylesheet in the Autumn theme, you can set this variable to True. Either way, you will have the same outcome. Save themeblackandblueconfig.php, and refresh your web browser window. You should see something similar to the following screenshot. Note that your blocks may be different to the ones below, but you can ignore this. What just happened? Okay, so now you have a copy of the standard theme that uses the Autumn theme (by Patrick Malley) as its parent. You might have noticed that the header isn't correct and that the proper Autumn theme header isn't showing. Well, this is because you are essentially using the copy of the standard theme and that the header from this theme is the one that you see above. It's only the CSS files that are included in this hierarchy, so any HTML changes will not be seen until you edit your standard theme's header.html file. Have a go hero – choose another parent theme Go back and have a look through some of the themes on Moodle.org and download one that you like. Add this theme as a parent theme to your blackandblue theme's config.php file, but this time choose which stylesheets you want to use from that theme. The Back to School theme is a good one for this exercise, as its stylesheets are clearly labeled. So you Copying the header and footer files To show that you are using the Autumn theme's CSS files and the standard theme's HTML files, you can just go and copy the header.html and footer.html files from Patrick Malley's Autumn theme and paste them into your blackandblue theme's folder. Don't worry about overwriting your header and footer files, as you can always just copy them again from the ac tual standard theme folder. Time for action – copying the header.html and footer.html files Browse to the Autumn theme's folder and highlight both the header.html and footer.html files by holding down the Ctrl key and clicking on them both. Right-click on the selected files and choose Copy. Browse to your blackandblue theme's folder and right-click and choose Paste. Go back to your browser window and press the F5 button to refresh the page. You will now see the full Autumn theme. What just happened? You have copied the autumn theme's header.html and footer.html files into your blackandblue theme, so you can see the full autumn theme working. You probably will not actually use the header.html and footer.html files that you just copied, as this was just an example of how the Moodle theming process works. So you now have an unmodified copy of the standard theme called blackandblue, which is using the autumn theme as its parent theme. All you need to do now to make changes to this theme is to edit your CSS file in the blackandblue theme folder. Theme folder housework However, there are a couple of things that you need to do first, as you have an exact copy of the standard theme apart from the header.html and footer.html files. This copied folder has files that you do not need, as the only file that you set for your theme to use was the user_styles.css file in the config.php file earlier. This was the first change that you made: $THEME->sheets = array('user_styles'); The user_style.css file does not exist in your blackandblue theme's folder, so you will need to create it. You will also need to delete any other CSS files that are present, as your new blackandblue theme will use only one stylesheet, namely the user_styles.css file that you will be creating in the following sections. Time for action – creating our stylesheet Right-click anywhere in your blackandblue folder and choose New Text Document|. Rename this text document to user_styles.css by right-clicking again and choosing Rename. Time for action – deleting CSS files that we don't need Delete the following CSS files by selecting them and then right-clicking on the selected files and choosing Delete. styles_color.css styles_ie6.css styles_ie6.css styles_ie7.css styles_layout.css styles_moz.css {background: #000000;} What just happened? In the last two tasks, you created an empty CSS file called user_style.css in your blackandblue theme's folder. You then deleted all of the CSS files in your blackandblue theme's folder, as you will no longer need them. Remember, these are just copies of the CSS files in the standard theme folder and you have set your theme to use the standard theme as its base in the blackandblue theme's config.php file. Let's make some changes Now you have set up your theme the way that you want it, that is, you are using your own blackandblue theme by using the standard theme as a base and the Autumn theme as the parent. Move on and make a few changes to your user_style.css file so that you can see what effect this has on your theme, and check that all of your config.php file's settings are correct. Remember that all of the current styles are being inherited from the Autumn theme. Time for action – checking our setup Open up your Moodle site with the current theme (which should be blackandblue but looks like the Autumn theme). Navigate to your blackandblue theme's folder, right-click on the user_style.css file, and choose Open. This file should be completely blank. Type in the following line of CSS for the body element, and then save the fi le: body {background: #000000;} Now refresh your browser window. You will see that the background is now black. Note: When using Firebug to identify styles that are being used, it might not always be obvious where they are or which style is controlling that element of the page. An example of this is the body {background: #000000;}code that we just pasted in our user_style.css file. If we had used Firebug to indentify that style, we would not have found it. Instead, I just took a look at the CSS file from the autumn theme. What I am trying to say here is that there will always be an element of poking around and trial and error. What just happened? All seems fine there, doesn't it? You have added one style declaration to your empty user_style.css file to change the background color, and have checked the changes in your browser. You now know how the parent themes work and know that you only need to copy the styles from Firebug into your user_style.css file and edit the style declarations that need to be changed.
Read more
  • 0
  • 1
  • 8476

article-image-working-dataform-microsoft-silverlight-4
Packt
10 May 2010
9 min read
Save for later

Working with DataForm in Microsoft Silverlight 4

Packt
10 May 2010
9 min read
Displaying and editing an object using the DataForm Letting a user work with groups of related data is a requirement of almost every application. It includes displaying a group of people, editing product details, and so on. These groups of data are generally contained in forms and the Silverlight DataForm (from the Silverlight Toolkit) is just that—a form. In the next few recipes, you'll learn how to work with this DataForm. As of now, let's start off with the basics, that is, displaying and editing the data. Getting ready For this recipe, we're starting with a blank solution, but you do need to install the Silverlight Toolkit as the assemblies containing the DataForm are offered through this. You can download and install it from http://www.codeplex.com/Silverlight/. You can find the completed solution in the Chapter05/Dataform_DisplayAndEdit_Completed folder in the code bundle that is available on the Packt website. How to do it... We're going to create a Person object, which will be displayed through a DataForm. To achieve this, we'll carry out the following steps: Start a new Silverlight solution, name it DataFormExample, and add a reference to System.Windows.Controls.Data.DataForm.Toolkit (from the Silverlight Toolkit). Alternatively, you can drag the DataForm from the Toolbox to the design surface. Open MainPage.xaml and add a namespace import statement at the top of this fi le (in the tag) as shown in the following code. This will allow us to use the DataForm, which resides in the assembly that we've just referenced. Add a DataForm to MainPage.xaml and name it as myDataForm. In the DataForm, set AutoEdit to False and CommandButtonsVisibility to All as shown in the following code: <Grid x_Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="40" ></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock Text="Working with the DataForm" Margin="10" FontSize="14" > </TextBlock> <df:DataForm x_Name="myDataForm" AutoEdit="False" CommandButtonsVisibility="All" Grid.Row="1" Width="400" Height="300" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" > </df:DataForm> </Grid> Add a new class named Person to the Silverlight project having ID, FirstName, LastName, and DateOfBirth as its properties. This class is shown in the following code. We will visualize an instance of the Person class using the DataForm. public class Person { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } } Open MainPage.xaml.cs and add a person property of the Person type to it. Also, create a method named InitializePerson in which we'll initialize this property as shown in the following code: public Person person { get; set; } private void InitializePerson() { person = new Person() { ID = 1, FirstName = "Kevin", LastName = "Dockx", DateOfBirth = new DateTime(1981, 5, 5) }; } Add a call to InitializePerson in the constructor of MainPage.xaml.cs and set the CurrentItem property of the DataForm to a person as shown in the following code: InitializePerson(); myDataForm.CurrentItem = person; You can now build and run your solution. When you do this, you'll see a DataForm that has automatically generated the necessary fields in order to display a person. This can be seen in the following screenshot: How it works... To start off, we needed something to display in our DataForm: a Person entity. This is why we've created the Person class: it will be bound to the DataForm by setting the CurrentItem property to an object of type Person. Doing this will make sure that the DataForm automatically generates the necessary fi elds. It looks at all the public properties of our Person object and generates the correct control depending on the type. A string will be displayed as a TextBox, a Boolean value will be displayed as a CheckBox, and so on. As we have set the CommandButtonsVisibility property on the DataForm to All, we get an Edit icon in the command bar at the top of the DataForm. (Setting AutoEdit to False makes sure that we start in the display mode, rather than the edit mode). When you click on the Edit icon, the DataForm shows the person in the editable mode (using the EditItemTemplate) and an OK button appears. Clicking on the OK button will revert the form to the regular displaying mode. Do keep in mind that the changes you make to the person are persisted immediately in memory (in the case of a TextBox, when it loses focus). If necessary, you can write extra code to persist the Person object from the memory to an underlying datastore by handling the ItemEditEnded event on the DataForm. There's more... At this moment, we've got a DataForm displaying a single item that you can either view or edit. But what if you want to cancel your edit? As of now, the Cancel button appears to be disabled. As the changes you make in the DataForm are immediately persisted to the underlying object in the memory, cancelling the edit would require some extra business logic. Luckily, it's not hard to do. First of all, you'll want to implement the IEditableObject interface on the Person class, which will make sure that cancelling is possible. As a result, the Cancel button will no longer be disabled. The following code is used to implement this: public class Person : IEditableObject { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public void BeginEdit() {} public void CancelEdit() {} public void EndEdit() {} } This interface exposes three methods: BeginEdit, CancelEdit, and EndEdit. If needed, you can write extra business logic in these methods, which is exactly what we need to do. For most applications, you might want to implement only CancelEdit, which would then refetch the person from the underlying data store. In our example, we're going to solve this problem by using a different approach. (You can use this approach if you haven't got an underlying database from which your data can be refetched, or if you don't want to access the database again.) In the BeginEdit method, we save the current property values of the person. When the edit has been cancelled, we put them back to the way they were before. This is shown in the following code: public void BeginEdit() { // save current values tmpPerson = new Person() { ID = this.ID, FirstName = this.FirstName, LastName = this.LastName, DateOfBirth = this.DateOfBirth }; } public void CancelEdit() { // reset values ID = tmpPerson.ID; FirstName = tmpPerson.FirstName; LastName = tmpPerson.LastName; DateOfBirth = tmpPerson.DateOfBirth; } Now, cancelling an edit is possible and it actually reverts to the previous property values. More on DataForm behavior The DataForm exposes various events such as BeginningEdit (when you begin to edit an item), EditEnding (occurs just before an item is saved), and EditEnded (occurs after an item has been saved). It also exposes properties that you can use to defi ne how the DataForm behaves. Validating a DataForm or a DataGrid As you might have noticed, the DataForm includes validation on your fields automatically. For example, try inputting a string value into the ID field. You'll see that an error message appears. This is beyond the scope of this recipe, but more on this will be discussed in the Validating the DataForm recipe. Managing the editing of an object on different levels There are different levels of managing the editing of an object. You can manage this on the control level itself by handling events such as BeginningEdit or ItemEditEnded in the DataForm. Besides that, you can also handle editing on a business level by implementing the IEditableObject interface and providing custom code for the BeginEdit, CancelEdit, or EndEdit methods in the class itself. Depending on the requirements of your application, you can use either of the levels or even both together. See also In this recipe, we've seen how the DataForm is created automatically. For most applications, you require more control over how your fi elds, for example, are displayed. The DataForm is highly customizable, both on a template level (through template customization) and on how the data is generated (through data annotations). If you want to learn about using the DataForm to display or edit a list of items rather than just one, have a look at the next recipe, Displaying and editing a collection using the DataForm. Displaying and editing a collection using the DataForm In the previous recipe, you learned how to work with the basic features of the DataForm. You can now visualize and edit an entity. But in most applications, this isn't enough. Often, you'll want to have an application that shows you a list of items with the ability to add a new item or delete an item from the list. You'll want the application to allow you to edit every item and provide an easy way of navigating between them. A good example of this would be an application that allows you to manage a list of employees. The DataForm can do all of this and most of it is built-in. In this recipe, you'll learn how to achieve this. Getting ready For this recipe, we're starting with the basic setup that we completed in the previous recipe. If you didn't complete that recipe, you can find a starter solution in the Chapter05/ Dataform_Collection_Starter folder in the code bundle that is available on the Packt website. The finished solution for this recipe can be found in the Chapter05/Dataform_ Collection_Completed folder. In any case, you'll need to install the Silverlight Toolkit as the assemblies containing the DataForm are offered through it. You can download and install it from http://www.codeplex.com/Silverlight/.
Read more
  • 0
  • 0
  • 11214
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-mysql-cluster-management-part-1
Packt
10 May 2010
10 min read
Save for later

MySQL Cluster Management : Part 1

Packt
10 May 2010
10 min read
(Read more interesting articles on MySQL High Availability here.) Configuring multiple management nodes Every MySQL Cluster must have a management node to start and also to carry out critical tasks such as allowing other nodes to restart, running online backups, and monitoring the status of the cluster. However, it is strongly recommended for a production cluster to ensure that a management node is always available, and this requires more than one node. In this recipe, we will discuss the minor complications that more than one management node will bring before showing the configuration of a new cluster with two management nodes. Finally, the modification of an existing cluster to add a second management node will be shown. Getting ready In a single management node cluster, everything is simple. Nodes connect to the management node, get a node ID, and join the cluster. When the management node starts, it reads the config.ini file, starts and prepares to give the cluster information contained within the config.ini file out to the cluster nodes as and when they join. This process can become slightly more complicated when there are multiple management nodes, and it is important that each management node takes a different ID. Therefore, the first additional complication is that it is an extremely good idea to specify node IDs and ensure that the HostName parameter is set for each management node in the config.ini file. It is technically possible to start two management nodes with different cluster configuration files in a cluster with multiple management nodes. It is not difficult to see that this can cause all sorts of bizarre behavior including a likely cluster shutdown in the case of the primary management node failing. Ensure that every time the config.ini file is changed, the change is correctly replicated to all management nodes. You should also ensure that all management nodes are always using the same version of the config.ini file. It is possible to hold the config.ini file on a shared location such as a NFS share, although to avoid introducing complexity and a single point of failure, the best practice would be to store the configuration file in a configuration management system such as Puppet (http://www.puppetlabs.com/) or Cfengine (http://www.cfengine.org/). How to do it... The following process should be followed to configure a cluster for multiple management nodes. In this recipe, High Availability with MySQL Cluster. Initially, this recipe will cover the procedure to be followed in order to configure a new cluster with two management nodes. Thereafter, the procedure for adding a second management node to an already running single management node cluster will be covered. The first step is to define two management nodes in the global configuration file config.ini on both management nodes. In this example, we are using IP addresses 10.0.0.5 and 10.0.0.6 for the two management nodes that require the following two entries of [ndb_mgmd] in the config.ini file: [ndb_mgmd]Id=1HostName=10.0.0.5DataDir=/var/lib/mysql-cluster[ndb_mgmd]Id=2HostName=10.0.0.6DataDir=/var/lib/mysql-cluster Update the [mysqld] section of each SQL node's /etc/my.cnf to point to both management nodes: [mysqld]ndb-connectstring=10.0.0.5,10.0.0.6 Update the [mysqld] section of each SQL node's /etc/my.cnf to point to both management nodes: [mysqld]ndb-connectstring=10.0.0.5,10.0.0.6 Now, prepare to start both the management nodes. Install the management node on both nodes, if it does not already exist. Before proceeding, ensure that you have copied the updated config.ini file to both management nodes. Start the first management node by changing to the correct directory and running the management node binary (ndb_mgmd) with the following flags: --initial: Deletes the local cache of the config.ini file and updates it (you must do this every time the config.ini file is changed). --ndb-nodeid=X: Tells the node to connect as this nodeid, as we specified in the config.ini file. This is technically unnecessary if there is no ambiguity as to which nodeid this particular node may connect to (in this case, both nodes have a HostName defined). However, defining it reduces the possibility of confusion. --config-file=config.ini: This is used to specify the configuration file. In theory, passing a value of the config.ini file in the local directory is unnecessary because it is the default value. But in certain situations, it seems that passing this in any case avoids issues, and again this reduces the possibility of confusion. [root@node6 mysql-cluster]# cd /usr/local/mysql-cluster[root@node6 mysql-cluster]# ndb_mgmd --config-file=config.ini --initial --ndb-nodeid=22009-08-15 20:49:21 [MgmSrvr] INFO -- NDB Cluster Management Server. mysql-5.1.34 ndb-7.0.62009-08-15 20:49:21 [MgmSrvr] INFO -- Reading cluster configuration from 'config.ini' Repeat this command on the other node using the correct node ID: [root@node5 mysql-cluster]# cd /usr/local/mysql-cluster[root@node5 mysql-cluster]# ndb_mgmd --config-file=config.ini --initial --ndb-nodeid=1 Now, start each storage node in turn. Use the storage management client's show command to show that both management nodes are connected and that all storage nodes have been reconnected: ndb_mgm> showConnected to Management Server at: 10.0.0.5:1186Cluster Configuration---------------------[ndbd(NDB)] 4 node(s)id=3 @10.0.0.1 (mysql-5.1.34 ndb-7.0.6, Nodegroup: 0, Master)id=4 @10.0.0.2 (mysql-5.1.34 ndb-7.0.6, Nodegroup: 0)id=5 @10.0.0.3 (mysql-5.1.34 ndb-7.0.6, Nodegroup: 1)id=6 @10.0.0.4 (mysql-5.1.34 ndb-7.0.6, Nodegroup: 1)[ndb_mgmd(MGM)] 2 node(s)id=1 @10.0.0.5 (mysql-5.1.34 ndb-7.0.6)id=2 @10.0.0.6 (mysql-5.1.34 ndb-7.0.6)[mysqld(API)] 4 node(s)id=11 @10.0.0.1 (mysql-5.1.34 ndb-7.0.6)id=12 @10.0.0.2 (mysql-5.1.34 ndb-7.0.6)id=13 @10.0.0.3 (mysql-5.1.34 ndb-7.0.6)id=14 @10.0.0.4 (mysql-5.1.34 ndb-7.0.6) Finally, restart all SQL nodes (mysqld processes). On RedHat-based systems, this can be achieved using the service command: [root@node1 ~]# service mysqld restart Congratulations! Your cluster is now configured with multiple management nodes. Test that failover works by killing a management node, in turn, the remaining management nodes should continue to work. There's more... It is sometimes necessary to add a management node to an existing cluster if for example, due to a lack of hardware or time, an initial cluster only has a single management node. Adding a management node is simple. Firstly, install the management client on the new node . Secondly, modify the config.ini file, as shown earlier in this recipe for adding the new management node, and copy this new config.ini file to both management nodes. Finally, stop the existing management node and start the new one using the following commands: For the existing management node, type: [root@node6 mysql-cluster]# killall ndb_mgmd [root@node6 mysql-cluster]# ndb_mgmd --config-file=config.ini --initial --ndb-nodeid=22009-08-15 21:29:53 [MgmSrvr] INFO -- NDB Cluster Management Server. mysql-5.1.34 ndb-7.0.62009-08-15 21:29:53 [MgmSrvr] INFO -- Reading cluster configuration from 'config.ini' Then type the following command for the new management node: [root@node5 mysql-cluster]# ndb_mgmd --config-file=config.ini --initial --ndb-nodeid=12009-08-15 21:29:53 [MgmSrvr] INFO -- NDB Cluster Management Server. mysql-5.1.34 ndb-7.0.62009-08-15 21:29:53 [MgmSrvr] INFO -- Reading cluster configuration from 'config.ini'torage node one at a time. Ensure that you only stop one node per nodegroup at a time and wait for it to fully restart before taking another node in the nodegroup, when offline, in order to avoid any downtime. See also Look at the section for the online addition of storage nodes (discussed later in this article) for further details on restarting storage nodes one at a time. Obtaining usage information This recipe explains how to monitor the usage of a MySQL Cluster, looking at the memory, CPU, IO, and network utilization on storage nodes. Getting ready MySQL Cluster is extremely memory-intensive. When a MySQL Cluster starts, the storage nodes will start using the entire DataMemory and IndexMemory allocated to them. In a production cluster with a large amount of RAM, it is likely that this will include a large proportion of the physical memory on the server. How to do it... An essential part of managing a MySQL Cluster is looking into what is happening inside each storage node. In this section, we will cover the vital commands used to monitor a cluster. To monitor the memory (RAM) usage of the nodes within the cluster, execute the &ltnodeid> REPORT MemoryUsage command within the management client as follows: ndb_mgm> 3 REPORT MemoryUsageNode 3: Data usage is 0%(21 32K pages of total 98304)Node 3: Index usage is 0%(13 8K pages of total 131104) This command can be executed for all storage nodes rather than just one by using ALL nodeid: ndb_mgm> ALL REPORT MemoryUsageNode 3: Data usage is 0%(21 32K pages of total 98304)Node 3: Index usage is 0%(13 8K pages of total 131104)Node 4: Data usage is 0%(21 32K pages of total 98304)Node 4: Index usage is 0%(13 8K pages of total 131104)Node 5: Data usage is 0%(21 32K pages of total 98304)Node 5: Index usage is 0%(13 8K pages of total 131104)Node 6: Data usage is 0%(21 32K pages of total 98304)Node 6: Index usage is 0%(13 8K pages of total 131104) This information shows that these nodes are actually using 0% of their DataMemory and IndexMemory. Memory allocation is important and unfortunately a little more complicated than a percentage used on each node. There is more detail about this in the How it works... section of this recipe, but the vital points to remember are: It is a good idea never to go over 80 percent of memory usage (particularly not for DataMemory) In the case of a cluster with a very high memory usage, it is possible that a cluster will not restart correctly MySQL Cluster storage nodes make extensive use of disk storage unless specifically configured not to, regardless of whether a cluster is using disk-based tables. It is important to ensure the following: There is sufficient storage available There is sufficient IO bandwidth for the storage node and the latency is not too high To confirm the disk usage on Linux, use the command df –h as follows: [root@node1 mysql-cluster]# df -hFilesystem Size Used Avail Use% Mounted on/dev/mapper/system-root7.6G 2.0G 5.3G 28% //dev/xvda1 99M 21M 74M 22% /boottmpfs 2.0G 0 2.0G 0% /dev/shm/dev/mapper/system-ndb_data2.0G 83M 1.8G 5% /var/lib/mysql-cluster/dev/mapper/system-ndb_backups2.0G 68M 1.9G 4% /var/lib/mysql-cluster/BACKUPS In this example, the cluster data directory and backup directory are on different logical volumes. This provides the following benefits: It is easy to see their usage (5% for data and 4% for backups) Each volume is isolated from other partitions or logical volumes—it means that they are protected from, let's say, a logfile growing in the logs directory To confirm the rate at which the kernel is writing to and reading from the disk, use the vmstat command: [root@node1 ~]# vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------r b swpd free buff cache si so bi bo in cs ussy id wa st0 0 0 2978804 324784 353856 0 0 1 121 39 15 00 100 0 03 0 0 2978804 324784 353856 0 0 0 0 497 620 00 99 0 10 0 0 2978804 324784 353856 0 0 0 172 529 665 00 100 0 0 The bi and bo columns represent the blocks read from a disk and blocks written to a disk, respectively. The first line can be ignored (it's the average since boot), and the number passed to the command, in this case, the refresh rate in seconds. By using a tool such as bonnie (refer to the See also section at the end of this recipe) to establish the potential of each block device, you can then check to see the maximum proportion of each block device is currently being used. At times of high stress, like during a hot backup, if the disk utilization is too high it is potentially possible that the storage node will start spending a lot of time in the iowait state—this will reduce performance and should be avoided. One way to avoid this is by using a separate block device (that is, disk or raid controller) for the backups mount point.
Read more
  • 0
  • 0
  • 2689

article-image-mysql-cluster-management-part-2
Packt
10 May 2010
11 min read
Save for later

MySQL Cluster Management : Part 2

Packt
10 May 2010
11 min read
Replication between clusters with a backup channel The previous recipe showed how to connect a MySQL Cluster to another MySQL server or another MySQL Cluster using a single replication channel. Obviously, this means that this replication channel has a single point of failure (if either of the two replication agents {machines} fail, the channel goes down). If you are designing your disaster recovery plan to rely on MySQL Cluster replication, then you are likely to want more reliability than that. One simple thing that we can do is run multiple replication channels between two clusters. With this setup, in the event of a replication channel failing, a single command can be executed on one of the backup channel slaves to continue the channel. It is not currently possible to automate this process (at least, not without scripting it yourself). The idea is that with a second channel ready and good monitoring of the primary channel, you can quickly bring up the replication channel in the case of failure, which means significantly less time spent with the replication channel down. How to do it… Setting up this process is not vastly different, however, it is vital to ensure that both channels are not running at any one time, or the data at the slave site will become a mess and the replication will stop. To guarantee this, the first step is to add the following to the mysqld section of /etc/my.cnf on all slave MySQL Servers (of which there are likely to be two): skip-slave-start Once added, restart mysqld. This my.cnf parameter prevents the MySQL Server from automatically starting the slave process. You should start one of the channels (normally, whichever channel you decide will be your master) normally, while following the steps in the previous recipe. To configure the second slave, follow the instructions in the previous recipe, but stop just prior to the CHANGE MASTER TO step on the second (backup) slave. If you configure two replication channels simultaneously (that is, forget to stop the existing replication channel when testing the backup), you will end up with a broken setup. Do not proceed to run CHANGE MASTER TO on the backup slave unless the primary channel is not operating. As soon as the primary communication channel fails, you should execute the following command on any one of the SQL nodes in your slave (destination) cluster and record the result: [slave] mysql> SELECT MAX(epoch) FROM mysql.ndb_apply_status;+---------------+| MAX(epoch) |+---------------+| 5952824672272 |+---------------+1 row in set (0.00 sec) The previous highlighted number is the ID of the most recent global checkpoint, which is run every couple of seconds on all storage nodes in the master cluster and as a result, all the REDO logs are synced to disk. Checking this number on a SQL node in the slave cluster tells you what the last global checkpoint that made it to the slave cluster was. You can run a similar command SELECT MAX(epoch) FROM mysql.ndb_binlog_index on any SQL node in the master (source) cluster to find out what the most recent global checkpoint on the master cluster is. Clearly, if your replication channel goes down, then these two numbers will diverge quickly. Use this number (5952824672272 in our example) to find the correct logfile and position that you should connect to. You can do this by executing the following command on any SQL node in the master (source) cluster that you plan to make the new master, ensuring that you substitute the output of the previous command with the correct number as an epoch field as follows: mysql> SELECT-> File,-> Position-> FROM mysql.ndb_binlog_index-> WHERE epoch > 5952824672272-> ORDER BY epoch ASC LIMIT 1;+--------------------+----------+| File | Position |+--------------------+----------+| ./node2-bin.000003 | 200998 |+--------------------+----------+1 row in set (0.00 sec) If this returns NULL, firstly, ensure that there is some activity in your cluster since the failure (if you are using batched updates, then there should be 32 KB of updates or more) and secondly, ensure that there is no active replication channel between the nodes (that is, ensure the primary channel has really failed). Using the filename and position mentioned previously, run the following command on the backup slave: It is critical that you run these commands on the correct node. The previous command, from which you get the filename and position, must be run on the new master (this is in the "source" cluster). The following command, which tells the new slave which master to connect to and its relevant position and filename, must be executed on the new slave (this is the "destination" cluster). While it is technically possible to connect the old slave to a new master or vice versa, this configuration is not recommended by MySQL and should not be used. If all is okay, then the highlighted rows in the preceding output will show that the slave thread is running and waiting for the master to send an event. [NEW slave] mysql> CHANGE MASTER TO MASTER_HOST='10.0.0.2', MASTER_USER='slave', MASTER_PASSWORD='password', MASTER_LOG_FILE='node2-bin.000003', MASTER_LOG_POS=200998;Query OK, 0 rows affected (0.01 sec)mysql> START SLAVE;Query OK, 0 rows affected (0.00 sec)mysql> show slave statusG;*************************** 1. row ***************************Slave_IO_State: Waiting for master to send eventMaster_Host: 10.0.0.2Master_User: slaveMaster_Port: 3306[snip]Relay_Master_Log_File: node2-bin.000003Slave_IO_Running: YesSlave_SQL_Running: YesReplicate_Do_DB:Replicate_Ignore_DB:Replicate_Do_Table:Replicate_Ignore_Table:[snip]Seconds_Behind_Master: 233 After a while, the Seconds_Behind_Master value should return to 0 (if the primary replication channel has been down for some time or if the master cluster has a very high write rate, then this may take some time) There's more… It is possible to increase the performance of MySQL Cluster replication by enabling batched updates. This can be accomplished by starting slave mysqld processes with the slave-allow-batching option (or add the slave-allow-batching option line to the [mysqld] section in my.cnf). This has the effect of applying updates in 32 KB batches rather than as soon as they are received, which generally results in lower CPU usage and higher throughput (particularly when the mean update size is low). See also To know more about Replication Compatibility Between MySQL Versions visit: http://dev.mysql.com/doc/refman/5.1/en/replication-compatibility.html User-defined partitioning MySQL Cluster vertically partitions data, based on the primary key, unless you configure it otherwise. The main aim of user-defined partitioning is to increase performance by grouping data likely to be involved in common queries onto a single node, thus reducing network traffic between nodes while satisfying queries. In this recipe, we will show how to define our own partitioning functions. If the NoOfReplicas in the global cluster configuration file is equal to the number of storage nodes, then each storage node contains a complete copy of the cluster data and there is no partitioning involved. Partitioning is only involved when there are more storage nodes than replicas. Getting ready Look at the City table in the world dataset; there are two integer fields (ID and Population). MySQL Cluster will choose ID as the default partitioning scheme as follows: mysql> desc City;+-------------+----------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------------+----------+------+-----+---------+----------------+| ID | int(11) | NO | PRI | NULL | auto_increment || Name | char(35) | NO | | | || CountryCode | char(3) | NO | | | || District | char(20) | NO | | | || Population | int(11) | NO | | 0 | |+-------------+----------+------+-----+---------+----------------+5 rows in set (0.00 sec) Therefore, a query that searches for a specific ID will use only one partition. In the following example, partition p3 is used: mysql> explain partitions select * from City where ID=1;+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+-------+| 1 | SIMPLE | City | p3 | const | PRIMARY | PRIMARY | 4 | const | 1 | |+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+-------+1 row in set (0.00 sec) However, searching for a Population involves searching all partitions as follows: mysql> explain partitions select * from City where Population=42;+----+-------------+-------+-------------+------+---------------+------+---------+------+------+-----------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+-------------+------+---------------+------+---------+------+------+-----------+| 1 | SIMPLE | City | p0,p1,p2,p3 | ALL | NULL | NULL | NULL | NULL | 4079 | Using where with pushed condition |+----+-------------+-------+-------------+------+---------------+------+---------+------+------+-----------+1 row in set (0.01 sec) The first thing to do when considering user-defined partitioning is to decide if you can improve on the default partitioning scheme. In this case, if your application makes a lot of queries against this table specifying the City ID, it is unlikely that you can improve performance with user-defined partitioning. However, in case it makes a lot of queries by the Population and ID fields, it is likely that you can improve performance by switching the partitioning function from a hash of the primary key to a hash of the primary key and the Population field. How to do it... In this example, we are going to add the field Population to the partitioning function used by MySQL Cluster. We will add this field to the primary key rather than solely using this field. This is because the City table has an auto-increment field on the ID field, and in MySQL Cluster, an auto-increment field must be part of the primary key. Firstly, modify the primary key in the table to add the field that we will use to partition the table by: mysql> ALTER TABLE City DROP PRIMARY KEY, ADD PRIMARY KEY(ID, Population);Query OK, 4079 rows affected (2.61 sec)Records: 4079 Duplicates: 0 Warnings: 0 Now, tell MySQL Cluster to use the Population field as a partitioning function as follows: mysql> ALTER TABLE City partition by key (Population);Query OK, 4079 rows affected (2.84 sec)Records: 4079 Duplicates: 0 Warnings: 0 Now, verify that queries executed against this table only use one partition as follows: mysql> explain partitions select * from City where Population=42;+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------+| 1 | SIMPLE | City | p3 | ALL | NULL | NULL | NULL | NULL | 4079 | Using where with pushed condition |+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------+1 row in set (0.01 sec) Now, notice that queries against the old partitioning function, ID, use all partitions as follows: mysql> explain partitions select * from City where ID=1;+----+-------------+-------+-------------+------+---------------+---------+---------+-------+------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+-------------+------+---------------+---------+---------+-------+------+-------+| 1 | SIMPLE | City | p0,p1,p2,p3 | ref | PRIMARY | PRIMARY | 4 | const | 10 | |+----+-------------+-------+-------------+------+---------------+---------+---------+-------+------+-------+1 row in set (0.00 sec) Congratulations! You have now set up user-defined partitioning. Now, benchmark your application to see if you have gained an increase in performance. There's more... User-defined partitioning can be particularly useful where you have multiple tables and a join. For example, if you had a table of Areas within Cities consisting of an ID field (primary key, auto increment, and default partitioning field) and then a City ID, you would likely find an enormous number of queries that select all of the locations within a certain city and also select the relevant city row. It would therefore make sense to keep: all of the rows with the same City value inside the Areas table together on one node each of these groups of City values inside the Areas table on the same node as the relevant City row in the City table This can be achieved by configuring both tables to use the City field as a partitioning function, as described earlier in the Population field.
Read more
  • 0
  • 0
  • 1639

article-image-working-binding-data-and-ui-elements-silverlight-4
Packt
10 May 2010
6 min read
Save for later

Working with Binding data and UI elements in Silverlight 4

Packt
10 May 2010
6 min read
Binding data to another UI element Sometimes, the value of the property of an element is directly dependent on the value of the property of another element. In this case, you can create a binding in XAML called an element binding or element-to-element binding . This binding links both values. If needed, the data can flow bidirectionally. In the banking application, we can add a loan calculator that allows the user to select an amount and the number of years in which they intend to pay the loan back to the bank, including (of course) a lot of interest. Getting ready To follow this recipe, you can either continue with your solution from the previous recipe or use the provided solution that can be found in the Chapter02/SilverlightBanking_ Element_Binding_Starter folder in the code bundle that is available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Element_Binding_Completed folder. How to do it... To build the loan calculator, we'll use Slider controls. Each Slider is bound to a TextBlock using an element-to-element binding to display the actual value. Let's take a look at the steps we need to follow to create this binding: We will build the loan calculator as a separate screen in the application. Add a new child window called LoanCalculation.xaml. To do so, right-click on the Silverlight project in the Solution Explorer, select Add | New Item..., and choose Silverlight Child Window under Visual C#. Within MainPage.xaml, add a Click event on the LoanCalculationButton as shown in the following code: <Button x_Name="LoanCalculationButton" Click="LoanCalculationButton_Click" /> In the code-behind's event handler for this Click event, we can trigger the display of this new screen with the following code: private void LoanCalculationButton_Click(object sender, RoutedEventArgs e) { LoanCalculation loanCalculation = new LoanCalculation(); loanCalculation.Show(); } The UI of the LoanCalculation.xaml is quite simple—it contains two Slider controls. Each Slider control has set values for its Minimum and Maximum values (not all UI code is included here; the complete listing can be found in the finished sample code) as shown in the following code: <Slider x_Name="AmountSlider" Minimum="10000" Maximum="1000000" SmallChange="10000" LargeChange="10000" Width="300" > </Slider> <Slider x_Name="YearSlider" Minimum="5" Maximum="30" SmallChange="1" LargeChange="1" Width="300" UseLayoutRounding="True"> </Slider> As dragging a Slider does not give us proper knowledge of where we are exactly between the two values, we add two TextBlock controls. We want the TextBlock controls to show the current value of the Slider control, even while dragging. This can be done by specifying an element-to-element binding as shown in the following code: <TextBlock x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value}"> </TextBlock> <TextBlock x_Name="MonthTextBlock" Text="{Binding ElementName=YearSlider, Path=Value}"> </TextBlock> Add a Button that will perform the actual calculation called CalculateButton and a TextBlock called PaybackTextBlock to show the results. This can be done using the following code: <Button x_Name="CalculateButton" Content="Calculate" Click="CalculateButton_Click"> </Button> <TextBlock x_Name="PaybackTextBlock"></TextBlock> The code for the actual calculation that is executed when the Calculate button is clicked uses the actual value for either the Slider or the TextBlock. This is shown in the following code: private double percentage = 0.0345; private void CalculateButton_Click(object sender, RoutedEventArgs e) { double requestedAmount = AmountSlider.Value; int requestedYears = (int)YearSlider.Value; for (int i = 0; i < requestedYears; i++) { requestedAmount += requestedAmount * percentage; } double monthlyPayback = requestedAmount / (requestedYears * 12); PaybackTextBlock.Text = "€" + Math.Round(monthlyPayback, 2); } Having carried out the previous steps, we now have successfully linked the value of the Slider controls and the text of the TextBlock controls. The following screenshot shows the LoanCalculation.xaml screen as it is included in the finished sample code containing some extra markup: How it works... An element binding links two properties of two controls directly from XAML. It allows creating a Binding where the source object is another control. For this to work, we need to create a Binding and specify the source control using the ElementName property. This is shown in the following code: <TextBlock Text="{Binding ElementName=YearSlider, Path=Value}" > </TextBlock> Element bindings were added in Silverlight 3. Silverlight 2 did not support this type of binding. There's more... An element binding can also work in both directions, that is, from source to target and vice versa. This can be achieved by specifying the Mode property on the Binding and setting it to TwoWay. The following is the code for this. In this code, we replaced the TextBlock by a TextBox. When entering a value in the latter, the Slider will adjust its position: <TextBox x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value, Mode=TwoWay}" > </TextBox> Element bindings without bindings Achieving the same effect in Silverlight 2—which does not support this feature—is also possible, but only through the use of an event handler as shown in the following code. Element bindings eliminate this need: private void AmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { AmountSlider.Value = Math.Round(e.NewValue); AmountTextBlock.Text = AmountSlider.Value.ToString(); } See also Element-to-element bindings can be easily extended to use converters. For more information on TwoWay bindings, take a look at the Using the different modes of data binding to allow persisting data recipe in this article. Binding collections to UI elements Often, you'll want to display lists of data in your application such as a list of shopping items, a list of users, a list of bank accounts, and so on. Such a list typically contains a bunch of items of a certain type that have the same properties and need to be displayed in the same fashion. We can use data binding to easily bind a collection to a Silverlight control (such as a ListBox or DataGrid) and use the same data binding possibilities to defi ne how every item in the collection should be bound. This recipe will show you how to achieve this. Getting ready For this recipe, you can fi nd the starter solution in the Chapter02/SilverlightBanking_ Binding_Collections_Starter folder and the completed solution in the Chapter02/SilverlightBanking_Binding_Collections_Completed folder in the code bundle that is available on the Packt website.
Read more
  • 0
  • 0
  • 4518

article-image-introduction-data-binding
Packt
10 May 2010
10 min read
Save for later

Introduction to Data Binding

Packt
10 May 2010
10 min read
Introduction Data binding allows us to build data-driven applications in Silverlight in a much easier and much faster way compared to old-school methods of displaying and editing data. This article and the following one take a look at how data binding works. We'll start by looking at the general concepts of data binding in Silverlight 4 in this article. Analyzing the term data binding immediately reveals its intentions. It is a technique that allows us to bind properties of controls to objects or collections thereof. The concept is, in fact, not new. Technologies such as ASP.NET, Windows Forms, and even older technologies such as MFC (Microsoft Foundation Classes) include data binding features. However, WPF's data binding platform has changed the way we perform data binding; it allows loosely coupled bindings. The BindingsSource control in Windows Forms has to know of the type we are binding to, at design time. WPF's built-in data binding mechanism does not. We simply defi ne to which property of the source the target should bind. And at runtime, the actual data—the object to which we are binding—is linked. Luckily for us, Silverlight inherits almost all data binding features from WPF and thus has a rich way of displaying data. A binding is defined by four items: The source or source object: This is the data we are binding to. The data that is used in data binding scenarios is in-memory data, that is, objects. Data binding itself has nothing to do with the actual data access. It works with the objects that are a result of reading from a database or communicating with a service. A typical example is a Customer object. A property on the source object: This can, for example, be the Name property of the Customer object. The target control: This is normally a visual control such as a TextBox or a ListBox control. In general, the target can be a DependencyObject. In Silverlight 2 and Silverlight 3, the target had to derive from FrameworkElement; this left out some important types such as transformations. A property on the target control: This will, in some way—directly or after a conversion—display the data from the property on the source. The data binding process can be summarized in the following image: In the previous image, we can see that the data binding engine is also capable of synchronization. This means that data binding is capable of updating the display of data automatically. If the value of the source changes, Silverlight will change the value of the target as well without us having to write a single line of code. Data binding isn't a complete black box either. There are hooks in the process, so we can perform custom actions on the data fl owing from source to target, and vice versa. These hooks are the converters. Our applications can still be created without data binding. However, the manual process—that is getting data and setting all values manually on controls from code-behind—is error prone and tedious to write. Using the data-binding features in Silverlight, we will be able to write more maintainable code faster. In this article, we'll explore how data binding works. We'll start by building a small data-driven application, which contains the most important data binding features, to get a grasp of the general concepts. We'll also see that data binding isn't tied to just binding single objects to an interface; binding an entire collection of objects is supported as well. We'll also be looking at the binding modes. They allow us to specify how the data will flow (from source to target, target to source, or both). We'll finish this article series by looking at the support that Blend 4 provides to build applications that use data binding features. In the recipes of this article and the following one, we'll assume that we are building a simple banking application using Silverlight. Each of the recipes in this article will highlight a part of this application where the specific feature comes into play. The following screenshot shows the resulting Silverlight banking application: Displaying data in Silverlight applications When building Silverlight applications, we often need to display data to the end user. Applications such as an online store with a catalogue and a shopping cart, an online banking application and so on, need to display data of some sort. Silverlight contains a rich data binding platform that will help us to write data-driven applications faster and using less code. In this recipe, we'll build a form that displays the data of the owner of a bank account using data binding. Getting ready To follow along with this recipe, you can use the starter solution located in the Chapter02/ SilverlightBanking_Displaying_Data_Starter folder in the code bundle available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Displaying_Data_Completed folder. How to do it... Let's assume that we are building a form, part of an online banking application, in which we can view the details of the owner of the account. Instead of wiring up the fields of the owner manually, we'll use data binding. To get data binding up and running, carry out the following steps: Open the starter solution, as outlined in the Getting Ready section. The form we are building will bind to data. Data in data binding is in-memory data, not the data that lives in a database (it can originate from a database though). The data to which we are binding is an instance of the Owner class. The following is the code for the class. Add this code in a new class fi le called Owner in the Silverlight project. public class Owner{public int OwnerId { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public string Address { get; set; }public string ZipCode { get; set; }public string City { get; set; }public string State { get; set; }public string Country { get; set; }public DateTime BirthDate { get; set; }public DateTime CustomerSince { get; set; }public string ImageName { get; set; }public DateTime LastActivityDate { get; set; }public double CurrentBalance { get; set; }public double LastActivityAmount { get; set; }} Now that we've created the class, we are able to create an instance of it in the MainPage.xaml.cs file, the code-behind class of MainPage.xaml. In the constructor, we call the InitializeOwner method, which creates an instance of the Owner class and populates its properties. private Owner owner;public MainPage(){InitializeComponent();//initialize owner dataInitializeOwner();}private void InitializeOwner(){owner = new Owner();owner.OwnerId = 1234567;owner.FirstName = "John";owner.LastName = "Smith";owner.Address = "Oxford Street 24";owner.ZipCode = "W1A";owner.City = "London";owner.Country = "United Kingdom";owner.State = "NA";owner.ImageName = "man.jpg";owner.LastActivityAmount = 100;owner.LastActivityDate = DateTime.Today;owner.CurrentBalance = 1234.56;owner.BirthDate = new DateTime(1953, 6, 9);owner.CustomerSince = new DateTime(1999, 12, 20);} Let's now focus on the form itself and build its UI. For this sample, we're not making the data editable. So for every field of the Owner class, we'll use a TextBlock. To arrange the controls on the screen, we'll use a Grid called OwnerDetailsGrid. This Grid can be placed inside the LayoutRoot Grid.We will want the Text property of each TextBlock to be bound to a specifi c property of the Owner instance. This can be done by specifying this binding using the Binding "markup extension" on this property. <Grid x_Name="OwnerDetailsGrid"VerticalAlignment="Stretch"HorizontalAlignment="Left"Background="LightGray"Margin="3 5 0 0"Width="300" ><Grid.RowDefinitions><RowDefinition Height="100"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="*"></RowDefinition></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Image x_Name="OwnerImage"Grid.Row="0"Width="100"Height="100"Stretch="Uniform"HorizontalAlignment="Left"Margin="3"Source="/CustomerImages/man.jpg"Grid.ColumnSpan="2"></Image><TextBlock x_Name="OwnerIdTextBlock"Grid.Row="1"FontWeight="Bold"Margin="2"Text="Owner ID:"></TextBlock><TextBlock x_Name="FirstNameTextBlock"Grid.Row="2"FontWeight="Bold"Margin="2"Text="First name:"></TextBlock><TextBlock x_Name="LastNameTextBlock"Grid.Row="3"FontWeight="Bold"Margin="2"Text="Last name:"></TextBlock><TextBlock x_Name="AddressTextBlock"Grid.Row="4"FontWeight="Bold"Margin="2"Text="Adress:"></TextBlock><TextBlock x_Name="ZipCodeTextBlock"Grid.Row="5"FontWeight="Bold"Margin="2"Text="Zip code:"></TextBlock><TextBlock x_Name="CityTextBlock"Grid.Row="6"FontWeight="Bold"Margin="2"Text="City:"></TextBlock><TextBlock x_Name="StateTextBlock"Grid.Row="7"FontWeight="Bold"Margin="2"Text="State:"></TextBlock><TextBlock x_Name="CountryTextBlock"Grid.Row="8"FontWeight="Bold"Margin="2"Text="Country:"></TextBlock><TextBlock x_Name="BirthDateTextBlock"Grid.Row="9"FontWeight="Bold"Margin="2"Text="Birthdate:"></TextBlock><TextBlock x_Name="CustomerSinceTextBlock"Grid.Row="10"FontWeight="Bold"Margin="2"Text="Customer since:"></TextBlock><TextBlock x_Name="OwnerIdValueTextBlock"Grid.Row="1"Grid.Column="1"Margin="2"Text="{Binding OwnerId}"></TextBlock><TextBlock x_Name="FirstNameValueTextBlock"Grid.Row="2"Grid.Column="1"Margin="2"Text="{Binding FirstName}"></TextBlock><TextBlock x_Name="LastNameValueTextBlock"Grid.Row="3"Grid.Column="1"Margin="2"Text="{Binding LastName}"></TextBlock><TextBlock x_Name="AddressValueTextBlock"Grid.Row="4"Grid.Column="1"Margin="2"Text="{Binding Address}"></TextBlock><TextBlock x_Name="ZipCodeValueTextBlock"Grid.Row="5"Grid.Column="1"Margin="2"Text="{Binding ZipCode}"></TextBlock><TextBlock x_Name="CityValueTextBlock"Grid.Row="6"Grid.Column="1"Margin="2"Text="{Binding City}"></TextBlock><TextBlock x_Name="StateValueTextBlock"Grid.Row="7"Grid.Column="1"Margin="2"Text="{Binding State}"></TextBlock><TextBlock x_Name="CountryValueTextBlock"Grid.Row="8"Grid.Column="1"Margin="2"Text="{Binding Country}"></TextBlock><TextBlock x_Name="BirthDateValueTextBlock"Grid.Row="9"Grid.Column="1"Margin="2"Text="{Binding BirthDate}"></TextBlock><TextBlock x_Name="CustomerSinceValueTextBlock"Grid.Row="10"Grid.Column="1"Margin="2"Text="{Binding CustomerSince}"></TextBlock><Button x_Name="OwnerDetailsEditButton"Grid.Row="11"Grid.ColumnSpan="2"Margin="3"Content="Edit details..."HorizontalAlignment="Right"VerticalAlignment="Top"></Button><TextBlock x_Name="CurrentBalanceValueTextBlock"Grid.Row="12"Grid.Column="1"Margin="2"Text="{Binding CurrentBalance}" ></TextBlock><TextBlock x_Name="LastActivityDateValueTextBlock"Grid.Row="13"Grid.Column="1"Margin="2"Text="{Binding LastActivityDate}" ></TextBlock><TextBlock x_Name="LastActivityAmountValueTextBlock"Grid.Row="14"Grid.Column="1"Margin="2"Text="{Binding LastActivityAmount}" ></TextBlock></Grid> At this point, all the controls know what property they need to bind to. However, we haven't specifi ed the actual link. The controls don't know about the Owner instance we want them to bind to. Therefore, we can use DataContext. We specify the DataContext of the OwnerDetailsGrid to be the Owner instance. Each control within that container can then access the object and bind to its properties . Setting the DataContext in done using the following code: public MainPage(){InitializeComponent();//initialize owner dataInitializeOwner();OwnerDetailsGrid.DataContext = owner;} The result can be seen in the following screenshot:
Read more
  • 0
  • 0
  • 7072
article-image-configuration-release-and-change-management-oracle
Packt
07 May 2010
9 min read
Save for later

Configuration, Release and Change Management with Oracle

Packt
07 May 2010
9 min read
One of the largest changes to Oracle is the recent acquisition of several other software lines and technologies. Oracle has combined all of these technologies and customers under a single support site called My Oracle Support at http://support.oracle. com, effective from Fall 2009. Along the way, Oracle also completely redesigned the interface, making it flash-based in order to provide a personalized GUI. To take full advantage of the personalization features, you will need to install a free utility on each node and each ORACLE_HOME you would like to monitor. The following paragraphs outline several reasons for use and suggestions for getting started. Configuration management Are you the only Oracle DBA in your company? How do you provide disaster recovery and redundancy for personnel in that situation? MOS has a tool that provides an Automatic Document Repository (my words) called Oracle Configuration Manager (OCM). The real purpose of this tool is to manage all of your configurations (different systems, servers, databases, application servers) when dealing with Oracle support. It is automatic in the sense that if you are out of the office, temporarily or permanently, the system configurations are available for viewing by anyone with the same Oracle Customer Support Identifier (CSI) number . The information is also available to Oracle support personnel. The repository is located on My Oracle Support. The systems are for you to choose, whether you want to only include production and/or non-production systems. What information does OCM collect and upload? It contains extensive hardware details, software installs (not just Oracle products), databases, and Oracle application servers. There is enough information to help in recreating your site if there is a complete disaster. The GUI interface allows managers and other IT personnel to see how nodes and applications are related and how they fit into your architectural framework. The information can only be updated by the upload process. Using OCM in disconnected mode with masking There is sensitive information being collected from the OCM tool. If you are employed by an organization that doesn't allow you to reveal such information or allow direct access by the servers to the Internet, there are steps to improve the security of this upload process. This section is highly recommended to be reviewed before enabling OCM. You must know what types of information are there and how that information is used before enabling uploading capabilities to a support website. To disable the collection of IP and MAC addresses, you add the following entries to the $ORACLE_HOME/ccr/config/collector.properties file. To disable the collection of network addresses, add the following entry: ccr.metric.host.ecm_hw_nic.inet_address=false To disable the collection of the MAC address, add the following entry: ccr.metric.host.ecm_hw_nic.mac_address=false The OCM collector collects the schema usernames for databases configured for configuration collections. The collection of this information is filtered or masked when ccr.metric.oracle_database.db_users.username is assigned the value of 'mask' in the $ORACLE_HOME/ccr/config/collector.properties file. The default behavior of the collector is to not mask this data. MOS customers may request deletion of their configuration information by logging a Service Request (SR) indicating the specific configuration information and scope of the deletion request. Disconnected mode is carried out with something called Oracle Support Hub, which is installed at your site. This hub is configured as a local secure site for direct uploads from your nodes, which the hub can then upload to MOS through the Internet. This protects each of your nodes from any type of direct Internet access. Finally, there is a way to do a manual upload of a single node using the method outlined in the MOS document 763142.1: How to upload the collection file ocmconfig.jar to My Oracle Support for Oracle Configuration Manager (OCM) running in Disconnected Mode. This is probably the safest method to use for OCM. Run it for a specific purpose with appropriate masking built-in and then request the information to be deleted by entering a SR request. These tips came from these locations as well as the OCM licensing agreement found on MOS: http://www.oracle.com/support/collateral/customersupport- security-practices.pdf http://download.oracle.com/docs/html/E12881_01/toc.htm The Oracle Support Hub can by found on the OCM Companion Distribution Disk at: http://www.oracle.com/technology/ documentation/ocm.html. Each node with an installed OCM collector can be automated to upload any changes on a daily basis or interval of your choice. OCM is now an optional part of any of the 10.2.0.4+ Oracle Product GUI installs. The OCM collector is also found by logging into MOS and selecting the collector tab. It is recommended to use at least the 3.2 version for ease of installation across the enterprise. Be aware! The collector install actually creates the Unix cron entry to automatically schedule the uploads. Mass deployment utility The OCM collector utility has been out for over a year, but a recent enhancement makes installation easier with a mass deployment utility. On the MOS collector tab, find Configuration Manager Repeater & Mass Deployment Tools and the OCM Companion Distribution Guide. The template file required to install the collector on multiple servers is in csv format, which you may find difficult to edit using vi or vim. The template doesn't have an initial entry and the length is wider than the average session window. Once the first entry is filed out (try using desktop spreadsheet software), editing this file with a command-line tool is easier. It has a secure password feature so that no password is stored in clear text. You can enter a password at the prompt or allow the password utility to encrypt the open text passwords in the template file during the install run. Running the utility runs very quickly from a single node that has SSH access to all entries in the template. It auto detects if OCM was already installed and bypasses any of those entries. You may encounter an issue where the required JAVA version is higher than what is installed. Other prerequisites include SSH on Linux or CYGWIN for Windows. A downside is that all configuration information is available to everyone with the same CSI number. In a small IT shop, this isn't a problem as long as MOS access is maintained properly when personnel changes. Providing granular group access within a CSI number to your uploaded configurations is a highly anticipated feature. Release management As a DBA you must be consistent in the different aspects of administration. This takes dedication to keep all of your installed Oracle products up-to-date on critical patches. Most DBAs keep up-to-date with production down issues that require a patch install. But what about the quarterly security fixes? The operating systems that your system admin is in charge of will probably be patched more regularly than Oracle. Why is that the case? It seems to take an inordinate amount of effort to accomplish what appears to be a small task. Newer versions of Oracle are associated with major enhancements—as shown by the differences between versions 11.1 and 11.2. Patch sets contain at least all the cumulative bug fixes for a particular version of Oracle and an occasional enhancement as shown in the version difference between 11.1.0.6 and 11.1.0.7. Oracle will stop supporting certain versions, indicating which is the most stable version (labeling it as the terminal release). For example, the terminal release of Oracle 10.1.x is 10.1.0.5, as that was the last patch set released. See the following document on MOS for further information on releases—Oracle Server (RDBMS) Releases Support Status Summary [Doc ID: 161818.1]. In addition to applying patch sets on a regular basis (usually an annual event) to keep current with bug fixes, there are other types of patches released on a regular basis. Consider these to be post-patch set patches. There is some confusing information from MOS, with two different methods of patching on a quarterly basis (Jan, April, July, Oct.)—Patch Set Updates and Critical Patch Updates. CPUs only contain security bug fixes. The newer method of patching—PSU—includes not only the security fixes but other major bugs. These are tested as a single unit and contain bug fixes that have been applied in customers' production environments. See the following for help in identifying a database version in relationship to PSUs: MOS Doc ID 850471.1 1st digit-Major release number 2nd digit-Maintenance release 3rd digit-Application server release 4th digit-Release component specific 5th digit-Platform specific release First PSU for Oracle Database Version-10.2.0.4.1 Second PSU for Oracle Database Version-10.2.0.4.2 While either PSUs or CPUs can be applied to a new or existing system, Oracle recommends that you stick to one type. If you have applied CPUs in the past and want to continue—that is one path. If you have applied CPUs in the past and now want to apply a PSU, you must now only apply PSUs from this point to prevent conflicts. Switching back and forth will cause problems and ongoing issues with further installs, and it requires significant effort to start down this path. You may need a merge patch when migrating from a current CPU environment, called a Merge Request on MOS. Important information on differences between CPUs and PSUs can be found in the following locations. If there is a document number, then that is found on the MOS support site: http://blogs.oracle.com/gridautomation/ http://www.oracle/technology/deploy/security/alerts. htm Doc 864316.1 Application of PSU can be automated through Deployment Procedures Doc 854428.1 Intro to Patch Set Updates Doc 756388.1 Recommended Patches Upgrade Companions 466181.1, 601807.1 Error Correction Policy 209768.1 Now to make things even more complicated for someone new to Oracle; let's discuss recommended patches. These are released between the quarterly PSUs and CPUs with common issues for targeted configurations . The following are targeted configurations: Generic—General database use Real Application Clusters and CRS—For running multiple instances on a single database with accompanying Oracle Clusterware software DataGuard (and/or Streams)—Oracle Redo Apply technology for moving data to a standby database or another read/write database Exadata—Vendor-specific HP hardware storage solution for Oracle Ebusiness Suite Certification—Oracle's version of Business Applications, which runs on an Oracle Database Recommended patches are tested as a single combined unit, reducing some of the risk involved with multiple patches. They are meant to stabilize production environments, hopefully saving time and cost with known issues starting with Oracle Database Release 10.2.0.3—see Doc ID: 756671.1.
Read more
  • 0
  • 0
  • 2555

article-image-oracle-when-use-log-miner
Packt
07 May 2010
6 min read
Save for later

Oracle: When to use Log Miner

Packt
07 May 2010
6 min read
Log Miner has both a GUI interface in OEM as well as the database package, DBMS_LOGMNR. When this utility is used by the DBA, its primary focus is to mine data from the online and archived redo logs. Internally Oracle uses the Log Miner technology for several other features, such as Flashback Transaction Backout, Streams, and Logical Standby Databases. This section is not on how to run Log Miner, but looks at the task of identifying the information to restore. The Log Miner utility comes into play when you need to retrieve an older version of selected pieces of data without completely recovering the entire database. A complete recovery is usually a drastic measure that means downtime for all users and the possibility of lost transactions. Most often Log Miner is used for recovery purposes when the data consists of just a few tables or a single code change. Make sure supplemental logging is turned on (see the Add Supplemental Logging section). In this case, you discover that one or more of the following conditions apply when trying to recover a small amount of data that was recently changed: Flashback is not enabled Flashback logs that are needed are no longer available Data that is needed is not available in the online redo logs Data that is needed has been overwritten in the undo segments Go to the last place available: archived redo logs. This requires the database to be in archivelog mode and for all archive logs that are needed to still be available or recoverable. Identifying the data needed to restore One of the hardest parts of restoring data is determining what to restore, the basic question being when did the bad data become part of the collective? Think the Borg from Star Trek! When you need to execute Log Miner to retrieve data from a production database, you will need to act fast. The older the transactions the longer it will take to recover and traverse with Log Miner. The newest (committed) transactions are processed first, proceeding backwards. The first question to ask is when do you think the bad event happened? Searching for data can be done in several different ways: SCN, timestamp, or log sequence number> Pseudo column ORA_ROWSCN SCN, timestamp, or log sequence number If you are lucky, the application also writes a timestamp of when the data was last changed. If that is the case, then you determine the archive log to mine by using the following queries. It is important to set the session NLS_DATE_FORMAT so that the time element is displayed along with the date, otherwise you will just get the default date format of DD-MMM-RR. The data format comes from the database startup parameters— the NLS_TERRITORY setting. Find the time when a log was archived and match that to the archive log needed. Pseudo column ORA_ROWSCN While this method seems very elegant, it does not work perfectly, meaning it won't always return the correct answer. As it may not work every time or accurately, it is generally not recommended for Flashback Transaction Queries. It is definitely worth trying to narrow the window that you will have to search. It uses the SCN information that was stored for the associated transaction in the Interested Transaction List. You know that delayed block cleanout is involved. The pseudo column ORA_ROWSCN contains information for the approximate time this table was updated for each row. In the following example the table has three rows, with the last row being the one that was most recently updated. It gives me the time window to search the archive logs with Log Miner. Log Miner is the basic technology behind several of the database Maximum Availability Architecture capabilities—Logical Standby, Streams, and the following Flashback Transaction Backout exercise. Flashback Transaction Query and Backout Flashback technology was first introduced in Oracle9i Database. This feature allows you to view data at different points in time and with more recent timestamps (versions), and thus provides the capability to recover previous versions of data. In this article, we are dealing with Flashback Transaction Query (FTQ) and Flashback Transaction Backout (FTB), because they both deal with transaction IDs and integrate with the Log Miner utility. See the MOS document: "What Do All 10g Flashback Features Rely on and what are their Limitations?" (Doc ID 435998.1). Flashback Transaction Query uses the transaction ID (Xid) that is stored with each row version in a Flashback Versions Query to display every transaction that changed the row. Currently, the only Flashback technology that can be used when the object(s) in question have been changed by DDL is Flashback Data Archive. There are other restrictions to using FTB with certain data types (VARRAYs, BFILES), which match the data type restrictions for Log Miner. This basically means if data types aren't supported, then you can't use Log Miner to find the undo and redo log entries. When would you use FTQ or FTB instead of the previously described methods? The answer is when the data involves several tables with multiple constraints or extensive amounts of information. Similar to Log Miner, the database can be up and running while people are working online in other schemas of the database to accomplish this restore task. An example of using FTB or FTQ would be to reverse a payroll batch job that was run with the wrong parameters. Most often a batch job is a compiled code (like C or Cobol) run against the database, with parameters built in by the application vendor. A wrong parameter could be the wrong payroll period, wrong set of employees, wrong tax calculations, or payroll deductions. Enabling flashback logs First off all flashback needs to be enabled in the database. Oracle Flashback is the database technology intended for a point-in-time recovery (PITR) by saving transactions in flashback logs. A flashback log is a temporary Oracle file and is required to be stored in the FRA, as it cannot be backed up to any other media. Extensive information on all of the ramifications of enabling flashback is found in the documentation labeled: Oracle Database Backup and Recovery User's Guide. See the following section for an example of how to enable flashback: SYS@NEWDB>ALTER SYSTEM SET DB_RECOVERY_FILE_DEST='/backup/flash_recovery_area/NEWDB' SCOPE=BOTH;SYS@NEWDB>ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE=100M SCOPE=BOTH;--this is sized for a small test databaseSYS@NEWDB> SHUTDOWN IMMEDIATE;SYS@NEWDB> STARTUP MOUNT EXCLUSIVE;SYS@NEWDB> ALTER DATABASE FLASHBACK ON;SYS@NEWDB> ALTER DATABASE OPEN;SYS@NEWDB> SHOW PARAMETER RECOVERY; The following query would then verify that FLASHBACK had been turned on: SYS@NEWDB>SELECT FLASHBACK_ON FROM V$DATABASE;
Read more
  • 0
  • 0
  • 4101

article-image-blender-249-scripting-impression-using-different-mesh-each-frame-object
Packt
07 May 2010
7 min read
Save for later

Blender 2.49 Scripting: Impression using Different Mesh on Each Frame of Object

Packt
07 May 2010
7 min read
(Read more interesting articles on Blender 2.49 Scripting here.) Revisiting mesh—making an impression The following illustration gives some impression of what is possible. The tracks are created by animating a rolling car tire on a subdivided plane: In the following part, we will refer to the object mesh being deformed as the source and the object, or objects, doing the deforming as targets. In a sense, this is much like a constraint and we might have implemented these deformations as pycontraints. However, that wouldn't be feasible because constraints get evaluated each time the source or targets move; thereby causing the user interface to come to a grinding halt as calculating the intersections and the resulting deformation of meshes is computationally intensive. Therefore, we choose an approach where we calculate and cache the results each time the frame is changed. Our script will have to serve several functions, it must: Calculate and cache the deformations on each frame change Change vertex coordinates when cached information is present And when run standalone, the script should: Save or restore the original mesh Prompt the user for targets Associate itself as a script link with the source object Possibly remove itself as a script link An important consideration in designing the script is how we will store or cache the original mesh and the intermediate, deformed meshes. Because we will not change the topology of the mesh (that is, the way vertices are connected to each other), but just the vertex coordinates, it will be sufficient to store just those coordinates. That leaves us with the question: where to store this information. If we do not want to write our own persistent storage solution, we have two options: Use Blender's registry Associate the data with the source object as a property Blender's registry is easy to use but we must have some method of associating the data with an object because it is possible that the user might want to associate more than one object with an impression calculation. We could use the name of the object as a key, but if the user would change that name, we would lose the reference with the stored information while the script link functionality would still be there. This would leave the user responsible for removing the stored data if the name of the object was changed. Associating all data as a property would not suffer from any renaming and the data would be cleared when the object is deleted, but the types of data that may be stored in a property are limited to an integer, a floating point value, or a string. There are ways to convert arbitrary data to strings by using Python's standard pickle module, but, unfortunately, this scenario is thwarted by two problems: Vertex coordinates in Blender are Vector instances and these do not support the pickle protocol The size of string properties is limited to 127 characters and that is far too small to store even a single frame of vertex coordinates for a moderately sized mesh Despite the drawbacks of using the registry, we will use it to devise two functions—one to store vertex coordinates for a given frame number and one to retrieve that data and apply it to the vertices of the mesh. First, we define a utility function ckey() that will return a key to use with the registry functions based on the name of the object whose mesh data we want to cache(download full code from here): def ckey(ob): return meshcache+ob.name Not all registries are the sameDo not confuse Blender's registry with the Windows registry. Both serve the similar purpose of providing a persistent storage for all sorts of data, but both are distinct entities. The actual data for Blender registry items that are written to disk resides in .blender/scripts/bpydata/config/ by default and this location may be altered by setting the datadir property with Blender.Set(). Our storemesh() function will take an object and a frame number as arguments. Its first action is to extract just the vertex coordinates from the mesh data associated with the object. Next, it retrieves any data stored in Blender's registry for the object that we are dealing with and we pass the extra True parameter to indicate that if there is no data present in memory, GetKey() should check for it on disk. If there is no data stored for our object whatsoever, GetKey() will return None, in which case we initialize our cache to an empty dictionary. Subsequently, we store our mesh coordinates in this dictionary indexed by the frame number (highlighted in the next code snippet). We convert this integer frame number to a string to be used as the actual key because Blender's SetKey() function assumes all of the keys to be strings when saving registry data to disk, and will raise an exception if it encounters an integer. The final line calls SetKey() again with an extra True argument to indicate that we want the data to be stored to disk as well. def storemesh(ob,frame): coords = [(v.co.x,v.co.y,v.co.z) for v in ob.getData().verts] d=Blender.Registry.GetKey(ckey(ob),True) if d == None: d={} d[str(frame)]=coords Blender.Registry.SetKey(ckey(ob),d,True) The retrievemesh() function will take an object and a frame number as arguments. If it finds cached data for the given object and frame, it will assign the stored vertex coordinates to vertices in the mesh. We first define two new exceptions to indicate some specific error conditions retrievemesh() may encounter: class NoSuchProperty(RuntimeError): pass;class NoFrameCached(RuntimeError): pass; retrievemesh() will raise the NoSuchProperty exception if the object has no associated cached mesh data and a NoFrameCached exception if the data is present but not for the indicated frame. The highlighted line in the next code deserves some attention. We fetch the associated mesh data of the object with mesh=True. This will yield a wrapped mesh, not a copy, so any vertex data we access or alter will refer to the actual data. Also, we encounter Python's built-in zip() function that will take two lists and returns a list consisting of tuples of two elements, one from each list. It effectively lets us traverse two lists in parallel. In our case, these lists are a list of vertices and a list of coordinates and we simply convert these coordinates to vectors and assign them to the co-attribute of each vertex: def retrievemesh(ob,frame): d=Blender.Registry.GetKey(ckey(ob),True) if d == None: raise NoSuchProperty("no property %s for object %s" %(meshcache,ob.name)) try: coords = d[str(frame)] except KeyError: raise NoFrameCached("frame %d not cached on object %s" %(frame,ob.name)) for v,c in zip(ob.getData(mesh=True).verts,coords): v.co = Blender.Mathutils.Vector(c) To complete our set of cache functions we define a function clearcache() that will attempt to remove the registry data associated with our object. The try … except … clause will ensure that the absence of stored data is silently ignored: def clearcache(ob): try: Blender.Registry.RemoveKey(ckey(ob)) except: pass
Read more
  • 0
  • 0
  • 5219
article-image-blender-249-scripting-animating-visibility-objects
Packt
07 May 2010
8 min read
Save for later

Blender 2.49 Scripting: Animating the Visibility of objects

Packt
07 May 2010
8 min read
(Read more interesting articles on Blender 2.49 Scripting here.) Script links are scripts that may be associated with Blender objects (Meshes, Cameras, and so on, but also Scenes and World objects) and that can be set up to run automatically on the following occasions: Just before rendering a frame Just after rendering a frame When a frame is changed When an object is updated When the object data is updated Scene objects may have script links associated with them that may be invoked on two additional occasions: On loading a .blend file On saving a .blend file Space handlers are Python scripts that are invoked each time the 3D view window is redrawn or a key or mouse action is detected. Their primary use is to extend the capabilities of Blender's user interface. Animating the visibility of objects An often recurring issue in making an animation is the wish to make an object disappear or fade away at a certain frame, either for the sake of the effect itself or to replace the object by another one to achieve some dramatic impact (such as an explosion or a bunny rabbit changing into a ball). There are many ways to engineer these effects, and most of them are not specifically tied to script links reacting on a frame change (many can simply be keyed as well). Nevertheless, we will look at two techniques that may easily be adapted to all sorts of situations, even ones that are not easily keyed. For example, we demand some specific behavior of a parameter that is easy to formulate in an expression but awkward to catch in an IPO. Fading a material Our first example will change the diffuse color of a material. It would be just as simple to change the transparency, but it is easier to see changes in diffuse color in illustrations. Our goal is to fade the diffuse color from black to white and back again, spaced over a period of two seconds. We therefore define a function setcolor() that takes a material and changes its diffuse color (the rgbColor attribute). It assumes a frame rate of 25 frames per second and, therefore, the first line fetches the current frame number and performs a modulo operation to determine what fraction of the current whole second is elapsed. The highlighted line in the following code snippet determines whether we are in an odd or even second. If we are in an even second, we ramp up the diffuse color to white so we just keep our computed fraction. If we are in an odd second, we tone down the diffuse color to black so we subtract the fraction from the maximum possible value (25). Finally, we scale our value to lie between 0 and 1 and assign it to all three color components to obtain a shade of gray: import Blenderdef setcolor(mat): s = Blender.Get('curframe')%25 if int(Blender.Get('curframe')/25.0)%2 == 0: c = s else: c = 25-s c /= 25.0 mat.rgbCol = [c,c,c]if Blender.bylink and Blender.event == 'FrameChanged': setcolor(Blender.link) The script ends with an important check: Blender.bylink is True only if this script is called as a script handler and in that case Blender.event holds the event type. We only want to act on frame changes so that is what we check for here. If these conditions are satisfied, we pass Blender.link to our setcolor() function as it holds the object our scriptlink script is associated with—in this case that will be a Material object. (This script is available as MaterialScriptLink.py in scriptlinks.blend- download full code from here) The next thing on our list is to associate the script with the object whose material we want to change. We therefore select the object and in the Buttons Window we select the Script panel. In the Scriptlinks tab, we enable script links and select the MaterialScriptLinks button. (If there is no MaterialScriptLinks button then the selected object has no material assigned to it. Make sure it has.) There should now be a label Select Script link visible with a New button. Clicking on New will show a dropdown with available script links (files in the text editor). In this case, we will select MaterialScriptLink.py and we are done. We can now test our script link by changing the frame in the 3D view (with the arrow keys). The color of our object should change with the changing frame number. (If the color doesn't seem to change, check whether solid or shaded viewing is on in the 3D view.) Changing layers If we want to change the visibility of an object, changing the layer(s) it is assigned to is a more general and powerful technique than changing material properties. Changing its assigned layer has, for instance, the advantage that we can make the object completely invisible for lamps that are configured to illuminate only certain layers and many aspects of an animation (for example, deflection of particles by force fields) may be limited to certain layers as well. Also, changing layers is not limited to objects with associated materials. You can just as easily change the layer of a Lamp or Camera. For our next example, we want to assign an object to layer 1 if the number of elapsed seconds is even and to layer 2 if the number of seconds is odd. The script to implement this is very similar to our material changing script. The real work is done by the function setlayer(). The first line calculates the layer the object should be on in the current frame and the next line (highlighted) assigns the list of layer indices (consisting of a single layer in this case) to the layers attribute of the object. The final two lines of the setlayer() function ensure that the layer's change is actually visible in Blender. import Blenderdef setlayer(ob): layer = 1+int(Blender.Get('curframe')/25.0)%2 ob.layers = [ layer ] ob.makeDisplayList() Blender.Window.RedrawAll()if Blender.bylink and Blender.event == 'FrameChanged': setlayer(Blender.link) As in our previous script, the final lines of our script check whether we are called as a script link and on a frame change event, and if so, pass the associated object to the setlayer() function. (The script is available as OddEvenScriptlink.py in scriptlinks.blend.) All that is left to do is to assign the script as a scriptlink to a selected object. Again, this is accomplished in the Buttons Window | Script panel by clicking on Enabling Script Links in the Scriptlinks tab (if necessary, it might still be selected because of our previous example. It is a global choice, that is, it is enabled or disabled for all objects). This time, we select the object scriptlinks instead of the material scriptlinks and click on New to select OddEvenScriptlink.py from the dropdown. Countdown—animating a timer with script links One of the possibilities of using a script link that acts on frame changes is the ability to modify the actual mesh either by changing the vertices of a Mesh object or by associating a completely different mesh with a Blender object. This is not possible when using IPOs as these are limited to shape keys that interpolate between predefined shapes with the same mesh topology (the same number of vertices connected in the same way). The same is true for curves and text objects. One application of that technique is to implement a counter object that will display the number of seconds since the start of the animation. This is accomplished by changing the text of a Text3d object by way of its setText() method. The setcounter() function in the following code does exactly that together with the necessary actions to update Blender's display. (The script is available as CounterScriptLink.py in scriptlinks.blend.) import Blenderobjectname='Counter'scriptname='CounterScriptLink.py'def setcounter(counterob): seconds = int(Blender.Get('curframe')/25.0)+1 counterob.getData().setText(str(seconds)) counterob.makeDisplayList() Blender.Window.RedrawAll()if Blender.bylink: setcounter(Blender.link)else: countertxt = Blender.Text3d.New(objectname) scn = Blender.Scene.GetCurrent() counterob = scn.objects.new(countertxt) setcounter(counterob) counterob.clearScriptLinks([scriptname]) counterob.addScriptLink(scriptname,'FrameChanged') This script may be associated as a script link with any Text3d object as shown before. However, if run with Alt + P from the text editor it will create a new Text3d object and will associate itself to this object as a script link. The highlighted lines show how we check for this just like in the previous scripts, but in this case we take some action when not called as a script link as well (the else clause). The final two highlighted lines show how we associate the script with the newly created object. First, we remove (clear) any script links with the same name that might have been associated earlier. This is done to prevent associating the same script link more than once, which is valid but hardly useful. Next, we add the script as a script link that will be called when a frame change occurs. The screenshot shows the 3D view with a frame from the animation together with the Buttons window (top-left) that lists the association of the script link with the object. Note that although it is possible to associate a script link with a Blender object from within a Python script, script links must be enabled manually for them to actually run! (In the ScriptLinks tab.) There is no functionality in the Blender Python API to do this from a script.
Read more
  • 0
  • 0
  • 4471

article-image-creating-and-modifying-filters-moodle-19
Packt
06 May 2010
6 min read
Save for later

Creating and Modifying Filters in Moodle 1.9

Packt
06 May 2010
6 min read
Moodle filters modify content from the database as it is output to the screen, thus adding function to the display. An example of this is the multimedia filter, which can detect references to video and audio files, and can replace them with a "mini-player" embedded in the content. How a filter works Before trying to build a filter, it would help to understand how it works. To begin with, any text written to the screen in Moodle should be processed through the format_text function. The purpose of this function is to process the text, such that it is always safe to be displayed. This means making sure there are no security issues and that any HTML used contains only allowed tags. Additionally, the output is run through the filter_text function, and this is the function we are interested in. This function takes the text destined for the screen, and applies all enabled filters to it. The resulting text will be the result of all of these filters. filter_text applies each enabled filter to the text in the order defined in the filter configuration screen (shown in the following screenshot). The order is important; each filter will be fed the output of the previous filter's text. So it is always possible that one filter may change the text in a way that impacts the next filter. Building a filter Now it's time to build our own filter. To begin with, let's come up with a requirement. Let's assume that our organization, called "Learning is Fun", has a main website at http://2fun2learn.org. Now, we need any instance of the phrase learning is fun to be hyperlinked to the website URL every time it appears on the screen, as in the forum post shown in the following screenshots: We can do this by implementing a policy with our content creators that forces them to create hyperlink tags around the phrase every time they write it. However, this will be difficult to enforce and will be fraught with errors. Instead, wouldn't it be easier if the system itself could recognize the phrase and create the hyperlink for us? That's what our filter will do. Getting started We need a name for our filter. It is the name that will be used for the directory the filter will reside in. We want a name that will describe what our filter does and will be unlikely to conflict with any other filter name. Let's call it "learningisfunlink". To start with, create a new subdirectory in the /filter directory and call it learningisfunlink. Next, create a new file called filter.php. This is the only file required for a filter. Open the new filter.php file in your development environment. The filter only requires one function, which is named after the filter name and suffixed with _filter. Add the PHP open and close tags (<?php and ?>), and an empty function called learningisfunlink_filter that takes two arguments: a course ID and the text to filter. When completed, you should have a file that looks like this: <?phpfunction learningisfunlink_filter($courseid, $text) {return $text;}?> We now have the bare minimum required for the filter to be recognized by the system. It doesn't do what we want yet, but it will be present. Creating the language file Log in to the site (that makes use of your new filter) as an administrator. On the main page of your site, look for the Modules Filters| folder in the Site Administration block. Click on the Manage filters link. If you have the default filter setup, you will see your new filter near the bottom of the list, called Learningisfunlink, as shown in the following screenshot: Now, even though the name is reasonably descriptive, it will be better if it were a phrase similar to the others in the list; something like Main website link. To do this, we need to create a new directory in our /filter/learningisfunlink directory called lang/en_utf8/ (the en_utf8 is the language specific part—English in this case). In this directory, we create a new file called filter_learningisfunlink.php. This name is the concatenation of the phrase filter_ and the name of our filter. In this file, we need to add the following line: $string['filtername'] = "Main website link"; This language string defines the text that will be displayed as the name of our filter, replacing the phrase Learningisfunlink that we saw earlier with Main website link. This file will contain any other strings that we may output to the screen, specifically for this filter. Once we have created this file, returning to the Manage filters page should now show our filter with the name that we provided for it in our language file. Creating the filter code We now have a filter that is recognized by the system and that displays the name we want it to. However, we haven't made it do anything. Let's create the code to add some functionality. Remember, what we want this filter to do is to search the text and add a hyperlink pointing to our website for all occurrences of the phrase "learning is fun". We could simply perform a search and replace function on the text and return it, and that would be perfectly valid. However, for the sake of learning more about the Moodle API, we'll use some functions that are set up specifically for filters. To that end, we'll look at two code constructs: the filterobject class and the filter_phrases function, both of which are contained in the /lib/filterlib.php file. The filterobject class defines an object that contains all of the information required by the filter_phrases function to change the text to the way the filter wants it to be. It contains the phrase to be filtered, the tag to start the replacement with, the tag to end the replacement with, whether to match case, whether a full match is required, and any replacement text for the match. An array of filterobjects is sent to the filter_phrases function, along with the text to search in. It's intended to be used when you have a number of phrases and replacements to apply at one time, but we'll use it anyway. Let's initialize our filter strings: $searchphrase = "learning is fun";$starttag = "<a href="http://2fun2learn.org">";$endtag = "</a>"; Now, let's create our filterobject: $filterobjects = array();$filterobjects[] = new filterobject($searchphrase, $starttag, $endtag); Lastly, let's pass the structure to the filter_phrases function, along with the text to be filtered: $text = filter_phrases($text, $filterobjects); Our function now has the code to change any occurrence of the phrase "learning is fun" to a hyperlinked phrase. Let's go test it
Read more
  • 0
  • 0
  • 2576
Modal Close icon
Modal Close icon