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
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Web Development

1797 Articles
article-image-adding-advanced-form-features-using-chronoforms
Packt
31 Aug 2010
16 min read
Save for later

Adding Advanced Form Features using ChronoForms

Packt
31 Aug 2010
16 min read
(For more resources on ChronoForms, see here.) Using PHP to create "select" dropdowns One frequent request is to create a select drop-down from a set of records in a database table. Getting ready You'll need to know the MySQL query to extract the records you need from the database table. This requires some Joomla! knowledge and some MySQL know-how. Joomla! keeps its articles in the jos_content database table and the two-table columns that we want are the article title and the article id. A quick check in the database tells us that the columns are appropriately called title and id. We can also see that the section id column is called sectionid (with no spaces); the column that tells us if the article is published or not is called state and takes the values 1 for published and 0 for not published. How to do it . . . We are going to use some PHP to look up the information about the articles in the database table and then output the results it finds as a series of options for our drop-down box. You'll recall that normal HTML code for a drop-down box looks something like this: <select . . .> <option value='option_value_1'>Option 1 text</option> <option value='option_value_2'>Option 2 text</option> . . .</select> This is simplified a little so that we can see the main parts that concern us here—the options. Each option uses the same code with two variables—a value attribute and a text description. The value will be returned when the form is submitted; the text description is shown when the form is displayed on your site. In simple forms, the value and the description text are often the same. This can be useful if all you are doing with the results is to display them on a web page or in an e-mail. If you are going to use them for anything more complicated than that, it can be much more useful to use a simplified, coded form in the value. For our list of articles, it will be helpful if our form returns the ID of the article rather than its title. Hence, we need to set the options to be something like this: <option value='99'>Article title</option> Having the article ID will let us look up the article in the database and extract any other information that we might need, or to update the record to change the corresponding record. Here's the code that we'll use. The beginning and ending HTML lines are exactly the same as the standard drop-down code that ChronoForms generates but the "option" lines are replaced by the section inside the <?php . . . ?> tags. The PHP snippet looks up the article IDs and titles from the jos_content table, then loops through the results writing an <option> tag for each one: <div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> Articles</label> <select class="cf_inputbox validate-selection" id="articles" size="1" name="articles"> <option value=''>--?--</option><?phpif (!$mainframe->isSite() ) {return;}$db =& JFactory::getDBO();$query = " SELECT `id`, `title` FROM `#__content` WHERE `sectionid` = 1 AND `state` = 1 ;";$db->setQuery($query);$options = $db->loadAssocList();foreach ( $options as $o ) { echo "<option value='".$o[id]."'>".$o[title]."</option>";}?> </select> </div> <div class="cfclear">&nbsp;</div></div> The resulting HTML will be a standard select drop-down that displays the list of titles and returns the article ID when the form is submitted. Here's what the form input looks like: A few of the options from the page source are shown: <option value='1'>Welcome to Joomla!</option><option value='2'>Newsflash 1</option><option value='3'>Newsflash 2</option>. . . How it works... We are loading the values of the id and title columns from the database record and then using a PHP for each loop to go through the results and add each id and title pair into an <option> tag. There's more... There are many occasions when we want to add select drop-downs into forms with long lists of options. Date and time selectors, country and language lists, and many others are frequently used. We looked here to get the information from a database table which is simple and straightforward when the data is in a table or when the data can conveniently be stored in a table. It is the preferred solution for data such as article titles that can change from day to day. There are a couple of other solutions that can also be useful: Creating numeric options lists directly from PHP Using arrays to manage option lists that change infrequently Creating numeric options lists Let's imagine that we need to create a set of six numeric drop-downs to select: day, month, year, hour, minute, and second. We could clearly do these with manually-created option lists but it soon gets boring creating sixty similar options. There is a PHP method range() that lets us use a similar approach to the one in the recipe. For a range of zero to 60, we can use range(0, 60). Now, the PHP part of our code becomes: <div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> Minutes</label> <select class="cf_inputbox validate-selection" id="minutes" size="1" name="minutes"> <option value=''>--?--</option><?phpif (!$mainframe->isSite() ) {return;}foreach ( range(0, 60) as $v ) { echo "<option value='$v'>$v</option>";}?> </select> </div> <div class="cfclear">&nbsp;</div></div> This is slightly simpler than the database foreach code, as we don't need the quotes round the array values. This will work very nicely and we could repeat something very similar for each of the other five drop-downs. However, when we think about it, they will all be very similar and that's usually a sign that we can use more PHP to do some of the work for us. Indeed we can create our own little PHP function to output blocks of HTML for us. Looking at this example, there are four things that will change between the blocks—the label text, the name and id, and the range start and the range end. We can set these as variables in a PHP function: <?phpif ( !$mainframe->isSite() ) {return;}function createRangeSelect($label, $name, $start, $end) {?><div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> <?php echo $label; ?></label> <select class="cf_inputbox validate-selection" id="<?php echo $name; ?>" size="1" name="<?php echo $name; ?>"> <option value=''>--?--</option><?php foreach ( range($start, $end) as $v ) { echo "<option value='$v'>$v</option>"; }?> </select> </div> <div class="cfclear">&nbsp;</div></div><?php}?> Notice that this is very similar to the previous code example. We've added the function . . . line at the start, the } at the end, and replaced the values with variable names. It's important to get the placement of the <?php . . . ?> tags right. Code inside the tags will be treated as PHP, outside them as HTML. All that remains now is to call the function to generate our drop-downs: <?phpif (!$mainframe->isSite() ) {return;}createRangeSelect('Day', 'day', 0, 31);createRangeSelect('Month', 'month', 1, 12);createRangeSelect('Year', 'year', 2000, 2020);createRangeSelect('Hour', 'hour', 0, 24);createRangeSelect('Minute', 'minute', 0, 60);createRangeSelect('Second', 'second', 0, 60);function createRangeSelect($label, $name, $start, $end) {. . . The result tells us that we have more work to do on the layout, but the form elements work perfectly well. Creating a drop-down from an array In the previous example, we used the PHP range() method to generate our options. This works well for numbers but not for text. Imagine that we have to manage a country list. These do change, but not frequently. So they are good candidates for keeping in an array in the Form HTML. It's not too difficult to find pre-created PHP arrays of countries with a little Google research and it's probably easier to use one of these and correct it for your needs than to start from scratch. As we mentioned with the Article list, it's generally simpler and more flexible to use a list with standard IDs (we've used two-letter codes below). With countries, this can remove many problems with special characters and translations. Here are the first few lines of a country list: $countries = array( 'AF'=>'Afghanistan', 'AL'=>'Albania', 'DZ'=>'Algeria', 'AS'=>'American Samoa', . . .); Once we have this, it's easy to modify our foreach . . . loop to use it: foreach ( $countries as $k => $v ) { echo "<option value='$k'>$v</option>";} If you are going to use the country list in more than one form, then it may be worthwhile keeping it in a separate file that is included in the Form HTML. That way, any changes you make will be updated immediately in all of your forms. Using Ajax to look up e-mail addresses It's not very difficult to add Ajax functionality to ChronoForms, but it's not the easiest task in the world either. We'll walk through a fairly simple example here which will provide you with the basic experience to build more complex applications. You will need some knowledge of JavaScript to follow through this recipe. Normally, the only communication between the ChronoForms client (the user in their browser) and the server (the website host) is when a page is loaded or a form is submitted. Form HTML is sent to the client and a $_POST array of results is returned. Ajax is a technique, or a group of techniques, that enables communication while the user is browsing the page without them having to submit the form. As usual, at the browser end the Ajax communication is driven by JavaScript and at the server end we'll be responding using PHP. Put simply, the browser asks a question, the server replies, then the browser shows the reply to the user. For the browser JavaScript and the server PHP to communicate, there needs to be an agreed set of rules about how the information will be packaged. We'll be using the JSON (www.json.org) format. The task we will work on will use a newsletter form. We'll check to see if the user's e-mail is already listed in our user database. This is slightly artificial but the same code can easily be adapted to work with the other database tables and use more complex checks. Getting ready We'll need a form with an e-mail text input. The input id needs to be email for the following code to work: <div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label" style="width: 150px;">Email</label> <input class="cf_inputbox" maxlength="150" size="30" title="" id="email" name="email" type="text" /> </div> <div class="cfclear">&nbsp;</div></div> The form we use will also have a name text input and a submit button, but they are to make it look like a real form and aren't used in the Ajax coding. How to do it . . . We'll follow the action and start with the user action in the browser. We need to start our check when the user makes an entry in the e-mail input. So, we'll link our JavaScript to the blur event in that input. Here's the core of the code that goes in the Form JavaScript box: / set the url to send the request tovar url = 'index.php?option=com_chronocontact &chronoformname=form_name&task=extra&format=raw';// define 'email'var email = $('email');// set the Ajax call to run// when the email field loses focusemail.addEvent('blur', function() { // Send the JSON request var jSonRequest = new Json.Remote(url, { . . . }).send({'email': email.value});}); Note that the long line starting with var url = . . . &format=raw'; is all one line and should not have any breaks in it. You also need to replace 'form_name' with the name of your form in this URL. There really isn't too much to this. We are using the MooTools JSON functions and they make sending the code very simple. The next step is to look at what happens back on the server. The URL we used in the JavaScript includes the task=extra parameter. When ChronoForms sees this, it will ignore the normal Form Code and instead run the code from the Extra Code boxes at the bottom of the Form Code tab. By default, ChronoForms will execute the code from Extra code 1. If you need to access one of the other boxes, then use for example, task=extra&extraid=3 to run the code from Extra Code box 3. Now, we are working back on the server. So, we need to use PHP to unpack the Ajax message, check the database, and send a message back: <?php// clean up the JSON message$json = stripslashes($_POST['json']);$json = json_decode($json);$email = strtolower(trim($json->email));// check that the email field isn't empty$response = false;if ( $email ) { // Check the database $db =& JFactory::getDBO(); $query = " SELECT COUNT(*) FROM `#__users` WHERE LOWER(`email`) = ".$db->quote($email)."; "; $db->setQuery($query); $response = (bool) !$db->loadResult();}$response = array('email_ok' => $response );//send the replyecho json_encode($response);// stop the from running$MyForm->stopRunning = true;die;?> This code has three main parts: To start with, we "unwrap" the JSON message. Then, we check if it isn't empty and run the database query. Lastly, we package up the reply and tidy up at the end to stop any more form processing from this request. The result we send will be array('email_ok' => $response ) where $response will be either true or false. This is probably the simplest JSON message possible, but is enough for our purpose. Note that here, true means that this e-mail is not listed and is OK to use. The third step is to go back to the form JavaScript and decide how we are going to respond to the JSON reply. Again, we'll keep it simple and just change the background color of the box—red if the e-mail is already in use (or isn't a valid e-mail) or green if the entry isn't in use and is OK to submit. Here's the code snippet to do this using the onComplete parameter of the MooTools JSON function: onComplete: function(r) { // check the result and set the background color if ( r.email_ok ) { email.setStyle('background-color', 'green'); } else { email.setStyle('background-color', 'red'); }} Instead of (or as well as) changing the background color, we could make other CSS changes, display a message, show a pop-up alert, or almost anything else. Lastly let's put the two parts of the client-side JavaScript together with a little more code to make it run smoothly and to check that there is a valid e-mail before sending the JSON request. window.addEvent('domready', function() { // set the url to send the request to var url = 'index.php?option=com_chronocontact &chronoformname=form_name&task=extra&format=raw'; var email = $('email'); email.addEvent('blur', function() { // clear any background color from the input email.setStyle('background-color', 'white'); // check that the email address is valid regex = /^([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})$/i; var value = email.value.trim(); if ( value.length > 6 && regex.test(value) ) { // if all is well send the JSON request var jSonRequest = new Json.Remote(url, { onComplete: function(r) { // check the result and set the background color if ( r.email_ok ) { email.setStyle('background-color', 'green'); } else { email.setStyle('background-color', 'red'); } } }).send({'email': email.value}); } else { // if this isn't a valid email set background color red email.setStyle('background-color', 'red'); } });}); Note that the long line starting with var url = . . . &format=raw'; is all one line and should not have any breaks in it. You also need to replace form_name with the name of your form in this URL. Make sure both the code blocks are in place in the Form JavaScript box and in the Extra Code 1 box, save, and publish your form. Then, test it to make sure that the code is working OK. The Ajax may take a second or two to respond but once you move out of the e-mail, input by tabbing on to another input or clicking somewhere else; the background colour should go red or green. How it works... As far as the Ajax and JSON parts of this are concerned, all we can say here is that it works. You'll need to dig into the MooTools, Ajax, or JSON documents to find out more. From the point of view of ChronoForms, the "clever" bit is the ability to interpret the URL that the Ajax message uses. We ignored most of it at the time but the JavaScript included this long URL (with the query string broken up into separate parameters): index.php?option=com_chronocontact&chronoformname=form_name&task=extra&format=raw The option parameter is the standard Joomla! way to identify which extension to pass the URL to. The chronoformname parameter tells ChronoForms which form to pass the URL to. The task=extra parameter tells ChronoForms that this URL is a little out of the ordinary (you may have noticed that forms usually have &task=send in the onSubmit URL). When ChronoForms sees this, it will pass the URL to the Extra Code box for processing and bypass the usual OnSubmit processing. Lastly, the format=raw parameter tells Joomla! to show the resulting code without any extra formatting and without adding the template code. This means that all that is sent back is just the JSON message. Without it we'd have to dig the message out from loads of surrounding HTML we don't need.
Read more
  • 0
  • 0
  • 4585

article-image-using-chronoforms-add-more-features-your-joomla-form
Packt
31 Aug 2010
11 min read
Save for later

Using ChronoForms to add More Features to your Joomla! Form

Packt
31 Aug 2010
11 min read
(For more resources on ChronoForms, see here.) Showing a YouTube video This is the "not really a form" recipe in this article, it just opens a little door to some of the other, more unexpected, capabilities of ChronoForms. For the most part Joomla! protects the content you can display on your pages; it's easy to show HTML + CSS formatted content, more difficult to show PHP and JavaScript. There are many modules, plug-ins and extensions that can help with this but if you have ChronoForms installed then it may be able to help. ChronoForms is designed to show pages that use HTML, CSS, PHP, and JavaScript working together. Most often the pages created are forms but nothing actually requires that any form inputs are included so we can add any code that we like. ChronoForms will wrap our code inside <form>. . .</form> tags which means that we can't embed a form (why would we want to?), but otherwise most things are possible.   Getting ready You will need the ID of the YouTube video that you want to display. We're going to use a video from a conference at Ashridge Business School, but any video will work in essentially the same way. This recipe was developed for this particular video to force display of the HD version. At that time HD was a new option on YouTube and was not readily accessible as it is now. How to do it... Find the video you want on YouTube and look for the links boxes in the right hand column. Here we've clicked on the "customize" icon—the little gear wheel—to open up the options menu. When you've set the options you want copy the code from the Embed box. Here is the code from this video with some added line breaks for clarity: <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> To create a good looking page, we are going to add some HTML before and after this snippet: <h3>Video Postcards from the Edge</h3><div>The video of the 2008 AMOC Conference</div><div style='margin:6px; padding:0px; border:6px solid silver;width:425px;'><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl =en&fs=1&ap=%2526fmt%3D18"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en&fs =1&ap=%2526fmt%3D18" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><div>Some more text . . .</div> If you look closely, you'll see that there is also a new parameter in the URL—&ap=%2526fmt%3D18—which is there to force the HD version of the video to be used. Paste this code into the Form HTML box of a new form, save, and publish it. Of course, it would be entirely possible to embed the video and to add form inputs in the same page, maybe to ask for comments or reviews. How it works... Very simply ChronoForms allows you to embed scripts into the page HTML that are not permitted in standard Joomla! articles. Adding a barcode to a form e-mail Sometimes it's important to add a unique identifier to the form response, for example travel or event tickets. In this recipe we will look at generating a "random" identifier and adding it to the form e-mail as a scannable barcode. Getting ready We're going to need a simple form. Our newsletter form will be perfect although we'll be adding to the code in the Form HTML box. We'll need a simple function to create the "random identifier" which we will see shortly. Lastly we"ll need code to generate a barcode. Rather than taking time reinventing this particular wheel, we're going to use a PHP program created by Charles J Scheffold and made available for use or download from http://www.sid6581.net/cs/php-scripts/barcode/. How to do it... First, grab a copy of the barcode.php file from sid6581.net. We'll need to make this file accessible to our form. So let's create a new folder inside the ChronoForms front-end folder. You'll probably need to use an FTP client to do this, or install the "exTplorer" Joomla! extension which will allow you to create folders from within the Joomla! Site Admin interface. Browse to [root]/components/com_chronocontact and create a new includes folder Copy the standard Joomla! index.html file from the com_chronocontact folder into the new folder Upload the barcode.php file into the new includes folder Now, we are going to add the function to create a "random" identifier to the Form HTML. This is a small function that creates an alphanumeric string when it is called. <?phpif ( !$mainframe->isSite() ) { return; }/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> We call this function using generateIdent() or generateIdent('pattern') where the pattern is a string of As and 9s that defines the shape of the ident we want. The default is AA9999A, giving idents like KX4629G. This will be perfectly fine for our example here. We also want to add the ident into the form and we'll use a hidden field to do that, but to make it visible we'll also display the value. <?php$ident = generateIdent();echo "<div>Ident is $ident</div>";?><input type='hidden' name='ident' id='ident' value='<?php echo $ident; ?>' /> In day to day use we probably wouldn't generate the ident until after the form is submitted. There is often no useful value in displaying it on the form and essentially the same code will work in the OnSubmit boxes. However, here it makes the process clearer to generate it in the form HTML. We can add both these code snippets to our form just before the submit button element. Then apply or save the form and view it in your browser. The layout may not be very elegant but the Ident is there. Refresh the browser a few times to be sure that it is different each time. It's simpler and tempting to use serial numbers to identify records. If you are saving data in a table then these are generated for you as record IDs. It does create some problems though; in particular, it can make it very easy to guess what other IDs are valid and if, as we often do, we include the ID in a URL it may well be possible to guess what other URLs will be valid. Using a random string like this makes that kind of security breach more difficult and less likely. We said though that we'd generate a barcode, so let's develop this form one more step and show the barcode in the form. If you look at the code in barcode.php, it shows a list of parameters and says what we can use. For example: <img src="barcode.php?barcode=123456&width=320&height=200"> We need to modify this a little to link to the new folder for the file and to add our generated ident value: <img src="/components/com_chronocontact/includes/barcode.php?barcode=<? php echo $ident;?>&width=320&height=8"> This code can go in place of the "echo" line we used to display the ident value: <?php$ident = generateIdent();echo "<img src='".JURI::base()."components/com_chronocontact/includes/barcode.php?barcode=".$ident."&width=320&height=80' />";?> Apply or save the form and view it in your browser. There we have it—a bar code in our form showing the random ident that we have created. If you don't see any graphic and the code appears to be correct then you may not have the PHP GD graphics library installed. Check on the AntiSpam tab for any of your forms and you will see a GD Info box. The GD library is now included in the vast majority of PHP installations. If you don't have it then check with your ISP to see if the library can be enabled. Now that's actually not of much use except to show that it works, you can't scan a bar code off the screen. Where we want it is in our Email template. The code to add to the template is: <div>Your code: {ident}</div><img src="<?php echo JURI::base().'components/com_chronocontact/ includes/'; ?>barcode.php?barcode={ident}&width=280&height=100" /> As this includes some PHP, we can't add it using the Rich Text Editor. First we need to go to the Email Setup | Properties box and set Use Template Editor to No, apply the Properties, then apply the form and go to the Email Template tab. To avoid an "oddity" in the current release of ChronoForms it may be necessary to comment out the generateIdent() function code block in the Form HTML, while you create an Email Setup. Just put /* & */ before and after the block if you get a blank page or see a PHP Error message about re-declaring the function. Now click on the Email Template tab and paste the code at the end of the textarea. Submit the form to test. We now have a printable e-mail complete with a barcode showing our random ident. How it works... In this recipe we did a couple of things. We added some more complex PHP to the Form HTML that we had before and we imported a PHP script found on the internet and successfully used that in combination with ChronoForms. There are many hundreds of useful scripts available for almost any conceivable function. Not all are of good quality and not all will work in this way but, with a little work, a surprising number will function perfectly well. There's more... We said earlier that it might be better to generate the ident after the form is submitted. Here's the code to use in the OnSubmit Before code box to get the same result in the e-mail: <?phpif ( ! $mainframe->isSite() ) { return; }JRequest::setVar('ident', generateIdent());/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> If you use this, then you can remove all of the additional code from the Form HTML box leaving just the basic HTML generated by the Form Wizard. The Email template code remains as we created it previously.
Read more
  • 0
  • 0
  • 2517

article-image-model-view-controller-pattern-and-configuring-web-scripts-alfresco
Packt
30 Aug 2010
13 min read
Save for later

The Model-View-Controller pattern and Configuring Web Scripts with Alfresco

Packt
30 Aug 2010
13 min read
(For more resources on Alfresco, see here.) One way of looking at the Web Scripts framework is as a platform for implementing RESTful Web Services. Although, as we have seen, your service won't actually be RESTful unless you follow the relevant guiding principles, Web Scripts technology alone does not make your services RESTful as if by magic. Another way of looking at it is as an implementation of the Model-View-Controller, or MVC pattern. Model-View-Controller is a long-established pattern in Computer Science, often used when designing user-facing, data-oriented applications. MVC stipulates that users of the application send commands to it by invoking the controller component, which acts on some sort of data model, then selects an appropriate view for presenting the model to the users. While the applicability of MVC to Web application has often been debated, it is still a useful framework for partitioning concerns and responsibilities and for describing the roles of the various components of the Alfresco Web Scripts framework. In the latter, the role of controller is carried out by the scripting component. It should be stressed that, in the MVC pattern, the controller's role is purely that of governing the user interaction by selecting an appropriate model and a corresponding view for presentation, possibly determining which user actions are applicable given the present state of the application. It is not the controller's role to carry out any kind of business logic or to operate on the model directly. Rather, the controller should always delegate the execution of data manipulation operations and queries to a suitable business logic or persistence layer. In the context of Alfresco Web Scripts, this means that your controller script should avoid doing too many things by using the repository APIs directly. It is the responsibility of the controller to: Validate user inputs Possibly convert them to data types suitable for the underlying logic layers Delegate operations to those layers Take data returned by them Use the data to prepare a model for the view to display and nothing more All complex operations and direct manipulations of repository objects should ideally be carried out by code that resides somewhere else, like in Java Beans or JavaScript libraries, which are included by the present script. In practice, many Web Scripts tend to be quite small and simple, so this strict separation of concerns is not always diligently applied. However, as the size and complexity of controller scripts grows, it is considered as a good practice to modularize an application's logic in order to make it easier to follow and to maintain. Some people also have a preference for the relative safety of a static language like Java, compared to JavaScript, and for the use of modern Java IDEs. Therefore, it is frequent to see Web Scripts applications that place the very minimum of logic in controller scripts that use Java Beans to carry out more complex tasks. Coming to the view, which in Alfresco Web Scripts is implemented as FreeMarker templates, it should be noted that in a departure from the "pure" MVC pattern, the freedom accorded to the controller itself of choice between different possible views is rather limited as which view to use is determined exclusively by selecting a template for the specific output format requested by the user through the format specification in the request URL. The model that the view can access is also only partially the responsibility of the controller. Whereas the latter can add more objects to the model available to the view, it cannot reduce the visibility of the predefined, root-scoped objects. It is therefore possible for the view to perform quite a bit of logic without even having a controller to do it. This is why Web Scripts without a controller are acceptable. Whether this is a good practice or not is open to debate. The following diagram illustrates the steps that are involved when a Web Script is executed: The diagram can be explained as follows: An HTTP request, specifying a method and a URI is received. The dispatcher uses the HTTP method and the URI to select a Web Script to execute and executes the controller script. The controller script accesses the repository services by means of the Alfresco JavaScript API. The model is populated and passed to the FreeMarker template engine for rendering. FreeMarker renders a response using the appropriate template. The response is returned to the client. URL matching We've already seen how the dispatcher selects a particular Web Script by matching the URL of the HTTP request against the value of the url element in the descriptors of the registered Web Scripts. There is actually a bit more to this process than simple, exact matching, as we are going to see. First, let's have a look at the structure of a Web Script's request URL: http[s]://<host>:<port>/[<contextPath>/]/<servicePath>[/ <scriptPath>][?<scriptArgs>] The meaning of host and port should be obvious. contextPath is the name of the web application context, that is, where your application is deployed in your application server or Servlet container. It will often be alfresco, but could be share, as the Share application is able to host Web Scripts. It could be missing, if the application is deployed in the root context, or it could really be anything you want. The value of servicePath will usually be either service or wcservice. Using the former, if the Web Script requires authentication, this is performed using the HTTP Basic method. This means that the browser will pop up a username/password dialog box. When the latter is used, authentication is performed by the Alfresco Explorer (also known as Web Client). This means that no further authentication is required if you are already logged into the Explorer, otherwise you will be redirected to the Explorer login page. scriptPath is the part of the URL that is matched against what is specified in the descriptor. Arguments can optionally be passed to the script by specifying them after the question mark, as with any URL. With this in mind, let's look at the value of the <url> element in the descriptor. This must be a valid URI template, according to the JSR-311 specification. Basically, a URI template is a (possibly relative) URI, parts of which are tokens enclosed between curly braces, such as: /one/two/three /api/login/ticket/{ticket} /api/login?u={username}&pw={password?} Tokens stand for variable portions of the URI and match any value for a path element or a parameter. So, the first template in the previous list only matches /one/two/three exactly, or more precisely: http[s]://<host>:<port>/[<contextPath>/]/<servicePath>/one/two/three The second template here matches any URI that begins with /api/login/ticket/, whereas the third matches the /api/login URI when there is a u parameter present and possibly a pw parameter as well. The ? symbol at the end of a token indicates that the parameter or path element in question is not mandatory. Actually, the mandatory character of a parameter is not enforced by Alfresco, but using the question mark is still valuable for documentation purposes to describe what the Web Script expects to receive. We can now precisely describe the operation of the dispatcher as follows: When the dispatcher needs to select a Web Script to execute, it will select the one matching the specific HTTP method used by the request and whose URI template more specifically matches the script path and arguments contained in the request URL. A Web Script descriptor can also have more than one URI template specified in its descriptor, simply by having more than one <url> element. All of them are consulted for matching. The actual values of the path elements specified as tokens are available to the script as entries in the url.templateArgs map variable. For instance, when the /x/foo URL is matched by the /x/{token} template, the value of the expression url. templateArgs["token"] will be equal to foo. Values of request arguments are accessible from the script or template as properties of the args object, such as args.u and args.pw for the third example here. The format requested, which can be specified in the URL by means of the filename extension or of a format argument, need not be specified in the URI template. Authentication In the last version of our Web Script, we specified a value of user for the <authentication> element. When you use this value, users are required to authenticate when they invoke the Web Script's URL, but they can use any valid credentials. When a value of none is present, the Web Script will not require any authentication and will effectively run anonymously. This tends to not be very useful, as all operations using repository objects will require authentication anyway. If you require no authentication, but try to access the repository anyway, the script will throw an exception. A value of guest requires authentication as the guest user. This can be used for scripts accessed from the Explorer, where users are automatically logged in as guest, unless they log in with a different profile. A value of admin requires authentication as a user with the administrator role, typically admin. Run as Scripts can be run as if they were invoked by a user, other than the one who actually provided the authentication credentials. In order to do this, you need to add a runAs attribute to the <authentication> element: <authentication runAs="admin">user</authentication> This can be used, as in the previous example, to perform operations which require administrator privileges without actually logging in as an admin. As this can be a security risk, only scripts loaded from the Java classpath, and not those loaded from the Data Dictionary, can use this feature. The Login service Web Scripts that render as HTML and are therefore intended to be used by humans directly can either use HTTP Basic authentication or Alfresco Explorer authentication, as it is assumed that some person will fill in a login dialog with his username and password. When a script is meant to implement some form of Web Service that is intended for consumption by another application, HTTP Basic or form-based authentication is not always convenient. For this reason, Alfresco provides the login service, which can be invoked using the following URL: http[s]://<host>:<port>/[<contextPath>/]/service/api/login?u={username }&pw={password?} If authentication is successful, the script returns an XML document with the following type of content: <ticket>TICKET_024d0fd815fe5a2762e40350596a5041ec73742a</ticket> Applications can use the value of the ticket element in subsequent requests in order to avoid having to provide user credentials with each request, simply by adding an alf_ticket=TICKET_024d0fd815fe5a2762e40350596a5041ec73742a argument to the URL. As the username and the password are included, unencrypted, in the request URL, it is recommended that any invocations of the login service be carried out over HTTPS. Transactions Possible values of the transaction element are: none/li> required/li> requiresnew When none is used, scripts are executed without any transactional support. Since most repository operations require a transaction to be active, using none will result in an error whenever the script tries to call repository APIs. required causes the execution of the script to be wrapped in a transaction, which is the normal thing to do. If a transaction is already active when the script is invoked, no new transaction is started. requiresnew, on the other hand, always initiates a new transaction, even if one is already active. Requesting a specific format The format element in the Web Script descriptor indicates how clients are expected to specify which rendering format they require. This is what the element looks like: <format [default="default format"]>extension|argument</format> A value of extension indicates that clients should specify the format as a filename extension appended to the Web Script's path. For example: http://localhost:8080/alfresco/service/myscript.html http://localhost:8080/alfresco/service/myscript.xml A value of argument indicates that the format specification is to be sent as the value of the format URL parameter: http://localhost:8080/alfresco/service/myscript?format=html http://localhost:8080/alfresco/service/myscript?format=xml When the client fails to specify a particular format, the value of the default attribute is taken as the format to use. Once a format has been determined, the corresponding template is selected for rendering the model, after the script finishes its execution, on the basis of the template's filename, which must be of the form: <basename>.<method>.<format>.ftl Status Sometimes it can be necessary for the Web Script to respond to a request with an HTTP status code other than the usual 200 OK status, which indicates that the request has been processed successfully. There might also be a requirement that the response body be different depending on the status code, like, for instance, when you want to display a specific message to indicate that some resource could not be found, together with a status code of 404 Not Found. You can easily do this by manipulating the status object: if (document != null){ status.code = 404 status.message = "No such file found." status.redirect = true} You need to set the value of status.redirect to true in order for Alfresco to use an alternative error handling template. When you do this, the Web Scripts framework goes looking for a template with a file name of <basename>.<method>.<format>.<code>.ftl, like, for instance, myscript.get.html.404.ftl and uses it, if found, instead of the usual myscript.get.html.ftl. In this template, you can access the following properties of the status variable to customize your output: Property name Meaning status.code Numeric value of the HTTP status code (for example, 404) status.codeName String value of the status code (for example, Not Found) status.message Possibly set by the script status.exception The exception that caused this status If your script sets a status code between 300 and 399, which usually means a redirection, you can set the value of status.location to control the value of the location HTTP header: status.code = 301; // Moved permanentlystatus.location = 'http://some.where/else'
Read more
  • 0
  • 0
  • 1563
Visually different images

article-image-overview-rest-concepts-and-developing-your-first-web-script-using-alfresco
Packt
30 Aug 2010
10 min read
Save for later

Overview of REST Concepts and Developing your First Web Script using Alfresco

Packt
30 Aug 2010
10 min read
(For more resources on Alfresco, see here.) Web Scripts allow you to develop entire web applications on Alfresco by using just a scripting language—JavaScript and a templating language—FreeMarker. They offer a lightweight framework for quickly developing even complex interfaces such as Alfresco Share and Web Studio. Besides this, Web Scripts can be used to develop Web Services for giving external applications access to the features of the Alfresco repository. Your Web Services, implemented according to the principles of the REST architectural style, can be easily reused by disparate, heterogeneous systems. Specifically, in this article, you will learn: What REST means and how it compares to SOAP What elements are needed to implement a Web Script A lightweight alternative to SOAP Web Services The term Web Services is generally intended to denote a large family of specifications and protocols, of which SOAP is only a small part, which are often employed to let applications provide and consume services over the World Wide Web (WWW). This basically means exchanging XML messages over HTTP. The main problem with the traditional approach to Web Services is that any implementation has to be compliant with a huge, and complicated set of specifications. This makes the application itself complex and typically hard to understand, debug, and maintain. A whole cottage industry has grown with the purpose of providing the tools necessary for letting developers abstract away this complexity. It is virtually impossible to develop any non-trivial application without these tools based on SOAP. In addition, one or more of the other Web Services standards such as WS-Security, WS-Transaction, or WS-Coordination are required. It is also impossible for any one person to have a reasonably in-depth knowledge of a meaningful portion of the whole Web Services stack (sometimes colloquially referred to as WS-*). Recently, a backlash against this heavyweight approach in providing services over the Web has begun and some people have started pushing for a different paradigm, one that did not completely ignore and disrupt the architecture of the World Wide Web. The main objection that the proponents of the REST architectural style, as this paradigm is called, raise with respect to WS-* is that the use of the term Web in Web Services is fraudulent and misleading. The World Wide Web, they claim, was designed in accordance with REST principles and this is precisely why it was able to become the largest, most scalable information architecture ever realized. WS-*, on the other hand, is nothing more than a revamped, RPC-style message exchange paradigm. It's just CORBA once again, only this time over HTTP and using XML, to put it bluntly. As it has purportedly been demonstrated, this approach will never scale to the size of the World Wide Web, as it gets in the way of important web concerns such as cacheability, the proper usage of the HTTP protocol methods, and of well-known MIME types to decouple clients from servers. Of course, you don't have to buy totally into the REST philosophy—which will be described in the next section—in order to appreciate the elegance, simplicity, and usefulness of Alfresco Web Scripts. After all, Alfresco gives you the choice to use either Web Scripts or the traditional, SOAP-based, Web Services. But you have to keep in mind that the newer and cooler pieces of Alfresco, such as Surf, Share, Web Studio, and the CMIS service, are being developed using Web Scripts. It is, therefore, mandatory that you know how the Web Scripts work, how to develop them, and how to interact with them, if you want to be part of this brave new world of RESTful services. REST concepts The term REST had been introduced by Roy T. Fielding, one of the architects of the HTTP protocol, in his Ph.D dissertation titled Architectural Styles and the Design of Network-based Software Architectures (available online at http://www.ics.uci.edu/ ~fielding/pubs/dissertation/top.htm). Constraints In his work, Dr. Fielding introduces an "architectural style for distributed hypermedia systems" called Representational State Transfer (REST). It does so by starting from an architectural style that does not impose any constraints on implementations (called the Null Style) and progressively adds new constraints that together define what REST is. Those constraints are: Client-Server interaction Statelessness Cacheability Uniform Interface Layered System Code-On-Demand (optional) Fielding then goes on to define the main elements of the REST architectural style. Foremost among those are resources and representations. In contrast with distributed object systems, where data is always hidden behind an interface that only exposes operations that clients may perform on said data, "REST components communicate by transferring a representation of a resource in a format matching one of an evolving set of standard data types, selected dynamically based on the capabilities or desires of the recipient and the nature of the resource." Resources It is important to understand what a resource is and what it isn't. A resource is some information that can be named. It can correspond to a specific entity on a data management system such as a record in a database or a document in a DMS such as Alfresco. However, it can also map to a set of entities, such as a list of search results, or a non-virtual object like a person in the physical world. In any case, a resource is not the underlying entity. Resources need to be named, and in a globally distributed system such as the World Wide Web, they must be identified in a way that guarantees the universality and possibly the univocity of identifiers. On the Web, resources are identified using Uniform Resource Identifiers (URI). A specific category of URIs are Uniform Resource Locators (URL) , which provide a way for clients to locate, that is to find, a resource anywhere on the Web, in addition to identifying it. It is also assumed that URIs never change over the lifetime of a resource, no matter how much the internal state of the underlying entities changes over time. This allows the architecture of the Web to scale immensely, as the system does not need to rely on centralized link servers that maintain references separated from the content. Representations Representations are sequences of bytes intended to capture the current or intended state of a resource, as well as metadata (in the form of name / value pairs) about the resource or the representation itself. The format of a representation is called its media type. Examples of media types are plain text, HTML , XML, JPEG, PDF, and so on. When servers and clients use a set of well-known, standardized media types, interoperability between systems is greatly simplified. Sometimes, it is possible for clients and servers to negotiate a specific format from a set that is supported by both. Control data, which is exchanged between systems together with the representation, is used to determine the purpose of a message or the behavior of any intermediaries. Control data can be used by the client, for instance, to inform the server that the representation being transferred is meant to be the intended new state of the resource, or it can be used by the server to control how proxies, or the client itself, may cache representations. The most obvious example of control data on the Web is HTTP methods and result codes. By using the PUT method, for example, a client usually signals to a server that it is sending an updated representation of the resource. REST in practice As we mentioned, REST is really just an abstract architectural style, not a specific architecture, network protocol, or software system. While no existing system exactly adheres to the full set of REST principles, the World Wide Web is probably the most well-known and successful implementation of them. Developing Web Services that follow the REST paradigm boils down to following a handful of rules and using HTTP the way it was meant to be used. The following sections detail some of those rules. Use URLs to identify resources It is important that you design the URLs for your Web Service in such a way that they identify resources and do not describe the operations performed on said resources. It is a common mistake to use URLs such as: /widgetService/createNewWidget /widgetService/readWidget?id=1 /widgetService/updateWidget?id=1 /widgetService/deleteWidget?id=1 whenever, for instance, you want to design a web service for doing CRUD operations on widgets. A proper, RESTful URL space for this kind of usage scenario could instead be something like the following: /widgets/ To identify a collection of widgets /widgets/id To identify a single widget. Then again, a RESTful interaction with a server that implements the previous service would be along the lines of the following (where we have indicated the HTTP verb together with the URL): POST /widgets/ To create a new widget, whose representation is contained in the body of the request GET /widgets/ To obtain a representation (listing) of all widgets of the collection GET /widgets/1 To obtain a representation of the widget having id=1 POST /widgets/1 To update a widget by sending a new representation (the PUT verb could be used here as well) DELETE /widgets/1 To delete a widget You can see here how URLs representing resources and the appropriate usage of HTTP methods can be used to implement a correctly designed RESTful Web Service for CRUD operations on server-side objects. Use HTTP methods properly There are four main methods that a client can use to tell a server which kind of operation to perform. You can call them commands, if you like. These are GET, POST, PUT, and DELETE. The HTTP 1.1 specification lists some other methods, such as HEAD, TRACE, and OPTIONS, but we can ignore them as they are not frequently used. GET GET is meant to be used for requests that are not intended to modify the state of a resource. This does not mean that the processing by the server of a GET request must be free of side effects—it is perfectly legal, for instance, to increment a counter of page views. GET requests, however, should be idempotent. The property of idempotency means that a sequence of N identical requests should have the same side effects as a single request. The methods GET, HEAD, PUT, and DELETE share this property. Basically, by using GET, a client signals that it intends to retrieve the representation of a resource. The server can perform any operation that causes side effects as part of the execution of the method, but the client cannot be held accountable for them. PUT PUT is generally used to send the modified representation of a resource. It is idempotent as well—multiple, identical PUT requests have the same effect as a single request. DELETE DELETE can be used to request the removal of a resource. This is another idempotent method. POST The POST method is used to request that the server accepts the entity enclosed in the request as a new subordinate of the resource identified by the URI named in the request. POST is a bit like the Swiss army knife of HTTP and can be used for a number of purposes, including: Annotation of existing resources Posting a message to a bulletin board, newsgroup, or mailing list Providing a block of data, such as the result of submitting a form, to a data-handling process Extending a database through an append operation POST is not an idempotent method. One of the main objections proponents of REST raise with respect to traditional Web Service architectures is that, with the latter, POST is used for everything. While you shouldn't feel compelled to use every possible HTTP method in your Web Service (it is perfectly RESTful to use only GET and POST), you should at least know the expectations behind them and use them accordingly.
Read more
  • 0
  • 0
  • 1958

article-image-building-ejb-30-persistence-model-oracle-jdeveloper
Packt
27 Aug 2010
5 min read
Save for later

Building an EJB 3.0 Persistence Model with Oracle JDeveloper

Packt
27 Aug 2010
5 min read
(For more resources on Oracle, see here.) WebLogic server 10.x provides some value-added features to facilitate EJB 3 development. WebLogic server 10.x supports automatic deployment of a persistence unit based on the injected variable's name. The @javax.persistence. PersistenceContext and @javax.persistence.PersistenceUnit annotation s are used to inject the persistence context in an EntityManager or EntityManagerFactory variable . A persistence context is a set of entities that are mapped to a database with a global JNDI name. If the name of the injected variable is the same as the persistence unit, the unitName attribute of the @PersistenceContext or @PersistenceUnit is not required to be specified. The EJB container automatically deploys the persistence unit and sets its JNDI name to be the same as the persistence unit name in persistence.xml. For example, if the persistence unit name in the persistence.xml file is em, an EntityManager variable may be injected with the persistence context as follows: @PeristenceContextprivate EntityManager em; We did not need to specify the unitName attribute in the @PersistenceContext because the variable name is the same as the persistence unit. Similarly, an EntityManagerFactory variable may be injected with the persistence context as follows, emf being also the persistence unit name: @PersistenceUnitprivate EntityManagerFactory emf; Another value-added feature in WebLogic server 10.x is support for vendor-specific subinterfaces of the EntityManager interface. For example, the BEA Kodo persistence provider provides the KodoEntityManager subinterface, which may be injected with the persistence context as follows: @PersistenceContextprivate KodoEntityManager em; Setting the environment Before getting started, we need to install Oracle JDeveloper 11g, which may be downloaded from http://www.oracle.com/technology/products/jdev/index.html. Download the Studio Edition, which is the complete version of JDevloper with all the features. Oracle JDeveloper 11g is distributed as a GUI self-extractor application. Click on the jdevstudio11110 install application. The Oracle Installer gets started. Click on Next in the Oracle Installer. Choose a middleware home directory and click on Next: Choose the Install Type as Complete, which includes the integrated WebLogic Server, and click on Next: Confirm the default Product Installation directories and click on Next: The WebLogic Server installation directory is the wlserver_10.3 folder within the middleware home directory. Choose a shortcut location and click on Next. The Installation Summary lists the products that are installed, which include the WebLogic Server and the WebLogic JDBC drivers. Click on Next to install Oracle JDeveloper 11g and the integrated WebLogic Server 10.3. We also need to install the Oracle database 10g/11g or the lightweight Oracle XE, which may be downloaded from http://www.oracle.com/technology/software/products/database/index.html. When installing Oracle database, also install the sample schemas. Creating a datasource in JDeveloper Next, we create a JDBC datasource in JDeveloper. We shall use the datasource in the EJB 3.0 entity bean for database persistence. First, we need to create a database table in some sample schema, OE for example. Run the following SQL script in SQL *Plus: CREATE TABLE Catalog (id INTEGER PRIMARY KEY NOT NULL,journal VARCHAR(100), publisher VARCHAR(100), edition VARCHAR(100),title VARCHAR(100), author VARCHAR(100)); A database table gets created in the OE sample schema. Next, we need to create a JDBC connection in JDeveloper with Oracle database. Open the Database Navigator or select the Database Navigator tab if already open. Right-click on the IDE Connections node and select New Connection: In the Create Database Connection window, specify a Connection Name, select Connection Type as Oracle (JDBC), specify Username as OE, which is the schema in which the Catalog table is created, and specify the password for the OE schema. Select Driver as thin, Host Name as localhost, SID as ORCL, and JDBC Port as 1521. Click on the Test Connection button to test the connection. If the connection gets established, click on OK: The OracleDBConnection gets added to the Database Navigator view. The CATALOG table that we created is listed in the Tables: (Move the mouse over the image to enlarge.) Creating an EJB 3 application In this section, we create an EJB 3.0 application in JDeveloper. Select New Application: Specify an Application Name, select the Java EE Web Application template, which consists of a Model project and a ViewController project, and click on Next: Next, specify the name (EJB3ViewController) for the View and Controller project. In the Project Technologies tab, transfer the EJB project technology from the Available list to the Selected list using the > button. We have selected the EJB project technology, as we shall be creating an EJB 3.0 model. Click on Next: Select the default Java settings for the View project and click on Next: Configure the EJB Settings for the View project. Select EJB Version as Enterprise JavaBeans 3.0 and select Using Annotations. Click on Next. Next, create the Model project. Specify the Project Name (EJB3Model for example), and in the Project Technologies tab transfer the EJB project technology from the Available list to the Selected list using the > button. We have added the EJB project technology, as the EJB 3.0 application client is created in the View project. Click on Next: Select the default Java settings for the Model project and click on Next: Similar to the View project, configure the EJB settings for the Model project. Select EJB Version as Enterprise JavaBeans 3.0, select Using Annotations and click on Finish. As we won't be using a jndi.properties file or an ejb-jar.xml file , we don't need to select the generate option for the jndi.properties file and the ejb-jar.xml file: An EJB 3.0 application, which consists of a Model project and a ViewController project, get added in the Application tab: Select the EJB3Model project in the Application navigator and select Tools | Project Properties. In the Project Properties window, select the Libraries and Classpath node. The EJB 3.0 library should be in the Classpath Entries: Select the EJB Module node and select the OracleDBConnection in the Connection drop-down list. The datasource corresponding to the OracleDBConnection is jdbc/OracleDBConnectionDS.
Read more
  • 0
  • 0
  • 2813

article-image-developing-ejb-30-entity-weblogic-server
Packt
27 Aug 2010
3 min read
Save for later

Developing an EJB 3.0 entity in WebLogic Server

Packt
27 Aug 2010
3 min read
(For more resources on Oracle, see here.) Setting the environment In the following sections, we will learn how to set up the environment. Installing required products First, download and install the following required products; when installing the MySQL database, select the option to add the MySQL bin directory to the Windows system PATH environment variable: Oracle WebLogic Server 11g (http://www.oracle.com/technology/software/products/ias/htdocs/wls_main.html). Oracle Enterprise Pack for Eclipse All-In-One edition (http://www.oracle.com/technology/software/products/oepe/oepe_11113.html). MySQL 5.x database (http://www.oracle.com/us/products/mysql/index.html). Creating a MySQL database table Next, create a database table in the MySQL database as follows: Log in to the MySQL database with the following command: >mysql Set database as test: mysql>use test Run the following SQL script, which creates a Catalog table for the EJB 3 entity: CREATE TABLE Catalog (id INT PRIMARY KEY NOT NULL, journal VARCHAR(100), publisher VARCHAR(100), date VARCHAR(100), title VARCHAR(100), author VARCHAR(100)); The output from the CREATE TABLE SQL script is shown in the following screenshot: The table description may be listed with the desc command, as shown in the following illustration: Configuring WebLogic Server with MySQL database We shall be using a MySQL database for persistence. Therefore, we need to create a data source in WebLogic Server. Start the WebLogic Server and log in to the Administration Console. Creating a data source Select the base_domain | Services | JDBC | Data Sources. Click on New in the Data Sources table. Specify a data source name and a JNDI Name (jdbc/MySQLDS) for the data source. Select Database Type as MySQL and Database Driver as MySQL's Driver (Type 4): com.mysql.jdbc.Driver. Click on Next, as shown in the following screenshot: (Move the mouse over the image to enlarge.) In the Transaction Options window, select Supports Global Transactions and One-Phase Commit. Click on Next, as shown in the following screenshot: Specify the connection properties: Database Name as test, Host Name as localhost, Port as 3306, and Database User Name as root. Specify the Password used when installing MySQL and click on Next, as shown in the following screenshot: In the Test Database Connection window, the Driver Class Name and connection URL are specified, normally filled from the information you entered in the previous screen. Click on Test Configuration to test the connection. Click on Finish, as shown in the following screenshot: A data source gets added to the Data Sources table with its data source JNDI Name as jdbc/MySQLDS, as shown in the following screenshot: Deploying the data source Next, we deploy the data source to a target server. Click on the data source link in the Data Sources table and select the Targets tab. Select the AdminServer checkbox and click on Save, as shown in the following screenshot: The target server changes get applied and saved: Testing the data source To test the data source, click on Test Data Source. If the data source tests without an error, a message indicating the same gets displayed as shown next:
Read more
  • 0
  • 0
  • 1851
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 €14.99/month. Cancel anytime
article-image-configuring-and-deploying-ejb-30-entity-weblogic-server
Packt
27 Aug 2010
8 min read
Save for later

Configuring and Deploying the EJB 3.0 Entity in WebLogic Server

Packt
27 Aug 2010
8 min read
(For more resources on Oracle, see here.) Creating a Persistence Configuration file An EJB 3.0 entity bean is required to have a persistence.xml configuration file, which defines the database persistence properties. A persistence.xml file gets added to the META-INF folder when a JPA project is defined. Copy the following listing to the persistence.xml file in Eclipse: <?xml version="1.0" encoding="UTF-8" ?> <persistence xsi_schemaLocation= "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="em"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/MySQLDS</jta-data-source> <class>ejb3.Catalog</class> <properties> <property name="eclipselink.target-server" value="WebLogic_10" /> <property name="javax.persistence.jtaDataSource" value="jdbc/ MySQLDS" /> <property name="eclipselink.ddl-generation" value="create-tables" /> <property name="eclipselink.target-database" value="MySQL" /> </properties> </persistence-unit> </persistence> The persistence-unit is required to be named and may be given any name. We had configured a JDBC data source with JNDI jdbc/MySQLDS in WebLogic Server. Specify the JNDI name in the jta-data-source element. The properties element specifies vendor-specific properties. The eclipselink.ddl-generation property is set to create-tables, which implies that the required database tables will be created unless they are already created . The persistence.xml configuration file is shown in the Eclipse project in the following illustration: (Move the mouse over the image to enlarge.) Creating a session bean For better performance, one of the best practices in developing EJBs is to access entity beans from session beans. Wrapping an entity bean with a session bean reduces the number of remote method calls as a session bean may invoke an entity bean locally. If a client accesses an entity bean directly, each method invocation is a remote method call and incurs an overhead of additional network resources. We shall use a stateless session bean, which consumes less resources than a stateful session bean, to invoke entity bean methods. In this section, we create a session bean in Eclipse. A stateless session bean class is just a Java class annotated with the @Stateless annotation. Therefore, we create Java classes for the session bean and session bean remote interface in Eclipse. To create a Java class, select File | New. In the New window, select Java | Class and click on Next> In the New Java Class window, select the Source folder as EJB3JPA/src, EJB3JPA being the project name. Specify Class Name as CatalogTestBean and click on Finish. Similarly, create a CatalogTestBeanRemote interface by selecting Java | Interface in the New window. The session bean class and the remote interface get added to the EJB3JPA project. The session bean class The stateless session bean class, CatalogTestBean implements the CatalogTestRemote interface. We shall use the EntityManager API to create, find, query, and remove entity instances. Inject an EntityManager using the @PersistenceContext annotation. Specify unitName as the same as the persistence-unit name in the persistence.xml configuration file: @PersistenceContext(unitName = "em") EntityManager em; Next, create a test() method, which we shall invoke from a test client. In the test() method we shall create and persist entity instances, query an entity instance, and delete an entity instance, all using an EntityManager object, which we had injected earlier in the session bean class. Injecting an EntityManager implies that an instance of EntityManager is made available to the session bean. Create an instance of the Entity bean class: Catalog catalog = new Catalog(new Integer(1), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Put Your Arrays in a Bind","Mark Williams"); Persist the entity instance to the database using the persist() method: em.persist(catalog); Similarly, persist two more entity instances. Next, create a query using the createQuery() method of the EntityManager object. The query string may be specified as a EJB-QL query. Unlike HQL, the SELECT clause is not optional in EJB-QL. Execute the query and return the query result as a List using the getResultList() method. As an example, select the catalog entry corresponding to author David Baum. The FROM clause of a query is directed towards the mapped entity bean class, not the underlying database. List catalogEntry =em.createQuery("SELECT c from Catalog c where c.author=:name").setParameter("name","David Baum"). getResultList(); Iterate over the result list to output the properties of the entity instance: for (Iterator iter = catalogEntry.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue =retValue + "<br/>" + element.getJournal() + "<br/>" + element.getPublisher() +"<br/>" + element.getDate() + "<br/>" + element.getTitle() + "<br/>" + element.getAuthor() +"<br/>"; } The variable retValue is a String that is returned by the test() method. Similarly, create and run a EJB-QL query to return all titles in the Catalog database: List allTitles =em.createQuery("SELECT c from Catalog c"). getResultList(); An entity instance may be removed using the remove() method: em.remove(catalog2); The corresponding database row gets deleted from the Catalog table. Subsequently, create and run a query to list all the entity instances mapped to the database. The session bean class, CatalogTestBean, is listed next: package ejb3; import java.util.Iterator; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * Session Bean implementation class CatalogTestBean */ @Stateless(mappedName = "EJB3-SessionEJB") public class CatalogTestBean implements CatalogTestBeanRemote { @PersistenceContext(unitName = "em") EntityManager em; /** * Default constructor. */ public CatalogTestBean() { // TODO Auto-generated constructor stub } public String test() { Catalog catalog = new Catalog(new Integer(1), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Put Your Arrays in a Bind","Mark Williams"); em.persist(catalog); Catalog catalog2 = new Catalog(new Integer(2), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Oracle Fusion Middleware 11g: The Foundation for Innovation", "David Baum"); em.persist(catalog2); Catalog catalog3 = new Catalog(new Integer(3), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Integrating Information","David Baum"); em.persist(catalog3); String retValue = "<b>Catalog Entries: </b>"; List catalogEntry = em.createQuery("SELECT c from Catalog c where c.author=:name").setParameter("name", "David Baum").getResultList(); for (Iterator iter = catalogEntry.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element.getJournal() + "<br/>" + element.getPublisher() + "<br/>" + element.getDate() + "<br/>" + element.getTitle() + "<br/>" + element.getAuthor() + "<br/>"; } retValue = retValue + "<b>All Titles: </b>"; List allTitles = em.createQuery("SELECT c from Catalog c").getResultList(); for (Iterator iter = allTitles.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element.getTitle() + "<br/>"; } em.remove(catalog2); ); retValue = retValue + "<b>All Entries after removing an entry: </b>"; List allCatalogEntries = em.createQuery("SELECT c from Catalog c"). getResultList(); for (Iterator iter = allCatalogEntries.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element + "<br/>"; } return retValue; } } We also need to add a remote or a local interface for the session bean: package ejb3; import javax.ejb.Remote; @Remote public interface CatalogTestBeanRemote { public String test(); } The session bean class and the remote interface are shown next: We shall be packaging the entity bean and the session bean in a EJB JAR file, and packaging the JAR file with a WAR file for the EJB 3.0 client into an EAR file as shown next: EAR File | | |-WAR File | |-EJB 3.0 Client |-JAR File | |-EJB 3.0 Entity Bean EJB 3.0 Session Bean Next, we create an application.xml for the EAR file. Create a META-INF folder for the application.xml. Right-click on the EJB3JPA project in Project Explorer and select New>Folder. In the New Folder window, select the EJB3JPA folder and specify the new Folder name as META-INF. Click on Finish. Right-click on the META-INF folder and select New | Other. In the New window, select XML | XML and click on Next. In the New XML File window, select the META-INF folder and specify File name as application.xml. Click on Next. Click on Finish. An application.xml file gets created. Copy the following listing to application.xml: <?xml version = '1.0' encoding = 'windows-1252'?> <application> <display-name></display-name> <module> <ejb>ejb3.jar</ejb> </module> <module> <web> <web-uri>weblogic.war</web-uri> <context-root>weblogic</context-root> </web> </module> </application> The application.xml in the Project Explorer is shown next:
Read more
  • 0
  • 2
  • 7365

article-image-styling-your-joomla-form-using-chronoforms
Packt
27 Aug 2010
11 min read
Save for later

Styling your Joomla! form using ChronoForms

Packt
27 Aug 2010
11 min read
(For more resources on ChronoForms, see here.) Introduction Styling forms is more a subject for a book on Joomla! templating, but as not all templates handle it very well, ChronoForms has some basic formatting capabilities that we will look at here. We'll look at two areas—applying CSS to change the "look and feel" of a form and some simple layout changes that may be helpful. We'll be assuming here that you have some knowledge of both CSS and HTML. Using ChronoForms default style ChronoForms recognizes that many Joomla! templates are not strong in their provision of form styling, so it offers some default styling that you can apply (or not) and edit to suit your needs. Getting ready It might be helpful to have a form to look at. Try creating a test form using the ChronoForms Wizard to add "one of each" of the main inputs to a new form and then save it. How to do it... Each of the five steps here describes a different way to style your forms. You can choose the one (or more) that best meets your needs: When you create a form with the Wizard, ChronoForms does three things: Adds some <div> tags to the form HTML to give basic structure Adds classes to the <div> tags and to the input tags to allow CSS styling Loads some default CSS that uses the classes to give the form a presentable layout If you look at the Form HTML created by the Wizard you will see something like this (this is a basic text input): <div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label" style="width: 150px;"> Click Me to Edit</label> <input class="cf_inputbox" maxlength="150" size="30" title="" id="text_2" name="text_2" type="text" /> </div> <div class="cfclear">&nbsp;</div></div> This example uses the default values from the Wizard. The label text, size, and name may have been changed in the Wizard Properties box. There is a wrapper <div> with a class of form_item. Then, there is a second wrapper around the <label> and <input> tags with two classes—form_element and cf_textbox. There are the <label> and <input> tags themselves with classes of cf_label and cf_inputbox respectively. And lastly there is an "empty" <div> with a class of cfclear that is used to end any CSS floats used in styling the previous tags. The coding for other types of input is very similar, and usually the only difference is the class of the input tag and the <div> tag wrapped around the label and the input. There is nothing very special about any of this; it provides a basic framework for styling. You can't change the default styling used by the Wizard but you can use your own HTML, or edit the Form HTML created by the Wizard. If you change the class names or override the ChronoForms CSS styling with your own styles, then the ChronoForms CSS will no longer apply. Here's what the test form looks like with the default ChronoForms styling: To see the effect of the ChronoForms CSS, open the form in the Form Editor. Go to the General tab, open Core/View Form Settings, and change Load Chronoforms CSS/ JS Files to No. Save the form and refresh the front-end view. Here is the same form without the ChronoForms CSS styling loaded. Not so pretty, but still fully functional. Note: If you create your form in the Form Editor rather than the Wizard, the default setting for Load Chronoforms CSS/JS Files is No. So, you need to turn it on if you want to use the default styling. See also W3Schools CSS tutorials and references at http://www.w3schools.com/css/ default.asp provide a useful online introduction to CSS Switching styles with "Transform Form" The ChronoForms default styling doesn't always suit. So, ChronoForms provides a basic form theming capability. There are only two themes provided—"default" and "theme1". Getting ready We're using the same form as in the previous recipe. How to do it... In the Forms Manager, check the box next to your form name and then click the Transform Form icon in the toolbar. You will see a warning that using Transform Form will overwrite any manual changes to the Form HTML and two form images—one for the "default" theme and one for "theme1". There's a radio button under each theme, and Preview and Transform & Save buttons at the bottom left. The Preview button allows you to see your form with the theme applied. This will not overwrite manual changes; Transform & Save will! Warning: Using Transform & Save will recreate the Form HTML from the version that ChronoForms has saved in the database table. Any manual changes that you have made to the Form HTML will be lost. Applying "theme1" changes the Form HTML structure significantly. Select the "theme1" radio button and click the Preview button to see the result. You can't see this from the preview screen but here's what the text input block now looks like: <div class="cf_item"> <h3 class="cf_title" style="width: 150px;"> Click Me to Edit</h3> <div class="cf_fields"> <input name="text_2" type="text" value="" title="" class="cf_inputtext cf_inputbox" maxlength="150" size="30" id="text_2" /> <br /> <label class="cf_botLabel"></label> </div></div> The wrapping <div> tags and the input are still the same; the old label is now an <h3> tag and there's a new <label> after the input with a cf_botlabel class. The <div> with the cfclear class has gone. This theme may work better with forms that need narrower layouts or where the cfclear <div> tags cause large breaks in the form layout. Neither theme creates a very accessible form layout, and "theme1" is rather less accessible than the "default" theme. If this is important for you then you can create your own form theme. How it works... A ChronoForms theme has two parts—a PHP file that defines the form elements and a CSS file that sets the styling. The Transform Form gets the "Wizard" version of your form that is saved in the database, and regenerates the form HTML using the element structures from the PHP file. When the file is loaded, the theme CSS file will be loaded instead of the default ChronoForms CSS. See also The article "Accessible Forms using WCAG 2.0" (http://www.usability.com.au/resources/wcag2/) is a practical introduction to the topic of web form accessibility. Adding your own CSS styling Many users will want to add their own styling to their forms. This is a short guide about ways to do that. It's not a guide to create the CSS. To add your own Form CSS, you will need to have a working knowledge of HTML and CSS. Getting ready You need nothing to follow the recipe, but when you come to it out, you'll need CSS and a form or two. How to do it... Adding CSS directly in the Form HTML: The quickest and least desirable way of styling is to add CSS directly to the Form HTML. The HTML is accessible on the Form Code tab in the Form Editor. You can type directly into the text area. For example: <input name="text_2" type="text" value="" title="" class="cf_inputtext cf_inputbox" maxlength="150" size="30" id="text_2" style="border: 1px solid blue;" /> The only time when you might need to use this approach is to mark one or two inputs in some special way. Even then it might be better to use a class and define the style outside the Form HTML. Using the Form CSS styles box: In the Form Code tab, ChronoForms has a CSS Styles box, which is opened by clicking the [+/-] link beside CSS Styles. You can add valid CSS definitions in this box (without <style> or </style> tags) and the CSS will be included in the page when it is loaded. For example, you could put this definition into the box: cf_inputbox { border: 1px solid blue; } This will add the following script snippet to the page. If you look at the page source for your form in the front-end you'll find it correctly loaded inside the <head> section. <style type="text/css">cf_inputbox { border: 1px solid blue; } </style> Editing the ChronoForms default CSS: If you have Load Chronoforms CSS/JS Files? set to Yes, then ChronoForms will apply one of its themes, the default one unless you have picked another. The theme CSS files that are used in the front-end are in the components/com_ chronocontact/themes/{theme_name}/css/ folder. Usually there are three files in the folder. The style1-ie6.css file is loaded if the browser detected is IE6; style1-ie7. css is loaded as well for IE7 or IE8; Lstyle1.css is loaded for other browsers. If you edit the ChronoForms CSS, you may need to edit all three files. Note: The themes are duplicated in the Administrator part of ChronoForms, but those files are used in the Transform Form page only. Editing the template CSS: If you want to apply styling more broadly across your site then you may want to integrate the Form CSS with your template style sheets. This is entirely possible; the only thing to make sure of is that the classes in your Form HTML are reflected in the template CSS. You can either manually edit the Form HTML or add the ChronoForms classes to your template styles sheets. Note that this is a much better approach than editing the ChronoForms theme CSS files. Upgrading ChronoForms could well overwrite the theme files. If you have the styles in your template's style sheets, this is not a problem. Creating a new ChronoForms theme is a better solution than editing the default themes as it is protected against overwriting, and allows you to change the layout of the HTML elements in the form. The simplest way to do this is to copy one of the existing theme folders, rename the copy, and edit the files in the new folder. The CSS files are straightforward, but the elements.php file needs a little explanation. If you open the file in an editor, you will find a series of code blocks that define the way in which ChronoForms will structure each of the form elements in the Wizard. Here is an example of a text input: <!--start_cf_textbox--><div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label"{cf_labeloptions}>{cf_labeltext} </label> <input class="{cf_class}" maxlength="{cf_maxlength}" size="{cf_size}" title="{cf_title}" id="{cf_id}" name="{cf_name}" type="{cf_type}" /> {cf_tooltip} </div> <div class="cfclear">&nbsp;</div></div><!--end_cf_textbox--> The comment lines at the beginning and end mark out this element and must be left intact. Between the comment lines you may add any valid HTML body tags that you like, except that the text input element must include <input type='text' . . . /> and so on. The entries in curly brackets, for example {cf_labeltext}, will be replaced by the corresponding values from the Properties box for this element in the Form Wizard. If they appear they must be exactly the same as the entries in the ChronoForms default theme. Most of the time you will not need to create a new theme, but if you are building Joomla! applications, this provides a very flexible way of letting users create forms with a predetermined structure and style. Note that if you create a new theme, you need to ensure that the files are the same in both theme folders (administrator/ components/com_chronocontact/themes/ and components/com_chronocontact/themes/). Maybe a future version of ChronoForms will remove the duplication.
Read more
  • 0
  • 0
  • 3556

article-image-syntax-validation-javascript-testing
Packt
26 Aug 2010
10 min read
Save for later

Syntax Validation in JavaScript Testing

Packt
26 Aug 2010
10 min read
(For more resources on JavaScript, see here.) So without further ado, let us get started with a lighter topic—the difference between validating and testing. The difference between validating and testing There's a thin line separating validating and testing. If you have some idea about sets (as in sets from mathematics), I would say that validation can lead to better testing results, while testing does not necessarily lead to a valid code. Let us consider the scenario—you wrote a JavaScript program and tested it on major browsers such as the Internet Explorer and Firefox; and it worked. In this case, you have tested the code to make sure that it is functional. However, the same code that you have created may or may not be valid; valid code is akin to writing a code that has the following characteristics: Well formed Has good coding style (such as proper indentation, well-commented code, properly spaced) Meets the specification of the language (in our case, JavaScript) There may come a point in time where you will notice that good coding style is highly subjective—there are various validators that may have different opinions or standards as to what is known as "good coding style". Therefore, if you do use different validators to validate your code, do not freak out if you see different advice for your coding style. This does not mean that valid code leads to code that is functional (as you will see later) and that code that is functional leads to validated code as both have different standards for comparison. However, valid code often leads to less errors, and code that is both functional and valid is often quality code. This is due to the fact that writing a piece of JavaScript code, that is both valid and correct, is much more difficult than just writing a code that is correct. Testing often means that we are trying to get the code working correctly; while validation is making sure that the code is syntactically correct, with good style and that it meets the specification of the language. While good coding styles may be subjective, there is often a coding style that is accepted by most programmers, such as, making sure that the code is properly commented, indented, and there is no pollution of the global namespace (especially in the case of JavaScript). To make the case clearer, following are three situations that you can consider: Code that is valid but wrong–validation doesn't find all the errors This form of errors would most probably be caused by logic errors in JavaScript. Logic errors can be syntactically correct but they may be logically flawed. A classic example would be an infinite for loop or infinite while loop. Code that is invalid but right This would most probably be the case for most functional code; a piece of JavaScript may be functionally correct and working, but it may be invalid. This may be due to poor coding style or any other characteristics in a valid code that are missing. Later on in this article, you will see a full working example of a piece of JavaScript code that is right but invalid. Code that is invalid and wrong–validation finds some errors that might be difficult to spot any other way In this case, the code error can be caused by all three forms of JavaScript errors that are mentioned in the article such as loading errors, runtime errors, and logic errors. While it is more likely that errors caused by syntax errors might be spotted by good validators, it is also possible that some errors are buried deep inside the code, such that it is difficult to spot them using manual methods. Now that we have some common understanding as to what validation and testing is about, let us move on to the next section which discusses the issues surrounding quality code. Code quality While there are many views as to what is quality code, I personally believe that there are a few agreed standards. Some of the most commonly mentioned standards may include code readability, ease of extension, efficiency, good coding style, and meeting language specifications, and so on. For our purpose here, we will focus on the factors that make a piece of code valid—coding style and meeting specifications. In general, good coding style almost guarantees that the code is highly readable (even to third parties) and this will help us to spot errors manually. Most importantly, having a good coding style allows us to quickly understand the code, specially if we need to work in teams or are required to debug the code on our own. You will notice that we will focus on the importance of code validity for testing purposes in later parts of the article. But now, let us start with the first building block of quality code—valid HTML and CSS. HTML and CSS needs to be valid before you start on JavaScript We have a common understanding that JavaScript breathes life into a web page by manipulating the Document Object Model (DOM) of the HTML documents. This means that the DOM must be present in the code before JavaScript can operate on it. Here's an important fact that is directly related to HTML, CSS, and browsers—browsers are generally forgiving towards invalid HTML and CSS code as compared to compilers for languages like C or Python. This is because, all browsers have to do is parse the HTML and CSS so as to render the web page for its browsers. On the other hand, compilers are generally unforgiving towards invalid code. Any missing tag, declarations, and so on will lead to a compilation error. Therefore, it is ok to write invalid or even buggy HTML and CSS, yet get a "usual" looking web page. Based on the previous explanation, we should see that we would need to have valid HTML and CSS in order to create quality JavaScript code. A short list of reasons, based on my personal experience, as to why valid HTML and CSS is an important prerequisite before you start working on JavaScript are as follows: Valid HTML and CSS helps ensure that JavaScript works as intended. For example, consider a situation where you might have two div elements that have the same id , code that is supposed to work on the above mentioned HTML element with the id. This will result in unintended consequences. Valid HTML and CSS helps improve the predictability on how your web page will work; there is no point trying to fi x buggy HTML or CSS using JavaScript. You are most probably better off if you start with valid HTML and CSS, and then apply JavaScript. Invalid HTML and CSS may result in different behaviour in different browsers. For example, an HTML tag that is not enclosed may be rendered differently in different browsers. In short, one of the most important building blocks of creating quality JavaScript code is to have valid HTML and CSS. What happens if you don't validate your code You may disagree with me on the previous section as to why HTML and CSS should be valid. In general, validation helps you to prevent errors that are related to coding style and specifications. However, do take note that using different validators may give you different results since validators might have different standards in terms of code style. In case you are wondering if invalid code can affect your JavaScript code, I would advise you to make your code as valid as possible; invalid code may lead to sticky issues such as cross-browser incompatibility, difficulty in reading code, and so on. Invalidated code means that your code may not be foolproof; in the early days of the Internet, there were websites that were dependent on the quirks of the early Netscape browser. Back track to the time where the Internet Explorer 6 was widely used, there were also many websites that worked in quirks mode to support Internet Explorer 6. Now, most browsers are supporting or are moving towards supporting web standards (though slightly different, they are supporting in subtle manners), writing valid code is one of the best ways to ensure that your website works and appears the way it is intended to. How validation can simplify testing While invalid code may not cause your code to be dysfunctional, valid code often simplifies testing. This is due to the focus on coding style and specifications; codes that are valid and have met specifications are typically more likely to be correct and much easier to debug. Consider the following code that is stylistically invalid: function checkForm(formObj){alert(formObj.id)//alert(formObj.text.value);var totalFormNumber = document.forms.length;// check if form elements are empty and are digitsvar maxCounter = formObj.length; // this is for checking for emptyvaluesalert(totalFormNumber);// check if the form is properly filled in order to proceedif(checkInput(formObj)== false){alert("Fields cannot be empty and it must be digits!");// stop executing the code since the input is invalidreturn false;}else{;}var i = 0;var formID;while(i < totalFormNumber){if(formObj == document.forms[i]){formID = i;alert(i);}i++;}if(formID<4){formID++;var formToBeChanged = document.forms[formID].id;// alert(formToBeChanged);showForm(formToBeChanged);}else{// this else statement deals with the last form// and we need to manipulate other HTML elementsdocument.getElementById("formResponse").style.visibility = "visible";}return false;} The previous code is an extreme example of poor code style, especially in terms of indentation. Imagine if you have to manually debug the second code snippet that you saw earlier! I am pretty sure that you will find it frustrating to check the code, because you will have little visual sense of what is going on. More importantly, if you are working in a team, you will be required to write legible code; in short, writing valid code typically leads to code that is more legible, easier to follow, and hence, less erroneous. Validation can help you debug your code As mentioned in the previous section, browsers are in general forgiving towards invalid HTML and CSS. While this is true, there may be errors that are not caught, or are not rendered correctly or gracefully. This means that while the invalid HTML and CSS code may appear fine on a certain platform or browser, it may not be supported on others. This means that using valid code (valid code typically means standard code set by international organizations such as W3C) will give you a much greater probability of having your web page rendered correctly on different browsers and platforms. With valid HTML and CSS, you can safely write your JavaScript code and expect it to work as intended, assuming that your JavaScript code is equally valid and error free. Validation helps you to code using good practices Valid code typically requires coding using good practices. As mentioned frequently in this article, good practices include the proper enclosing of tags, suitable indentation to enhance code readability, and so on. If you need more information about good practi ces when using JavaScript, feel free to check out the creator of JSLint, Douglas Crockford, at http://crockford.com.. Or you can read up John Resigs blog (the creator of JQuery) at http://ejohn.org. Both are great guys who know what great JavaScript is about. Validation To summarize the above sections, the DOM is provided by HTML, and both CSS and JavaScript are applied to the DOM. This means that if there is an invalid DOM, there is a chance that the JavaScript that is operating on the DOM (and sometimes the CSS) might result in errors. With this summary in mind, we'll focus on how you can spot validation errors by using color coding editors.
Read more
  • 0
  • 0
  • 2072

article-image-building-facebook-clone-using-ruby
Packt
25 Aug 2010
8 min read
Save for later

Building the Facebook Clone using Ruby

Packt
25 Aug 2010
8 min read
(For more resources on Ruby, see here.) This is the largest clone and has many components. Some of the less interesting parts of the code are not listed or described here. To get access to the full source code please go to http://github.com/sausheong/saushengine. Configuring the clone We use a few external APIs in Colony so we need to configure our access to these APIs. In a Colony all these API keys and settings are stored in a Ruby file called config.rb as below. S3_CONFIG = {}S3_CONFIG['AWS_ACCESS_KEY'] = '<AWS ACCESS KEY>'S3_CONFIG['AWS_SECRET_KEY'] = '<AWS SECRET KEY>'RPX_API_KEY = '<RPX API KEY>' Modeling the data You will find a large number of classes and relationships in this article. The following diagram shows how the clone is modeled: User The first class we look at is the User class. There are more relationships with other classes and the relationship with other users follows that of a friends model rather than a followers model. class User include DataMapper::Resource property :id, Serial property :email, String, :length => 255 property :nickname, String, :length => 255 property :formatted_name, String, :length => 255 property :sex, String, :length => 6 property :relationship_status, String property :provider, String, :length => 255 property :identifier, String, :length => 255 property :photo_url, String, :length => 255 property :location, String, :length => 255 property :description, String, :length => 255 property :interests, Text property :education, Text has n, :relationships has n, :followers, :through => :relationships, :class_name => 'User', :child_key => [:user_id] has n, :follows, :through => :relationships, :class_name => 'User', :remote_name => :user, :child_key => [:follower_id] has n, :statuses belongs_to :wall has n, :groups, :through => Resource has n, :sent_messages, :class_name => 'Message', :child_key => [:user_id] has n, :received_messages, :class_name => 'Message', :child_key => [:recipient_id] has n, :confirms has n, :confirmed_events, :through => :confirms, :class_name => 'Event', :child_key => [:user_id], :date.gte => Date.today has n, :pendings has n, :pending_events, :through => :pendings, :class_name => 'Event', :child_key => [:user_id], :date.gte => Date.today has n, :requests has n, :albums has n, :photos, :through => :albums has n, :comments has n, :activities has n, :pages validates_is_unique :nickname, :message => "Someone else has taken up this nickname, try something else!" after :create, :create_s3_bucket after :create, :create_wall def add_friend(user) Relationship.create(:user => user, :follower => self) end def friends (followers + follows).uniq end def self.find(identifier) u = first(:identifier => identifier) u = new(:identifier => identifier) if u.nil? return u end def feed feed = [] + activities friends.each do |friend| feed += friend.activities end return feed.sort {|x,y| y.created_at <=> x.created_at} end def possessive_pronoun sex.downcase == 'male' ? 'his' : 'her' end def pronoun sex.downcase == 'male' ? 'he' : 'she' end def create_s3_bucket S3.create_bucket("fc.#{id}") end def create_wall self.wall = Wall.create self.save end def all_events confirmed_events + pending_events end def friend_events events = [] friends.each do |friend| events += friend.confirmed_events end return events.sort {|x,y| y.time <=> x.time} end def friend_groups groups = [] friends.each do |friend| groups += friend.groups end groups - self.groups endend As mentioned in the design section above, the data used in Colony is user-centric. All data in Colony eventually links up to a user. A user has following relationships with other models: A user has none, one, or more status updates A user is associated with a wall A user belongs to none, one, or more groups A user has none, one, or more sent and received messages A user has none, one, or more confirmed and pending attendances at events A user has none, one, or more user invitations A user has none, one, or more albums and in each album there are none, one, or more photos A user makes none, one, or more comments A user has none, one, or more pages A user has none, one, or more activities Finally of course, a user has one or more friends Once a user is created, there are two actions we need to take. Firstly, we need to create an Amazon S3 bucket for this user, to store his photos. after :create, :create_s3_bucketdef create_s3_bucket S3.create_bucket("fc.#{id}")end We also need to create a wall for the user where he or his friends can post to. after :create, :create_walldef create_wall self.wall = Wall.create self.saveend Adding a friend means creating a relationship between the user and the friend. def add_friend(user) Relationship.create(:user => user, :follower => self) end Colony treats the following relationship as a friends relationship. The question here is who will initiate the request to join? This is why when we ask the User object to give us its friends, it will add both followers and follows together and return a unique array representing all the user's friends. def friends (followers + follows).uniqend In the Relationship class, each time a new relationship is created, an Activity object is also created to indicate that both users are now friends. class Relationship include DataMapper::Resource property :user_id, Integer, :key => true property :follower_id, Integer, :key => true belongs_to :user, :child_key => [:user_id] belongs_to :follower, :class_name => 'User', :child_key => [:follower_id] after :save, :add_activity def add_activity Activity.create(:user => user, :activity_type => 'relationship', :text => "<a href='/user/#{user.nickname}'>#{user.formatted_name}</a> and <a href='/user/#{follower.nickname}'>#{follower.formatted_name}</a> are now friends.") end end Finally we get the user's news feed by taking the user's activities and going through each of the user's friends, their activities as well. def feed feed = [] + activities friends.each do |friend| feed += friend.activities end return feed.sort {|x,y| y.created_at <=> x.created_at}end Request We use a simple mechanism for users to invite other users to be their friends. The mechanism goes like this: Alice identifies another Bob whom she wants to befriend and sends him an invitation This creates a Request class which is then attached to Bob When Bob approves the request to be a friend, Alice is added as a friend (which is essentially making Alice follow Bob, since the definition of a friend in Colony is either a follower or follows another user) class Request include DataMapper::Resource property :id, Serial property :text, Text property :created_at, DateTime belongs_to :from, :class_name => User, :child_key => [:from_id] belongs_to :user def approve self.user.add_friend(self.from) endend Message Messages in Colony are private messages that are sent between users of Colony. As a result, messages sent or received are not tracked as activities in the user's activity feed. class Message include DataMapper::Resource property :id, Serial property :subject, String property :text, Text property :created_at, DateTime property :read, Boolean, :default => false property :thread, Integer belongs_to :sender, :class_name => 'User', :child_key => [:user_id] belongs_to :recipient, :class_name => 'User', :child_key => [:recipient_id] end A message must have a sender and a recipient, both of which are users. has n, :sent_messages, :class_name => 'Message', :child_key => [:user_id]has n, :received_messages, :class_name => 'Message', :child_key => [:recipient_id] The read property tells us if the message has been read by the recipient, while the thread property tells us how to group messages together for display. Album An activity is logged, each time an album is created. class Album include DataMapper::Resource property :id, Serial property :name, String, :length => 255 property :description, Text property :created_at, DateTime belongs_to :user has n, :photos belongs_to :cover_photo, :class_name => 'Photo', :child_key => [:cover_photo_id] after :save, :add_activity def add_activity Activity.create(:user => user, :activity_type => 'album', :text => "<a href='/user/#{user.nickname}'>#{user.formatted_name}</a> created a new album <a href='/album/#{self.id}'>#{self.name}</a>") end end
Read more
  • 0
  • 0
  • 1575
article-image-trapping-errors-using-built-objects-javascript-testing
Packt
25 Aug 2010
6 min read
Save for later

Trapping Errors by Using Built-In Objects in JavaScript Testing

Packt
25 Aug 2010
6 min read
(For more resources on JavaScript, see here.) The Error object An Error is a generic exception, and it accepts an optional message that provides details of the exception. We can use the Error object by using the following syntax: new Error(message); // message can be a string or an integer Here's an example that shows the Error object in action. The source code for this example can be found in the file error-object.html. <html><head><script type="text/javascript">function factorial(x) { if(x == 0) { return 1; } else { return x * factorial(x-1); } } try { var a = prompt("Please enter a positive integer", ""); if(a < 0){ var error = new Error(1); alert(error.message); alert(error.name); throw error; } else if(isNaN(a)){ var error = new Error("it must be a number"); alert(error.message); alert(error.name); throw error; } var f = factorial(a); alert(a + "! = " + f); } catch (error) { if(error.message == 1) { alert("value cannot be negative"); } else if(error.message == "it must be a number") { alert("value must be a number"); } else throw error; } finally { alert("ok, all is done!"); } </script> </head> <body> </body> </html> You may have noticed that the structure of this code is similar to the previous examples, in which we demonstrated try, catch, finally, and throw. In this example, we have made use of what we have learned, and instead of throwing the error directly, we have used the Error object. I need you to focus on the code given above. Notice that we have used an integer and a string as the message argument for var error, namely new Error(1) and new Error("it must be a number"). Take note that we can make use of alert() to create a pop-up window to inform the user of the error that has occurred and the name of the error, which is Error, as it is an Error object. Similarly, we can make use of the message property to create program logic for the appropriate error message. It is important to see how the Error object works, as the following built-in objects, which we are going to learn about, work similarly to how we have seen for the Error object. (We might be able to show how we can use these errors in the console log.) The RangeError object A RangeError occurs when a number is out of its appropriate range. The syntax is similar to what we have seen for the Error object. Here's the syntax for RangeError: new RangeError(message); message can either be a string or an integer. <html><head><script type="text/javascript">try { var anArray = new Array(-1); // an array length must be positive}catch (error) { alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> We'll start with a simple example to show how this works. Check out the following code that can be found in the source code folder, in the file rangeerror.html: When you run this example, you should see an alert window informing you that the array is of an invalid length. After this alert window, you should receive another alert window telling you that The error is RangeError, as this is a RangeError object. If you look at the code carefully, you will see that I have deliberately created this error by giving a negative value to the array's length (array's length must be positive). The ReferenceError object A ReferenceError occurs when a variable, object, function, or array that you have referenced does not exist. The syntax is similar to what you have seen so far and it is as follows: new ReferenceError(message); message can either be a string or an integer. As this is pretty straightforward, I'll dive right into the next example. The code for the following example can be found in the source code folder, in the file referenceerror.html. <html><head><script type="text/javascript">try { x = y; // notice that y is not defined // an array length must be positive}catch (error) { alert(error); alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> Take note that y is not defined, and we are expecting to catch this error in the catch block. Now try the previous example in your Firefox browser. You should receive four alert windows regarding the errors, with each window giving you a different message. The messages are as follows: ReferenceError: y is not defined y is not defined ReferenceError ok, all is done If you are using Internet Explorer, you will receive slightly different messages. You will see the following messages: [object Error] message y is undefined TypeError ok, all is done The TypeError object A TypeError is thrown when we try to access a value that is of the wrong type. The syntax is as follows: new TypeError(message); // message can be a string or an integer and it is optional An example of TypeError is as follows: <html><head><script type="text/javascript">try { y = 1 var test = function weird() { var foo = "weird string"; } y = test.foo(); // foo is not a function}catch (error) { alert(error); alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> If you try running this code in Firefox, you should receive an alert box stating that it is a TypeError. This is because test.foo() is not a function, and this results in a TypeError. JavaScript is capable of finding out what kind of error has been caught. Similarly, you can use the traditional method of throwing your own TypeError(), by uncommenting the code. The following built-in objects are less used, so we'll just move through quickly with the syntax of the built-in objects.
Read more
  • 0
  • 0
  • 1165

article-image-websphere-mq-sample-programs
Packt
25 Aug 2010
5 min read
Save for later

WebSphere MQ Sample Programs

Packt
25 Aug 2010
5 min read
(For more resources on IBM, see here.) WebSphere MQ sample programs—server There is a whole set of sample programs available to the WebSphere MQ administrator. We are interested in only a couple of them: the program to put a message onto a queue and a program to retrieve a message from a queue. The names of these sample programs depend on whether we are running WebSphere MQ as a server or as a client. There is a server sample program called amqsput, which puts messages onto a queue using the MQPUT call. This sample program comes as part on the WebSphere MQ samples installation package, not as part of the base package. The maximum length of message that we can put onto a queue using the amqsput sample program is 100 bytes. There is a corresponding server sample program to retrieve messages from a queue called amqsget. Use the sample programs only when testing that the queues are set up correctly—do NOT use the programs once Q Capture and Q Apply have been started. This is because Q replication uses dense numbering between Q Capture and Q Apply, and if we insert or retrieve a message, then the dense numbering will not be maintained and Q Apply will stop. The usual response to this is to cold start Q Capture! To put a message onto a Queue (amqsput) The amqsput utility can be invoked from the command line or from within a batch program. If we are invoking the utility from the command line, the format of the command is: $ amqsput <Queue> <QM name> < <message> We would issue this command from the system on which the Queue Manager sits. We have to specify the queue (<Queue>) that we want to put the message on, and the Queue Manager (<QM name>) which controls this queue. We then pipe (<) the message (<message>) into this. An example of the command is: $ amqsput CAPA.TO.APPB.SENDQ.REMOTE QMA < hello We put these commands into an appropriately named batch fle (say SYSA_QMA_TESTP_UNI_AB.BAT), which would contain the following: Batch file—Windows example: call "C:Program FilesIBMWebSphere MQbinamqsput" CAPA.TO.APPB.SENDQ.REMOTE QMA < QMA_TEST1.TXT Batch file—UNIX example: "/opt/mqm/samp/bin/amqsput" CAPA.TO.APPB.SENDQ.REMOTE QMA < QMA_TEST1.TXT Where the QMA_TEST1.TXT fle contains the message we want to send. Once we have put a message onto the Send Queue, we need to be able to retrieve it. To retrieve a message from a Queue(amqsget) The amqsget utility can be invoked from the command line or from within a batch program. The utility takes 15 seconds to run. We need to specify the Receive Queue that we want to read from and the Queue Manager that the queue belongs to: $ amqsget <Queue> <QM name> As example of the command is shown here: $ amqsget CAPA.TO.APPB.RECVQ QMB If we have correctly set up all the queues, and the Listeners and Channels are running, then when we issue the preceding command, we should see the message we put onto the Send Queue. We can put the amqsget command into a batch fle, as shown next: Batch file—Windows example: @ECHO This takes 15 seconds to runcall "C:Program FilesIBMWebSphere MQbinamqsget" CAPA.TO.APPB.RECVQ QMB@ECHO You should see: test1 Batch file—UNIX example: echo This takes 15 seconds to run"/opt/mqm/samp/bin/amqsget" CAPA.TO.APPB.RECVQ QMBecho You should see: test1 Using these examples and putting messages onto the queues in a unidirectional scenario, then the "get" message batch fle for QMA (SYSA_QMA_TESTG_UNI_BA.BAT) contains: @ECHO This takes 15 seconds to runcall "C:Program FilesIBMWebSphere MQbinamqsget" CAPA.ADMINQ QMA@ECHO You should see: test2 From CLP-A, run the fle as: $ SYSA_QMA_TESTG_UNI_BA.BAT The "get" message batch file for QMB (SYSB_QMB_TESTG_UNI_AB.BAT) contains: @ECHO This takes 15 seconds to runcall "C:Program FilesIBMWebSphere MQbinamqsget" CAPA.TO.APPB.RECVQ QMB@ECHO You should see: test1 From CLP-B, run the file as: $ SYSB_QMB_TESTG_UNI_AB.BAT To browse a message on a Queue It is useful to be able to browse a queue, especially when setting up Event Publishing. There are three ways to browse the messages on a Local Queue. We can use the rfhutil utility, or the amqsbcg sample program, both of which are WebSphere MQ entities, or we can use the asnqmfmt Q replication command. Using the WebSphere MQ rfhutil utility: The rfhutil utility is part of the WebSphere MQ support pack available to download from the web—to find the current download website, simply type rfhutil into an internet search engine. The installation is very simple—unzip the file and run the rfhutil.exe file. Using the WebSphere MQ amqsbcg sample program: The amqsbcg sample program displays messages including message descriptors. $ amqsbcg CAPA.TO.APPB.RECVQ QMB
Read more
  • 0
  • 0
  • 6120

article-image-setting-payment-model-opencart
Packt
25 Aug 2010
8 min read
Save for later

Setting Payment Model in OpenCart

Packt
25 Aug 2010
8 min read
(For more resources on OpenCart, see here.) Shopping cart system The shopping cart is special software which allows customers to add / delete products to a basket from a store catalogue and then complete the order. The shopping cart also automatically updates the total amount which the customer will pay according to product additions or deletions on the basket. OpenCart provides a built-in shopping cart system which provides all such functionality. So, you don't need to install or buy separate software for the shopping cart. Merchant account A merchant account is a special account type which differs from a usual bank account. Its sole purpose is to accept credit card payments. Opening a merchant account requires making a contract with the credit card network providers. Authorized card payments on the store are transferred to the merchant account. Then, as a merchant we can transfer the amount from merchant account to bank account (checking account). Since opening a merchant account can be a tiresome process for most businesses and individuals, there are various online businesses which can provide this functionality. Curious readers can learn the details of merchant accounts on the following links: http://en.wikipedia.org/wiki/Merchant_account http://www.merchantaccount.com/ Payment gateway A payment gateway is an online analogue of a physical credit card processing terminal that we can locate in retail shops. Its function is to process credit card information and return the results back to the store system. You can imagine the payment gateway as an element in the middle of an online store and credit card network. The software part of this service is included in OpenCart but we will have to use one of the payment gateway services. Understanding online credit card processing The following diagram shows the standard credit card processing flowchart in detail. Note that it is not essential to know every detail in steps shown in a red background color. These parts are executed on behalf of us by the payment system which we will use, so it is isolated both from the store and customer. For example, PayPal is such a system, which we will learn about now in detail. Let's explain the flowchart step by step to clearly understand the whole process: A customer successfully enters into the checkout page after filling the shopping cart with the products. Then, he/she enters the credit card information and clicks on the Pay button. Now, the store checkout page sends these details along with the total amount to the payment gateway securely. The payment gateway starts a series of processes. First of all, the information is passed to the merchant's bank processor where the merchant account was opened before. The information is then sent to the credit card network by this processor. Visa and MasterCard are two of the most popular credit card networks. The credit card network processes the validity of the credit card and sends the information to the customer's credit card issuer bank. As a result, the bank rejects or approves the transaction and sends the information back to the credit card network. Through the same routing in reverse, the payment information is finally submitted back to the online store with a special code. All this is done in a few seconds and the information flow starting from the payment gateway is isolated from both the customer and merchant. It means that we don't have to deal with what's going on after sending information to the payment gateway. As a merchant, we only need the result of the transaction. After the information is processed by credit card network during Step 6; the transaction funds are transferred to the merchant account by the credit card network as shown in Step a. Then, the merchant can transfer the funds from the merchant account to the usual checking bank account automatically or manually, as shown in Step b. OpenCart payment methods The current OpenCart version supports many established payment systems, including PayPal services, Authorize.net, Moneybookers, 2Checkout, and so on, as well as basic payment options such as Cash on Delivery, Bank Transfer, Check/money order, etc. We can also get more payment gateway modules on the OpenCart extensions section by searching in Payment Methods. http://www.opencart.com/index.php?route=extension/extension We will now briefly learn the most widely used methods and their differences and similarities to each other. PayPal PayPal is one of the most popular and easiest to use systems for accepting credit cards for an online store. PayPal has two major products to be used in OpenCart through built-in modules: PayPal Website Payment Standard PayPal Website Payment Pro Both of these payment methods provide both payment gateway and merchant account functionality. Let's understand the details of each now. PayPal Website Payment Standard It is the easiest method to implement accepting credit card payments on an online store. For merchants, a simple bank account and a PayPal account is enough to take payments. There are no monthly fees or setup costs charged by PayPal. The only cost is a fixed small percentage taken by PayPal for each transaction. So, you should consider this on price valuations of items in the store. Here is the link to learn about the latest commission rates per transaction: http://merchant.paypal.com When the customer clicks on the checkout button on OpenCart, he/she will be redirected to the PayPal site to continue with the payment. As you can see from the following sample screenshot, a customer can provide credit card information instantly or log in to his/her PayPal account to pay from the balance in the PayPal account: In the next step, after the final review, the user clicks on the Pay Now button. Notice that PayPal automatically localizes the total amount according to the PayPal owner's account currency. In this case, the price is calculated according to Dollar – Euro exchange rates. After the payment, the PayPal screen shows the result of the payment. The screen doesn't return to the merchant store automatically. There is a button for it: Return to Merchant. Finally, the website user is informed about the result of the purchase in the OpenCart store. The main advantage of PayPal Website Payment Standard is that it is easy to implement; many online people are familiar with using it. We can state one minor disadvantage. Some people may abandon the purchase since the payment gateway would leave the store temporarily to complete the transaction on the PayPal website. PayPal Website Payment Pro This is the paid PayPal solution for an online store as a payment gateway and merchant account. The biggest difference from PayPal Website Payment Standard is that customers do not leave the website for credit card processing. The credit card information is completely processed in the online store as it is the popular method of all established e-commerce websites. Even the customers will not know about the processor of the cards. Unless we put a PayPal logo ourselves, this information is well encapsulated. Using this method also only requires a bank account and PayPal account for the merchant. PayPal charges a monthly fee and a one-time setup fee for this service. The individual transactions are also commissioned by PayPal. This is a very professional way of processing credit cards online for a store but it can have a negative effect on some customers. Some customers can require seeing some indication of trust from the store before making a purchase. So, depending the on store owner's choice, it would be wise to put a remark and logo of PayPal stating that «Credit card is processed by PayPal safely and securely» For a beginner OpenCart administrator who wants to use PayPal for the online store, it is recommended to get experience with the free Standard payment option and then upgrade to the Pro option. We can get more information on PayPal Website Payment Pro service at: http://merchant.paypal.com At time of writing this book, PayPal only charges a fixed monthly fee ($30) and commissions on each transaction. There are no other setup costs or hidden charges. PayFlow Pro payment gateway If we already have a merchant account, we don't need to pay extra for it by using PayPal Standard or PayPal Pro. PayFlow Pro is cheaper than other PayPal services and allows us to accept credit card payments to an existing merchant account. Unfortunately, OpenCart currently does not support it as a built-in module but there are both free and paid modules. You can get them from the OpenCart official contributions page at: http://www.opencart.com/index.php?route=extension/extension
Read more
  • 0
  • 0
  • 3363
article-image-ibm-websphere-mq-commands
Packt
25 Aug 2010
10 min read
Save for later

IBM WebSphere MQ commands

Packt
25 Aug 2010
10 min read
(For more resources on IBM, see here.) After reading this article, you will not be a WebSphere MQ expert, but you will have brought your knowledge of MQ to a level where you can have a sensible conversation with your site's MQ administrator about what the Q replication requirements are. An introduction to MQ In a nutshell, WebSphere MQ is an assured delivery mechanism, which consists of queues managed by Queue Managers. We can put messages onto, and retrieve messages from queues, and the movement of messages between queues is facilitated by components called Channels and Transmission Queues. There are a number of fundamental points that we need to know about WebSphere MQ: All objects in WebSphere MQ are case sensitive We cannot read messages from a Remote Queue (only from a Local Queue) We can only put a message onto a Local Queue (not a Remote Queue) It does not matter at this stage if you do not understand the above points, all will become clear in the following sections. There are some standards regarding WebSphere MQ object names: Queue names, processes and Queue Manager names can have a maximum length of 48 characters Channel names can have a maximum length of 20 characters The following characters are allowed in names: A-Z,a-z,0-9, and . / _ % symbols There is no implied structure in a name — dots are there for readability Now let's move on to look at MQ queues in a little more detail. MQ queues MQ queues can be thought of as conduits to transport messages between Queue Managers. There are four different types of MQ queues and one related object. The four different types of queues are: Local Queue (QL), Remote Queue (QR), Transmission Queue (TQ), and Dead Letter Queue, and the related object is a Channel (CH). One of the fundamental processes of WebSphere MQ is the ability to move messages between Queue Managers. Let's take a high-level look at how messages are moved, as shown in the following diagram: When the application Appl1 wants to send a message to application Appl2, it opens a queue - the local Queue Manager (QM1) determines if it is a Local Queue or a Remote Queue. When Appl1 issues an MQPUT command to put a message onto the queue, then if the queue is local, the Queue Manager puts the message directly onto that queue. If the queue is a Remote Queue, then the Queue Manager puts the message onto a Transmission Queue. The Transmission Queue sends the message using the Sender Channel on QM1 to the Receiver Channel on the remote Queue Manager (QM2). The Receiver Channel puts the message onto a Local Queue on QM2. Appl2 issues a MQGET command to retrieve the message from this queue. Now let's move on to look at the queues used by Q replication and in particular, unidirectional replication, as shown in the following diagram. What we want to show here is the relationship between Remote Queues, Transmission Queues, Channels, and Local Queues. As an example, let's look at the path a message will take from Q Capture on QMA to Q Apply on QMB. (Move the mouse over the image to enlarge.) Note that in this diagram the Listeners are not shown. Q Capture puts the message onto a remotely-defned queue on QMA (the local Queue Manager for Q Capture). This Remote Queue (CAPA.TO.APPB.SENDQ.REMOTE) is effectively a "place holder" and points to a Local Queue (CAPA.TO.APPB.RECVQ) on QMB and specifes the Transmission Queue (QMB.XMITQ) it should use to get there. The Transmission Queue has, as part of its defnition, the Channel (QMA.TO.QMB) to use. The Channel QMA.TO.QMB has, as part of its defnition, the IP address and Listening port number of the remote Queue Manager (note that we do not name the remote Queue Manager in this defnition—it is specifed in the defnition for the Remote Queue). The defnition for unidirectional Replication Queue Map (circled queue names) is: SENDQ: CAPA.TO.APPB.SENDQ.REMOTE on the source RECVQ: CAPA.TO.APPB.RECVQ on the target ADMINQ: CAPA.ADMINQ.REMOTE on the target Let's look at the Remote Queue defnition for CAPA.TO.APPB.SENDQ.REMOTE, shown next. On the left-hand side are the defnitions on QMA, which comprise the Remote Queue, the Transmission Queue, and the Channel defnition. The defnitions on QMB are on the right-hand side and comprise the Local Queue and the Receiver Channel. Let's break down these defnitions to the core values to show the relationship between the different parameters, as shown next: We defne a Remote Queue by matching up the superscript numbers in the defnitions in the two Queue Managers: For defnitions on QMA, QMA is the local system and QMB is the remote system. For defnitions on QMB, QMB is the local system and QMA is the remote system. Remote Queue Manager name Name of the queue on the remote system Transmission Queue name Port number that the remote system is listening on The IP address of the Remote Queue Manager Local Queue Manager name Channel name Queue names: QMB: Decide on the Local Queue name on QMB—CAPA.TO.APPB.RECVQ. QMA: Decide on the Remote Queue name on QMB—CAPA.TO.APPB.SENDQ.REMOTE. Channels: QMB: Defne a Receiver Channel on QMB, QMA.TO.QMB—make sure the channel type (CHLTYPE) is RCVR. The Channel names on QMA and QMB have to match: QMA.TO.QMB. QMA: Defne a Sender Channel, which takes the messages from the Transmission Queue QMB.XMITQ and which points to the IP address and Listening port number of QMB. The Sender Channel name must be QMA.TO.QMB. Let's move on from unidirectional replication to bidirectional replication. The bidirectional queue diagram is shown next, which is a cut-down version of the full diagram of the The WebSphere MQ layer and just shows the queue names and types without the details. The principles in bidirectional replication are the same as for unidirectional replication. There are two Replication Queue Maps—one going from QMA to QMB (as unidirectional replication) and one going from QMB to QMA. MQ queue naming standards The naming of the WebSphere MQ queues is an important part of Q replication setup. It may be that your site already has a naming standard for MQ queues, but if it does not, then here are some thoughts on the subject (WebSphere MQ naming standards were discussed in the Introduction to MQ section): Queues are related to Q Capture and Q Apply programs, so it would be useful to have that fact refected in the name of the queues. A Q Capture needs a local Restart Queue and we use the name CAPA.RESTARTQ. Each Queue Manager can have a Dead Letter Queue. We use the prefx DEAD.LETTER.QUEUE with a suffx of the Queue Manager name giving DEAD.LETTER.QUEUE.QMA. Receive Queues are related to Send Queues. For every Send Queue, we need a Receive Queue. Our Send Queue names are made up of where they are coming from, Q Capture on QMA (CAPA), and where they are going to, Q Apply on QMB (APPB), and we also want to put in that it is a Send Queue and that it is a remote defnition, so we end up with CAPA.TO.APPB.SENDQ.REMOTE. The corresponding Receive Queue will be called CAPA.TO.APPB.RECVQ. Transmission Queues should refect the names of the "to" Queue Manager. Our Transmission Queue on QMA is called QMB.XMITQ, refecting the Queue Manager that it is going to, and that it is a Transmission Queue. Using this naming convention on QMB, the Transmission Queue is called QMA.XMITQ. Channels should refect the names of the "from" and "to" Queue Managers. Our Sender Channel defnition on QMA is QMA.TO.QMB refecting that it is a channel from QMA to QMB and the Receiver Channel on QMB is also called QMA.TO.QMB. The Receiver Queue on QMA is called QMB.TO.QMA for a Sender Channel of the same name on QMB. A Replication Queue Map defnition requires a local Send Queue, and a remote Receive Queue and a remote Administration Queue. The Send Queue is the queue that Q Capture writes to, the Receive Queue is the queue that Q Apply reads from, and the Administration Queue is the queue that Q Apply writes messages back to Q Capture with. MQ queues required for different scenarios This section lists the number of Local and Remote Queues and Channels that are needed for each type of replication scenario. The queues and channels required for unidirectional replication (including replicating to a Stored Procedure) and Event Publishing are shown in the following tables. Note that the queues and channels required for Event Publishing are a subset of those required for unidirectional replication, but creating extra queues and not using them is not a problem. The queues and channels required for unidirectional (including replicating to a Stored Procedure) are shown in the following table: QMA (7) QMB (7) 3 Local Queues: CAPA.ADMINQ CAPA.RESTARTQ DEAD.LETTER.QUEUE.QMA 1 Remote Queue: CAPA.TO.APPB.SENDQ.REMOTE 1 Transmission Queue: QMB.XMITQ 1 Sender Channel: QMA.TO.QMB 1 Receiver Channel: QMB.TO.QMA 2 Local Queues: CAPA.TO.APPB.REVCQ DEAD.LETTER.QUEUE.QMB 1 Remote Queue: CAPA.ADMINQ.REMOTE 1 Transmission Queue: QMA.XMITQ 1 Sender Channel: QMB.TO.QMA 1 Receiver Channel: QMA.TO.QMB 1 Model Queue: IBMQREP.SPILL.MODELQ   The queues required for Event Publishing are shown in the following table: QMA (7) QMB (7) 3 Local Queues: CAPA.ADMINQ CAPA.RESTARTQ DEAD.LETTER.QUEUE.QMA 1 Remote Queue: CAPA.TO.APPB.SENDQ.REMOTE 1 Transmission Queue: QMB.XMITQ 1 Sender Channel: QMA.TO.QMB 1 Receiver Channel: QMB.TO.QMA 2 Local Queues: CAPA.TO.APPB.REVCQ DEAD.LETTER.QUEUE.QMB 1 Receiver Channel: QMA.TO.QMB The queues and channels required for bidirectional/P2P two-way replication are shown in the following table: QMA (10) QMB (10) 4 Local Queues: CAPA.ADMINQ CAPA.RESTARTQ DEAD.LETTER.QUEUE.QMA CAPB.TO.APPA.RECVQ 2 Remote Queues: CAPA.TO.APPB.SENDQ.REMOTE CAPB.ADMINQ.REMOTE 1 Transmission Queue: QMB.XMITQ 1 Sender Channel: QMA.TO.QMB 1 Receiver Channel: QMB.TO.QMA 1 Model Queue: IBMQREP.SPILL.MODELQ 4 Local Queues: CAPB.ADMINQ CAPB.RESTARTQ DEAD.LETTER.QUEUE.QMB CAPA.TO.APPB.RECVQ 2 Remote Queues: CAPB.TO.APPA.SENDQ.REMOTE CAPA.ADMINQ.REMOTE 1 Transmission Queue: QMA.XMITQ 1 Sender Channel: QMB.TO.QMA 1 Receiver Channel: QMA.TO.QMB 1 Model Queue: IBMQREP.SPILL.MODELQ The queues and channels required for P2P three-way replication are shown in the following table: QMA (16) QMB (16) QMC (16) 5 Local Queues: CAPA.ADMINQ CAPA.RESTARTQ DEAD.LETTER.QUEUE. QMA CAPB.TO.APPA.RECVQ CAPC.TO.APPA.RECVQ 4 Remote Queues: CAPA.TO.APPB. SENDQ.REMOTE CAPB.ADMINQ.REMOTE CAPA.TO.APPC. SENDQ.REMOTE CAPC.ADMINQ.REMOTE 2 Transmission Queues: QMB.XMITQ QMC.XMITQ 2 Sender Channels: QMA.TO.QMC QMA.TO.QMB 2 Receiver Channels: QMC.TO.QMA QMB.TO.QMA 1 Model Queue: IBMQREP.SPILL. MODELQ 5 Local Queues: CAPB.ADMINQ CAPB.RESTARTQ DEAD.LETTER.QUEUE. QMB CAPA.TO.APPB.RECVQ CAPC.TO.APPB.RECVQ 4 Remote Queues: CAPB.TO.APPA. SENDQ.REMOTE CAPA.ADMINQ.REMOTE CAPB.TO.APPC. SENDQ.REMOTE CAPC.ADMINQ.REMOTE 2 Transmission Queues: QMA.XMITQ QMC.XMITQ 2 Sender Channels: QMB.TO.QMA QMB.TO.QMC 2 Receiver Channels: QMA.TO.QMB QMC.TO.QMB 1 Model Queue: IBMQREP.SPILL. MODELQ 5 Local Queues: CAPC.ADMINQ CAPC.RESTARTQ DEAD.LETTER. QUEUE.QMC CAPA.TO.APPC.RECVQ CAPB.TO.APPC.RECVQ 4 Remote Queues: CAPC.TO.APPA. SENDQ.REMOTE CAPA.ADMINQ.REMOTE CAPC.TO.APPB. SENDQ.REMOTE CAPB.ADMINQ.REMOTE 2 Transmission Queues: QMA.XMITQ QMB.XMITQ 2 Sender Channels: QMC.TO.QMA QMC.TO.QMB 2 Receiver Channels: QMA.TO.QMC QMB.TO.QMC 1 Model Queue: IBMQREP.SPILL. MODELQ
Read more
  • 0
  • 0
  • 11699

article-image-basics-exception-handling-mechanism-javascript-testing
Packt
25 Aug 2010
6 min read
Save for later

Basics of Exception Handling Mechanism in JavaScript Testing

Packt
25 Aug 2010
6 min read
(For more resources on JavaScript, see here.) Issues with combining scripts Consider the real-life situation where we typically use external JavaScript; what happens if we use more than one JavaScript file? What kind of issues can we expect if we use more than one external JavaScript file? We'll cover all of this in the subsections below. We'll start with the first issue—combining event handlers. JavaScript helps to bring life to our web page by adding interactivity. Event handlers are the heartbeat of interactivity. For example, we click on a button and a pop-up window appears, or we move our cursor over an HTML div element and the element changes color to provide visual feedback. To see how we can combine event handlers, consider the following example, which is found in the source code folder in the files combine-event-handlers.html and combine-event-handlers.js as shown in the following code: In combine-event-handlers.html, we have: <html> <head> <title>Event handlers</title> <script type="text/javascript" src="combine-event- handlers.js"></script> </head> <body> <div id="one" onclick="changeOne(this);"><p>Testing One</p></div> <div id="two" onclick="changeTwo(this);"><p>Testing Two</p></div> <div id="three" onclick="changeThree(this);"><p>Testing Three</p></div> </body></html> Notice that each of the div elements is handled by different functions, namely, changeOne(), changeTwo(), and changeThree() respectively. The event handlers are found in combine-event-handlers.js: function changeOne(element) { var id = element.id; var obj = document.getElementById(id); obj.innerHTML = ""; obj.innerHTML = "<h1>One is changed!</h1>"; return true;}function changeTwo(element) { var id = element.id; var obj = document.getElementById(id); obj.innerHTML = ""; obj.innerHTML = "<h1>Two is changed!</h1>"; return true;}function changeThree(element) { var id = element.id; var obj = document.getElementById(id); obj.innerHTML = ""; obj.innerHTML = "<h1>Three is changed!</h1>"; return true;} You might want to go ahead and test the program. As you click on the text, the content changes based on what is defined in the functions. However, we can rewrite the code such that all of the events are handled by one function. We can rewrite combine-event-handlers.js as follows: function combine(element) { var id = element.id; var obj = document.getElementById(id); if(id == "one"){ obj.innerHTML = ""; obj.innerHTML = "<h1>One is changed!</h1>"; return true;}else if(id == "two"){ obj.innerHTML = ""; obj.innerHTML = "<h1>Two is changed!</h1>"; return true;}else if(id == "three"){ obj.innerHTML = ""; obj.innerHTML = "<h1>Three is changed!</h1>"; return true;}else{ ; // do nothing }} When we use if else statements to check the id of the div elements that we are working on, and change the HTML contents accordingly, we will save quite a few lines of code. Take note that we have renamed the function to combine(). Because we have made some changes to the JavaScript code, we'll need to make the corresponding changes to our HTML. So combine-event-handlers.html will be rewritten as follows: <html> <head> <title>Event handlers</title> <script type="text/javascript" src="combine-event- handlers.js"></script> </head> <body> <div id="one" onclick="combine(this);"><p>Testing One</p></div> <div id="two" onclick="combine(this);"><p>Testing Two</p></div> <div id="three" onclick="combine(this);"><p>Testing Three</p></div> </body></html> Notice that the div elements are now handled by the same function, combine(). These rewritten examples can be found in combine-event-handlers-combined.html and combine-event-handlers-combined.js. Naming clashes Removing name clashes is the next issue that we need to deal with. Similar to the issue of combining event handlers, naming clashes occur when two or more variables, functions, events, or other objects have the same name. Although these variables or objects can be contained in different files, these name clashes do not allow our JavaScript program to run properly. Consider the following code snippets: In nameclash.html, we have the following code: <html> <head> <title>testing</title> <script type="text/javascript" src="nameclash1.js"></script> </head> <body> <div id="test" onclick="change(this);"><p>Testing</p></div> </body></html> In nameclash1.js, we have the following code: function change(element) { var id = element.id; var obj = document.getElementById(id); obj.innerHTML = ""; obj.innerHTML = "<h1>This is changed!</h1>"; return true;} If you run this code by opening the file in your browser and clicking on the text Testing, the HTML contents will be changed as expected. However, if we add &ltscript type="text/javascript" src="nameclash2.js"></script> after the &lttitle></title> tag, and if the content of nameclash2.js is as follows: function change(element) { alert("so what?!");} Then we will not be able to execute the code properly. We will see the alert box instead of the HTML contents being changed. If we switch the arrangement of the external JavaScript, then the HTML contents of the div elements will be changed and we will not be able to see the alert box. With such naming clashes, our program becomes unpredictable; the solution to this is to use unique names in your functions, classes, or events. If you have a relatively large program, it would be advisable to use namespaces, which is a common strategy in several JavaScript libraries such as YUI and jQuery.
Read more
  • 0
  • 0
  • 1468