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

7019 Articles
article-image-user-interaction-and-email-automation-symfony-13-part2
Packt
18 Nov 2009
8 min read
Save for later

User Interaction and Email Automation in Symfony 1.3: Part2

Packt
18 Nov 2009
8 min read
Automated email responses Symfony comes with a default mailer library that is based on Swift Mailer 4, the detailed documentation is available from their web site at http://swiftmailer.org. After a user has signed up to our mailing list, we would like an email verification to be sent to the user's email address. This will inform the user that he/she has signed up, and will also ask him or her to activate their subscription. To use the library, we have to complete the following three steps: Store the mailing settings in the application settings file. Add the application logic to the action. Create the email template. Adding the mailer settings to the application Just like all the previous settings, we should add all the settings for sending emails to the module.yml file for the signup module. This will make it easier to implement any modifications required later. Initially, we should set variables like the email subject, the from name, the from address, and whether we want to send out emails within the dev environment. I have added the following items to our signup module's setting file, apps/frontend/config/module.yml: dev: mailer_deliver: true all: mailer_deliver: true mailer_subject: Milkshake Newsletter mailer_from_name: Tim mailer_from_email: no-reply@milkshake All of the settings can be contained under the all label. However, you can see that I have introduced a new label called dev. These labels represent the environments, and we have just added a specific variable to the dev environment. This setting will allow us to eventually turn off the sending of emails while in the dev environment. Creating the application logic Triggering the email should occur after the user's details have been saved to the database. To demonstrate this, I have added the highlighted amends to the submit action in the apps/frontend/modules/signup/actions/actions.class.php file, as shown in the following code: public function executeSubmit(sfWebRequest $request) { $this->form = new NewsletterSignupForm(); if ($request->isMethod('post') && $this->form-> bindAndSave($request->getParameter($this->form-> getName()))) { //Include the swift lib require_once('lib/vendor/swift-mailer/lib/swift_init.php'); try{ //Sendmail $transport = Swift_SendmailTransport::newInstance(); $mailBody = $this->getPartial('activationEmail', array('name' => $this->form->getValue('first_name'))); $mailer = Swift_Mailer::newInstance($transport); $message = Swift_Message::newInstance(); $message->setSubject(sfConfig::get('app_mailer_subject')); $message->setFrom(array(sfConfig:: get('app_mailer_from_email') => sfConfig::get('app_mailer_from_name'))); $message->setTo(array($this->form->getValue('email')=> $this-> form->getValue('first_name'))); $message->setBody($mailBody, 'text/html'); if(sfConfig::get('app_mailer_deliver')) { $result = $mailer->send($message); } } catch(Exception $e) { var_dump($e); exit; } $this->redirect('@signup'); } //Use the index template as it contains the form $this->setTemplate('index'); } Symfony comes with a sfMailer class that extends Swift_Mailer. To send mails you could simply implement the following Symfony method: $this->getMailer()->composeAndSend('from@example.com', 'to@example.com', 'Subject', 'Body'); Let's walk through the process: Instantiate the Swift Mailer. Retrieve the email template (which we will create next) using the $this->getPartial('activationEmail', array('name' => $this->form->getValue('first_name'))) method. Breaking this down, the function itself retrieves a partial template. The first argument is the name of the template to retrieve (that is activationEmail in our example) which, if you remember, means that the template will be called _activationEmail.php. The next argument is an array that contains variables related to the partial template. Here, I have set a name variable. The value for the name is important. Notice how I have used the value within the form object to retrieve the first_name value. This is because we know that these values have been cleaned and are safe to use. Set the subject, from, to, and the body items. These functions are Swift Mailer specific: setSubject(): It takes a string as an argument for the subject setFrom(): It takes the name and the mailing address setTo(): It takes the name and the mailing address setBody(): It takes the email body and mime type. Here we passed in our template and set the email to text/html Finally we send the email. There are more methods in Swift Mailer. Check out the documentation on the Swift Mailer web site (http://swiftmailer.org/). The partial email template Lastly, we need to create a partial template that will be used in the email body. In the templates folder of the signup module, create a file called _activationEmail.php and add the following code to it: Hi <?php echo $name; ?>, <br /><br /> Thank you for signing up to our newsletter. <br /><br /> Thank you, <br /> <strong>The Team</strong> The partial is no different from a regular template. We could have opted to pass on the body as a string, but using the template keeps our code uniform. Our signup process now incorporates the functionality to send an email. The purpose of this example is to show you how to send an automated email using a third-party library. For a real application, you should most certainly implement a two-phase option wherein the user must verify his or her action. Flashing temporary values Sometimes it is necessary to set a temporary variable for one request, or make a variable available to another action after forwarding but before having to delete the variable. Symfony provides this level of functionality within the sfUser object known as a flash variable. Once a flash variable has been set, it lasts until the end of the overall request before it is automatically destroyed. Setting and getting a flash attribute is managed through two of the sfUser methods. Also, you can test for a flash variable's existence using the third method of the methods listed here: $this->getUser()->setFlash($name, $value, $persist = true) $this->getUser()->getFlash($name) $this->getUser()->hasFlash($name) Although a flash variable will be available by default when a request is forwarded to another action, setting the argument to false will delete the flash variable before it is forwarded. To demonstrate how useful flash variables can be, let's readdress the signup form. After a user submits the signup form, the form is redisplayed. I further mentioned that you could create another action to handle a 'thank you' template. However, by using a flash variable we will not have to do so. As a part of the application logic for the form submission, we can set a flash variable. Then after the action redirects the request, the template can test whether there is a flash variable set. If there is one, the template should show a message rather than the form. Let's add the $this->getUser()->setFlash() function to the submit action in the apps/frontend/modules/signup/actions/actions.class.php file: //Include the swift lib require_once('lib/vendor/swift-mailer/lib/swift_init.php'); //set Flash $this->getUser()->setFlash('Form', 'completed'); try{ I have added the flash variable just under the require_once() statement. After the user has submitted a valid form, this flash variable will be set with the name of the Form and have a value completed. Next, we need to address the template logic. The template needs to check whether a flash variable called Form is set. If it is not set, the template shows the form. Otherwise it shows a thank you message. This is implemented using the following code: <?php if(!$sf_user->hasFlash('Form')): ?> <form action="<?php echo url_for('@signup_submit') ?>" method="post" name="Newsletter"> <div style="height: 30px;"> <div style="width: 150px; float: left"> <?php echo $form['first_name']->renderLabel() ?></div> <?php echo $form['first_name']->render(($form['first_name']-> hasError())? array('class'=>'boxError'): array ('class'=>'box')) ?> <?php echo ($form['first_name']->hasError())? ' <span class="errorMessage">* '.$form['first_name']->getError(). '</span>': '' ?> <div style="clear: both"></div> </div> .... </form> <?php else: ?><h1>Thank you</h1>You are now signed up.<?php endif ?> The form is now wrapped inside an if/else block. Accessing the flash variables from a template is done through $sf_user. To test if the variable has been set, I have used the hasFlash() method, $sf_user->hasFlash('Form'). The else part of the statement contains the text rather than the form. Now if you submit your form, you will see the result as shown in the following screenshot: We have now implemented an entire module for a user to sign up for our newsletter. Wouldn't it be really good if we could add this module to another application without all the copying, pasting, and fixing?
Read more
  • 0
  • 0
  • 8654

article-image-ground-sql-azure-migration-using-ms-sql-server-integration-services
Packt
18 Nov 2009
5 min read
Save for later

Ground to SQL Azure migration using MS SQL Server Integration Services

Packt
18 Nov 2009
5 min read
Enterprise data can be of very different kinds ranging from flat files to data stored in relational databases with the recent trend of storing data in XML data sources. The extraordinary number of database related products, and their historic evolution, makes this task exacting. The entry of cloud computing has turned this into one of the hottest areas as SSIS has been one of the methods indicated for bringing ground based data to cloud storage in SQL Azure, the next milestone in Microsoft Data Management. The reader may review my book on this site, "Beginners Guide to Microsoft SQL Server Integration Services" to get a jump start on learning this important product from Microsoft. SQL Azure SQL Azure is one of the three pillars of Microsoft's Azure cloud computing platform. It is a relational database built on SQL Server Technologies maintained on Microsoft's physical site where subscribers like you and me can rent out storage of data. Since the access is over the internet it is deemed to be in the cloud and Microsoft would provide all data maintenance. Some of the key benefits of this 'Database usage as a service' are: Manageability High Availability Scalability Which in other words means taking away a lot headache from you like worrying about hardware and software (SQL Azure Provisioning takes care of this), replication, DBAs with attitudes etc. Preparation for this tutorial You need some preparation to work with this tutorial. You must have a SQL Server 2008 installed to start with. You also need to register yourself with Microsoft to get an invitation to use SQL Azure by registering for the SQL Azure CTP. Getting permission is not immediate and may take days. After you register agreeing to the license terms, you get the permission (You become a subscriber to the service) to use the Azure Platform components (SQL Azure is one of them). After subscribing you can create a database on the SQL Azure instance. You will be the administrator of your instance (Your login will be known as the server level principal equivalent to the landbased sa login), and you can web access the server with a specific connection string provided to you and a strong password which you create. When you access the Azure URL, you provide the authentication to get connected to your instance of the server by signing in. Therein, you can create a database or delete an existing database. You have couple of tools available to work with this product. Read the blog post mentioned in the summary. Overview of this tutorial In this tutorial you will be using MS SQL Server Integration Services to create a package that can transfer a table from SQL Server 2008 to SQL Azure for which you have established your credentials. In my case the credentials are: Server: tcp:XXXXXX.ctp.database.windows.net User ID: YYYYY Password: ZZZZZ Database: PPPPPP Trusted_Connection=False; Here XXXXXX, YYYY,ZZZZZ, and PPPPPP are all the author's personal authentication values and you would get yours when you register as previously mentioned. Table to be migrated on SQL Server 2008 The table to be migrated on the SQL Server 2008 (Enterprise server, evaluation edition is shown in the next figure). PrincetonTemp is a simple table in the TestNorthwind database on the default instance of the local server on a Windows XP machine, with a few columns and no primary key. Create a SQL Server Integration Services Package Open BIDS (a Visual Studio add-in extending support to build database applications with SQL Server) and create a new SQL Server Integration Services project[Use File |New |Project...in the IDE]. Herein the Visual Studio 2008 with SP1 is used. You need to provide a name which for this project is GroundToCloud. The program creates the project for you which you can see in the Solution Explorer. By default it creates a package for you, Package.dtsx. You may rename the package (herein ToAzure.dtsx)and the project folders and file appear as shown. Add an ADO.NET Source component Drag and drop a Data Flow Task to the tabbed page Control Flow in the package designer. Into the Data flow tabbed page drag and drop an ADO.NET Source component from the Toolbox. Double click the component you just added, from the pop-up menu choose Edit... The ADO.NET Source editor gets displayed. If there are previously configured connections one of them may show up in this window. We will be creating a new connection and therefore click the New... button to display an empty Configure ADO.NET Connection Manager as shown (again, if there are existing connections they all will show up in this window). A connection is needed in connecting to a source outside the IDE. Double click the New... button to display the Connection Manager window which is all but empty. Fill in the details for your instance of ground based server as shown (the ones shown are for this article at the author's site). You may test the connection by hitting the Test Connection button. Clicking the OK buttons on the Connection Manager and the Configure ADO.NET Connection Manager will bring you back to the ADO.NET Source Editor displaying the connection you have just made as shown. A connection string also gets added to the bottom pane of the package designer as well as to the Configure ADO.NET Connection Manager. Click on the drop-down and pick the table (PrincetonTemp) that needs to be migrated to the cloud based server, SQL Azure. Click OK. The Columns navigation on the left would reveal all the columns in the table if it were to be clicked. The Preview button would return the data returned by a SELECT query on the columns as shown.
Read more
  • 0
  • 0
  • 4000

article-image-controlling-which-class-sees-our-resources-moodle-19
Packt
18 Nov 2009
4 min read
Save for later

Controlling Which Class Sees Our Resources in Moodle 1.9

Packt
18 Nov 2009
4 min read
While for the most part, teachers on the same course would want to cover the same material, it can sometimes be the case that one teacher might only want their own class to see a particular item but keep it hidden from others. I myself am doing this currently on a Certificate course whereby the students who have finished are able to view some extension activities that other students still working on the qualification do not have access to. Hiding resources from some students and showing them to others can be done by using "groupings" in Moodle. Groupings – a way to hide resources from some and display to others In order for this to work we need to check certain features: We are using Moodle 1.9. Groups and groupings have been enabled by our Moodle admin (in Site Admin > Experimental as below). We have the students on our Moodle course set up in different teacher groups. Ok – let us assume, we want group French 1 only to see our forum and wiki and we want group French 2 only to see our assignment. If we click on groups in the course administration block we see: If we look to the top of the Groups screen we see three tabs. The one to select next is Groupings. Having clicked on it, we get presented with a screen asking us to create a new grouping. A grouping is like an invisibility cloak (think: Harry Potter!) whereby any people in the grouping can be made invisible to others on the course. If we click on Create grouping we are then asked to give a name (and optional description) for our grouping. Note that we have not yet added any people to the grouping; we are merely setting it up. Once we have scrolled down and saved the changes we are returned to the above screen where we see the grouping has been created – but it has no people and it has no activities assigned to it: The next action to take is to click on the people icon in the Edit box. This sends us to a screen where we can choose which groups to put into this grouping "invisibility cloak": By clicking on a group on the right and moving it across with the arrow to the left we can assign a group to a grouping. You cannot assign individuals to a grouping; you can only assign groups. However –there is nothing preventing you making a group of one single person and then assigning that group! You can also have more than one group in a grouping, should you wish to. We now have our group French 1 in a grouping. The next step is to repeat the process for the group French 2. When that is done, it is important to check in the course settings (in the course admin block) that groups and groupings are enabled. Finally, we go to the activities we have set up – in this instance, a forum, wiki and assignment. We need to assign the tasks to the appropriate groupings. If the tasks have already been set up, as here, we click on the pen/hand icon to go into the editing area. If we are setting them up from scratch we assign the grouping at the time of creation. Scroll down to the section Common Module Settings and choose the appropriate grouping for that task, also checking Available for group members only: The same process must be gone through with the other tasks we want to control access to (in this instance, the wiki and assignment). And then – it’s done! If we the teacher look at the course we see that each activity has the name of the grouping greyed out next to it: Summary A student in one of those groupings, however, would only see their own activities and have no idea the others existed! A simple but effective way to control access to your Moodle tasks on a shared course. If you have read this article you may be interested to view : Setting up your Moodle Grade Book Adding Worksheets and Resources with Moodle Interacting with the Students using Moodle 1.9 (part 1)
Read more
  • 0
  • 0
  • 1505

article-image-most-wanted-apache-myfaces-trinidad-12-tags-and-tag-attributes
Packt
18 Nov 2009
6 min read
Save for later

Most Wanted Apache MyFaces Trinidad 1.2 Tags and Tag Attributes

Packt
18 Nov 2009
6 min read
Component library structure Trinidad's approach to web technology is comprehensive: Aimed at full control of all the bits and pieces that make up a web application, little should be left that needs to be added. So based on such a closed world, Trinidad presents itself with a wealth of components and tags that even include very basic XHTML tags as replacements for the real XHTML originals. This is no radical replacement approach, rather it enables Trinidad to remain in full control of mechanisms such as partial-page rendering (PPR, also generally known as Ajax) that otherwise would need to deal with potentially incompatible libraries externally. The following image provides an outline of Trinidad's structural package design: Trinidad is divided into the following two namespaces: tr: It is the usual tag library id that references Trinidad's core library tags. It's a large library of over 100 components ranging from layout components and navigational components, to special viewer components that all implicitly support skinning, partial-page rendering, popup dialogs, error or info messaging, and so on. trh: It is the usual tag library id that references Trinidad's XHTML support library tags, a small companion that offers alternatives for those XHTML tags that are usually applied to build XHTML structures, for example, XHTML tables. Let us take a closer look at both namespaces. The upcoming image shows the core API's hierarchical structure. The tags are backed by two types of Trinidad classes—UIX* classes that deal with the JSF component requirements to implement specific JSF lifecycle processing methods, and Core* classes that deal with the specific properties (getters or setters). Trinidad’s XHTML tag library namespace (trh) Two groups can be distinguished from the trh namespace. The first one deals with the definition of an XHTML page and provides the developer with the following tags: <trh:html>: It is used to define the whole XHTML page, analogous to <html> <trh:head>: It is used to define the header, analogous to <head> <trh:body>: It is used to define the main contents, analogous to <body> <trh:script>: It is used to define a JavaScript to be executed, analogous to <script> <trh:tableLayout>: It is used to define an XHTML table. <trh:rowLayout>: It is used to define an XHTML table line, analogous to <tr>; note that it can also be used to display an arbitrary line, particularly when elements need to be kept in one and the same line. Alternatively, it is particularly interesting to look at the tr namespace as it provides some less heavy structures free from table constructions, for instance panelGroupLayout with a layout set to vertical or a panelBorderLayout, both generating div structures instead. <trh:cellFormat>: It is used to define an XHTML table cell as part of an XHTML table. The attributes of each tag are defined in a most consistent, and thus recognizable way. By the way, there are also tags for the construction of framesets such as trh:frame in case anyone still wants to make use of framesets. However, before we deal with the attributes let us conclude this structural overview by a look at the organization of the functionality of the core tag library. Trinidad’s core tag library namespace (tr) The following groups can be functionally distinguished which is also reflected in the packages structure of Trinidad's API (all beginning with org.apache.myfaces.trinidad.component; which has been left out here to avoid repetition). Note that, for completeness, we will also include information on the pure Java side as well as information on the few components that stem from the trh namespace: Basic document composition tags from the core API: document, stylesheet, form, subform. poll also appears here although it is not a composition tag. Form input and display tags, components from the core.input API: inputText, inputDate, inputListOfValues, and so on. Command or navigation tags from core.nav that includes two tag types: One that is focused on command tags that assumes a given form, presupposing the use of form and display tags from the foregoing group—commandButton, commandLink, goButton, goLink, and so on. The other deals exclusively with navigation: navigationTree, navigationPane, breadCrumbs, and so on. Large input and output component tags from core.data, for example, table, tree, and treeTable components. Layout component tags from core.layout, for example, all the swing-like panel tags, such as panelBorderLayout, panelHorizontalLayout, panelAccordion, showDetail, showDetailItem, and so on. Basic output components from core.output that are almost always used in a web application, for example, messages, outputText, outputLabel, spacer, statusIndicator, and so on. Model objects from core.model devised for various tags ; they provide the corresponding view models for their tag viewer counterparts, for example, SortableModel, CollectionModel and RowKeySet for tr:table, ChildPropertyTreeModel for tr:tree and ChartModel for tr:chart. A couple of converter components from trinidad.convert equip JSF and Trinidad input components with powerful JSF conversion, that is, convertNumber and convertDateTime. Validator components from trinidad.validator equip JSF and Trinidad input components with powerful JSF validation such as range validation (validateDateTimeRange) and validation by regular expression match (validateRegExp). Events and event listeners from trinidad.event add new event types and listeners specific for Trinidad components such as those that support Trinidad's dialog framework, for example, commandButton to launch a popup dialogue using LaunchEvent, ReturnEvent, and ReturnListener. It provides only a few tags, but these can be very utile, for example, fileDownloadActionListener, resetActionListener, returnActionListener, and setActionListener. There is a lot more to be found on the pure Java API side that either surfaces indirectly on the tag library as attributes, or is used implicitly by the tags themselves. Furthermore, there are utility classes and context support classes—RequestContext being probably the most prominent one because it offers a lot of functionality, for example, PPR from the server side. The following figure illustrates the Java side of things (it shows what the structure of some of the classes behind core.input look like): The preceding figure is an outline of the core.input API hierarchy. Again, we can see the typical UIX* and Core* structure. Finally, let us take a closer look at the tag attributes.
Read more
  • 0
  • 0
  • 1913

article-image-datagrid-api-ibm-websphere-extreme-scale-6-part-1
Packt
18 Nov 2009
19 min read
Save for later

The DataGrid API with IBM WebSphere eXtreme Scale 6: Part 1

Packt
18 Nov 2009
19 min read
In a client-server ObjectGrid interaction, local ObjectGrid instances run in the same memory process as the business application. Access to objects stored in the grid is extremely fast, and there are no network hops or routing done on ObjectGrid operations. The disadvantage with a local ObjectGrid instance is that all objects stored in the grid must fit into the heap space of one JVM. The client-server distributed ObjectGrid instances overcomes that single heap space disadvantage by combining the resources of multiple JVMs on multiple servers. These combined resources hide behind the façade of an ObjectGrid instance. The ObjectGrid instance has far more CPU, memory, and network I/O available to it than the resources available to any single client. In this article, we'll learn how to use those resources held by the ObjectGrid instance to co-locate data and business logic on a single JVM. The client-server model relies on a client pulling objects across a network from an ObjectGrid shard. The client performs some operations on those objects. Any object whose state has changed must be sent back across the network to the appropriate shard. The client-server programming model co-locates data and code by moving data to the code. The data grid programming model does the opposite by moving code to the data. Rather than dragging megabytes of objects from an ObjectGrid shard to a client, only to send it right back to the ObjectGrid, we instead send our much smaller application code to an ObjectGrid shard to operate on the data in place. The end result is the same: code and data are co-located. We now have the resources of an entire data grid available to run that code instead of one client process. What does DataGrid do for me? The DataGrid API provides encapsulation to send application-specific methods into the grid and operate directly on the objects in shards. The API consists of only five public classes. These five classes provide us with several patterns to make an ObjectGrid instance do the heavy lifting for a client application. The client application did a lot of work by operating on the objects in the grid. The client requires a network hop to get an object from the grid and performs an operation on it, persisting that the object requires another network hop to the grid. In a single client environment, the probable bottlenecks in dealing with ObjectGrid are all on the client side. A single client will not stress the resources in the ObjectGrid deployment. The client application is most likely the bottleneck. With all computers in a deployment being equal, one client application on one computer will not stress the combined resources of the grid. In a naïve application that performs single object get and put operations, our application will first notice a bottleneck due to data starvation. This is where a client cannot get the data it needs fast enough, caused by network latency. Single object get and put operations (and the corresponding Entity API calls) won't saturate a gigabit ethernet connection by any means, but the latency in making the RPC is higher than what the CPU can handle. The application works, but it's slow. A smarter application would use the ObjectMap#getAll method. This would go out to the grid and get an object for every key in the list. Instead of waiting for each individual object, the client application waits for the entire list to come over the network. While the cost of network RPC is amortized over the size of the list, the client still incurs that cost. In addition to these network latency concerns, we may not want a near-cache that eats up client-side memory. Turning off the near-cache means that every get operation is an RPC. Turning it on means that some of our JVM heap space is used to store objects, which we may not need after the first use. The fundamental problem is that our objects and client application are architecturally separated. For our application to do anything, it needs to operate on objects that exist in the grid. In the client-server model, we copy data from the server to the client. At this point, our data and code are co-located, and the application can perform some business logic with that data. This model breaks down when there are huge data sets copied between boxes. Databases co-locate data and code with stored procedures. The processing power of the stored procedure is a product of the CPU and memory resources of the computer running the database. The stored procedure is code compiled into a module and executed by the database. Within that process, the stored procedure accesses data available in the same process. ObjectGrid gives us the ability to run code in the same process that gives an object access via the DataGrid API. Unlike the database example, where the throughput and latency of getting the store procedure result is limited to the power of the server it's on, ObjectGrid's power is limited by the number of CPUs in the deployment, and it can scale out at any time. ObjectGrid co-locates our code and objects by sending serialized classes with our application code methods to primary partitions in the grid. There are two ways to do this. The first way sends the code to every primary partition in the grid. The code executes and returns a result to the client. In the second way, we supply a collection of keys to the DataGrid API. With a list of keys, ObjectGrid only sends the application code to the partitions that contain at least one object with a key in the list. This reduces the amount of container processes doing the work for our client application, and is preferred instead of making the entire grid service on one client request. Let's look at finding an object by key in the client-server distributed model. The client has a key for an object. Calling the ObjectMap#get(key) method creates some work for the client. It first needs to determine to which partition the key belongs. The partition is important because the ClientClusterContext, already obtained by the client, knows how to get to the container that holds the primary shard in one hop. We find out the partition ID (pID) for a key with the PartitionManager class: BackingMap bMap = grid.getMap("Payment");PartitionManager pm = bMap.getPartitionManager();int pId = pm.getPartition(key); After obtaining the partition ID and the host running the container process, the client performs a network hop to request the object. The object is serialized and sent back to the client, where the client performs some operation with the object. Persisting an updated object requires one more network hop to put it back in the primary shard. We can now repeat that process for every object in our multi-million object collection. On second thought, that may not be such a great idea. Instead, we'll create an agent that we send to the grid. The agent encapsulates the logic we want to perform. An AgentManager serializes the agent and sends it to each primary shard in the deployment. Once on a primary shard, the agent executes and produces a result which is sent back to the client.   Borrowing from functional programming The DataGrid API borrows the "map" and "reduce" concepts from the world of functional programming. Just so we're all on the same page, let's go over the concepts behind these two functions. Functional programming focuses more on what a program does, instead of how it does it. This is in contrast to the most imperative programming we do in the C family of languages. That's not to say we can't follow a functional programming model, it's just that we don't. Other languages, like Lisp and its descendants, make functional programming the natural thing to do. Map and reduce are commonly found in functional programming. They are known as higher-order functions because they take functions as arguments. This is similar to how we would use a function pointer in C, or an anonymous inner class in Java, to implement callbacks. Though the focus is on what to do, at some point, we need to tell our program how to do it. We do this with the function passed as an argument to map or reduce. Let's look at a simple example in Ruby, which has both functional and imperative programming influences: >> numbers = [0,1,2,3,4,5,6,7,8,9]>> numbers.map { |number| number * 2 }=> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] We assign an array of numbers 0-9 to the variable numbers. The array has a method called map that we call in the second line. Map is a higher-order function and accepts a function as its argument. The Array#map method calls the passed-in function for each element in the array. It passes the element in the variable numbers. In this way, we return a new array that contains the results of each call to our function which performs number * 2. Let's look at the reduce method. In Ruby, reduce is called inject but the concept is the same: >> numbers = [0,1,2,3,4,5,6,7,8,9]>> numbers.inject(0) { |sum, number| sum = sum + number }=> 45 The inject (read as reduce) method takes a function that performs a running total on the numbers in the array. Instead of an array as our return type, we only get one number. The reduce operation returns a single result for an entire data set. The map operation returns a new set based on running the original set through a given function. These concepts are relevant in the data grid environment because we work with large data sets where we frequently need to work with large segments of data. Pulling raw data across the network, and operating over the data set on one client, are both too slow. Map and reduce helps us by using the remote CPU resources of the grid to cut down on the data sent across the network and the CPU power required on the client. This help comes from writing methods that work like map and reduce and sending them to our objects in the grid. java.util.M  ap, BackingMaps, ObjectMaps, HashMaps, like we need one more use for the word "map". We just saw the functional origin of the map concept. Let's take a look at a Java implementation. Map implements an algorithm that performs an operation on each element in a collection and returns a new collection of results: public Collection doubleOddInts(Collection c) {Collection results = new HashSet();Iterator iter = c.iterator();while (iter.hasNext()) {int i = (Integer)iter.next();if (i % 2 == 0) {[ 172 ]results.add(i);} else {results.add(i*2);}}return results;} Our needs go beyond performing a map function over an array. In order to be useful in a DataGrid environment, the map function must operate on a distributed collection of objects in an ObjectGrid instance. The DataGrid API supports this by giving us the MapGridAgent interface. A business logic class implements the two methods in MapGridAgent to encapsulate the code we intend to run in the grid. Classes that implement MapGridAgent must implement two methods, namely, MapGridAgent#process(Session session, ObjectMap map, Object key) and MapGridAgent#processAllEntries(Session session, ObjectMap map). Let's implement the doubleOddInts algorithm with MapGridAgent. We first create a class that implements the MapGridAgent interface. We give this class a meaningful name that describes the map operation implemented in the process methods: public class DoubleOddIntsMapAgent implements Serializable,MapGridAgent {public Object process(Session session, ObjectMap map, Object key){int i = (Integer)map.get(key);if (i % 2 == 0) {return i;} else {return i*2;}}public Map processAllEntries(Session session, ObjectMap map) {// nothing to do here for now!}} The map function itself is called by our client code. The process (session, map, key) method performs the how in the map function. Because ObjectGrid gives us the what for free (the map function), we only need to implement the how part. Like the Ruby example, this process (session, map, key) method is performed for each element in a collection. The Session and ObjectMap arguments are supplied by the AgentManager based on the current session and ObjectMap that starts the map function. The key is the crucial object for a given value in the collection, and that collection is supplied by us when we run the DoubleOddIntsMapAgent. After implementing the MapGridAgent#process(session, map, key) method, the DoubleOddIntsMapAgent is ready to run. We want it to run on each shard in an ObjectGrid instance that has a key in the collection we pass to it. We do this with an instance of the AgentManager class. The AgentManager class has two methods to send a MapGridAgent to the grid: AgentManager#callMapAgent(MapGridAgent agent, Collection keys) and AgentManager#callMapAgent(MapGridAgent agent). The first method provides a set of keys for our agent to use when run on each partition. Using this method is preferable to the non-keyed version because the non-keyed version runs the code on every primary shard in the grid. The Agent Manager#callMapAgent(agent, keys) method only runs the code on primary partitions that contain at least one key in the key collection. Whenever we have the choice to use part of the grid instead of the entire grid, we should take the choice that uses only part of the grid. Whenever we use the entire grid for one operation, we limit scalability and throughput. The AgentManager serializes the DoubleOddIntsMapAgent agent and sends it to each partition that has a key in the keys collection. Once on the primary partition, the process (session, map, key) method is called for each key in the keys collection supplied to AgentManager#callMapAgent(agent, keys). This set of keys is a subset of all of the keys in the BackingMap, and likely a subset of keys in each partition. Let's create an instance of this agent and submit it to the grid: Collection numbers = new ArrayList();for(int i = 0; i < 10000; i++) {numbers.add(i);}MapGridAgent agent = new DoubleOddIntsAgent();AgentManager am = session.getMap("Integer").getAgentManager();am.callMapAgent(agent, numbers); This example assumes that we have a BackingMap of Integer for both the key and value objects. The numbers collection is a list of keys to use. Once we create the agent, we submit it to the grid with the 10,000 keys to operate on. Before running the agent, the AgentManager sorts the keys by partition. The agent only runs on partitions that have a list of keys that hash to that partition. The agent runs on each partition that has a list of keys that hash to it. In each primary partition, the DoubleOddIntsMapAgent#process(session, map, key) method is called only for the keys that map to that partition. GridAgent and Entity GridAgent works with Entity classes as well. We don't directly use key objects when working with Entity objects. The Entity API hides the key/value implementation from us to make working with Entity objects easier than working with the ObjectMap API. The method definition for MapGridAgent#process(session, map, key) normally expects an object to be used as a key for an ObjectMap. We can still find the value object by converting key and value objects to their Tuple representations, but the DataGrid API makes it much easier for us. Instead of passing a key to the process method, we can convince the primary shard to pass us the Entity object itself, rather than a key using the EntityAgentMixin interface. EntityAgentMixin has one method, namely, EntityAgentMixin#getClassForEntity(). The implementation of this method should return the class object of the Entity. DataGrid needs this method defined in the grid agent implementation so it can provide the Entity object itself, rather than its key to the MapGridAgent#process(session, map, key) method. Let's assume that we have an Entity MyInteger that acts as a wrapper for Integer: public class DoubleOddIntsMapAgent implements Serializable,MapGridAgent, EntityAgentMixin {public Object process(Session session, ObjectMap map, Object key){MyInteger myInt = (MyInteger)key;if (myInt.mod(2) == 0) {return myInt;} else {return myInt.multiplyBy(2);}}public Map processAllEntries(Session session, ObjectMap map) {// nothing to do here for now!}public Class getClassForEntity() {return MyInteger.class;}} Our agent now implements the EntityAgentMixin interface and the getClassForEntity() method. The key is converted to the correct class before the MapGridAgent#process(session, map, key) method is called. Instead of the Tuple key for an Entity, the process method is passed a reference to the Entity itself. Because it is passed as an object, we must cast the Entity to its defined class. There is no need to look up for the Entity in its BackingMap because it's already the Entity we want to work with. This means the collection of keys passed to AgentManager#callMapAgent(agent, keys) is a collection with all elements of the c lass returned by getClassForEntity(). GridAgent with an unknown key set We may not always know the keys for each object we want to submit to an agent. In this situation, we send an agent into the grid without a key set. The grid agent cannot call the process (session, map, key) method because we don't know which keys to use. Instead, our grid agent method relies on the Query API to narrow the number of objects in each partition we work with. The MapGridAgent interface gives us the MapGridAgent#processAllEntries(Session session, ObjectMap map) method for this situation. The MapGridAgent#processAllEntries(session, map) method lets us specify what to do when we potentially need to work with all objects in a partition. Particularly, it lets us narrow the field with a query. In the past, we used a query to find card and address objects in a local ObjectGrid instance. This was fine for local instances with only one partition. The real power of the Query API is revealed when used with the DataGrid API. Query does not work across partitions when called from an ObjectGrid client in a distributed environment. It works with just one partition. In a distributed deployment, where we use the DataGrid API, a grid agent instance runs on one partition. Each partition has an instance of the grid agent running in it and each agent can see the objects in its partition. If we have 20 partitions, then we have 20 grid agents running, one in each partition. Because we're working with a single partition in each grid agent, we use the Query API to determine which objects are of interest to the business logic. Now that we know how to run code in the grid, the Query API is suddenly much more useful. Now, we want a query to run against just one partition. Using a query in a GridAgent is a natural fit. Each agent runs on one partition, and each query runs on that partition in the primary shard container process: public class DoubleOddIntsMapAgent implements Serializable,MapGridAgent, EntityAgentMixin {public Object process(Session session, ObjectMap map, Object key){MyInteger myInt = (MyInteger)key;if (myInt.mod(2) == 0) {return myInt;} else {return myInt.multiplyBy(2);}}public Map processAllEntries(Session session, ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select m from MyInteger m " +"where m.integer > 0 " +"and m.integer < 10000");Iterator iter = q.getResultIterator();Map<MyInteger, Integer> results =new HashMap<MyInteger, Integer)();while (iter.hasNext()) {MyInteger mi = (MyInteger)iter.next();results.put(mi, (Integer)process(session, map, mi));}return results;}public Class getClassForEntity() {return MyInteger.class;}} The MapGridAgent#processAllEntries(session, map) method generally follows the same pattern when implemented: Narrow the scope of objects in the partition. This is important in the MapGridAgent because it returns a result for every object it processes. This can result in hundreds of megabytes of objects sent back to a client from every partition for an indiscriminate query. Create a map to hold the results of each process operation. This map is keyed with the key object, or the value object, when using ObjectMap. The client application can perform its own gets if the keys are returned. Otherwise, it works directly with the value objects. We can also return a map of key/value objects. The map is keyed with the Entity class itself when using Entity. Iterate over the query results calling MapGridAgent#process(session, map, key) for each result. Calling the process method is required here since we didn't pass a collection of keys to the AgentManager#callMapAgent(agent) method. The key set is unknown before the agent runs. The agent finds all objects in a partition that meet our criteria for processing, and then we call process to get each result. Return the results. This map contains an entry for each object that meets our processing criteria in this partition. This map is merged, client-side, with the maps from every other partition where the agent ran. The merged map is the final result, and it is the return value to the AgentManager#callMapAgent(agent) method. Following the call to AgentManager#callMapAgent(agent), we have a Map that contains the combined agent results from every partition. We also split the workload between N partitions rather than performing all of the processing on the client. The ObjectGrid deployment performed our business logic because we passed the business logic to the grid rather than pulling objects out of the grid. One of the great things about this pattern is that our task on many partitions completes in about 1/Nth the amount of time it would take for one huge partition containing the same objects running on one computer. Of course, there is the overhead of the merge operation and network connections, but this is amortized over the number of primary partitions used by the agent. This is distinctly different than scaling up a database server when it needs more CPU speed for stored procedures. Instead of incurred downtime for database server migration, we simply add more containers on additional computers. The power of our grid increases as easily as starting a few more JVMs. >> Continue Reading: The DataGrid API with IBM WebSphere eXtreme Scale 6: Part 2
Read more
  • 0
  • 0
  • 1388

article-image-build-advanced-contact-manager-using-jboss-richfaces-33-part-1
Packt
18 Nov 2009
11 min read
Save for later

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

Packt
18 Nov 2009
11 min read
The main layout Let's start preparing the space for the core features of the application. We want a three-column layout for groups, contacts list, and contact detail. Let's open the home.xhtml file and add a three-column panel grid inside the body: <h:panelGrid columns="3" width="100%" columnClasses="main-group-column, main-contacts-list-column,  main-contact-detail-column"></h:panelGrid> We are using three new CSS classes (one for every column). Let's open the /view/stylesheet/theme.css file and add the following code: .main-group-column { width: 20%; vertical-align: top;}.main-contacts-list-column { width: 40%; vertical-align: top;}.main-contact-detail-column { width: 40%; vertical-align: top;} The main columns are ready; now we want to split the content of every column in a separate file (so we don't have a large and difficult file to read) by using the Facelets templating capabilities—let's create a new folder inside the/view folder called main, and let's create the following empty files inside it: contactsGroups.xhtml contactsList.xhtml contactEdit.xhtml contactView.xhtml Now let's open them and put the standard code for an empty (included) file: <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><ui:composition ><!-- my code here --></ui:composition> Now, we have all of the pieces ready to be included into the home.xhtml file, let's open it and start adding the first column inside h:panelGrid: <a:outputPanel id="contactsGroups"> <ui:include src="main/contactsGroups.xhtml"/></a:outputPanel> As you can see, we surrounded the include with an a:outputPanel that will be used as a placeholder for the re-rendering purpose. Include a Facelets tag (ui:include) into the a:outputPanel that we used in order to include the page at that point. Ajax placeholders A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements in the page.For this reason, if you want to append some code, you need to use a placeholder. RichFaces has a component that can be used as a placeholder—a4j:outputPanel. Inside a4j:outputPanel, you can put other components that use the "rendered" attribute in order to decide if they are visible or not. When you want to re-render all the included components, just re-render the outputPanel, and all will work without any problem. Here is a non-working code snippet: <h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out1" /> </h:inputText></h:form><h:outputText id="out1" value="#{aBean.myText}" rendered="#{not empty aBean.myText}"/> This code seems the same as that of the a4j:support example, but it won't work. The problem is that we added the rendered attribute to outputText, so initially, out1 will not be rendered (because the text property is initially empty and rendered will be equal to false). After the Ajax response, the JavaScript Engine will not find the out1 element (it is not in the page because of rendered="false"), and it will not be able to update it (remember that you can't add or delete elements, only replace them). It is very simple to make the code work: <h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out2" /> </h:inputText></h:form><a4j:outputPanel id="out2"> <h:outputText id="out1" rendered="#{not empty aBean.myText}" value="#{aBean.myText}" /></a4j:outputPanel> As you can see, you just have to put the out1 component inside a4j:outputPanel (called out2) and tell a4j:support to re-render out2 instead of out1. Initially, out2 will be rendered but empty (because out1 will not be rendered). After the Ajax response, the empty out2 will be replaced with markup elements that also contain the out1 component (that is now visible, because the myText property is not empty after the Ajax update and the rendered property is true). A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements of the page. For this reason, if you want to append some code, you need to use a placeholder. The groups box This box will contain all the contacts groups, so the user will be able to organize contacts in different groups in a better way. We will not implement the group box features in this article. Therefore, by now the group column is just a rich:panel with a link to refresh the contact list. Let's open the contactsGroups.xhtml file and insert the following code: <h:form> <rich:panel> <f:facet name="header"> <h:outputText value="#{messages['groups']}" /> </f:facet> <h:panelGrid columns="1"> <a:commandLink value="#{messages['allContacts']}" ajaxSingle="true" reRender="contactsList"> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}" /> </a:commandLink> </h:panelGrid> </rich:panel></h:form> As you can see, we've put a three-column h:panelGrid (to be used in the future) and a:commandLink, which just sets the contactsList property of the homeContactListHelper bean (that we will see in the next section) to null, in order to make the list be read again. At the end of the Ajax interaction, it will re-render the contactsList column in order to show the new data. Also, notice that we are still supporting i18n for every text using the messages property; the task to fill the messages_XX.properties file is left as an exercise for the user. The contacts list The second column inside h:panelGrid of home.xhtml looks like: <a:outputPanel id="contactsList"> <ui:include src="main/contactsList.xhtml"/></a:outputPanel> As for groups, we used a placeholder surrounding the ui:include tag. Now let's focus on creating the data table—open the /view/main/contactsList.xhtml file and add the first snippet of code for dataTable: <h:form> <rich:dataTable id="contactsTable" reRender="contactsTableDS" rows="20" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column width="45%"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column width="45%"> <h:outputText value="#{contact.surname}"/> </rich:column> <f:facet name="footer"> <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/> </f:facet> </rich:dataTable> <h:outputText value="#{messages['noContactsInList']}" rendered="#{homeContactsListHelper.contactsList.size()==0}"/></h:form> We just added the rich:dataTable component with some columns and an Ajax data scroller at the end. Differences between h:dataTable and rich:dataTable RichFaces provides its own version of h:dataTable, which contains more features and is better integrated with the RichFaces framework. The first important additional feature, in fact, is the skinnability support following the RichFaces standards. Other features are row and column spans support (we will discuss it in the Columns and column groups section), out-of-the-box filter and sorting (discussed in the Filtering and sorting section), more JavaScript event handlers (such as onRowClick, onRowContextMenu, onRowDblClick, and so on) and the reRender attribute. Like other data iteration components of the RichFaces framework, it also supports the partial-row update. Data pagination Implementing Ajax data pagination using RichFaces is really simple—just decide how many rows must be shown in every page by setting the rows attribute of dataTable (in our case, we've chosen 20 rows per page), and then "attach" the rich:datascroller component to it by filling the for attribute with the dataTable id: <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/> Here you can see another very useful attribute (renderIfSinglePage) that makes the component hidden when there is just a single page in the list (it means the list contains a number of items that is less than or equal to the value of the rows attribute). A thing to keep in mind is that the rich:datascroller component must stay inside a form component (h:form or a:form) in order to work. Customizing rich:datascroller is possible not only by using CSS classes (as usual), but also by personalizing our own parts using the following facets: pages controlsSeparator first, first_disabled last, last_disabled next, next_disabled previous, previous_disabled fastforward, fastforward_disabled fastrewind, fastrewinf_disabled Here is an example with some customized facets (using strings): <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First" /> </f:facet> <f:facet name="last"> <h:outputText value="Last" /> </f:facet></rich:datascroller> Here is the result: You can use an image (or another component) instead of text, in order to create your own customized scroller. Another interesting example is: <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First"/> </f:facet> <f:facet name="last"> <h:outputText value="Last"/> </f:facet> <f:attribute name="pageIndexVar" value="pageIndexVar"/> <f:attribute name="pagesVar" value="pagesVar"/> <f:facet name="pages"> <h:panelGroup> <h:outputText value="Page #{pageIndexVar} / #{pagesVar}"/> </h:panelGroup> </f:facet></rich:datascroller> The result is: By setting the pageIndexVar and pagesVar attributes, we are able to use them in an outputText component, as we've done in the example. A useful attribute of the component is maxPages that sets the maximum number of page links (the numbers in the middle), which the scroller shows—therefore, we can control the size of it. The page attribute could be bound to a property of a bean, in order to switch to a page giving the number—a simple use-case could be using an inputText and a commandButton, in order to let the client insert the page number that he/she wants to go to. Here is the code that shows how to implement it: <rich:datascroller for="contactsList" maxPages="20" fastControls="hide" page="#{customDataScrollerExampleHelper.scrollerPage}" pagesVar="pages" id="ds"> <f:facet name="first"> <h:outputText value="First" /> </f:facet> <f:facet name="first_disabled"> <h:outputText value="First" /> </f:facet> <f:facet name="last"> <h:outputText value="Last" /> </f:facet> <f:facet name="last_disabled"> <h:outputText value="Last" /> </f:facet> <f:facet name="previous"> <h:outputText value="Previous" /> </f:facet> <f:facet name="previous_disabled"> <h:outputText value="Previous" /> </f:facet> <f:facet name="next"> <h:outputText value="Next" /> </f:facet> <f:facet name="next_disabled"> <h:outputText value="Next" /> </f:facet> <f:facet name="pages"> <h:panelGroup> <h:outputText value="Page "/> <h:inputText value="#{customDataScrollerExampleHelper. scrollerPage}" size="4"> <f:validateLongRange minimum="0" /> <a:support event="onkeyup" timeout="500" oncomplete="#{rich:component('ds')}. switchToPage(this.value)" /> </h:inputText> <h:outputText value=" of #{pages}"/> </h:panelGroup> </f:facet></rich:datascroller> As you can see, besides customizing the text of the First, Last, Previous, and Next sections, we defined a pages facet by inserting h:inputText connected with an integer value inside a backing bean. We also added the a:support tag, in order to trim the page change after the keyup event is completed. We've also set the timeout attribute, in order to call the server every 500 ms and not every time the user types. You can see a screenshot of the feature here:
Read more
  • 0
  • 0
  • 1601
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 $19.99/month. Cancel anytime
article-image-unity-game-development-interactions-part-1
Packt
18 Nov 2009
8 min read
Save for later

Unity Game Development: Interactions (Part 1)

Packt
18 Nov 2009
8 min read
To detect physical interactions between game objects, the most common method is to use a Collider component—an invisible net that surrounds an object's shape and is in charge of detecting collisions with other objects. The act of detecting and retrieving information from these collisions is known as collision detection. Not only can we detect when two colliders interact, but we can also pre-empt a collision and perform many other useful tasks by utilizing a technique called Ray Casting, which draws a Ray—put simply, an invisible (non-rendered) vector line between two points in 3D space—which can also be used to detect an intersection with a game object's collider. Ray casting can also be used to retrieve lots of other useful information such as the length of the ray (therefore—distance), and the point of impact of the end of the line. In the given example, a ray facing the forward direction from our character is demonstrated. In addition to the direction, a ray can also be given a specific length, or allowed to cast until it finds an object. Over the course of the article, we will work with the outpost model. Because this asset has been animated for us, the animation of the outpost's door opening and closing is ready to be triggered—once the model is placed into our scene. This can be done with either collision detection or ray casting, and we will explore what you will need to do to implement either approach. Let's begin by looking at collision detection and when it may be appropriate to use ray casting instead of, or in complement to, collision detection. Exploring collisions When objects collide in any game engine, information about the collision event becomes available. By recording a variety of information upon the moment of impact, the game engine can respond in a realistic manner. For example, in a game involving physics, if an object falls to the ground from a height, then the engine needs to know which part of the object hit the ground first. With that information, it can correctly and realistically control the object's reaction to the impact. Of course, Unity handles these kinds of collisions and stores the information on your behalf, and you only have to retrieve it in order to do something with it. In the example of opening a door, we would need to detect collisions between the player character's collider and a collider on or near the door. It would make little sense to detect collisions elsewhere, as we would likely need to trigger the animation of the door when the player is near enough to walk through it, or to expect it to open for them. As a result, we would check for collisions between the player character's collider and the door's collider. However, we would need to extend the depth of the door's collider so that the player character's collider did not need to be pressed up against the door in order to trigger a collision, as shown in the following illustration. However, the problem with extending the depth of the collider is that the game interaction with it becomes unrealistic. In the example of our door, the extended collider protruding from the visual surface of the door would mean that we would bump into an invisible surface which would cause our character to stop in their tracks, and although we would use this collision to trigger the opening of the door through animation, the initial bump into the extended collider would seem unnatural to the player and thus detract from their immersion in the game. So while collision detection will work perfectly well between the player character collider and the door collider, there are drawbacks that call for us as creative game developers to look for a more intuitive approach, and this is where ray casting comes in. Ray casting While we can detect collisions between the player character's collider and a collider that fits the door object, a more appropriate method may be to check for when the player character is facing the door we are expecting to open and is within a certain distance of this door. This can be done by casting a ray forward from the player's forward direction and restricting its length. This means that when approaching the door, the player needn't walk right up to it—or bump into an extended collider—in order for it to be detected. It also ensures that the player cannot walk up to the door facing away from it and still open it—with ray casting they must be facing the door in order to use it, which makes sense. In common usage, ray casting is done where collision detection is simply too imprecise to respond correctly. For example, reactions that need to occur with a frame-by-frame level of detail may occur too quickly for a collision to take place. In this instance, we need to preemptively detect whether a collision is likely to occur rather than the collision itself. Let's look at a practical example of this problem. The frame miss In the example of a gun in a 3D shooter game, ray casting is used to predict the impact of a gunshot when a gun is fired. Because of the speed of an actual bullet, simulating the flight path of a bullet heading toward a target is very difficult to visually represent in a way that would satisfy and make sense to the player. This is down to the frame-based nature of the way in which games are rendered. If you consider that when a real gun is fired, it takes a tiny amount of time to reach its target—and as far as an observer is concerned it could be said to happen instantly—we can assume that even when rendering over 25 frames of our game per second, the bullet would need to have reached its target within only a few frames. In the example above, a bullet is fired from a gun. In order to make the bullet realistic, it will have to move at a speed of 500 feet per second. If the frame rate is 25 frames per second, then the bullet moves at 20 feet per frame. The problem with this is a person is about 2 feet in diameter, which means that the bullet will very likely miss the enemies shown at 5 and 25 feet away that would be hit. This is where prediction comes into play. Predictive collision detection Instead of checking for a collision with an actual bullet object, we find out whether a fired bullet will hit its target. By casting a ray forward from the gun object (thus using its forward direction) on the same frame that the player presses the fire button, we can immediately check which objects intersect the ray. We can do this because rays are drawn immediately. Think of them like a laser pointer—when you switch on the laser, we do not see the light moving forward because it travels at the speed of light—to us it simply appears. Rays work in the same way, so that whenever the player in a ray-based shooting game presses fire, they draw a ray in the direction that they are aiming. With this ray, they can retrieve information on the collider that is hit. Moreover, by identifying the collider, the game object itself can be addressed and scripted to behave accordingly. Even detailed information, such as the point of impact, can be returned and used to affect the resultant reaction, for example, causing the enemy to recoil in a particular direction. In our shooting game example, we would likely invoke scripting to kill or physically repel the enemy whose collider the ray hits, and as a result of the immediacy of rays, we can do this on the frame after the ray collides with, or intersects the enemy collider. This gives the effect of a real gunshot because the reaction is registered immediately. It is also worth noting that shooting games often use the otherwise invisible rays to render brief visible lines to help with aim and give the player visual feedback, but do not confuse these lines with ray casts because the rays are simply used as a path for line rendering. Adding the outpost Before we begin to use both collision detection and ray casting to open the door of our outpost, we'll need to introduce it to the scene. To begin, drag the outpost model from the Project panel to the Scene view and drop it anywhere—bear in mind you cannot position it when you drag-and-drop; this is done once you have dropped the model (that is, let go off the mouse). Once the outpost is in the Scene, you'll notice its name has also appeared in the Hierarchy panel and that it has automatically become selected. Now you're ready to position and scale it!  
Read more
  • 0
  • 0
  • 3522

article-image-quality-assurance-asterisk-16
Packt
18 Nov 2009
10 min read
Save for later

Quality Assurance in Asterisk 1.6

Packt
18 Nov 2009
10 min read
The world has changed quite a bit in the last 150 years. Over this time, the telephone system has been invented, improved, and automated. Telephone switches no longer refer to people sitting in a large room connecting wires between the appropriate jacks. Flexible and powerful telephone service has moved from a dream to an expectation in large businesses, and for most of us it is a necessity. Today, telephone systems are the lifeblood of business. They are how we take orders, acquire supplies, and even call for emergency assistance. With the increase in prominence of telephones, the expectations of telephone users have increased proportionally. Not only have the technological expectations for telephone systems increased dramatically, but consumers are expecting more and more out of the businesses they call. Customers expect to be helped quickly and professionally. They want to know everything in a matter of minutes. Roads do not hold the only rage our society is facing today. As a business we have a variety of questions relating to our telephone system such as: How are our personnel handling angry callers? Are our employees answering the calls in a reasonable amount of time? Do we have any workers using the phone system for personal calls when they should be doing their job? We will never be able to make sure everybody does what they are supposed to do all of the time. What we will be able to do at the end of this article is perform spot-checks on how we are doing on customer service, and make sure our phone service isn't being used for unauthorized purposes. Ultimately, it comes down to a matter of trust; however, some people do not know better because they haven't been fully trained. Most will always act honorably; however, some just cannot and should not be trusted. We will try to find out who is who. Call Detail Records When we talk about security, what images come to mind? May be a big, burly guard? Perhaps a bunch of guys in green, carrying machine guns? Do we imagine a person with a metal-detecting wand? Or do we think of thick glass window panes? All of these are security features. It is just that some are a little more intrusive than others. Each time we increase security, we become a little bit less friendly. We all have to decide how far we are willing (and able) to go. In the continuum of security, Call Detail Records are the least intrusive. No special usernames or passwords have to be remembered. No fear of big brother breathing down your customers' and users' necks need be felt. We are simply doing the same thing telephone companies do—tracking what calls were made, when they were made, how long they lasted, where they came from, and a few other bits of information. This information is then available for us to review at our leisure. Asterisk gives us a few options on how we track this information. The two major choices are flat-file logging and database logging. Flat-file CDR logging By default, Asterisk includes a module called cdr_csv. Right out of the box, Asterisk logs all calls coming in and going out. The information for these calls is placed in a Comma Separated Value (CSV) file. This CSV file is located in var/log/asterisk/cdr-csv. All information is available in Master.csv, and some channels can be configured to send some information to other files as well. The benefit of using a CSV file is the simplicity. Right after compiling and installing Asterisk, this method will work. No additional configuration is required. Also, no additional network traffic is generated, and no additional services have to be installed on our server. When using the CSV form of CDR, we will see lists and lists of values. They are not very easy to parse, so here is the format, in the order in which they appear: account code: As determined by the channel (for DAHDI) or the user (for IAX and SIP) source: The source of the call destination: The destination of the call destination context caller ID channel: The channel of the source destination channel: If applicable last application: The last application run on the channel last application argument: The last argument to the last application on the channel start time: The time the call commenced answer time: The time the call was answered end time: The time the call ended duration: The difference between start time and end time billable seconds: The difference between answer time and end time, which must be less than the duration disposition: Either ANSWERED, NO ANSWER, or BUSY amaflags: As set for the channel or user, like account code uniqueid: A unique call identifier userfield: A user field set by the SetCDRUserField command We see that there are many items of information logged for each and every call. We can compare the billable seconds with our phone bill at the end of the month to make sure they're close. We can look at the destination and figure out if the calls were authorized. This gives us enough information to answer most questions we may have about a phone call. While we have enough information to answer questions, finding that answer is not very easy. We would have to scan through the entire file to try to find anything. If we are going to use an accounting package or reporting software, CSV may be exactly what we need. However, if we wish to use it in a more ad hoc sort of way, it is not very readable. Database CDR logging If we wish to read our CDR logs, it is most easily accomplished when the records are sortable. The easiest way to do this is to store our CDR records in a database. Even in this, Asterisk gives us choices. Included with Asterisk is support for PostgreSQL databases. In order to be able to install this, we must first have the postgresql-devel package installed on our system. If you have to install this package, you'll need to reinstall Asterisk. The automake system will automatically detect that we have the capability to use PostgreSQL and compile that module for us. Aside from the development packages we have installed, we will also need a PostgreSQL server somewhere in our network. It can be the same machine as the Asterisk server, but it doesn't necessarily need to be. In fact, it probably makes sense to have only one such database server on our network, and we don't want to tie up too much of our PBX's resources with database maintenance and storage. There is a script in /usr/src/asterisk/contrib/scripts/ called postgres_cdr.sql, which creates the correct table structure for us. This script should be run from the database server. If we get an error message while rebuilding that says something like "cannot find-lz", then we need to install zlib-devel. Now that we have set up our database and installed the CDR module, we must configure Asterisk to use the correct database. In order to do this, we need to edit /etc/asterisk/cdr_pgsql.conf. All of the configuration variables are in the global section. Our file should look like the following: [global]hostname=dbserver.mydomain.tldport=5432dbname=asteriskpassword=supersecretuser=asteriskuser Once we have these variables set, the next time we restart Asterisk, all CDR records will be logged in the database. If PostgreSQL is not our database of choice, we can use MySQL. This is not a part of the normal distribution of Asterisk. But as we have already installed asterisk-addons, we should already have the ability to use MySQL for CDR logging. Before we compile, we need to make sure that we have mysql-devel installed. First, we need to decide which version we're going to use. Because of some license quibbles, MySQL version 4.0 and later is not in the automatic package distribution chain. Instead, if we do need to download it, we will have to get it directly from www.mysql.com. However, the older version (3.x) will work with Asterisk and hence, you may wish to take a look at the differences between what version 3 offered and what later versions give us. Other than the development package mentioned, we will also need a MySQL server somewhere in our network. Just as with PostgreSQL, we can choose to have it on the same server as Asterisk, but for the same reasons, we probably shouldn't. Next, on the database server, we need to create the database with a user and a table for the CDR data. We do this by running the following code: # mysqladmin create database asteriskcdrdb # mysqlmysql> GRANT ALL PRIVILEGES   -> ON asteriskcdrdb.*   -> TO asteriskcdruser   -> IDENTIFIED BY 'changethis2yourpassword';mysql> USE asteriskcdrdb;mysql> CREATE TABLE cdr (   -> uniqueid varchar(32) NOT NULL default '',   -> userfield varchar(255) NOT NULL default '',   -> accountcode varchar(20) NOT NULL default '',   -> src varchar(80) NOT NULL default '',   -> dst varchar(80) NOT NULL default '',   -> dcontext varchar(80) NOT NULL default '',   -> clid varchar(80) NOT NULL default '',   -> channel varchar(80) NOT NULL default '',   -> dstchannel varchar(80) NOT NULL default '',   -> lastapp varchar(80) NOT NULL default '',   -> lastdata varchar(80) NOT NULL default '',   -> calldate datetime NOT NULL default '0000-00-00 00:00:00',   -> duration int(11) NOT NULL default '0',   -> billsec int(11) NOT NULL default '0',   -> disposition varchar(45) NOT NULL default '',   -> amaflags int(11) NOT NULL default '0'-> ); That's all there is to it! We only have to do this once, so it's really not so bad. Next, we have to modify the /etc/asterisk/cdr_mysql.conf file to correctly reflect our choices. [global]hostname=ourdbserver.ourdomain.tlddbname=asteriskcdrdbpassword=changethis2yourpassworduser=asteriskcdruserport=3306userfield=1 The next time we restart Asterisk, our CDR information will be stored in the MySQL database. What does that give us? We now have the ability to use a number of very powerful tools to search our CDR records to find trends and patterns.
Read more
  • 0
  • 0
  • 1680

article-image-integrating-websphere-extreme-scale-data-grid-relational-database-part-1
Packt
18 Nov 2009
10 min read
Save for later

Integrating Websphere eXtreme Scale Data Grid with Relational Database: Part 1

Packt
18 Nov 2009
10 min read
As stated above there are three compelling reasons to integrate with a database backend. First, reporting tools do not have good data grid integration. Using CrystalReports and other reporting tools, don't work with data grids right now. Loading data from a data grid into a data warehouse with existing tools isn't possible either. The second reason we want to use a database with a data grid is when we have an extremely large data set. A data grid stores data in memory. Though much cheaper than in the past, system memory is still much more expensive than a typical magnetic hard disk. When dealing with extremely large data sets, we want to structure our data so that the most frequently used data is in the cache and less frequently used data is on the disk. The third compelling reason to use a database with a data grid is that our application may need to work with legacy applications that have been using relational databases for years. Our application may need to provide more data to them, or operate on data already in the legacy database in order to stay ahead of a processing load.In this article, we will explore some of the good and not-so-good uses of an in-memory data grid. We'll also look at integrating Websphere eXtreme Scale with relational databases. You're going where? Somewhere along the way, we all learned that software consists of algorithms and data. CPUs load instructions from our compiled algorithms, and those instructions operate on bits representing our data. The closer our data lives to the CPU, the faster our algorithm can use it. On the x86 CPU, the registers are the closest we can store data to the instructions executed by the CPU. CPU registers are also the smallest and most expensive data storage location. The amount of data storable in registers is fixed because the number and size of CPU registers is fixed. Typically, we don't directly interact with registers because their correct usage is important to our application performance. We let the compiler writers handle translating our algorithms into machine code. The machine code knows better than we do, and will use register storage far more effectively than we will most of the time. Less expensive, and about an order of magnitude slower, we have the Level 1 cache on a CPU (see below). The Level 1 cache holds significantly more data than the combined storage capacity of the CPU registers. Reading data from the Level 1 cache, and copying it to a register, is still very fast. The Level 1 cache on my laptop has two 32K instruction caches, and two 32K data caches. Still less expensive, and another order of magnitude slower, is the Level 2 cache. The Level 2 cache is typically much larger than Level 1 cache. I have 4MB of the Level 2 cache on my laptop. It still won't fit the contents of the Library of Congress into that 4MB, but that 4MB isn't a bad amount of data to keep near the CPU. Up another level, we come to the main system memory. Consumer level PCs come with 4GB RAM. A low-end server won't have any less than 8GB. At this point, we can safely store a large chunk of data, if not all of the data, used by an application. Once the application exits, its data is unloaded from the main memory, and all of the data is lost. In fact, once our data is evicted from any storage at or below this level, it is lost. Our data is ephemeral unless it is put onto some secondary storage. The unit of measurement for accessing data in a register, either Level 1 or 2 cache and main memory, is a nanosecond. Getting to secondary storage, we jump up an SI-prefix to a microsecond. Accessing data in the secondary storage cache is on the order of microseconds. If the data is not in cache, the access time is on the order of milliseconds. Accessing data on a hard drive platter is one million times slower than accessing that same data in main memory, and one billion times slower than accessing that data in a register. However, secondary storage is very cheap and holds millions of times more than primary storage. Data stored in secondary storage is durable. It doesn't disappear when the computer is reset after a crash. Our operation teams comfortably build secondary storage silos to store petabytes of data. We typically build our applications so the application server interacts with some relational database management system that sits in front of that storage silo. The network hop to communicate with the RDBMS is in the order of microseconds on a fast network, and milliseconds otherwise. Sharing data between applications has been done with the disk + network + database approach for a long time. It's become the traditional way to build applications. Load balancer in front, application servers or batch processes constantly communicating with a database to store data for the next process that needs it. As we see with computer architecture, we insert data where it fits. We squeeze it as close to the CPU as possible for better performance. If a data segment doesn't fit in one level, keep squeezing what fits into each higher storage level. That leaves us with a lot of unused memory and disk space in an application deployment. Storing data in the memory is preferable to storing it on a hard drive. Memory segmentation in a deployment has made it difficult to store useful amounts of data at a few milliseconds distance. We just use a massive, but slow, database instead. Where does an IMDG fit? We've used ObjectGrid to store all of our data so far. This diagram should look pretty familiar by now: Because we're only using the ObjectGrid APIs, our data is stored in-memory. It is not persisted to disk. If our ObjectGrid servers crash, then our data is in jeopardy (we haven't covered replication yet). One way to get our data into a persistent store is to mark up our classes with some ORM framework like JPA. We can use the JPA API to persist, update, and remove our objects from a database after we perform the same operations on them using the ObjectMap or Entity APIs. The onus is on the application developer to keep both cache and database in sync: If you take this approach, then all of the effort would be for naught. Websphere eXtreme Scale provides functionality to integrate with an ORM framework, or any data store, through Loaders. A Loader is a BackingMap plugin that tells ObjectGrid how to transform an object into the desired output form. Typically, we'll use a Loader with an ORM specification like JPA. Websphere eXtreme Scale comes with a few different Loaders out of the box, but we can always write our own. A Loader works in the background, transforming operations on objects into some output, whether it's file output or SQL queries. A Loader plugs into a BackingMap in an ObjectGrid server instance, or in a local ObjectGrid instance. A Loader does not plug into a client-side BackingMap, though we can override Loader settings on a client-side BackingMap. While the Loader runs in the background, we interact with an ObjectGrid instance. We use the ObjectMap API for objects with zero or simple relationships, and the Entity API for objects with more complex relationships. The Loader handles all of the details in transforming an object into something that can integrate with external data stores: Why is storing our data in a database so important? Haven't we seen how much faster Websphere eXtreme Scale is than an RDBMS? Shouldn't all of our data be stored in in-memory? An in-memory data grid is good for certain things. There are plenty of things that a traditional RDBMS is good at that any IMDG just doesn't support. An obvious issue is that memory is significantly more expensive than hard drives. 8GB of server grade memory costs thousands of dollars. 8GB of server grade disk space costs pennies. Even though the disk is slower than memory, we can store a lot more data on it. An IMDG shines where a sizeable portion of frequently-changing data can be cached so that all clients see the same data. The IMDG provides orders of magnitude with better latency, read, and write speeds than any RDBMS. But we need to be aware that, for large data sets, an entire data set may not fit in a typical IMDG. If we focus on the frequently-changing data that must be available to all clients, then using the IMDG makes sense. Imagine a deployment with 10 servers, each with 64GB of memory. Let's say that of the 64GB, we can use 50GB for ObjectGrid. For a 1TB data set, we can store 50% of it in cache. That's great! As the data set grows to 5TB, we can fit 10% in cache. That's not as good as 50%, but if it is the 10% of the data that is accessed most frequently, then we come out ahead. If that 10% of data has a lot of writes to it, then we come out ahead. Websphere eXtreme Scale gives us predictable, dynamic, and linear scalability. When our data set grows to 100TB, and the IMDG holds only 0.5% of the total data set, we can add more nodes to the IMDG and increase the total percentage of cacheable data (see below). It's important to note that this predictable scalability is immensely valuable. Predictable scalability makes capacity planning easier. It makes hardware procurement easier because you know what you need. Linear scalability provides a graceful way to grow a deployment as usage and data grow. You can rest easy knowing the limits of your application when it's using an IMDG. The IMDG also acts as a shock absorber in front of a database. We're going to explore some of the reasons why an IMDG makes a good shock absorber with the Loader functionality. There are plenty of other situations, some that we have already covered, where an IMDG is the correct tool for the job. There are also plenty of situations where an IMDG just doesn't fit. A traditional RDBMS has thousands of man-years of research, implementation tuning, and bug fixing already put into it. An RDBMS is well-understood and is easy to use in application development. There are standard APIs for interacting with them in almost any language: In-memory data grids don't have the supporting tools built around them that RDBMSs have. We can't plug CrystalReports into an ObjectGrid instance to get daily reports out of the data in the grid. Querying the grid is useful when we run simple queries, but fails when we need to run the query over the entire data set, or run a complex query. The query engine in Websphere eXtreme Scale is not as sophisticated as the query engine in an RDBMS. This also means the data we get from ad hoc queries is limited. Running ad hoc queries in the first place is more difficult. Even building an ad hoc query runner that interacts with an IMDG is of limited usefulness. An RDBMS is a wonderful cross-platform data store. Websphere eXtreme Scale is written in Java and only deals with Java objects. A simple way for an organization to share data between applications is in a plaintext database. We have standard APIs for database access in nearly every programming language. As long as we use the supported database driver and API, we will get the results as we expect, including ORM frameworks from other platforms like .NET and Rails. We could go on and on about why an RDBMS needs to be in place, but I think the point is clear. It's something we still need to make our software as useful as possible.
Read more
  • 0
  • 0
  • 2157

article-image-archiva-team-part-2
Packt
18 Nov 2009
7 min read
Save for later

Archiva in a Team: Part 2

Packt
18 Nov 2009
7 min read
Deleting artifacts in your repository Sometimes the need for deleting artifacts from the repository arises. For example, if an artifact was deployed by accident to the repository or the artifact has already been released but an old snapshot version is still available. In Archiva, there are different ways of deleting artifacts from the repository—through WebDAV, via the web application, through the scheduled repository purging, or by directly deleting it in the file system. It is not recommended that artifacts be deleted directly from the file system. Not only does it require access to the server itself, it is also prone to error. Artifacts that should not be deleted could be deleted by mistake. In case you still want to directly delete an artifact from the file system, all files related to the artifact such as metadata files and checksums must also be deleted. The repository must be scanned as well in order to update the metadata files. This can be done by clicking the Scan Repository Now button of the repository configuration in the Repositories page. The database scanning also needs to be explicitly executed to immediately remove the deleted artifact from the database. One of the advantages of using the Delete Artifact form in the web application is that you do not need to have direct access to the server. All you need is the required Archiva permissions, which come with the Repository Manager role (without the permissions Delete Artifact will not be visible in the navigation menu). Another advantage is that the repository scanning no longer needs to be explicitly executed as Archiva already executes the repository and database scanning consumers to update the index and the database for you. Now, let's try deleting an old artifact from one of the repositories. If you go to http://localhost:8081/archiva/repository/snapshots/com/effectivemaven/centrepoint/centrepoint, the old 1.0-SNAPSHOT version of the project still exists. We will remove this artifact from the repository using the delete artifact web form. First, click Delete Artifact from the navigation menu and then fill in the form as follows: Click the Submit button. After the artifact has been deleted, you should see the confirmation message Artifact 'com.effectivemaven.centrepoint:centrepoint:1.0-SNAPSHOT' was successfully deleted from repository 'snapshots'. If you browse the repository at http://localhost:8081/archiva/repository/snapshots, the related artifacts such as the POM, maven-metadata.xml, and the checksums were also deleted. To delete artifacts through WebDAV, just open the repository using a WebDAV client and delete the artifact like in a regular file system. As for the scheduled repository purging, we will discuss this in the following sections. We have tackled the subjects of repository groups, RSS feeds, and deleting artifacts in the repository. This article would never be complete without covering repository maintenance. The succeeding sections will be all about that. The Archiva reports Archiva generates two types of reports. These are the repository statistics, providing information such as statistical data of a repository's content and the repository health report, which makes us aware of any problems in the repository such as artifacts that have invalid POM files. Both accept different criteria for customizing the generated output as seen in the following screenshot: Now, let's discuss the configuration for each report. Repository statistics This report provides statistical repository information such as the total number of artifacts in the repository, its total size, the number of plugins in the repository, and the likes based on a given repository scan execution time. This report can be used for analyzing the current content of your repositories, and tracking its growth, usage, and evolution over time. The report can be constrained by the given Start Date and End Date. If no Start Date and End Date are provided, all statistics right from the start up to the current date will be included in the report (to a maximum of the number of rows given in the Row Count). For the Repository Statistics, we can also configure the Repositories To Be Compared. If only one repository is selected in Repositories To Be Compared, the generated report will contain details of a single repository. The following is a sample report where only one repository is selected: Let's run through the contents of the sample Repository Statistics report given previously for repository internal. The Total File Count pertains to the total number of files in the repository during each execution of the repository scan. The Total Size, on the other hand, is the size (in bytes) of the repository at that time. The number of unique groups and artifact names are broken down in the report as well as the number of plugins, archetypes, JAR, and WAR files. The last two columns—number of deployments and artifact requests—are not yet implemented but will be fixed in the future releases. On the other hand, if more than one repository is selected in the Repositories To Be Compared, the generated report would contain a comparison of the latest statistics of the repositories based on the specified End Date. This is useful for tracking which repositories are the most utilized. For example, if different development groups host their own repositories, the comparison can show which groups are using the most space. Look at the following screenshot for a sample comparison report to see the difference from the previous one: To allow you to view this report outside of the web application, the report can be exported as a CSV file by clicking on the Export to CSV link. You should be able to open the exported file as an Excel spreadsheet. Repository health One of the secrets behind a successful and reproducible build is a clean and healthy repository. Corrupt metadata or an invalid or missing POM file are the usual causes for a build to break. To prevent this from happening, we must ensure that the repositories we are getting our artifacts from are in good health. Archiva provides a way of doing this through the Repository Health report and its built-in utilities for updating metadata and fixing checksums. The Repository Health report provides a detailed list of artifacts in the repository that are found to be defective. It gives a starting point for correcting any problems and can be used when diagnosing build errors with a particular artifact. For example, a common reason for an artifact being defective is when the version of the artifact specified in the POM is different from the actual version in its filename. This could easily happen when using deploy:deploy-file (or even using the Archiva web upload form) as the actual filename used for the uploaded artifact is determined based on the supplied parameters. It is a possibility that the included POM in the upload has different coordinates from the provided parameters. These defects are discovered during Archiva's database scan, when the actual POM file is read and added to the database. We can narrow down the report by providing a specific Group ID and/or a Repository ID which will be used for querying defective artifacts that match these criteria. If you try querying for the report using the default configuration, you should be able to see a generated report similar to the following one, which shows a defective POM in repository internal. To repair such an error, you can manually fix the POM in the Archiva repository by updating it in the file system. If the defect is caused by a transfer error when the artifact was proxied, you can delete the artifact (including the metadata and checksums) then force Archiva to retrieve it again by requesting it. A word of caution though—making these changes could affect the reproducibility of a dependent project's build. For example, it is possible that the actual artifact in the central repository is the defective one. If you fixed the artifact in your internal Archiva repository, project builds that go through the local proxy may get a successful build. However, the project is built directly off central and the build fails because the dependency artifact is defective. That summarizes monitoring the health of our repositories. The next section discusses the built-in Archiva utilities which in one way or another clean up and repair broken artifacts and metadata in the repositories.    
Read more
  • 0
  • 0
  • 1572
article-image-build-advanced-contact-manager-using-jboss-richfaces-33-part-3
Packt
18 Nov 2009
11 min read
Save for later

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 3

Packt
18 Nov 2009
11 min read
  The ajaxSingle and the process attributes The ajaxSingle property is very useful to control the form submission when ajaxSingle is set to true—the form is not submitted and, just the Ajax component data is sent. This attribute is available in every Ajax action component and we can use it to call an action from a button, skipping the form validation (like the JSF immediate property does), or to send the value of just an input into a form without validation and submitting the other ones. The second use case can be used, for example, when we need an input menu that dynamically changes the value of other inputs without submitting the entire form: <h:form> <!-- other input controls --> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" reRender="city" /> </h:selectOneMenu> <h:selectOneMenu id="city" value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --></h:form> In this example, every time the user selects a new country, the value is submitted to the bean that recalculates the myCities property for the new country, after that the city menu will be re-rendered to show the new cities. All that without submitting the form or blocking the changes because of some validation problem. What if you would like to send more than one value, but still not the entire form? We can use Ajax regions (we will see in the next sections), or we can use the process attribute. It contains a list of components to process while submitting the Ajax action: <h:form> <!-- other input controls --> <h:inputText id="input1" ... /> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" process="input2, input3" reRender="city" /> </h:selectOneMenu> <h:inputText id="input2" ... /> <h:inputText id="input3" ... /> <h:selectOneMenu id="city" value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --></h:form> In this example, we also wanted to submit the input2 and the input3 values together with the new country, because they are useful for retrieving the new cities list—just by setting the process attribute with the id list and during the submission, they will be processed. Thus input1 will not be sent. Also, for action components such as buttons, you can decide what to send using the ajaxSingle and process attributes. Form submission and processingWe speak about form "submission" to simplify the concept and make things more understandable. In reality, for every request, all of the form is submitted, but only the selected components (using ajaxSingle and/or process attributes) will be "processed". By "processed" we mean "pass through" the JSF phases (decoding, conversion, validation, and model updating). More Ajax! For every contact, we would like to add more customizable fields, so let's use the ContactField entity connected to every Contact instance. First of all, let's create a support bean called HomeSelectedContactOtherFieldsHelper inside the book.richfaces.advcm.modules.main package. It might look like this: @Name("homeSelectedContactOtherFieldsHelper")@Scope(ScopeType.CONVERSATION)public class HomeSelectedContactOtherFieldsHelper { @In(create = true) EntityManager entityManager; @In(required = true) Contact loggedUser; @In FacesMessages facesMessages; @In(required = true) HomeSelectedContactHelper homeSelectedContactHelper; // my code} A notable thing is highlighted—we injected the homeSelectedContactHelper component, because to get the list of the customized fields from the database, we need the contact owner. We also set the required attribute to true, because this bean can't live without the existence of homeSelectedContactHelper in the context. Now, let's add the property containing the list of personalized fields for the selected contact: private List<ContactField> contactFieldsList;public List<ContactField> getContactFieldsList() { if (contactFieldsList == null) { // Getting the list of all the contact fields String query = "from ContactField cf where cf.contact.id=:idContactOwner order by cf.id"; contactFieldsList = (List<ContactField>) entityManager.createQuery(query) .setParameter("idContactOwner", homeSelectedContactHelper.getSelectedContact() .getId()).getResultList(); } return contactFieldsList;}public void setContactFieldsList(List<ContactField> contactFieldsList) { this.contactFieldsList = contactFieldsList;} As you can see, it is a normal property lazy initialized using the getter. This queries the database to retrieve the list of customized fields for the selected contact. We have to put into the bean some other method useful to manage the customized field (adding and deleting field to and from the database), let's add those methods: public void createNewContactFieldInstance() { // Adding the new instance as last field (for inserting a new field) getContactFieldsList().add(new ContactField());}public void persistNewContactField(ContactField field) { // Attaching the owner of the contact field.setContact(homeSelectedContactHelper.getSelectedContact()); entityManager.persist(field);}public void deleteContactField(ContactField field) { // If it is in the database, delete it if (isContactFieldManaged(field)) { entityManager.remove(field); } // Removing the field from the list getContactFieldsList().remove(field);}public boolean isContactFieldManaged(ContactField field) { return field != null && entityManager.contains(field);} The createNewContactFieldInstance() method will just add a new (not yet persisted), empty instance of the ContactField class into the list. After the user has filled the values in, he/she will press a button that calls the persistNewContactField() method to save the new data into the database. In order to delete it, we are going to use the deleteContactField() method, and to determine if an instance is persisted into the database or not, we are going to use the isContactFieldManaged() method. Now, let's open the /view/main/contactView.xhtml file and add the code to show the personalized fields after h:panelGrid— i shows the standard ones: <a:repeat value="#{homeSelectedContactOtherFieldsHelper.contactFieldsList}" var="field"> <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value"> <h:outputText value="#{field.type} (#{field.label}):"/> <h:outputText value="#{field.value}"/> </h:panelGrid></a:repeat> We are using a new RichFaces data iteration component that permits us to iterate over a collection and put the data we want (the rich:dataTable component would instead create a table for the elements list). In our case, the h:panelGrid block will be repeated for every element of the collection (so for every customized field). Now, let's open the /view/main/contactEdit.xhtml file and add the code for editing the customized fields into the list: <a:region> <a:outputPanel id="otherFieldsList"> <a:repeat value="#{homeSelectedContactOtherFieldsHelper. contactFieldsList}" var="field"> <h:panelGrid columns="3" rowClasses="prop" columnClasses="name,value,validatormsg"> <h:panelGroup> <h:inputText id="scOtherFieldType" value="#{field.type}" required="true" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=" ("/> <h:inputText id="scOtherFieldLabel" value="#{field.label}" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=")"/><br/> <rich:message for="scOtherFieldType" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <h:inputText id="scOtherFieldValue" value="#{field.value}" required="true"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText><br/> <rich:message for="scOtherFieldValue" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <a:commandButton image="/img/add.png" reRender="otherFieldsList" action="#{homeSelectedContactOtherFieldsHelper. persistNewContactField(field)}" rendered="#{!homeSelectedContactOtherFieldsHelper. isContactFieldManaged(field)}"> </a:commandButton> <a:commandButton image="/img/remove.png" reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. deleteContactField(field)}"> </a:commandButton> </h:panelGroup> </h:panelGrid> </a:repeat> <a:commandLink reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. createNewContactFieldInstance}" rendered="#{homeSelectedContactHelper. selectedContactManaged}" styleClass="image-command-link"> <h:graphicImage value="/img/add.png"/> <h:outputText value="#{messages['addNewField']}"/> </a:commandLink> </a:outputPanel></a:region> The code looks very similar to the one in the view box, except for the action buttons (to add a new instance, persist, save, or delete) and, for the presence of the surrounding tag a:region (highlighted). This is very important in order to make sure the form works correctly; we will see why in the next section. Also, notice that every input component has the a:support tag as a child that will update the bean with the edited value at the onblur event (which means that every time you switch the focus to another component, the value of the last one is submitted). So, if you delete or add a field, you will now loose the edited values for other fields. It is also used for Ajax validation, as the user is informed that the value is not valid when it moves the cursor to another input. Here is a screenshot with the new feature in the edit box: Using a:support only for Ajax validation If you want to use the a:support tag only for validation purpose, remember to set its bypassUpdates attribute to true, so the process would be faster as the JSF Update Model and Invoke Application phases will not be invoked. Ajax containers While developing a web application with RichFaces, it's very useful to know how to use Ajax containers (such as the a:region component) in order to optimize Ajax requests. In this section, we'll discuss about the a:region component. It is a very important component of the framework—it can define Ajax areas to limit the part of the component tree to be processed during an Ajax request. Regions can be nested during an Ajax request and the closest one will be used. By setting to true the a:region attribute called regionRenderOnly, you can use this component to limit the elements' update—In this way, in fact, only the components inside the region can be updated. Another important attribute is selfRendered; setting this to true tells the framework to render the response basing on component tree without referring to the page code—it is faster, but all of the transient elements that are not saved in the tree (such as f:verbatim or HTML code written directly without using JSF components) will be lost at the first refresh, so you can't use them in this case. To summarize, it is very useful to control the rendering process and optimize it, in order to limit the elements of a form to send during an Ajax request without validation problems, to show different indicators for Ajax status. Example of using a:region: <h:form> <a:region> <h:inputText id="it1" value="#{aBean.text1}"> <a:support event="onkeyup" reRender="text1" /> </h:inputText> <h:inputText id="it2" value="#{aBean.text2}" /> </a:region> <h:inputText id="it3" value="#{aBean.text3}" /> <a:commandButton action="#{aBean.saveTexts}" reRender="text1,text2" /></h:form><h:outputText id="text1" value="#{aBean.text1}" /><h:outputText id="text2" value="#{aBean.text2}" /> In this example, while the user is typing in the text1 value of inputText, a:support sends an Ajax request containing only the it1 and it2 values of inputText. In this case, in fact, a:region limits the components sent by every Ajax request originated from inside the region. So, the Ajax request will only update aBean.text1 and aBean.text2. Wrapping only a component inside an Ajax region is the equivalent of using the ajaxSingle property set to true. If the user clicks on the a:commandButton aBean.text1, the aBean.text2 and aBean.text3 values will be updated by the Ajax request. Coming back to our application, as all the customized fields are inside the same form component, we surround each one with the a:region tag. In this way, the single field is submitted regardless of the other ones. For example, without using a:region, if the user empties the name input value and then tries to insert a new customized field, the process will fail because the name input is not validated. If we use the a:region component, the name field will not be processed and a new field will be inserted. Now that we know how to use the a:region tag, we can combine it with ajaxSingle and process in order to decide what to send at every request, and to better optimize Ajax interactions into the application.
Read more
  • 0
  • 0
  • 1402

article-image-ubuntu-910-how-upgrade
Packt
18 Nov 2009
5 min read
Save for later

Ubuntu 9.10: How To Upgrade

Packt
18 Nov 2009
5 min read
So the new Ubuntu is here and you’re just dying to upgrade and have a look at all the new features! With just a few simple steps you'll be up and running the new system in no time! Before you dive right in, there are a few things you should know, and a few ways to (hopefully) make your upgrade process more pleasant. This article is broken up into sections outlining the preparation, requirements and upgrade steps needed for each platform. It is important to follow the steps in order to ensure a full and painless upgrade. Also, please follow only one of the upgrade paths. In other words, there are different methods for a Desktop as compared to a Server. You only need to follow those steps applicable to you. A Note Regarding Upgrades vs Fresh Installations You may be wondering whether it is better to upgrade your current installation or do a fresh install from CD. There are benefits to doing a fresh installation to be sure, but there are also benefits to upgrading your system in place. I know people that swear by one method, and others that swear by another. In the end, both methods are supported and will give you the same Ubuntu experience. Fresh installations will require a complete wipe of your hard disk. This means that you'll need to backup any important documents, pictures or other files that you'll want to keep. Have you ever done a fresh installation before and realized only too late that you forgot to back something up? I have. It's easy to miss something. Using the in-place upgrade methods found in this article you won't need to worry about backups. With an in-place upgrade you can generally keep working on your machine while applications are upgraded in the background. This means you can continue to browse the web or send and receive email while the system is upgraded. Bottom line is that upgrades are thoroughly tested and just as well supported as fresh installations. Preparation When upgrading your system from one release to the next, there are certain requirements that you must meet in order to be successful. First of all, and most importantly in this instance, this upgrade path is only possible from Ubuntu 9.04 "Jaunty Jackalope" to Ubuntu 9.10 "Karmic Koala". If you are using a release previous to 9.04 (8.10 or earlier), stop now. This upgrade process will not work, is not supported and will likely cause problems. If you are unsure which version you have installed, you can run this command in your terminal to find out. (Applications > Accessories > Terminal) lsb_release -a If you find that you are on a release previous to Ubuntu 9.04, you will need to decide whether it is best to do a fresh installation or do an incremental upgrade leading up to 9.10. Incremental upgrades, as well as fresh installations are beyond the scope of this article, but there is detailed documentation on the matter found here: https://help.ubuntu.com/community/UpgradeNotes Updates Once you have verified that you are using Ubuntu 9.04 "Jaunty Jackalope" you will be able to begin the upgrade proccess. In order for the latest version to become available to you, you'll need to apply any pending updates to your current version. There are two ways to apply available updates pending a system upgrade. The first method applies to the graphical Desktop or Laptop platform. The second method applies to a server, or non-graphical installation. Remember, please only follow the steps applicable to you. Graphical Updates (Pre-Upgrade) If you are using the graphical environment you can check for and apply updates by way of the Update Manager tool. This can be found by navigating to: (System > Administration > Update Manager). This tool will automatically scan for and list any pending updates. Be sure to apply all available updates before moving to the next step. You can ensure that there are no more pending updates by clicking Check and verifying that it displays the message "Your system is up to date". Command Line Updates (Pre-Upgrade) For those more comfortable with the command line interface, or those running a non-graphical Server installation, you can run the following command to check for and apply any available system updates. sudo aptitude update && sudo aptitude safe-upgrade && sudo aptitude full-upgrade Apply any updates that are pending from the command above before you move to the next step. You can repeat this command until no more updates are offered to ensure you are ready. Now that you have applied the remainder of the updates for your current system, you can move to the next step. In the next step, Selecting a Mirror, you will learn how to use an alternate, often faster, package repository for your updates. This means that instead of using the default and often overwhelmed main Ubuntu servers for updates you can configure your system to use one closer to you. This often results in faster downloads and upgrades.
Read more
  • 0
  • 0
  • 13470

article-image-datagrid-api-ibm-websphere-extreme-scale-6-part-2
Packt
18 Nov 2009
21 min read
Save for later

The DataGrid API with IBM WebSphere eXtreme Scale 6: Part 2

Packt
18 Nov 2009
21 min read
Aggregate results One thing to be aware of with the MapGridAgent interface is its potential for a partition to send huge result maps to a client. This is the nature of the map function. Its output size can be proportional to its input size if we don't use a query to select    specific objects to work with or specify a key set. In this case, we need a specific result for every key, with the key set as narrow as we can make it. We then just need to deal with large maps once in a while. What if we need an aggregate result for a key set? Instead of an operation and result for each element, we need an operation over all elements with just one result. Simple examples include the highest or lowest number in a set, and the earliest or total payroll expenses in a management hierarchy. In these examples, we need data from a set of elements in a partition, but we don't need a result for each. We only want one result for the entire set of objects. Going back to our functional programming reference, this is where the reduce function shines. Like the map function, reduce has a corresponding grid agent interface. The reduce function takes a collection of input keys and only produces one result for the entire collection. The result is typically an aggregate result: a sum, product, max, min, average, or any other aggregate function. Classes that implement ReduceGridAgent are used as parameters to the AgentManager#callReduceAgent(ReduceGridAgent agent, Collection keys) and AgentManager#callReduceAgent(agent) methods. The implementation itself is similar to the MapGridAgent pattern. The reduce grid agent we write operates on a collection of known keys or an unknown key set. If we have a known key set, then we will run the agent with AgentManager#callReduceAgent(agent, keys). If the key set is not known, and if we need a query to find the interesting objects, then we will call the AgentManager#callReduceAgent(agent). Let's write a ReduceGridAgent that finds the largest integer in a set. We'll start with a naïve implementation for finding the largest integer in an array: public int findLargestInteger(Integer[] ints) {int largestInt = ints[0];for (int i = 0; i < ints.length; i++) {if (ints[i] > largestInt) {largestInt = ints[i];}}return largestInt;} Implementing ReduceGridAgent requires three methods. Two of those methods look like the process methods in MapGridAgent. We have ReduceGridAgent#reduce(session, map, keys) and ReduceGridAgent#reduce(session, map). Like its MapGridAgent counterparts, the reduce method that accepts keys in the signature works with keys or Entity objects. The reduce method without keys in the signature should use a Query to find the objects most interesting to our business logic. public class LargestIntReduceAgent implements ReduceGridAgent,EntityAgentMixin {public Object reduce(Session session, ObjectMap map,Collection keys) {MyInteger largestInt = null;Iterator iter = keys.iterator();while (iter.hasNext()) {(MyInteger)myInt = (MyInteger)iter.next();if (myInt.greaterThan(largestInt)) {largestInt = myInt;}}return largestInt;}public Object reduce(Session session,ObjectMap map) {// Nothing to do for now!}public Object reduceResults(Collection results) {// Nothing to do for now!}public Class getClassForEntity() {return MyInteger.class;}} The first reduce method is similar in signature to the MapGridAgent#process(session, map, key) method. The difference here is that the third argument in ReduceGridAgent#reduce(session, map, keys) is a collection of keys rather than one key. This immediately illustrates the difference between the two. A Map operation takes place on only one element. Reduce operates on the entire collection. With a known key set, the ReduceGridAgent#reduce(session, map, keys) method is called. Without a key set passed to the AgentManager#callReduceAgent(agent) method, the GridReduceAgent#reduce(session, map) method is called. This method should use a Query to ?  nd the objects we want to use in our business logic. The keys or entity objects can then be passed to the ReduceGridAgent#reduce(session, map, keys) method for the actual business logic. We submit this agent to the grid in almost the same way as we submit a MapGridAgent to the grid. AgentManager has two callReduceAgent methods. The first takes a collection of keys as an argument, while the second does not. Submitting this agent to the grid looks like this: Collection numbers = new ArrayList();for(int i = 0; i < 10000; i++) {numbers.add(i);}ReduceGridAgent agent = new LargestIntReduceAgent();AgentManager am = session.getMap("MyInteger").getAgentManager();am.callReduceAgent(agent, numbers); This looks so similar to submitting a MapGridAgent to the grid and you may miss the method change to am.callReduceAgent(agent, keys). The programming models are so similar you may ask why there isn't just one generic callAgent method. Take a look at the ReduceGridAgent, particularly the ReduceGridAgent#reduceResults(results)  method. This method is called on the client side after all instances of the agent return their results. At this point, we have a collection of results for each partition. It is acceptable for the AgentManager#callMapAgent(agent, keys) to return the merged results here. AgentManager#callReduceAgent(agent, keys) must return one result for the entire operation. The ReduceGridAgent#reduceResults(results) method aggregates each partition's aggregate results: public class LargestIntReduceAgent implements ReduceGridAgent,EntityAgentMixin {public Object reduce(Session session, ObjectMap map,Collection keys) {return findLargestInt(keys);}public Object reduce(Session session,ObjectMap map) {// Nothing to do for now!}public Object reduceResults(Collection results) {findLargestInt(results);}public Class getClassForEntity() {return MyInteger.class;}private MyInteger findLargestInt(Collection keys) {MyInteger largestInt = null;Iterator iter = keys.iterator();while (iter.hasNext()) {(MyInteger)myInt = (MyInteger)iter.next();if (myInt.greaterThan(largestInt)) {largestInt = myInt;}}return largestInt;}} ReduceGridAgent#reduceResults(keys) is responsible for producing the final result passed back to the AgentManager#callReduceAgent(agent, keys) caller. Sometimes, the reduce operation performed in this final aggregation is the same as the operation performed in the ReduceGridAgent#reduce(session, map, keys) method. Sometimes, the operation is different. In our case, it is the same, and we refactor the reduce operation into a private method. Finishing off the ReduceGridAgent, we come to ReduceGridAgent#reduce(session, map). The method signature is similar to MapGridAgent#processAllEntries(session, map) and should be a hint that they have a similar purpose. The ReduceGridAgent#reduce(session, map) is called when a key list is not provided to AgentManager#callReduceAgent(agent). ReduceGridAgent#reduce(session, map) should limit the number of objects used in the reduce operation. Like MapGridAgent#processAllEntries(session, map), we typically use a Query. While the reduce agent does not send large results back to the client, we still care about finding objects that meet our criteria to use in the reduce operation: public Object reduce(Session session,ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select m from MyInteger m " +"where m.integer > 0 " +"and m.integer < 10000");Iterator iter = q.getResultIterator();Collection<MyInteger> keys = new ArrayList<MyInteger)();while (iter.hasNext()) {MyInteger mi = (MyInteger)iter.next();keys.add(mi);}return reduce(session, map, keys);} Though these are not strict rules, this method usually follows a pattern like MapGridAgent#processAllEntries(session, map). Run a query to limit the number of objects used in the reduce operation. Create a collection of keys used by the reduce operation. We're using entities here. Rather than duplicating the reduce operation in this method, we use put entities from the Query in the key collection. ReduceGridAgent#reduce(session, map, keys), when using Entities, expects a collection of MyInteger objects. Call ReduceGridAgent#reduce(session, map, keys) using the key collection we just created. There is no rule against re-implementing the reduce operation in each method but we'll be good software engineers and keep it DRY. If we can massage the query results into arguments, the reduce method accepts, and then we have enough reason to reuse it. At this point, we can submit this agent to the grid with or without a set of known keys and get the largest MyInteger back. In both, the MapGridAgent and ReduceGridAgent, we used a Query to limit the number of objects used in each operation: Query q = em.createQuery("select m from MyInteger m " +"where m.integer > 0 " +"and m.integer < 10000");Iterator iter = q.getResultIterator(); Obviously, this query is limited in what it can do. The criteria is hardcoded into the query. This query can only find MyIntegers with values between 0 and 10,000. Initially, we hardcoded these values because the agent runs on a partition in a container. Fortunately, we can pass additional data along with our agent.   Using ephemeral objects in agents In the previous examples, we hard coded the query criteria in the process and reduce methods. We should let the client-side program set those parameters instead of dictating what range of numbers the queries operate on. Right now, our queries are limited to exactly what is coded. A grid agent is just a POJO. It can have fields, getter and setter methods, and any other methods outside of the implemented grid agent interface. It's probably best to limit functionality to grid agent functionality but that doesn't mean that we can't have fields or other objects on the implementing class. Classes that implement the agent interfaces are POJOs. We'll send additional data to the grid by adding fields to the implementing class: public class LargestIntReduceAgent implements ReduceGridAgent,EntityAgentMixin {private Integer minValue;private Integer maxValue;// Reduce methods omitted for brevitypublic void setMinValue(Integer min) {this.minValue = min;}public void setMaxValue(Integer max) {this.maxValue = max;}} The only requirement for sending these additional fields to the grid is that they must each be serializable. Sending these objects to the grid is probably a one-way trip. Unless they're passed back as part of a map result, we cannot use them to communicate the state between client and grid. The grid agent instance used on the client side does not get a copy of the state of grid agent variables when the agents finish execution in the grid. Including grid state objects in the result set is bad practice and unnecessary. Before we pass the agent to AgentManager#callReduceAgent(agent), we set the fields used in the partition-side query: ReduceGridAgent agent = new LargestIntReduceAgent();agent.setMinValue(500);agent.setMaxValue(5000);AgentManager am = session.getMap("MyInteger").getAgentManager();am.callReduceAgent(agent); The ReduceGridAgent#reduce(session, map) method requires a small change to use our new query parameters: public Object reduce(Session session,ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select m from MyInteger m " +"where m.integer > ?1 " +"and m.integer < ?2");query.setParameter(1, minValue);query.setParameter(2, maxValue);Iterator iter = q.getResultIterator();Collection<MyInteger> keys = new ArrayList<MyInteger)();while (iter.hasNext()) {MyInteger mi = (MyInteger)iter.next();keys.add(mi);}return reduce(session, map, keys);} It's almost the same as before. We've just parameterized the query. It now uses the two values we sent into the grid with the agent. We can send more than query parameters along with an agent. We can send additional, complex business logic. If we obey the principles of object-oriented design, then we favor composition over inheritance. This allows the composition of agents with complex map or reduce operations, without cluttering the agent implementation class with business logic. To demonstrate, we'll refactor the findLargestInt(collection) method out of the LargestIntReduceAgent class: public interface MyHelper {public MyInteger call(Collection keys);}public class AgentHelper implements MyHelper, Serializeable {public MyInteger call(Collection keys) {MyInteger largestInt = null;Iterator iter = keys.iterator();while (iter.hasNext()) {(MyInteger)myInt = (MyInteger)iter.next();if (myInt.greaterThan(largestInt)) {largestInt = myInt;}}return largestInt;}} This is just a class that encapsulates the method formerly known as findLargestInt(collection). The name changed to conform to an imaginary calling convention is used by our agents. The ReduceGridAgent changes a bit to accommodate this calling convention: public class LargestIntReduceAgent implements ReduceGridAgent,EntityAgentMixin {private Integer minValue;private Integer maxValue;private MyHelper helper;public Object reduce(Session session, ObjectMap map,Collection keys) {return helper.call(keys);}public Object reduce(Session session,ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select m from MyInteger m " +"where m.integer > ?1 " +"and m.integer < ?2");query.setParameter(1, minValue);query.setParameter(2, maxValue);Iterator iter = q.getResultIterator();Collection<MyInteger> keys = new ArrayList<MyInteger)();while (iter.hasNext()) {MyInteger mi = (MyInteger)iter.next();keys.add(mi);}return reduce(session, map, keys);}public Object reduceResults(Collection results) {helper.call(results);}public getClassForEntity() {return MyInteger.class;}public void setMinValue(Integer min) {this.minValue = min;}public void setMaxValue(Integer max) {this.maxValue = max;}public void setHelper(MyHelper helper) {this.helper = helper;}} LargestIntReduceAgent's concern is interacting with the grid. Refactoring the findLargestInt method into different classes keeps our code clean and more easily testable. It also allows algorithm replacement. If we come up with a better map or a reduce method, then the GridAgent implementation doesn't change. LargestIntReduceAgent calls the helper.call(collection) method. The AgentHelper class is serialized with the agent and sent to each partition the agent is sent to. Once on the grid, the AgentHelper#call(collection) method is available to the agent. The normal Java serialization process handles agent serialization. Anything serializable in that processes is sent to the grid. Serializing these objects, and sending them to the grid requires that the appropriate class files be on the classpath of each ObjectGrid container process before the agent is sent to the grid. Updates with agents The agents we've seen so far are idempotent. They do not change any objects in the grid. They create new objects as a result of their operation but the objects queried by the agents remained unchanged. There is no rule against updating objects in an agent. Any operation valid inside an ObjectGrid transaction can also be performed in an agent, including inserts, updates, and deletes. In this way, an agent doesn't necessarily need to perform a map or reduce operation. It acts as a code transport between the client and server. We should be cautious with this relaxed approach to agents because there is a lot of potential for abuse. Used with caution, running agents on the grid for inserts, updates, and deletes creates a powerful application controlled by submitting agents to the grid. Building an application around agents reduces the need for running large numbers of client processes. Let's go back to our payment processor example to look at updates using a GridAgent. Specifically, we'll update a batch of deposit payments with a status of BatchStatus.SENT_TO_NETWORK after we receive the payments from the merchant and check for duplicates. We need to make a choice between using a MapGridAgent and a ReduceGridAgent. The choice depends on the behavior our application needs with the result of the operation. If we want to do more work with each payment after it is sent to the network, then we choose a MapGridAgent. Because we only care that the payments are updated, we'll choose the ReduceGridAgent. ReduceGridAgent gives one result for the entire operation, which in this case is the status of the operation, either success or failure. We don't have a particular known key set for all of the payments in a batch. A large batch has payments spread across nearly all partitions. We call our PaymentStatusReduceAgent with the AgentManager#callReduceAgent(agent) method: PaymentStatusReduceAgent agent = new PaymentStatusReduceAgent();agent.setBatch(batch);agent.setFromStatus(PaymentStatus.WAITING);agent.setToStatus(PaymentStatus.SENT_TO_NETWORK);AgentManager am = session.getMap("Payment").getAgentManager();am.callReduceAgent(agent); We use the AgentManager#callReduceAgent(agent) method because we want all partitions in the grid to participate in the reduce operation. The reduce operation begins by finding all payments that match a certain criteria. We want all payments for a batch that have a status of WAITING. We set these properties on the agent so that the AgentManager serializes them and sends them to the grid along with the agent. They are used as query parameters in the ReduceGridAgent#reduce(session, map) method: public Object reduce(Session session,ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select p from Payment p " +"where p.batch = ?1 " +"and p.status = ?2");query.setParameter(1, batch);query.setParameter(2, fromStatus);Iterator iter = q.getResultIterator();Collection<MyInteger> keys = new ArrayList<MyInteger)();while (iter.hasNext()) {Payment payment = (Payment)iter.next();keys.add(payment);}return reduce(session, map, keys);} We create a collection of payments to pass to the ReduceGridAgent#reduce(session, map, keys) method. In there, we perform the update payment status operations. Instead of an aggregate result based on calculations of objects in the grid, it is based on the success or failure of the update operations to each object. The ReduceGridAgent#reduce(session, map, keys) method returns a  Boolean value if the update succeeds, and throws an exception if it does not: public Object reduce(Session session, ObjectMap map,Collection keys) {try{Session s = session.getObjectGrid().getSession();EntityManager em = s.getEntityManager();Iterator iter = keys.iterator();while (iter.hasNext()) {Payment payment = (Payment)iter.next();payment.setStatus(toStatus);em.merge(payment);}return Boolean.TRUE;} catch(ObjectGridException e) {throw new ObjectGridRuntimeException(e);}} Throwing an exception doesn't exactly follow the spirit of the reduce operation. If the update operation fails, then the exception is thrown up the call stack and across the network to AgentManager#callReduceAgent(agent). If the update operation fails, then we have bigger problems to worry about than the exception uncovered by the update operation. We throw the exception here because the situation is unrecoverable by the reduce operation. A call to ReduceGridAgent#reduceResults(results) is meaningless when there is an exception. Absent from this code are explicit transaction demarcations. When the MapGridAgent and ReduceGridAgent methods are called, they are under an already-active transaction on the session passed in to them. Should the grid agent methods throw an exception, the transaction is rolled back. This transaction is independent of the client transaction and any other active agent transactions. If one of the agent transactions rolls back, then the client transaction rolls back too. We see a few interesting things from the payment update implemented as a reduce operation. In the happy-path case, each agent will return Boolean.TRUE. We only return Boolean.TRUE to conform to the method signature. A collection of values of Boolean.TRUE is passed to the ReduceGridAgent#reduceResults(Collection results) method. There is nothing more to do in the reduce operation. The values in the results collection do not play any part in the update operation. The update was successful. We know this because an exception wasn't thrown in any of the reduce methods. These two things let us implement a very simple ReduceGridAgent#reduceResults(Collection results) method: public Object reduceResults(Collection results) {return null;} Either the update succeeds and we don't need to do any more, or we know the update failed by getting an exception thrown out of the AgentManager#callReduceAgent(agent) method. It may seem strange that we don't  confirm the update is successful. Do we always explicitly check that JDBC updates were successful? No. We assume that because there was no thrown exception, the update happened. The same goes for our update in the ReduceGridAgent. For clarity, let's look at the PaymentStatusReduceAgent in its entirety: public class PaymentStatusReduceAgent implements ReduceGridAgent,EntityAgentMixin {private Batch batch;private PaymentStatus fromStatus;private PaymentStatus toStatus;public Object reduce(Session session, ObjectMap map,Collection keys) {try{Session s = session.getObjectGrid().getSession();EntityManager em = s.getEntityManager();Iterator iter = keys.iterator();em.getTransaction().begin();while (iter.hasNext()) {Payment payment = (Payment)iter.next();payment.setStatus(toStatus);em.merge(payment);}em.getTransaction().commit();return Boolean.TRUE;} catch(ObjectGridException e) {throw new ObjectGridRuntimeException(e);}}public Object reduce(Session session,ObjectMap map) {EntityManager em = session.getEntityManager();Query q = em.createQuery("select p from Payment p " +"where p.batch = ?1 " +"and p.status = ?2");query.setParameter(1, batch);query.setParameter(2, fromStatus);Iterator iter = q.getResultIterator();Collection<MyInteger> keys = new ArrayList<MyInteger)();while (iter.hasNext()) {Payment payment = (Payment)iter.next();keys.add(payment);}return reduce(session, map, keys);}public Object reduceResults(Collection results) {return null;}public getClassForEntity() {return Payment.class;}public void setBatch(Batch b) {this.batch = b;}public void setFromStatus(PaymentStatus status) {this.fromStatus = status;}public void setToStatus(PaymentStatus status) {this.toStatus = status;}} Scheduling agents The AgentManager methods are blocking methods. A method call on any method in AgentManager remains at that point in execution, while the data grid runs the agent instances against its primary partitions. The thread that calls the AgentManager method must wait for a return from the call before it proceeds. In case blocking is unacceptable, we should schedule the call to the AgentManager methods using the java.util.concurrent API. There are two cases to consider when thinking about scheduling agents. The first is with the AgentManager#callReduceAgent(agent) and AgentManager#callMapAgent(agent) methods. These methods do not pass any keys to the agents. In this case, the agent is executed on all primary partitions. It may be okay for a client application to block here while it waits for the result from the grid. Obviously, scheduling insert, update, and delete operations provides some performance improvement, if we work at the client-side in the future, that does not depend on those objects being in the grid (or not, as the case may be). A read operation where the client depends on the result before proceeding probably shouldn't schedule the agent. One case where scheduling read operations is important is when we have multiple sets of keys passed to agents of the same type. Given a large object set, where the objects partition many different primaries, we don't want to pass the entire key set to an agent. For a sufficiently large key set, an agent will spend most of its time processing (ignoring) keys that do not belong to its partition. Instead, we can pre-sort the keys into collections of objects where all belong to the same partition. We then send the smaller, pre-sorted collections to the grid. We determine an object's partition with a PartitionManager. Each BackingMap has a PartitionManager associated with it, which is obtained with the BackingMap#getPartitionManager() method. PartitionManager#getPartition(Object key) returns the 0-based partition number, which is the partition the PartitionManager puts the object in. This is easy when working with the ObjectMap API. Let's assume: MyInteger mi = (MyInteger)myIntMap.get(35);BackingMap map = session.getObjectGrid().getMap("MyInteger");int partitionId = map.getPartitionManager().getPartition(35); We don't need the first line. It only shows that we have a MyInteger with a key of 35. We obtain the ObjectGrid reference, and then the BackingMap for the MyInteger map from the session.  We then call the getPartition(key) method for that same key. The result of this call is the ID of the partition that holds the MyInteger object with the key 35. Now, we can use object and entity keys to sort objects based on partitions. After sorting the objects into smaller collections, we pass them to AgentManager#callMapAgent(agent, keys) and AgentManager#callReduceAgent(agent, keys). These calls should now be scheduled in different threads, rather than making each call in a loop. If we then make these method calls in a loop, we then effectively turn the data grid into an expensive client program. The client program blocks during each call to the AgentManager methods. If we have 20 key collections that map to 20 different partitions, we will send only one request at a time to the grid if we send the agents in a loop. Instead, we want them to execute in parallel. We can do this by sending each instance of grid agent to the grid using a java.util.concurrent.ExecutorService. Summary We covered a lot of ground again in this article. Working with objects where they live produces much higher throughput than dragging objects to a client and pushing them back to the grid when we're done. Co-locating logic and data is easy to do with the DataGrid API. DataGrid gives us a few patterns to follow when writing agents. It also makes us think in terms of map operations and reduce operations. Though these two methods seem limiting at first, they are useful when operating on very large data sets. The    map operation gives us a way to perform an algorithm on each object in a set. The reduce operation lets us create aggregate results from a set. We aren't limited to only sending logic to the grid with an agent. Thanks to Java serialization, we send any serializable object referenced by our agent to the grid along with it. This gives us flexibility in running queries in an agent, and in passing helper logic. We also looked at pre-sorting objects into maps based on their partition ID. This reduces the size of the bytes sent from the client to a partition, and lets the agent run only for keys known to be in the partition the agent runs on. With a little imagination, we can put more work on the grid. This gives us much higher throughput and scales horizontally with the resources given to our grid. Appropriately partitioned, a grid can scale out and return results at a predictable rate, no matter how many objects it stores.
Read more
  • 0
  • 0
  • 1303
article-image-authentication-zendauth-zend-framework-18
Packt
18 Nov 2009
6 min read
Save for later

Authentication with Zend_Auth in Zend Framework 1.8

Packt
18 Nov 2009
6 min read
Let's get started. Authentication versus Authorization Before we go any further, we need to first look at what exactly authentication and authorization is, as they are often misunderstood. Authorization is the process of allowing someone or something to actually do something. For example, if I go into a data centre, then the security guards control my authorization to the data centre and would, for instance, not allow me access to the server room if I was just a visitor but would if I worked there as a system admin. Authentication is the process of confirming someone or something's identity. For example, when I go to into the data centre the security guards will ask me for my identity, which most probably would be a card with my name and photo on. They use this to authenticate my identity. These concepts are very important so make sure you understand the difference. This is how I remember them: Authorization: Can they do this?Authentication: Are they who they say they are? Authentication with Zend_Auth To provide our authentication layer, we are going to use Zend_Auth. It provides an easy way to authenticate a request, obtain a result, and then store the identity of that authentication request. Zend_Auth Zend_Auth has three main areas—authentication adapters, authentication results, and identity persistence. Authentication adapters Authentication adapters work in a similar way to database adapters. We configure the adapter and then pass it to the Zend_Auth instance, which then uses it to authenticate the request. The following concrete adapters are provided by default: HTTP Digest authentication HTTP Basic authentication Database Table authentication LDAP authentication OpenID authentication InfoCard authentication All of these adapters implement the Zend_Auth_Adapter_Interface, meaning we can create our own adapters by implementing this interface. Authentication results All authentication adapters return a Zend_Auth_Result instance, which stores the result of the authentication request. The stored data includes whether the authentication request was successful, an identity if the request was successful, and any failure messages, if unsuccessful. Identity persistence The default persistence used is the PHP session. It uses Zend_Session_Namespace to store the identity information in the Zend_Auth namespace. There is one other type of storage available named NonPersistent, which is used for HTTP authentication. We can also create our own storage by implementing the Zend_Auth_Storage_Interface. Authentication Service We are going to create an Authentication Service that will handle authentication requests. We are using a service to keep the authentication logic away from our User Model. Let's create this class now: application/modules/storefront/services/Authentication.phpclass Storefront_Service_Authentication{ protected $_authAdapter; protected $_userModel; protected $_auth; public function __construct(Storefront_Model_User $userModel = null) { $this->_userModel = null === $userModel ? new Storefront_Model_User() : $userModel; } public function authenticate($credentials) { $adapter = $this->getAuthAdapter($credentials); $auth = $this->getAuth(); $result = $auth->authenticate($adapter); if (!$result->isValid()) { return false; } $user = $this->_userModel ->getUserByEmail($credentials['email']); $auth->getStorage()->write($user); return true;}public function getAuth(){ if (null === $this->_auth) { $this->_auth = Zend_Auth::getInstance(); } return $this->_auth;}public function getIdentity(){ $auth = $this->getAuth(); if ($auth->hasIdentity()) { return $auth->getIdentity(); } return false;}public function clear(){ $this->getAuth()->clearIdentity();}public function setAuthAdapter(Zend_Auth_Adapter_Interface $adapter){ $this->_authAdapter = $adapter;}public function getAuthAdapter($values){ if (null === $this->_authAdapter) { $authAdapter = new Zend_Auth_Adapter_DbTable( Zend_Db_Table_Abstract::getDefaultAdapter(), 'user', 'email', 'passwd' ); $this->setAuthAdapter($authAdapter); $this->_authAdapter ->setIdentity($values['email']); $this->_authAdapter ->setCredential($values['passwd']); $this->_authAdapter ->setCredentialTreatment( 'SHA1(CONCAT(?,salt))' ); } return $this->_authAdapter; }} The Authentication Service contains the following methods: __constuct: Creates or sets the User Model instance authenticate: Processes the authentication request getAuth: Returns the Zend_Auth instance getIdentity: Returns the stored identity clear: Clears the identity (log out) setAuthAdapter: Sets the authentication adapter to use getAuthAdapter: Returns the authentication adapter The Service is really separated into three areas. They are getting the Zend_Auth instance, configuring the adapter, and authenticating the request using Zend_Auth and the Adapter. To get the Zend_Auth instance, we have the getAuth() method. This method retrieves the singleton Zend_Auth instance and sets it on the $_auth property. It is important to remember that Zend_Auth is a singleton class, meaning that there can only ever be one instance of it. To configure the adapter, we have the getAuthAdapter() method. By default, we are going to use the Zend_Auth_Adapter_DbTable adapter to authenticate the request. However, we can also override this by setting another adapter using the setAuthAdapter() method. This is useful for adding authenticate strategies and testing. The configuration of the DbTable adapter is important here, so let's have a look at that code: $authAdapter = new Zend_Auth_Adapter_DbTable( Zend_Db_Table_Abstract::getDefaultAdapter(), 'user', 'email', 'passwd', 'SHA1(CONCAT(?,salt))');$this->setAuthAdapter($authAdapter);$this->_authAdapter->setIdentity($values['email']);$this->_authAdapter->setCredential($values['passwd']); The Zend_Auth_Adapter_DbTable constructor accepts five parameters. They are database adapter, database table, table name, identity column, and credential treatment. For our adapter, we supply the default database adapter for our table classes using the getDefaultAdapter() method, the user table, the email column, the passwd column, and the encryption and salting SQL for the password. Once we have our configured adapter, we set the identity and credential properties. These will then be used during authentication. To authenticate the request, we use the authenticate method. $adapter = $this->getAuthAdapter($credentials);$auth = $this->getAuth();$result = $auth->authenticate($adapter);if (!$result->isValid()) { return false;}$user = $this->_userModel ->getUserByEmail($credentials['email']);$auth->getStorage()->write($user);return true; Here we first get the configured adapter, get the Zend_Auth instance, and then fetch the result using Zend_Auth's authenticate method, while passing in the configured adapter. We then check that the authentication request was successful using the isValid() method. At this point, we can also choose to handle different kinds of failures using the getCode() method. This will return one of the following constants: Zend_Auth_Result::SUCCESSZend_Auth_Result::FAILUREZend_Auth_Result::FAILURE_IDENTITY_NOT_FOUNDZend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUSZend_Auth_Result::FAILURE_CREDENTIAL_INVALIDZend_Auth_Result::FAILURE_UNCATEGORIZED By using these, we could switch and handle each error in a different way. However, for our purposes, this is not necessary. If the authentication request was successful, we then retrieve a Storefront_Resource_User_Item instance from the User Model and then write this object to Zend_Auth's persistence layer by getting the storage instance using  getStorage() and writing to it using write(). This will then store the user in the session so that we can retrieve the user information throughout the session. Our Authentication Service is now complete, and we can start using it to create a login system for the Storefront.
Read more
  • 0
  • 0
  • 2793

article-image-customizing-document-joomla-15-part-1
Packt
18 Nov 2009
3 min read
Save for later

Customizing the Document with Joomla! 1.5: Part 1

Packt
18 Nov 2009
3 min read
Introduction The classes that extend JDocument are intended for different response formats. The following table describes the classes and their purposes: Class Format Default MIME type Purpose JDocumentError error text/html Display a fatal error JDocumentFeed feed application/rss+xml   or application/atom+xml Syndication feed, RSS, or Atom JDocumentHTML html text/html Default document used for all typical Joomla! responses JDocumentPDF pdf application/pdf Adobe PDF representation JDocumentRAW raw* text/html All other circumstances   So what exactly does the format column represent? When a request is made, Joomla! uses the value of the request variable format to determine which document type to use. We really see this only when we retrieve something other than an HTML document, because this always defaults to html. For example, when we request an article as a PDF, we use a URI similar to this: http://example.org/index.php?option=com_content&view=article&id=5&format=pdf The JDocumentError class is slightly different from the others. We should never really need to interact directly with this. We can, of course, invoke this document indirectly by raising a fatal error. For more information, refer to Error handling and reporting. The Joomla! document object and views in Joomla! MVC components are closely related. For each format that we provide a view, we create a new JView subclass. For example, when we examine the content component, we can see that the article view supports HTML and PDF simply by the presence of the view.html.php and view.pdf.php files. This article also deals with the static JResponse class. This class is used to define the HTTP response, including the HTTP headers. The separation between JResponse and the JDocument object is not always as clear as one would hope. However, this is somewhat inevitable because the two are inextricably linked—the response describes and includes the document output. For example, outputting an HTML response will require the response Content-Type header field to be set accordingly, that is, as text/html. Setting the document title This recipe explains how to set the title of the current document. The exact meaning of title will depend on the type of document. For example, in an HTML document, this is the value encapsulated in the <head> tag. Getting ready Before we do anything, we need the global document object. $document =& JFactory::getDocument(); How to do it... To set the title of the document, we use the JDocument::setTitle() method $document->setTitle('My Unique Title'); If we are outputting an HTML document, this should generate something like this: <title>My Unique Title</title> There's more... Menu items can also define page titles. Thus, the actual title we use should not necessarily be the title of whatever we are viewing. To deal with this, we should use something along these lines: // get the component and page parameters$application =& JFactory::getApplication();$params =& $application->getParams();// get the page title$pageTitle = $params->get('page_title', $defaultTitle);// set the document title$document->setTitle($pageTitle); Setting the document generator This recipe explains how to set the name of the piece of software that generated the page. The exact meaning of generator will depend on the type of document. For example, in an HTML document, this value is used in a tag. Getting ready Before we do anything, we need the global document object. $document =& JFactory::getDocument();
Read more
  • 0
  • 0
  • 2299
Modal Close icon
Modal Close icon