Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-preventing-sql-injection-attacks-your-joomla-websites
Packt
23 Oct 2009
6 min read
Save for later

Preventing SQL Injection Attacks on your Joomla Websites

Packt
23 Oct 2009
6 min read
Introduction Mark Twain once said, "There are only two certainties in life-death and taxes." Even in web security there are two certainties: It's not "if you are attacked", but "when and how" your site will be taken advantage of. There are several types of attacks that your Joomla! site may be vulnerable to such as CSRF, Buffer Overflows, Blind SQL Injection, Denial of Service, and others that are yet to be found. The top issues in PHP-based websites are: Incorrect or invalid (intentional or unintentional) input Access control vulnerabilities Session hijacks and attempts on session IDs SQL Injection and Blind SQL Injection Incorrect or ignored PHP configuration settings Divulging too much in error messages and poor error handling Cross Site Scripting (XSS) Cross Site Request Forgery, that is CSRF (one-click attack) SQL Injections SQL databases are the heart of Joomla! CMS. The database holds the content, the users' IDs, the settings, and more. To gain access to this valuable resource is the ultimate prize of the hacker. Accessing this can gain him/her an administrative access that can gather private information such as usernames and passwords, and can allow any number of bad things to happen. When you make a request of a page on Joomla!, it forms a "query" or a question for the database. The database is unsuspecting that you may be asking a malformed question and will attempt to process whatever the query is. Often, the developers do not construct their code to watch for this type of an attack. In fact, in the month of February 2008, twenty-one new SQL Injection vulnerabilities were discovered in the Joomla! land. The following are some examples presented for your edification. Using any of these for any purpose is solely your responsibility and not mine: Example 1 index.php?option=com_****&Itemid=name&cmd=section&section=-  000/**/union+select/**/000,111,222,      concat(username,0x3a,password),0,     concat(username,0x3a,password)/**/from/**/jos_users/* Example 2 index.php?option=com_****&task=****&Itemid=name&catid=97&aid=- 9988%2F%2A%2A%2Funion%2F%2A%2A%2Fselect/**/ concat(username,0x3a,password),0x3a,password, 0x3a,username,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0/**/ from/**/jos_users/* Both of these will reveal, under the right set of circumstances, the usernames and passwords in your system. There is a measure of protection in Joomla! 1.0.13, with an encryption scheme that will render the passwords useless. However, it does not make sense to allow extensions that are vulnerable to remain. Yielding ANY kind of information like this is unacceptable. The following screenshot displays the results of the second example running on a test system with the vulnerable extension. The two pieces of information are the username that is listed as Author, and the Hex string (partially blurred) that is the hashed password: You can see that not all MD5 hashes can be broken easily. Though it won't be shown here, there is a website available where you enter your hash and it attempts to crack it. It supports several popular hashes. When I entered this hash (of a password) into the tool, I found the password to be Anthony. It's worth noting that this hash and its password are a result of a website getting broken into, prompting the user to search for the "hash" left behind, thus yielding the password. The important news, however, is that if you are using Joomla! 1.0.13 or greater, the password's hash is now calculated with a "salt", making it nearly impossible to break. However, the standard MD5 could still be broken with enough effort in many cases. For more information about salting and MD5 see:http://www.php.net/md5. For an interesting read on salting, you may wish to read this link:www.governmentsecurity.org/forum/lofiversion/index.php/t19179.htm SQL Injection is a query put to an SQL database where data input was expected AND the application does not correctly filter the input. It allows hijacking of database information such as usernames and passwords, as we saw in the earlier example. Most of these attacks are based on two things. First, the developers have coding errors in their code, or they potentially reused the code from another application, thus spreading the error. The other issue is the inadequate validation of input. In essence, it means trusting the users to put in the RIGHT stuff, and not put in queries meant to harm the system. User input is rarely to be trusted for this reason. It should always be checked for proper format, length, and range. There are many ways to test for vulnerability to an SQL Injection, but one of the most common ones is as follows: In some cases, this may be enough to trigger a database to divulge details. This very simplistic example would not work in the login box that is shown. However, if it were presented to a vulnerable extension in a manner such as the following it might work: <FORM action=http://www.vulnerablesite.com/Search.php method=post><input type=hidden name=A value="me' or 1=1--"></FORM> This "posting" method (presented as a very generic exploit and not meant to work per se in Joomla!) will attempt to break into the database by putting forward queries that would not necessarily be noticed. But why 1=1- - ? According to PHP.NET, "It is a common technique to force the SQL parser to ignore the rest of the query written by the developer with-- which is the comment sign in SQL." You might be thinking, "So what if my passwords are hashed? They can get them but they cannot break them!" This is true, but if they wanted it badly, nothing keeps them from doing something such as this: INSERT INTO jos_mydb_users  ('email','password','login_id','full_name')  VALUES ('johndoe@email.com','default','Jdoe','John Doe');--'; This code has a potential if inserted into a query such as this: http://www.yourdomain/vulnerable_extension//index.php?option=com_vulext INSERT INTO jos_mydb_users ('email','password','login_id','full_name') VALUES ('johndoe@email.com','default','Jdoe','John Doe');--'; Again, this is a completely bogus example and is not likely to work. But if you can get an SQL DB to divulge its information, you can get it to "accept" (insert) information it should not as well. 
Read more
  • 0
  • 0
  • 10166

article-image-front-page-customization-moodle
Packt
23 Oct 2009
11 min read
Save for later

Front Page Customization in Moodle

Packt
23 Oct 2009
11 min read
Look and Feel: An Overview Moodle can be fully customized in terms of layout and branding. It has to be stressed that certain aspects of changing the look and feel require some design skills. While you as an administrator will be able to make most of the relevant adjustments, it might be necessary to get a professional designer involved, especially when it comes to styling. The two relevant components for customization are the Moodle front page and Moodle themes, though this article will focus only on Moodle front page. Before going into further details, let's try to understand which part is responsible for which element of the look and feel of your site. Have a look at the screenshot that would follow. It shows the front page of Moodle site after you are logged in as an administrator. It is not obvious which parts are driven by the Moodle theme and by the front page settings. The next table sheds some light on this: Element Settings Theme Other Logos - x - Logged-in information (location and font) - x - Language Drop Down - - x Site Administration block (position) x - - Available Courses block (position) x - - Available Courses block (content) - - x Course categories and Calendar block (position) x - - Course categories and Calendar block (icons, fonts, colors) - x - Footer text - x - Footer logo - x - Copyright statement - x -   While this list is by no means complete, it hopefully gives you an idea that the look and feel of your Moodle site is driven by a number of different elemen In short, the settings (mostly front page settings as well as a few related parameters) dictate what content users will see before and after they log on. The theme is responsible for the design scheme or branding, that is, the header and footer as well as colors, fonts, icons, and so on used throughout the site. Now let's move towards the core part of this article. Customizing Your Front Page The appearance of Moodle's front page changes after a user has logged in. The content and layout of the page before and after login can be customized to represent the identity of your organization. Look at the following screenshot. It is the same site that the preceding screenshot was taken from, but before a user has logged in. In this particular example, a Login block is shown on the left and the Course categories are displayed in the center, as opposed to the list of available courses. Front Page Settings To customize the front page, you either have to be logged in as Moodle administrator, or have front-page-related permissions in the Front Page context. From the Site Administration block, select Front Page | Front Page Settings. The screen showing all available parameters will be loaded displaying your current settings that are changeable. ts. Setting Description Full site name This is the name that appears in the browser's title bar. It is usually the full name of your organization, or the name of the dedicated course, or qualification the site is used for. Short name for site This is the name that appears as the first item in the breadcrumb trail. Front Page Description This description of the site will be displayed on the front page via the Site Description block. It can, therefore, only be displayed in the left or right column, never in the center of the front page. The description text is also picked up by the Google search engine spider, if allowed. Front Page Moodle can display up to four elements in the center column of the front page when not logged in. List of courses List of categories News items Combo list(categories and courses) The order of the elements is the same as the one chosen in the pull-down menus. Front page items when logged in Same as "Front Page", but used when logged in. Include a topic section If ticked, an additional topic section (just like the topic blocks in the center column of a topics-format course) appears on top of the front page's center column. It can contain any mix of resources or activities available in Moodle. It is very often used to provide information about the site. News items to show Number of news items that are displayed. Courses per page This is a threshold setting that is used when displaying courses within categories. If there are more courses in a category than specified, page navigation will be displayed at the top of the page. Also, when a combo list is used, course names are only displayed if the number is less than the specified threshold. For all other categories, only the number of courses is shown after the category name. Allow visible courses within hidden categories By default, courses in hidden categories are not shown unless the said setting is applied. Default frontpage role If logged-in users should be allowed to participate in front page activities, a default front page role should be set. The default is None.   Arranging Front Page Blocks To configure the left and right column areas with blocks, you have to turn on editing (using the Blocks editing on button). The menu includes blocks that are not available in courses such as Course/Site description and Main menu. Blocks are added to the front page in exactly the same way as in courses. To change their position, use the standard arrows. The Main Menu block allows you to add any installed Moodle resource or activity inside the block. For example, using labels and links to (internal or external) websites, you are able to create a menu-like structure on your front page. If the Include a topic section parameter has been selected in the Front Page settings, you have to edit the part and add any installed Moodle activity or resource. This topic section is usually used by organizations to add a welcome message to visitors, often accompanied by a picture or other multimedia content. Login From a Different Website The purpose of the Login block is for users to authenticate themselves by entering their username and password. It is possible to log into Moodle from a different website, maybe your organization's homepage, effectively avoiding the Login block. To implement this, you will have to add some HTML code on that page as shown: <form class="loginform" name="login" method="post" action="http://www.mysite.com/login/index.php">   <p>Username :     <input size="10" name="username" />   </p>   <p>Password :     <input size="10" name="password" type="password" />   </p>   <p>     <input name="Submit" value="Login" type="submit" />   </p></form> The form will pass the username and password to your Moodle system. You will have to replace www.mysite.com with your URL. This address has to be entered in the Alternate Login URL field at Users | Authentication | Manage authentication in the Site Administration block. Other Front Page Items The Moodle front page is treated as a standalone component in Moodle, and therefore has a top-level menu with a number of features that can all be accessed via the Front Page item in the Site Administration menu. Having now looked in detail at the front page settings, let's turn to examining the other available options. Front Page Roles The front page has its own context in which roles can be assigned to users. This allows a separate user to develop and maintain the front page without having access to any other elements in Moodle. Since the front page is treated as a course, a Teacher role is usually sufficient for this. Front Page Backup and Restore The front page has its own backup and restore facilities to back up and restore all elements of the front page including any content. The mechanism of performing backup and restore is the same as for course backups.   Front page backups are stored in the backupdata folder in the Site Files area, and can be accessed by anybody who is aware of the URL. It is therefore best to move the created ZIP files to a more secure location. Front Page Questions Since the Moodle front page is treated in the same way as a course, it also has its own question bank, which is used to store any questions used on front-page quizzes. For more information on quizzes and the question bank, go to the MoodleDocs at http://docs.moodle.org/en/Quiz . Site Files The files areas of all courses are separate from each other, that is, files in Moodle belong to a course and can only be accessed by users who have been granted appropriate rights. The difference between Site files and the files area of any other course is that files in Site files can be accessed without logging in. Files placed in this location are meant for the front page, but can be accessed from anywhere in the system. In fact, if the location is known, files can be even be accessed from outside Moodle. Make sure that in the Site files area, you only place files that are acceptable to be seen by users who are not authenticated on your Moodle system. Typical files to be placed in this area are any images you want to show on the front page (such as the logo of your organization) or any document that you want to be accessed (for example, the curriculum). However, it is also used for other files that are required to be accessible without access to a course, such as the Site Policy Agreement, which has to be accepted before starting Moodle. To access these publicly available Site files elsewhere (for example, as a resource within other courses), you have to copy the link location that has the format: http://mysite.com/file.php/1/file.doc. Allow Personalization via My Moodle By default, the same front page is displayed for all users on your Moodle system. To relax this restriction and to allow users to personalize their own front page, you have to activate the My Moodle feature via the Force users to use My Moodle setting in Appearance | My Moodle in the Site Administration block. Once enabled, Moodle creates a /my directory for each user (except administrators) at their first login, which is displayed instead of the main Moodle front page. It is a very flexible feature that is similar to a customizable dashboard, but requires some more disk space on your server. Once logged in, users will have the ability to edit their page by adding blocks to their My Moodle area. The center of the page will be populated by the main front page, for instance displaying a list of courses, that users cannot modify. Making Blocks Sticky There might be some blocks that you wish to "stick", that is, display on each My Moodle page, making them effectively compulsory blocks. For example, you might want to pin the Calendar block on the top right corner of each user's My Moodle page. To do this, go to Modules | Blocks | Sticky blocks in the Site Administration block and select My Moodle from the pull-down menu. You can now add any item from the pull-down menu in the Blocks block. If the block is single instance (that is, only one occurrence is allowed per page), the block will not be available for the user to choose from. If the user has already selected a particular block, a duplicate will appear on their site, which can be edited and deleted. To prevent users from editing their My Moodle pages, change the moodle/my: manageblocks capability in the Authenticated user role from Allow to Not set. The sticky block feature is also available for course pages. A course creator has the ability to add and position blocks inside a course unless they have been made sticky. Select the Course page item from the same menu to configure the sticky blocks for courses, as shown in the preceding screenshot. Summary After providing a general overview of look and feel elements in Moodle, the article covered front page customization. As mentioned earlier, the front page in Moodle is a course. This has advantages (you can do everything you can do in a course and a little bit more), but it also has certain limitations (you can only do what you can do in a course and might feel limited by this). However, some organizations are now using the Moodle front page as their homepage.
Read more
  • 0
  • 0
  • 17368

article-image-tapestry-5-advanced-components
Packt
23 Oct 2009
10 min read
Save for later

Tapestry 5 Advanced Components

Packt
23 Oct 2009
10 min read
Following are some of the components, we'll examine in Tapestry 5: The Grid component allows us to display different data in a fairly sophisticated table. We are going to use it to display our collection of celebrities. The BeanEditForm component greatly simplifies creating forms for accepting user input. We shall use it for adding a new celebrity to our collection. The DateField component provides an easy and attractive way to enter or edit the date. The FCKEditor component is a rich text editor, and it is as easy to incorporate into a Tapestry 5 web application, just as a basic TextField is. This is a third party component, and the main point here is to show that using a library of custom components in a Tapestry 5 application requires no extra effort. It is likely that a similar core component will appear in a future version of the framework. Grid Component It is possible to display our collection of celebrities with the help of the Loop component. It isn't difficult, and in many cases, that will be exactly the solution you need for the task at hand. But, as the number of displayed items grow (our collection grows) different problems may arise. We might not want to display the whole collection on one page, so we'll need some kind of pagination mechanism and some controls to enable navigation from page to page. Also, it would be convenient to be able to sort celebrities by first name, last name, occupation, and so on. All this can be achieved by adding more controls and more code to finally achieve the result that we want, but a table with pagination and sorted columns is a very common part of a user interface, and recreating it each time wouldn't be efficient. Thankfully, the Grid component brings with it plenty of ready to use functionality, and it is very easy to deal with. Open the ShowAll.tml template in an IDE of your choice and remove the Loop component and all its content, together with the surrounding table: <table width="100%"> <tr t_type="loop" t_source="allCelebrities" t:value="celebrity"> <td> <a href="#" t_type="PageLink" t_page="Details" t:context="celebrity.id"> ${celebrity.lastName} </a> </td> <td>${celebrity.firstName}</td> <td> <t:output t_format="dateFormat" t:value="celebrity.dateOfBirth"/> </td> <td>${celebrity.occupation}</td> </tr> </table> In place of this code, add the following line: <t:grid t_source="allCelebrities"/> Run the application, log in to be able to view the collection, and you should see the following result: Quite an impressive result for a single short line of code, isn't it? Not only are our celebrities now displayed in a neatly formatted table, but also, we can sort the collection by clicking on the columns' headers. Also note that occupation now has only the first character capitalized—much better than the fully capitalized version we had before. Here, we see the results of some clever guesses on Tapestry's side. The only required parameter of the Grid component is source, the same as the required parameter of the Loop component. Through this parameter, Grid receives a number of objects of the same class. It takes the first object of this collection and finds out its properties. It tries to create a column for each property, transforming the property's name for the column's header (for example, lastName property name gives Last Name column header) and makes some additional sensible adjustments like changing the case of the occupation property values in our example. All this is quite impressive, but the table, as it is displayed now, has a number of deficiencies: All celebrities are displayed on one page, while we wanted to see how pagination works. This is because the default number of records per page for  Grid component is 25—more than we have in our collection at the moment. The last name of the celebrities does not provide a link to the Details page anymore. It doesn't make sense to show the Id column. The order of the columns is wrong. It would be more sensible to have the Last Name in the first column, then First Name, and finally the Date of Birth. By default, to define the display of the order of columns in the table, Tapestry will use the order in which getter methods are defined in the displayed class. In the Celebrity class, the getFirstName method is the first of the getters and so the First Name column will go first, and so on. There are also some other issues we might want to take care of, but let's first deal with these four. Tweaking the Grid First of all let's change the number of records per page. Just add the following parameter to the component's declaration: <t:grid t_source="allCelebrities" rowsPerPage="5"/> Run the application, and here is what you should see: You can now easily page through the records using the attractive pager control that appeared at the bottom of the table. If you would rather have the pager at the top, add another parameter to the Grid declaration: <t:grid t_source="allCelebrities" rowsPerPage="5" pagerPosition="top"/> You can even have two pagers, at the top and at the bottom, by specifying pagerPosition="both", or no pagers at all (pagerPosition="none"). In the latter case however, you will have to provide some custom way of paging through records. The next enhancement will be a link surrounding the celebrity's last name and linking to the Details page. We'll be adding an ActionLink and will need to know which Celebrity to link to, so we have the Grid store using the row parameter. This is how the Grid declaration will look: <t:grid t_source="allCelebrities" rowsPerPage="5" row="celebrity"/> As for the page class, we already have the celebrity property in it. It should have been left from our experiments with the Loop component. It will also be used in exactly the same way as with Loop, while iterating through the objects provided by its source parameter, Grid will assign the object that is used to display the current row to the celebrity property. The next thing to do is to tell Tapestry that when it comes to the contents of the Last Name column, we do not want Grid to display it in a default way. Instead, we shall provide our own way of displaying the cells of the table that contain the last name. Here is how we do this: <t:grid t_source="allCelebrities" rowsPerPage="5" row="celebrity"> <t:parameter name="lastNameCell"> <t:pagelink t_page="details" t_context="celebrity.id"> ${celebrity.lastName} </t:pagelink> </t:parameter> </t:grid> Here, the Grid component contains a special Tapestry element , similar to the one that we used in the previous chapter, inside the If component. As before, it serves to provide an alternative content to display, in this case, the content which will fill in the cells of the Last Name column. How does Tapestry know this? By the name of the element, lastNameCell. The first part of this name, lastName, is the name of one of the properties of the displayed objects. The last part, Cell, tells Tapestry that it is about the content of the table cells displaying the specified property. Finally, inside , you can see an expansion displaying the name of the current celebrity and surrounding it with the PageLink component that has for its context the ID of the current celebrity. Run the application, and you should see that we have achieved what we wanted: Click on the last name of a celebrity, and you should see the Details page with the appropriate details on it. All that is left now is to remove the unwanted Id column and to change the order of the remaining columns. For this, we'll use two properties of the Grid—remove and reorder. Modify the component's definition in the page template to look like this: <t:grid t_source="celebritySource" rowsPerPage="5" row="celebrity" remove="id" reorder="lastName,firstName,occupation,dateOfBirth"> <t:parameter name="lastNameCell"> <t:pagelink t_page="details" t_context="celebrity.id"> ${celebrity.lastName} </t:pagelink> </t:parameter> </t:grid> Please note that re-ordering doesn't delete columns. If you omit some columns while specifying their order, they will simply end up last in the table. Now, if you run the application, you should see that the table with a collection of celebrities is displayed exactly as we wanted: Changing the Column Titles Column titles are currently generated by Tapestry automatically. What if we want to have different titles? Say we want to have the title, Birth Date, instead of Date Of Birth. The easiest and the most efficient way to do this is to use the message catalog, the same one that we used while working with the Select component in the previous chapter. Add the following line to the app.properties file: dateOfBirth-label=Birth Date Run the application, and you will see that the column title has changed appropriately. This way, appending -label to the name of the property displayed by the column, you can create the key for a message catalog entry, and thus change the title of any column. Now you should be able to adjust the Grid component to most of the possible requirements and to display with its help many different kinds of objects. However, one scenario can still raise a problem. Add an output statement to the getAllCelebrities method in the ShowAll page class, like this: public List<Celebrity> getAllCelebrities() { System.out.println("Getting all celebrities..."); return dataSource.getAllCelebrities(); } The purpose of this is simply to be aware when the method is called. Run the application, log in, and as soon as the table with celebrities is shown, you will see the output, as follows: Getting all celebrities... The Grid component has the allCelebrities property defined as its source, so it invokes the getAllCelebrities method to obtain the content to display. Note however that Grid, after invoking this method, receives a list containing all 15 celebrities in collection, but displays only the first five. Click on the pager to view the second page—the same output will appear again. Grid requested for the whole collection again, and this time displayed only the second portion of five celebrities from it. Whenever we view another page, the whole collection is requested from the data source, but only one page of data is displayed. This is not too efficient but works for our purpose. Imagine, however, that our collection contains as many as 10,000 celebrities, and it's stored in a remote database. Requesting for the whole collection would put a lot of strain on our resources, especially if we are going to have 2,000 pages. We need to have the ability to request the celebrities, page-by-page—only the first five for the first page, only the second five for the second page and so on. This ability is supported by Tapestry. All we need to do is to provide an implementation of the GridDataSource interface. Here is a somewhat simplified example of such an implementation.
Read more
  • 0
  • 0
  • 3096

article-image-third-party-video-hosting-drupal-websites
Packt
23 Oct 2009
7 min read
Save for later

Third-Party Video Hosting on Drupal Websites

Packt
23 Oct 2009
7 min read
Third-Party Video Providers Many sites desiring video will choose to use a third-party video provider such as YouTube or Blip.TV. This reduces the bandwidth requirement from their server, is easy to include in their posts, and allows videos to be easily shared virtually by users across the Internet. The easiest way, without further configuration of a basic Drupal installation, for an administrator to include a third-party video is to simply paste the video's embedded code in a post. Most video providers will offer a snippet of HTML that may be copied from a particular video page, which will embed the video. However, this requires using a filter that will allow <object>, <embed>, and <param> tags. But since they open the door to attacks on the site, they should only be used by administrators and trusted editors. You could also use the Full HTML filter, but this is even more dangerous as allowing that filter to be generally used would open the site to cross-site scripting (XSS) attacks. First, you'll need to set up a filter that allows the tags. Add an input format at Administer | Site configuration | Input formats (at /admin/settings/filters/add). After naming the filter, check the role(s) you wish to give access to this filter such as edit role. Check HTML corrector, HTML filter, and Line break converter. After pressing Save configuration, click on the Configure tab. Using YouTube as an example, an administrator would first need to upload a video to YouTube. This will require an account at YouTube, but they make it fairly painless for a user to jump in and contribute videos. You'll just need to follow their instructions: Once you have a video there, you will find the embedded code on the video page. You will need to click in the text field where that is provided, and copy the HTML for pasting on your own page: Next you will submit a node on your site such as from Node | Add | Page (at /node/add/page), and paste the embed code in the body for the node. You will need to enable either the new filter created earlier or Full HTML, as the embedded code will contain object and/or embedded tags, which would be filtered out by the default filter in Drupal. If you want editors to have the ability to select their filter, you will need to enable that ability for a role, and possibly set up a new filter depending on your needs. Also note that you will need to disable the TinyMCE Rich Text Editor when embedding video directly into content if the TinyMCE module is enabled on your site. After submitting, your video will appear in the content. As with any HTML embedded in your node body, you may manually place your video at any point within the content such as after the second paragraph or at the end of the node: Embedded Embedded Media Field Finally, we come to the alternative of hosting video from our own servers. Although using a module such as Media Mover combined with services such as Amazon S3 makes serving video a slightly easier task than it might have otherwise been, for most sites the bandwidth required for serving video is generally not a viable option. Additionally, sites may wish to take advantage of the viral opportunities of hosting video through a widely recognized provider such as YouTube or Blip.TV. There are several modules that provide some limited support for embedding third-party media, including both the Video and Asset modules. However, at the time of this writing, the most comprehensive and by far the easiest to configure and use is the Embedded Media Field, which includes the Embedded Video Field as part of its package. Install both of these modules and set up a new content type with an Embedded Video Field. You will need, of course, to have the CCK (Content) module installed as well. As with our other examples, you will first add your type from Administer | Content management | Content types | Add content type (at /admin/content/types/add), give it a name such as Video, and add the field from Administer | Content management | Content types | Video | Add field (at /admin/content/node-type/video/add_field). Before continuing, I must confess a bias here. I wrote the original Embedded Media Field module with assistance from Sam Tresler during DrupalCamp NYC in 2007, and rewrote it for a more solid and flexible API during OSCMS later that year. I am also indebted to Alex Urevick-Ackelsberg for his assistance in the ongoing maintenance and support. Without doing anything else, you may now add a new video from a provider by simply pasting its URL into the field. The module will then automatically parse and display the video appropriately. There are several settings on the following page that may be set, including allowed providers, video and thumbnail sizes, and whether the video plays automatically. You may leave the providers alone to allow content from any of them, or select only the providers you wish to allow editors and users to use The local checkbox is experimental at the time of this writing and may not actually be on the version you're reading. The module maintainers (myself included, of course) intend to hook into other APIs to provide better local video support without reinventing the wheel. That may or may not be ready by the time you read this book. The Custom URL provider is also used to experimentally support direct videos from any source available from an HTTP request, including your local server. It is not recommended for general use, as it would be easy to use that to unethically hotlink to videos from someone else's server. Hundreds of flying monkeys will hunt you down if you do that. Basically, always turn off support for that unless you have a specific (and moral) use for that feature. You can set video sizes in the next sections for full size and preview size video display. By default, videos will be displayed in full size. You can change the display to video preview or thumbnail at the display settings page, by browsing to Administer | Content management | Content types | Video | Display fields (at /admin/content/node-type/video/display). Videos will be forced to display at the size provided here, regardless of how they are offered by the provider. You can also determine if the video will autoplay or not. For instance, you might use a small video preview for teasers and a larger full-size video when viewing the node page, turning on the autoplay in that case. Finally, you may wish to use thumbnails, for instance when displaying a video as a teaser or when using views. Note that thumbnails are not yet supported for all video providers. Some providers do not offer an easy API to discover a particular video's thumbnail file. To learn if thumbnails are supported by a particular provider, go to Administer | Content management | Embedded Media Field Configuration (at /admin/content/emfield) and open the fieldset for Embedded Video Field. You will see the supported features for each provider within their particular fieldsets, where you may also disable them or enable unique settings. You may wish to provide for custom thumbnails, whether for providers lacking an automatic thumbnail or for any external video in general. For this purpose, the Embedded Custom Thumbnail module is included in the module's package. Just enable that module, and then check the Allow custom thumbnails for this field box on the type's administration screen We now have a full-featured video field in place, which is as easy to use as cut and paste. Summary Video is still a maturing media on the Internet. Much has happened as it has exploded onto sites across the world, and contributors to Drupal have made recent strides in supporting it. However, there is still much to be done to make it easier for administrators to support it. Also, although there are many new and traditional tools available such as Views and Embedded Media Field, these still require some setup to get working.
Read more
  • 0
  • 0
  • 1641

article-image-technical-best-practices-dynamics-ax-application-design-standards
Packt
23 Oct 2009
12 min read
Save for later

Technical Best Practices for Dynamics AX - Application Design Standards

Packt
23 Oct 2009
12 min read
Application Design Standards The Dynamics AX design standards consist of the following considerations: Code placement Performance optimization Using field groups in tables Auto property settings Code Placement Code placement is important as it affects the following: Performance Customization Reusability Maintainability (upgrade, extensibility, etc.) The general guidelines are that the code should be placed in such a way that various calls to other layers are minimized, the operation is performed at the layer where it is least expensive, and the same code need not be written at several places (e.g. if business logic is written on a form then it needs to be written in the enterprise portal for the web client also). So we should not only think about the tier of placement in the three-tier architecture, but also about the best AOT (Application Object Tree) element type for a piece of code. Once these have been designed we need to think about the type of method or objects in the classes, etc. Three-Tier Architecture Considerations The three tiers in this architecture are dedicated for the following three types of jobs: Client—The Presentation layer—This is where the forms are stored. Place client‑specific classes and methods here. Object server—The Business application logic layer—Transaction-oriented database update jobs should be run here, close to the database. Database server—The Database layer—Utilize the power of the database server by using aggregate functions, joins, and other calculating features of the database management system. Dynamics AX has a property, RunOn, for every AOT element, which indicates the layer where it should be executed i.e. Client, AOS, or Database server. This RunOn property may have one of three values i.e. Client, Called from, and Server. Client: The object will live on the client. Called from: The object will live at the tier where the object is created using the 'new' constructor. Server: The object will live on the server. Now we will discuss how to decide the RunOn property value. Classes The value of the RunOn property for a class will decide the location of the object created from that class. The value of RunOn property for a class will be same as the parent class if the parent class has a RunOn property other than Called from i.e. the RunOn property cannot be changed for a class if the parent class has as its value either Client or Server. If the parent class has Called from as its RunOn property value, it can be changed to Client or Server and if it is not changed it will retain the inherited value i.e. Called from. The Called from value of the RunOn property means the object will live at the tier where the code creating it (by calling the new constructor) is running. Methods Now we will discuss the execution place for various types of methods. Class static methods and table methods (except for the database methods) can have their default behavior. The execution place for a method can be changed to Server or Client by adding the Client or Server modifier keywords in the method declaration as shown below:   server static boolean mymethod(): to make server the execution place.   client static boolean mymethod(): to make client the execution place.   client server static boolean mymethod(): to make called from the execution place. The following table summarizes the execution place of various types of methods: AOT elements Default behavior Can be changed Class static methods Runs by default at the same place where the associated class runs i.e. if the associated class has the RunOn property value as server then the class static method will also be executed at the server. Yes Class instance methods Runs where the object of the class lives. The class objects live as described in the class RunOn property. No Table static methods Table static methods have the RunOn property as Called from and hence by default they run where they are called. Yes Table instance methods Table instance methods have the RunOn property as Called from and hence by default they run where they are called. The standard methods Insert/doInsert, Update/doUpdate, and Delete/doDelete run on the Server where the data source is located. No GUI Objects and Reports GUI objects always live on Client. GUI objects include the FormRun, FormDataSource, all FormControls, DialogBox, and OperationProgress objects. Reports always live on Called from, which means the object will live at the tier where the code creating it (by calling the new constructor) is running. Temporary Tables Temporary tables instantiate and live at the tier where data is first inserted and it does not matter where they are declared. Since the placement of temporary tables is very critical for performance, temporary tables should live at the tier where they are used. If a table is utilized in more than one tier then it should live on the tier where the greatest number of inserts and updates are performed. Queries QueryRun has Called from as the default value of the RunOn property. The QueryRun should always be supplied from the same tier from where it was originally run. If you want to create a new QueryRun in place of an old one, it should be created on the same tier where the old QueryRun was executed. AOT Element Type Consideration The following guidelines must be followed to decide the type of code container: AOT element Considerations Class Write code in class when either: Code is related to many tables. Code is not related to any table. Create class instance method when: Working on the instance variable of the class. Overriding is potentially useful. Create class static method when: Access to the class instance method is not required. Overriding is not needed. The functionality of the method is related to the class it is defined on. The method needs to be executed on a different tier than the method's tier. Table Write code in table method when: It is strictly related to a table. Create table instance method when: It is supposed to handle one record at a time. Create table static method when: It is supposed to handle none, some, or all the records at a time. Global class Write code in global class when: Code cannot be placed more logically in another class (or table). Code is general purpose, tool extending, and application neutral. Forms and reports Coding on forms or reports should be avoided as far as possible i.e. except for the calls to classes and table methods that handle complex layout and business logic. The edit and display methods must be avoided if they are placed in a table. If code cannot be placed anywhere else, i.e. the presentation tier is most suitable, then the following guidelines should be observed: Place the code at the data source or data source field level and not at the control level. Call classes from buttons on forms by using menu items. For example, rather than writing a code on the form or report, code could be written in a class and the class could be called from the menu item. Maps Write code in maps when a limited number of connected fields needs to be grouped. Views Do not place much code in views. Performance Optimization The performance optimization guidelines can be categorized into the following three categories: Database design AOS performance optimization General programming Database Design The database design principles are based on the following considerations: Minimizing the database calls by caching Minimizing database transactions Wise index designing Using the select statement in an optimum way Performing transactions in the shortest time possible Caching Database access should be avoided whenever it is not absolutely necessary as retrieving database records from memory is far cheaper and faster. Recording database records in memory is known as caching. The following are the possible type of caching on the server: Record caching Entire table caching Result-set caching Record Caching Record caching is a type of performance enhancement technique in which one or a group of records is retrieved from the memory rather than the database. Retrieving a record from memory rather than database significantly improves the data access. Record caching can be enabled only when the following conditions are satisfied: The CacheLookup property in the table should be enabled by selecting the values notITTS, Found, or FoundAndEmpty. The table has a unique index; either use the primary index or the first unique index. The index based on RecId (known as RecId index) does not qualify as a caching index. The retrieved records can be placed in cache if the following conditions are met: The table is cached i.e. the above conditions are met. The select statement used to read the record uses an equal operator (= =) on the caching key. All the fields in the record are retrieved. A record is looked for when the following conditions are met: The table is cached. The select statement used to read the record uses an equal operator (= =) on caching key. The select statement is either inside or outside TTS, but the value of the caching property for the table is not NotITTS and the select is not forupdate. The following table summarizes the different types of caching mechanism: CacheLookup property Explanation None No data will be cached or retrieved from the cache. This value of CacheLookup property is used when: Tables are frequently updated e.g. transaction tables. It is very critical to read fresh data. NotITTS All select queries that retrieved at least one result will be cached. Found All successful select queries based on caching key are cached for this type of caching. All select queries are returned from cache if the record exists there. A select forupdate in TTS will always read from the database and replace the record in cache. This value of the CacheLookup property is typically used for static tables like ZipCodes where the record usually exists. FoundAndEmpty All select queriesbased on caching keys are cached, even those select queries, which do not return data. All caching keys selects are returned from caching if the record exists or is marked as non-existing, and if it is neither marked as non-existing nor retrieving any result it will check the database and update the cache accordingly. A select forupdate in TTS will always read from the database and replace the record in cache. This value of the CacheLookup property is typically used for tables where registering non-existing keys is also important e.g. discount table. EntireTable A copy of table is created as temporary table. All selects against the table will be performed on the copy. Joins that include the table will only be performed against the copy when all tables participating in the join are EntireTable cached. Otherwise a database join is performed. Operations that change data (insert, update, and delete) are performed against the database as well as against the copy. The reread method will retrieve the data from database and update the copy data as well. The Microsoft Dynamics AX Object Server thin client will regard an EntireTable cached table as FoundAndEmpty cached as well, and will therefore build a recordCache locally when accessing the table. This value of the CacheLookup property is typically used for tables that are not supposed to be modified frequently.   Result-set Caching The RecordViewCache is useful for caching tables that are not of static nature, or contain so many records that the other caching methods would be impractical. This type of caching can be available through the RecordViewCache class. The RecordViewCache is instantiated using X++ select with a where clause that defines the result set. Technically the RecordViewCache can be instantiated using X++ select but it will create a copy of table in memory, which may be an inefficient use of memory. The following rules apply to the instantiating X++ select: It may not be a join. It must be noFetch. The table may not be temporary. When running a Dynamics AX Object Server thin client, instantiation must be on the server. The limitations of the result-set caching are as follows: The RecordViewCache is not shared between Dynamics AX clients. The RecordViewCache is deactivated as soon as the RecordViewCache object goes out of scope or is destroyed. In some cases result-set caching may be dangerous and hence only careful use is recommended. The following facts about result-set caching will be helpful in deciding the use of result-set caching. The database is simultaneously updated with the RecordViewCache. Updating the key of a row that did not qualify the result set at the time of instantiation will not result in the row being included in the cache. Inserts are always included in the RecordViewCaches for that table. It is definitely an advantage; however, care should be taken when inserting a large number of rows in a table and at the same time having a RecordViewCache on the same table as it will prolong the cache update time. A delete will remove the row from RecordViewCaches on that table but not the table. A Delete_from will invalidate RecordViewCaches on that table. As mentioned above the RecordViewCache can go out of synchronization and hence we may need to re-synchronize it again. X++ has a method reread, which retrieves the data from database and updates the cached copy.
Read more
  • 0
  • 0
  • 6713

article-image-planning-extensions-typo3
Packt
23 Oct 2009
8 min read
Save for later

Planning Extensions in TYPO3

Packt
23 Oct 2009
8 min read
Why is Planning Important? Most open source developers see planning as a boring task. Why plan if one can just go and code? The answer is as simple as the question: The "Go and code" approach does not let us create truly optimal code. Portions of code have to be changed while other portions are written. They often lead to redundant code or uninitialized variables, partially covered conditions, and wrong return results. Code gets a "do not touch" reputation because changing anything renders the whole project unstable. Often the code works, but the project is more a failure than a success because it cannot be extended or re-used. Another reason for planning is the ease of bug fixing and the costs associated with it. Open source developers often do not think about it until they start selling their services or work to commercial companies. As shown by recent studies, the cost of problem fixing grows rapidly toward the end of the project. The cost is minimal when development has not started yet, and the person in charge just collects requirements. When requirements are collected and a programmer (or a team of programmers) starts to think how to implement these requirements, a change of requirements, or fixing a problem in the requirements still does not cost much. But it may already be difficult for developers if they came to a certain implementation approach after reviewing requirements. Things become worse at the development stage. Imagine that the selected approach was wrong and it was uncovered close to the end of development. Lots of time is lost, and work may have to start from the beginning. Now imagine what happens if the project is released to the customer and the customer says that the outcome of the project does not work as expected (something was implemented differently (as compared to expectations), or something was not implemented at all). The cost of fixing is likely to be high and overshoot the budget. Next, imagine what would happen if problems occurred when a project went live. After reading the previous paragraph, some developers may ask how the situation applies to non-commercial development, as there is a false perception that there are no costs associated with it (at least, no direct costs). But, the costs exist! And often they are much more sensitive than financial costs. The cost in non-commercial development is reputation. If a developer's product does not work well or does not work at all or it has obvious flaws, the general opinion about the developer may become bad ("cannot trust his code"). Developers will also have troubles improving because often they do not understand what has gone wrong. But the answer is near. Do not rush! Plan it well! You may even think of something about the future code, and then start coding only when the picture is clear. Planning is an important part of software development. While freelancers can usually divide their time freely between planning and implementation, many corporate developers often do not have such freedom. And even worse, many managers still do not see planning as a necessary step in software development. This situation is well explained in The parable of the two programmers, which readers of this book are encouraged to read in full. When it comes to TYPO3, planning is more important than an average application. TYPO3 is very complex, and its implementation is also complex. Without planning, programmers will most likely have to change their already written code to fix unforeseen problems therefore, good planning for TYPO3 extensions is extremely important. But let us move on and see how to plan an extension. How to Plan There are several stages in planning. Typically, each stage answers one or more important questions about development. TYPO3 developers should think about at least three stages: Gathering requirements Implementation planning Documentation planning Of course, each project is unique and has other stages. But these three stages generally exist in every project. Gathering Requirements The first thing that a developer needs to know is what his/her extension will do. While it sounds pretty obvious, not many extension authors know exactly what functionality the extension has in the end. It evolves over time, and often the initial idea is completely different from the final implementation. Predictably, neither the original nor the final is done well. In the other case, when extension features are collected, though planned and implemented according to plan, they usually fit well together. So, the very first thing to do when creating an extension is to find out what that extension should do. This is called gathering requirements. For non-commercial extensions, gathering requirements simply means writing down what each extension should do. For example, for a news extension, it may be: Show list of news sorted by date Show list of latest news Show news archive Show only a small amount of text in news list view As we have seen, gathering requirements looks easier than it actually is. The process, however, may become more complex when an extension is developed for an external customer. Alan Cooper, in his famous About Face book, shows how users, architects, and developers see the same product. From the user's perspective, it looks like a perfect circle. An architect sees something closer to an octagon. A developer creates something that looks like a polygon with many segments connected at different degrees. These differences always exist and each participating party is interested in minimizing them. A developer must not be afraid of asking questions. The cleaner picture he/she has, the better he/she will understand the customer's requirements. Implementation Planning When the requirements are gathered, it is necessary to think which blocks an extension will have. It may be blocks responsible for data fetching, presentation, conversion, and so on. In the case of TYPO3 extension implementation, planning should result in a list of Frontend (FE) plugins, Backend (BE) modules, and standalone classes. The purpose of each plug-in, module, and/or class must be clear. When thinking of FE plugins, caching issues must be taken into account. While most of the output can be cached to improve TYPO3 performance, forms processing should not be cached. Some extensions completely prevent caching of the page when processing forms. But there is a better approach, a separate FE plug-in from the non-cached output. BE modules must take into account the ease of use. Standard BE navigation is not very flexible, and this must be taken into account when planning BE modules. Certain functionalities can be moved to separate classes. This includes common functions and any public APIs that an extension provides to the other extensions. Hooks or "user functions" are usually placed in separate classes depending on the functional zone or hooked class. Documentation Planning A good extension always comes with documentation. Documentation should also be planned. Typically, manuals for extensions are created using standard templates, which have standard sections defined. While this simplifies documentation writing for extension developers, they still have to plan what they will put into these sections. TYPO3-Specific Planning There are several planning issues specific to TYPO3. Developers must take care of them before the actual development. Extension Keys Each extension must have a unique key. Extension keys can be alphanumeric and contain underscore characters. It may not start with a digit, the letter u, or the test_ prefix. However, not every combination of these symbols makes a good extension key. An extension key must be descriptive but not too long. Having personal or company prefixes is not forbidden but is not recommended. Underscores should be avoided. Abbreviations should be avoided as well, because they often do not make sense for other users. Examples of good extension keys are: news comments usertracker loginbox Examples of bad extension keys are: news_extension mycorp_ustr myverygoodextensionthatdoesalotofthings mvgetdalot john_ext div2007 Database Structure Most TYPO3 extensions use a database to load and/or store their own data. Changing the data structure during application development may seriously slow down development, or may even cause damage to data if some data is already entered into the system. Therefore, it is extremely important to think about an extension's data structure well in advance. Such thinking requires knowledge about how TYPO3 database tables are organized. Tables in TYPO3 database must have certain structures to be properly managed by TYPO3. If a table does not fulfill TYPO3 requirements, users may see error messages in the BE (especially in the Web | List module), and data may become corrupted. Every record in every TYPO3 table belongs to a certain page inside TYPO3. TYPO3 has a way to identify which page the record belongs to.
Read more
  • 0
  • 0
  • 1502
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-customizing-drupal-6-interface
Packt
23 Oct 2009
19 min read
Save for later

Customizing Drupal 6 Interface

Packt
23 Oct 2009
19 min read
There is quite a lot involved in coming up with an entirely fresh, pleasing, and distinct look for a site. There are lots of fiddly little bits to play around with, so you should be prepared to spend some time on this section after all, a site's look and feel is really the face you present to the community, and in turn, the face of the community presents to the outside world. Take some time to look at what is already out there. Many issues that you will encounter while designing a site have already been successfully dealt with by others, and not only by Drupal users of course. Also, don't be scared to treat your design as an ongoing process while it is never good to drastically change sites on a weekly basis, regular tweaking or upgrading of the interface can keep it modern and looking shiny new. Planning a Web-Based Interface The tenet form follows function is widely applied in many spheres of human knowledge. It is a well understood concept that states the way something is built or made must reflect the purpose it was made for. This is an exceptionally sensible thought, and applying it to the design of your site will provide a yardstick to measure how well you have designed it. That's not to say one site should look like every other site that performs the same function. In fact, if anything, you want to make it as distinctive as possible, without stepping over the bounds of what the target user will consider good taste or common sense. How do you do that? The trick is to relate what you have or do as a website with a specific target audience. Providing content that has appeal to both sexes of all ages across all nationalities, races, or religions implies that you should go with something that everyone can use. If anything, this might be a slightly flavourless site because you wouldn't want to marginalize any group of users by explicitly making the site bias towards another group. Luckily though, to some extent your target audience will be slightly easier to define than this, so you can generally make some concessions for a particular type of user. Visual Design There's no beating about the bush on this issue. Make the site appear as visually simple as possible without hiding any critical or useful information. By this, I mean don't be afraid to leave a fairly large list of items on a page if all the items on that list are useful, and will be (or are) used frequently. Hiding an important thing from users no matter how easy it appears to be to find it on other pages will frustrate them, and your popularity might suffer. How a site looks can also have a big impact on how users understand it to work. For example, if several different fonts apply to different links, then it is entirely likely that users will not think of clicking on one type of link or another because of the different font styles. Think about this yourself for a moment, and visualize whether or not you would spend time hovering the pointer over each and every type of different content in the hope that it was a link. This can be summed up as: Make sure your site is visually consistent, and that there are no style discrepancies from one page to the next. By the same token, reading a page of text where the links are given in the same font and style as the writing would effectively hide that functionality. There are quite a few so-called rules of visual design, which can be applied to your site. Some that might apply to you are: the rule of thirds, which states that things divided up into thirds either vertically or horizontally are more visually appealing than other designs; or the visual center rule, which states that the visual center of the page (where the eye is most attracted to) is just above and to the right of the actual center of the page. You may wish to visit the website A List Apart at http://www.alistapart.com/ that has plenty of useful articles on design for the Web, or try searching on Google for more information. Language Now this is a truly interesting part of a site's design, and the art of writing for the Web is a lot more subtle than just saying what you mean. The reason for this is that you are no longer writing simply for human consumption, but also for consumption by machines. Because machines can only follow a certain number of rules when interpreting a page, the concessions on the language used must be made by the writers (if they want their sites to feature highly on search engines). Before making your site's text highly optimized for searching, there are a few more fundamental things that are important to consider. First off, make sure your language is clear and concise. This is the most important; rather sacrifice racy, stylized copy for more mundane text if the mundane text is going to elucidate important points better. People have very short attention spans when it comes to reading Web copy so keep things to the point. Apart from the actual content of your language, the visual and structural appearance of the copy is also important. Use bold or larger fonts to emphasize headings or important points, and ensure that text is spaced out nicely to make the page easier on the eye, and therefore easier to read and understand. Images Working with images for the Web is very much an art. I don't mean this in the sense that generally one should be quite artistic in order to make nice pictures. I mean that actually managing and dealing with image files is itself an art. There is a lot of work to be done for the aspiring website owner with respect to attaining a pleasing and meaningful visual environment. This is because the Web is an environment that is most reliant on visual images to have an effect on users because sight and sound are the only two senses that are targeted by the Internet (for now). In order to have the freedom to manipulate images, you really need to use a reasonably powerful image editor. Gimp, http://www.gimp.org/, is an example of a good image-editing environment, but anything that allows you to save files in a variety of different formats and provides resizing capabilities should be sufficient. If you have to take digital photographs yourself, then ensure you make the photos as uniform as possible, with a background that doesn't distract from the object in question editing the images to remove the background altogether is probably best. There are several areas of concern when working with images, all of which need to be closely scrutinized in order to produce an integrated and pleasing visual environment: One of the biggest problems with images is that they take up a lot more space and bandwidth than text or code. For this reason, having an effective method for dealing with large images is required—simply squashing large images into thumbnails will slow everything down because the server still has to download the entire large file to the user's machine. One common mistake people make when dealing with images is not working on them early on in the process to make them as uniform in size and type as possible. If all the images are of one size and of the same dimension, then you are going to have things a lot easier than most. In fact, this should really be your aim before doing anything involving the site—make sure your images are all as uniform as a given situation allows. Deciding what type of image you actually want to use from the variety available can also be a bit of an issue because some image types take up more space than others, and some may not even be rendered properly in a browser. By and large, there are really only three image types that are most commonly used—GIF, PNG, and JPG. The intended use of an image can also be a big factor when deciding how to create, size, and format the file. For example, icons and logos should really be saved as PNG or GIF files, whereas photos and large or complex images should be saved in the JPG format due to how efficiently JPG handles complex images. Let's take a quick look at those here. GIF, or Graphics Interchange Format, is known for its compression and the fact that it can store and display multiple images. The major drawback to GIF is that images can only display up to 256 distinct colors. For photographic-quality images, this is a significant obstacle. However, you should use GIFs for: Images with a transparent background Animated graphics Smaller, less complex images requiring no more than 256 colors PNG, or Portable Network Graphics, is actually designed as a replacement for GIF files. In general, it can achieve greater file compression, give a wider range of color depth, and quite a bit more. PNG, unlike GIF files, does not support animations. You can use PNG files for anything that you would otherwise use GIFs for, with the exception of animations. IE6 will not render transparency in PNG images correctly, so be aware that this may affect what people think about your site having ugly shaded regions around images can make your site appear to be of poor quality when in fact it is an aspect of their dated browser that causes the problem. Incidentally, there is also an MNG format that allows for animations you might want to check that out as an alternative to animated GIFs. JPG, or JPEG (Joint Photographic Experts Group), should be used when presenting photo-realistic images. JPG can compress large images while retaining the overall photographic quality. JPG files can use any number of colors, and so it's a very convenient format for images that require a lot of color. JPG should be used for: Photographs Larger, complex images requiring more than 256 to display properly Be aware that JPG uses lossy compression, which means that in order to handleimages efficiently, the compression process loses quality. Before we begin an in-depth look at themes that are responsible for just about everything when it comes to your site's look-and-feel, we will take a glance at CSS. CSS The pages in a Drupal site obtain their style-related information from associated stylesheets that are held in their respective theme folders. Using stylesheets gives designers excellent, fine-grained control over the appearance of web pages, and can produce some great effects. The appearance of pretty much every aspect of the site can be controlled from CSS within a theme, and all that is needed is a little knowledge of fonts, colors, and stylesheet syntax. It will make life easier if you have a ready-made list of the type of things you should look at setting using the stylesheet. Here are the most common areas (defined by HTML elements) where stylesheets can be used to determine the look-and-feel of a site's: Background Text Font Color Images Border Margin Padding Lists Besides being able to change all these aspects of HTML, different effects can be applied depending on whether certain conditions, like a mouse hovering over the specified area, are met this will be demonstrated a little later on. You can also specify attributes for certain HTML tags that can then be used to apply styles to those specific tags instead of creating application-wide changes. For example, imagine one paragraph style with a class attribute set, like this: <p class="signature"></p> You could reference this type of paragraph in a stylesheet explicitly by saying something like: p.signature {color: green;} Analyzing this line highlights the structure of the standard style-sheet code block in the form of a: Selector: in this case p.signature Property: in this case color Delimiter: always : Value: in this case green Note that all the property/value pairs are contained within curly braces, and each is ended with a semi-colon. It is possible to specify many properties for each selector, and indeed we are able to specify several selectors to have the same properties. For example, the following block is taken from the garland stylesheet, style.css, and is used to provide all the header text within the theme with a similar look-and-feel by giving them all the same properties: h1, h2, h3, h4, h5, h6 {margin: 0;padding: 0;font-weight: normal;font-family: Helvetica, Arial, sans-serif;} In this instance, multiple selectors have been specified in a comma delimited list, with each selector given four properties to control the margin, padding, font-weight, and font-family of the header tags. It is important to realize that tags can be referenced using either the class attribute, or the id attribute, or both. For example, the following HTML: <p class="signature" id="unique-signature"></p> ...makes it possible for this tag to be referenced both as part of a class of tags all with the same property, or specifically by its unique id attribute. The distinction between the two is important because class gives broad sweeping powers to make changes to all tags within that class, and id gives fine-grained control over a tag with the unique id. This introduction to CSS has been very brief, and there are plenty of excellent resources available. If you would like to learn more about CSS (and it is highly recommended), then visit: CSS Discuss: http://css-discuss.incutio.com/ HTML Dog: http://www.htmldog.com/ We are ready to begin looking at… Themes The use of themes makes Drupal exceptionally flexible when it comes to working with the site's interface. Because the functionality of the site is by and large decoupled from the presentation of the site, it is quite easy to chop and change the look, without having to worry about affecting the functionality. This is obviously a very useful feature because it frees you up to experiment knowing that if worst comes to worst, you can reset the default settings and start from scratch. You can think of a theme as a template for your site that can be modified in order to achieve virtually any design criteria. Of course, different themes have wildly varying attributes; so it is important to find the theme that most closely resembles what you are looking for in order to reduce the amount of work needed to match it to your envisaged design. Also, different themes are implemented differently. Some themes use fixed layouts with tables, while others use div tags and CSS you should play around with a variety of themes in order to familiarize yourself with a few different ways of creating a web page. We only have space to cover one here, but the lessons learned are easily transferred to other templates with a bit of time and practice. Before we go ahead and look at an actual example, it is important to get an overview of how themes are put together in general. Theme Anatomy Some of you might have been wondering what on earth a theme engine is, and how both themes and theme engines relate to a Drupal site. The following two definitions should clear up a few things: Theme: A file or set of files that defines and controls the features of Drupal's web pages (ranging from what functionality to include within a page, to how individual page elements will be presented) using PHP, HTML, CSS and images. Theme engine: Provides PHP-based functionality to create your own unique theme, which in turn, gives excellent control over the all aspects of a Drupal site. Drupal ships with the PHPTemplate engine that is utilized by most themes. Not all theme engines are pure PHP-based. For example, there is a Smarty theme engine available in Drupal for use by people who are familiar with Smarty templates. Looking at how theme files are set up within Drupal hints at the overall process and structure of that theme. Bear in mind that there are several ways to create a working theme, and not all themes make use of template files, but in the case of the Drupal's default theme setup, we have the following: The left-hand column shows the folders contained within the themes directory. There are a number of standard themes, accompanied by the engines folder that houses a phptemplate.engine file, to handle the integration of templates into Drupal's theming system. Looking at the files present in the garland folder, notice that there are a number of PHPTemplate files suffixed by .tpl.php. These files make use of HTML and PHP code to modify Drupal's appearance the default versions of these files, which are the ones that would be used in the event a theme had not implemented its own, can be found in the relevant modules directory. For example, the default comment.tpl.php file is found in modules/comment, and the default page.tpl.php file is located, along with others, in the modules/system folder. Each template file focuses on its specific page element or page, with the noted exception of template.php that is used to override non-standard theme functions i.e. not block, box, comment, node or page. The theme folder also houses the stylesheets along with images, and in the case of the default theme, colors. What's interesting is the addition of the mandatory .info file (.info files were present in Drupal 5 modules, but are only mandatory in themes for Drupal 6) that contains information about the theme to allow Drupal to find and set a host of different parameters. Here are a few examples of the type of information that the .info file holds: Name - A human readable theme name Description—A description of the theme Core—The major version of Drupal that the theme is compatible with Regions—The block regions available to the theme Features—Enables or disables features available in the theme—for example, slogan or mission statement Stylesheets—Stipulate which stylesheets are to be used by the theme Scripts—Specify which scripts to include PHP—Define a minimum version of PHP for which the theme will work To see how .info files can be put to work, look closely at the Minnelli theme folder. Notice that this is in fact a sub-theme that contains only a few images and CSS files. A sub-theme shares its parents' code, but modifies parts of it to produce a new look, new functionality or both. Drupal allows us to create new sub-themes by creating a new folder within the parent theme (in this case, Garland), and providing, amongst other things, new CSS. This is not the only way to create a subtheme a subtheme does not have to be in a subdirectory of its parent theme, rather it can specify the base theme directive in its .info file, in order to extend the functionality of the specified base, or parent, theme. As an exercise, access the Minnelli .info file and confirm that it has been used to specify the Minnelli stylesheet. So far we have only looked at templated themes, but Drupal ships with a couple of CSS driven themes that do not rely on the PHPTemplate engine, or any other, at all. Look at the chameleon theme folder: Notice that while it still has the mandatory .info file, a few images, and stylesheets, it contains no .tpl.php files. Instead of the template system, it uses the chameleon.theme file that implements its own versions of Drupal's themeable functions to determine the theme's layout. In this case, the Marvin theme is a nice example of how all themes can have sub-themes in the same way as the template-driven theme we saw earlier. It should be noted that engine-less themes are not quite as easy to work with as engine-based themes, because any customization must be done in PHP rather than in template files. In a nutshell, Drupal provides a range of default themeable functions that expose Drupal's underlying data, such as content and information about that content. Themes can pick and choose which snippets of rendered content they want to override the most popular method being through the use of PHP template files in conjunction with style sheets and a .info file. Themes and sub-themes are easily created and modified provided that you have some knowledge of CSS and HTML PHP helps if you want to do something more complicated. That concludes our brief tour of how themes are put together in Drupal. Even if you are not yet ready to create your own theme, it should be clear that this system makes building a new theme fairly easy, provided one knows a bit about PHP. Here's the process: Create a new themes folder in the sites/default directory and add your new theme directory in there call it whatever you want, except for a theme name that is already in use. Copy the default template files (or files from any other theme you want to modify) across to the new theme directory, along with any other files that are applicable (such as CSS files). Modify the layout (this is where your PHP and HTML skills come in handy) and add some flavor with your own stylesheet. Rewrite the .info file to reflect the attributes and requirements of the new theme. Now, when it is time for you to begin doing a bit of theme development, bear in mind that there are many types of browser, and not all of them are created equal. What this means is that a page that is rendered nicely on one browser might look bad, or worse, not even function properly on another. For this reason, you should test your site using several different browsers! The Drupal help site has this to say about browsers: It is recommended you use the Firefox browser with developer toolbar and the 'view formatted source' extensions. You can obtain a copy of the Firefox browser at http://www.mozilla.com/firefox/ if you wish to use something other than Internet Explorer. Firefox can also be extended with Firebug, which is an extremely useful tool for client-side web debugging. For the purposes of this article, we are going to limit ourselves to the selection of a base theme that we will modify to provide us with the demo site's new interface. This means that, for now, you don't have to concern yourself with the intricacies of PHP.
Read more
  • 0
  • 0
  • 1480

article-image-automation-python-and-stafstax
Packt
23 Oct 2009
13 min read
Save for later

Automation with Python and STAF/STAX

Packt
23 Oct 2009
13 min read
The reader should note that the solution is only intended to explain how Python and STAF may be used. No claim is made that the solution presented here is the best one in any way, just that is one more option that the reader may consider in future developments. The Problem Let's imagine that we have a computer network in which a machine periodically generates some kind of file with information that is of interest to other machines in that network. For example, let's say that this file is a new software build of a product that must transferred to a group of remote machines, in which its functionality has to be tested to make sure it can be delivered to the client. The Python-only solution Sequential A simple solution to make the software build available to all the testing machines could be to copy it to a specific directory whenever a new file is available. For additional security, let's suppose that we're required to verify that the md5 sum for both original and destination files is equal to ensure that build file was copied correctly. If it is considered that /tmp is a good destination directory, then the following script will do the job: 1 #!/usr/bin/python 2 """ 3 Copy a given file to a list of destination machines sequentially 4 """ 5 6 import os, argparse 7 import subprocess 8 import logging 9 10 def main(args): 11 logging.basicConfig(level=logging.INFO, format="%(message)s") 12 13 # Calculate md5 sum before copyin the file 14 orig_md5 = run_command("md5sum %s" % args.file).split()[0] 15 16 # Copy the file to every requested machine and verify 17 # that md5 sum of the destination file is equal 18 # to the md5 sum of the original file 19 for machine in args.machines: 20 run_command("scp %s %s:/tmp/" % (args.file, machine)) 21 dest_md5 = run_command("ssh %s md5sum /tmp/%s" 22 % (machine, os.path.basename(args.file))).split()[0] 23 assert orig_md5 == dest_md5 24 25 def run_command(command_str): 26 """ 27 Run a given command and another process and return stdout 28 """ 29 logging.info(command_str) 30 return subprocess.Popen(command_str, stdout=subprocess.PIPE, 31 shell=True).communicate()[0] 32 33 if __name__ == "__main__": 34 parser = argparse.ArgumentParser(description=__doc__) 35 parser.add_argument("file", 36 help="File to copy") 37 parser.add_argument(metavar="machine", dest="machines", nargs="+", 38 help="List of machines to which file must be copied") 39 40 args = parser.parse_args() 41 args.file = os.path.realpath(args.file) 42 main(args) Here it is assumed that ssh keys have been exchanged between origin and destination machines for automatic authentication without human intervention. The script makes use of the Popen class in the subprocess python standard library. This powerful library provides the capability to launch new operating system processes and capture not only the result code, but also the standard output and error streams. However, it should be taken into account that the Popen class cannot be used to invoke commands on a remote machine by itself. However, as it can be seen in the code, ssh and related commands may be used to launch processes on remote machines when configured properly. For example, if the file of interest was STAF325-src.tar.gz (STAF 3.2.5 source) and the remote machines were 192.168.1.1 and 192.168.1.2, then the file would be copied using the copy.py script in the following way: $ ./copy.py STAF325-src.tar.gz 192.168.1.{1,2}md5sum STAF325-src.tar.gzscp STAF325-src.tar.gz 192.168.1.1:/tmp/ssh 192.168.1.1 md5sum /tmp/STAF325-src.tar.gzscp STAF325-src.tar.gz 192.168.1.2:/tmp/ssh 192.168.1.2 md5sum /tmp/STAF325-src.tar.gz Parallel What would happen if the files were copied in parallel? For this example, it might not make much sense given that probably the network is at bottleneck and there isn't any increase in performance. However, in the case of the md5sum operation, it's a waste of time waiting for the operation to complete on one machine while the other is essentially idle waiting for the next command. Clearly, it would be more interesting to make both machines do the job in parallel to take advantage of CPU cycles. A parallel implementation similar to the sequential one is displayed below: 1 #!/usr/bin/python 2 """ 3 Copy a given file to a list of destination machines in parallel 4 """ 5 6 import os, argparse 7 import subprocess 8 import logging 9 import threading 10 11 def main(args): 12 logging.basicConfig(level=logging.INFO, format="%(threadName)s: %(message)s") 13 orig_md5 = run_command("md5sum %s" % args.file).split()[0] 14 15 # Create one thread for machine 16 threads = [ WorkingThread(machine, args.file, orig_md5) 17 for machine in args.machines] 18 19 # Run all threads 20 for thread in threads: 21 thread.start() 22 23 # Wait for all threads to finish 24 for thread in threads: 25 thread.join() 26 27 class WorkingThread(threading.Thread): 28 """ 29 Thread that performs the copy operation for one machine 30 """ 31 def __init__(self, machine, orig_file, orig_md5): 32 threading.Thread.__init__(self) 33 34 self.machine = machine 35 self.file = orig_file 36 self.orig_md5 = orig_md5 37 38 def run(self): 39 # Copy file to remote machine 40 run_command("scp %s %s:/tmp/" % (self.file, self.machine)) 41 42 # Calculate md5 sum of the file copied at the remote machine 43 dest_md5 = run_command("ssh %s md5sum /tmp/%s" 44 % (self.machine, os.path.basename(self.file))).split()[0] 45 assert self.orig_md5 == dest_md5 46 47 def run_command(command_str): 48 """ 49 Run a given command and another process and return stdout 50 """ 51 logging.info(command_str) 52 return subprocess.Popen(command_str, stdout=subprocess.PIPE, 53 shell=True).communicate()[0] 54 55 if __name__ == "__main__": 56 parser = argparse.ArgumentParser(description=__doc__) 57 parser.add_argument("file", 58 help="File to copy") 59 parser.add_argument(metavar="machine", dest="machines", nargs="+", 60 help="List of machines to which file must be copied") 61 62 args = parser.parse_args() 63 args.file = os.path.realpath(args.file) 64 main(args) Here the same assumptions as in the sequential case are made. In this solution the work that was done inside the for loop is now implemented in the run method of a class that is inherited from threading.Thread class, which is a class that provides an easy way to create working threads such as the ones in the example. In this case, the output of the command, using the same arguments as in the previous example, is: $ ./copy_parallel.py STAF325-src.tar.gz 192.168.1.{1,2}MainThread: md5sum STAF325-src.tar.gzThread-1: scp STAF325-src.tar.gz 192.168.1.1:/tmp/Thread-2: scp STAF325-src.tar.gz 192.168.1.2:/tmp/Thread-2: ssh 192.168.1.2 md5sum /tmp/STAF325-src.tar.gzThread-1: ssh 192.168.1.1 md5sum /tmp/STAF325-src.tar.gz As it can be seen in the logs, md5sum command execution isn't necessarily executed in the same order as threads were created. This solution isn't much more complex than the sequential one, but it finishes earlier. Hence, in the case in which a CPU intensive task must be performed in every machine, the parallel solution will be more convenient since the small increment in coding complex will pay off in execution performance. The Python+STAF solution Sequential The solutions to the problem presented in the previous section are perfectly fine. However, some developers may find it cumbersome to write scripts from scratch using Popen class and desire to work with a platform with feature such as launching process on remote machines already implemented. That's were STAF (Software Testing Automation Framework) might be helpful. STAF is a framework that provides the ability to automate jobs specially, but not uniquely, for testing environments. STAF is implemented as a process which runs on every machine that provides services that may be used by clients to accomplish different tasks. For more information regarding STAF, please refer to the project homepage. The Python+STAF sequential version of the program that has been used as example throughout this article is below: 1 #!/usr/bin/python 2 """ 3 Copy a given file to a list of destination machines sequentially 4 """ 5 6 import os, argparse 7 import subprocess 8 import logging 9 import PySTAF 10 11 def main(args): 12 logging.basicConfig(level=logging.INFO, format="%(message)s") 13 handle = PySTAF.STAFHandle(__file__) 14 15 # Calculate md5 sum before copyin the file 16 orig_md5 = run_process_command(handle, "local", "md5sum %s" % args.file).split()[0] 17 18 # Copy the file to every requested machine and verify 19 # that md5 sum of the destination file is equal 20 # to the md5 sum of the original file 21 for machine in args.machines: 22 copy_file(handle, args.file, machine) 23 dest_md5 = run_process_command(handle, machine, "md5sum /tmp/%s" 24 % os.path.basename(args.file)).split()[0] 25 assert orig_md5 == dest_md5 26 27 handle.unregister() 28 29 def run_process_command(handle, location, command_str): 30 """ 31 Run a given command and another process and return stdout 32 """ 33 logging.info(command_str) 34 35 result = handle.submit(location, "PROCESS", "START SHELL COMMAND %s WAIT RETURNSTDOUT" 36 % PySTAF.STAFWrapData(command_str)) 37 assert result.rc == PySTAF.STAFResult.Ok 38 39 mc = PySTAF.unmarshall(result.result) 40 return mc.getRootObject()['fileList'][0]['data'] 41 42 def copy_file(handle, filename, destination): 43 """ 44 Run a given command and another process and return stdout 45 """ 46 logging.info("copying %s to %s" % (filename, destination)) 47 48 result = handle.submit("local", "FS", "COPY FILE %s TODIRECTORY /tmp TOMACHINE %s" 49 % (PySTAF.STAFWrapData(filename), 50 PySTAF.STAFWrapData(destination))) 51 assert result.rc == PySTAF.STAFResult.Ok 52 53 if __name__ == "__main__": 54 parser = argparse.ArgumentParser(description=__doc__) 55 parser.add_argument("file", 56 help="File to copy") 57 parser.add_argument(metavar="machine", dest="machines", nargs="+", 58 help="List of machines to which file must be copied") 59 60 args = parser.parse_args() 61 args.file = os.path.realpath(args.file) 62 main(args) The code makes use of PySTAF, a python library, which is shipped with the STAF software that provides the ability to interact with the framework as a client. The typical usage of the library may summarized as follows: Register a handle in STAF (line 13): The communication with the server process is managed using handles. A client must have a handle to be able to send requests to local and/or remote machines. Submit requests (lines 35 and 48): Once the handle is available at the client, the client can use it to submit requests to any location and service. The two basic services that are used in this example are PROCESS, which is used to launch processes on a machine the same way ssh was used in the python-only version of the example; and FS, which is used to copy files between different machines as scp was used in the python-only solution. Check result code (lines 37 and 51): After a request has been submitted, result code should be checked to make sure that there wasn't any communication or syntax problem. Unmarshall results (lines 39-40): When the standard output is captured, it must be unmarshalled before using it in python since responses are encoded in a language independent format. Unregister handle (line 27): When STAF isn't needed anymore, it's advisable to unregister the handle to free resources allocated to the client in the server. Compared with the python-only solution, the advantages of STAF aren't appreciable at first sight. The handler syntax isn't easier than creating Popen objects and we have to deal with marshalling when we previously were just parsing text. However, as a framework, if has to be taken into account that it is has a learning curve and has much more functionality to offer than this one that makes it worthwhile. Please bear with me until section 5, in which the STAX solution we'll be shown, with an example with a completely different approach to the problem. Using the script in this section, the output would be pretty much the same as the previous sequential example: $ ./staf_copy.py STAF325-src.tar.gz 192.168.1.{1,2}md5sum STAF325-src.tar.gzcopying STAF325-src.tar.gz to 192.168.1.1md5sum /tmp/STAF325-src.tar.gzcopying STAF325-src.tar.gz to 192.168.1.2md5sum /tmp/STAF325-src.tar.gz As in the previous section, the sequential solution suffers the same problems when CPU intensive tasks are to be performed. Hence, the same comments apply. Parallel When using STAF, the parallel solution requires the same changes that were explained before. That is, create a new class that inherits from threading.Thread and implement the working threads. The code below shows how this might be implemented: 1 #!/usr/bin/python 2 """ 3 Copy a given file to a list of destination machines in parallel 4 """ 5 6 import os, argparse 7 import subprocess 8 import logging 9 import threading 10 import PySTAF 11 12 def main(args): 13 logging.basicConfig(level=logging.INFO, format="%(threadName)s %(message)s") 14 handle = PySTAF.STAFHandle(__file__) 15 orig_md5 = run_process_command(handle, "local", "md5sum %s" % args.file).split()[0] 16 17 # Create one thread for machine 18 threads = [ WorkingThread(machine, args.file, orig_md5) 19 for machine in args.machines] 20 21 # Run all threads 22 for thread in threads: 23 thread.start() 24 25 # Wait for all threads to finish 26 for thread in threads: 27 thread.join() 28 29 handle.unregister() 30 31 class WorkingThread(threading.Thread): 32 """ 33 Thread that performs the copy operation for one machine 34 """ 35 def __init__(self, machine, orig_file, orig_md5): 36 threading.Thread.__init__(self) 37 38 self.machine = machine 39 self.file = orig_file 40 self.orig_md5 = orig_md5 41 self.handle = PySTAF.STAFHandle("%s:%s" % (__file__, self.getName())) 42 43 def run(self): 44 # Copy file to remote machine 45 copy_file(self.handle, self.file, self.machine) 46 47 # Calculate md5 sum of the file copied at the remote machine 48 dest_md5 = run_process_command(self.handle, self.machine, "md5sum /tmp/%s" 49 % os.path.basename(self.file)).split()[0] 50 assert self.orig_md5 == dest_md5 51 self.handle.unregister() 52 53 def run_process_command(handle, location, command_str): 54 """ 55 Run a given command and another process and return stdout 56 """ 57 logging.info(command_str) 58 59 result = handle.submit(location, "PROCESS", "START SHELL COMMAND %s WAIT RETURNSTDOUT" 60 % PySTAF.STAFWrapData(command_str)) 61 assert result.rc == PySTAF.STAFResult.Ok 62 63 mc = PySTAF.unmarshall(result.result) 64 return mc.getRootObject()['fileList'][0]['data'] 65 66 def copy_file(handle, filename, destination): 67 """ 68 Run a given command and another process and return stdout 69 """ 70 logging.info("copying %s to %s" % (filename, destination)) 71 72 result = handle.submit("local", "FS", "COPY FILE %s TODIRECTORY /tmp TOMACHINE %s" 73 % (PySTAF.STAFWrapData(filename), 74 PySTAF.STAFWrapData(destination))) 75 assert result.rc == PySTAF.STAFResult.Ok 76 77 if __name__ == "__main__": 78 parser = argparse.ArgumentParser(description=__doc__) 79 parser.add_argument("file", 80 help="File to copy") 81 parser.add_argument(metavar="machine", dest="machines", nargs="+", 82 help="List of machines to which file must be copied") 83 84 args = parser.parse_args() 85 args.file = os.path.realpath(args.file) 86 main(args) As it happened before, this solution is faster since it takes advantage of having multiple CPUs working on md5sum calculation instead of just one at a time. The output we get invoking the script could be: $ ./staf_copy_parallel.py STAF325-src.tar.gz 192.168.1.{1,2}MainThread md5sum STAF325-src.tar.gzThread-1 copying STAF325-src.tar.gz to 192.168.1.1Thread-2 copying STAF325-src.tar.gz to 192.168.1.2Thread-2 md5sum /tmp/STAF325-src.tar.gzThread-1 md5sum /tmp/STAF325-src.tar.gz This time it can be seen that md5sum calculation mustn't necessarily start in the same order as file copy operation. Once again, this solution is slightly more complex, but the gain in performance makes it convenient when dealing with tasks with high computational cost.    
Read more
  • 0
  • 0
  • 7581

article-image-creating-web-page-displaying-data-sql-server-2008
Packt
23 Oct 2009
5 min read
Save for later

Creating a Web Page for Displaying Data from SQL Server 2008

Packt
23 Oct 2009
5 min read
This article by Jayaram Krishnaswamy describes how you may connect to SQL Server 2008 and display the retrieved data in a GridView Control on a web page. Trying to establish a connection to the SQL Server 2008 is not possible in Visual Studio 2008 as you will see soon in the tutorial. One way to get around this, as shown in this tutorial, is to create an ODBC connection to the SQL Server and then using the ODBC connection to retrieve the data. Visual Studio 2008 Version: 9.0.21022.8 RTM, Microsoft Windows XP Professional Media Center Edition, and SQL Server 'Katmai' were used for this tutorial. (For more resources on Microsoft, see here.) Connecting to SQL Server 2008 is Not Natively Supported in Microsoft Visual Studio 2008 Designer In the Visual Studio 2008 IDE make a right click on the Data Connections node in the Server Explorer. This will open up the Add Connection window where the default connection being displayed is MS SQL Server Compact. Click on the Change... button which opens the Change Data Source window shown in the next figure. Highlight Microsoft SQL Server as shown and click on the OK button. This once again opens the Add Connection window showing SQL Server 2008 on the machine, Hodentek as shown in the next figure in this case. The connection is set for Windows Authentication and should you test the connectivity you would get 'Success' as a reply. However when you click on the handle for the database name to retrieve a list of databases on this server, you would get a message as shown. Creating a ODBC DSN You will be using the ODBC Data Source Administrator on your desktop to create a ODBC DSN. You access the ODBC Source Administrator from Start | All Programs | Control Panel | Administrative Tools | Data Sources(ODBC). This opens up ODBC Data Source Administrator window as shown in the next figure. Click on System DSN tab and click on the Add... button. This opens up the Create New Data Source window where you scroll down to SQL Server Native Client 10.0. Click on the Finish button. This will bring up the Create a New Data Source to SQL Server window. You must provide a name in the Name box. You also provide a description and click on the drop-down handle for the question, Which SQL Server do you want to connect to? to reveal a number of accessible servers as shown. Highlight SQL Server 2008. Click on the Next button which opens a window where you provide the authentication information. This server uses windows authentication and if your server uses SQL Server authentication you will have to be ready to provide the LoginID and Password. You may accept the default for other configurable options. Click on the Next button which opens a window where you choose the default database to which you want to establish a connection. Click on the Next button which opens a window where you accept the defaults and click on the Finish button. This brings up the final screen, the ODBC Data SQL Server Setup which summarizes the options made as shown. By clicking on the Test Data Source... button you can verify the connectivity. When you click on the OK button you will be taken back to the ODBC Data Source Administrator window where the DSN you created is now added to the list of DSNs on your machine as shown. Retrieving Data from the Server to a Web Page You will be creating an ASP.NET website project. As this version of Visual Studio supports projects in different versions, choose the Net Framework 2.0 as shown. On to the Default.aspx page, drag and drop a GridView control from the Toolkit as shown in this design view. Click on the Smart task handle to reveal the tasks you need to complete this control. Click on the drop-down handle for the Choose Data Source: task as shown in the previous figure. Now click on the <New data Source...> item. This opens the Data Source Configuration Wizard window which displays the various sources from which you may get your data. Click on the Database icon. Now the OK button becomes visible. Click on the OK button. The wizard's next task is to guide you to get the connection information as in the next figure. Click on the New Connection... button. This will take you back to the Add Connection window. Click on the Change... button as shown earlier in the tutorial. In the Change Data Source window, you now highlight the Microsoft ODBC Data Source as shown in the next figure. Click on the OK button. This opens the Add Connection window where you can now point to the ODBC source you created earlier, using the drop-down handle for the Use user or system data source name. You may also test your connection by hitting the Test Connection button. Click on the OK button. This brings the connection information to the wizard's screen as shown in the next figure. Click on the Next button which opens a window in which you have the option to save your connection information to the configuration node of your web.config file. Make sure you read the information on this page. The default connection name has been changed to Conn2k8 as shown. Click on the Next button. This will bring up the screen where you provide a SQL Select statement to retrieve the columns you want. You have three options and here the Specify a custom SQL Statement or stored procedure option is chosen.
Read more
  • 0
  • 0
  • 23962

article-image-technical-best-practices-dynamics-ax-shared-and-aot-object-standards
Packt
23 Oct 2009
15 min read
Save for later

Technical Best Practices for Dynamics AX - Shared and AOT Object Standards

Packt
23 Oct 2009
15 min read
Shared Standards Some Dynamics AX customization best practices are applicable irrespective of AOT element. These standards include X++ standards, naming conventions, label standards, and Help Text guidelines. X++ Standards This section discusses some best practices related to the X++ language. Conformance to this standard results in improved execution time, ease in upgrading and further customization, efficient use of OOP concepts, better readability of code, etc. Some general principles are as follows: Variable or constant or parameter declarations should be as local as possible to utilize memory resources in an efficient way. Error conditions should be checked in the beginning so that minimum work is done for action and rollback of action. This will also hinder denial of service attacks. Denial of service attack is an attempt to stress the system with too many garbage requests so that an authorized user is not served. The parameters supplied as value must not be modified or manipulated as it may increase the chances of using wrong values somewhere else. Code should be written in a clean fashion, which means unused variables, methods, and classes should be removed from the code. The existing MorphX functions or functionality should be used as much as possible (unless other best practices stop you from doing so), rather than creating new ones as it will make upgrading easier. The user should not experience a run-time error. All possible cases should be foreseen and handled accordingly. If some unpredicted case appears during run time, it should show an error in the Infolog with a message to help the users on how to avoid the situation and what action can be taken to prevent it. The value of the this variable should not be changed. The reusability should be maximized. E.g. rather than repeating lines of code at different places, a single method can be written so that changes in the method can be reflected at all the places where this method is used. There should be only one successful return point (except in switch statements) so that object deletion, etc. can be ensured. A method should perform a single well-defined task and be named according to the task performed. Text Constant Standards All the text used in Dynamics AX is supposed to be in a label file irrespective of its use e.g. user interface or error or success message. The use of text constants can be classified into two broad categories i.e. user interface text and system-oriented text. The text used in the user interface should follow the following best practices: Modify property values on the extended data types or base enums inthe application. Never create duplicate label files i.e. the same text (in the same language) but a different label file. New label files can be created when customizing the text, but it is always recommended to reuse the standard labels. However, it may offer a disadvantage—all the changes made to the SYS layer label files will be gone whenever an upgrade occurs. So the decision of customizing an existing label file or creating new label file should be taken carefully. User interface text (labels files) should be used in double quotes. System-oriented text constants must be in single quotes. Exception Handling The principle uses of exception handling include freeing system resources (e.g. memory through object deletion, closing database connection, etc.) and providing constructive information in the Infolog so that the user can prevent such erroneous conditions. The following are a few recommended best practices related to exception handling: A try or catch deadlock or retry loop should always be created around database transactions that can cause deadlocks. In the retry clause the values of transient variables should be set back to the values before try. Branching A few recommended best practices related to the if-else statement and switch statement are as follows: Always use positive logic e.g. write if (true) rather than if (! false). Prefer switch statement rather than multiple if-else statements. Always end a case with a break or return or throw statement unless a fall through mechanism is intentionally used. When a fall through mechanism is used a comment should be given like //fall through so that it is clear to every reader. Code Layout For readability of the code, code should be written in a proper layout. Some chief best practices for code layout are as follows: Remove commented code before shipping code. Follow indentation rules. Follow case rules for naming classes, methods, tables, etc. Methods Following are a few best practices for methods: Methods should be small and logical so that it can be easily overridden or over-layered. Methods should perform a single well defined task and from their name the task performed should be clear. For static class methods and table methods, qualified client, server, or client server should be used in such a way that calls to other tiers are minimized. For greater details refer to the Best Practices for Designing section in the Developer's Guide. To ensure trustworthiness, appropriate access levels (public, private, or protected) should be assigned. Methods should be named according to the Dynamics AX naming conventions; the reserved keywords such as is, check, validate, set, get, and find should be used as per the Dynamics AX way of using these standard methods or functions. All methods using such keywords must not have side effects e.g. no assignment in validate, check, get, or is methods. Parameter's names must start with an underscore (_) character besides following other generalized naming conventions. Handling Dates Dates are sources of error due to variations in date presentation formats and in values due to differences in time zone. A few best practices for handling dates are as follows: Date fields must be stored or displayed in the date field only as IntelliMorph has the ability to display the date value in a format suitable for the user provided that the date format property is chosen as Auto and it is presented in a date control. The system date should not be considered as reliable information but in some cases (e.g. validation of information input by a user) system date should be read using the SystemDateGet() function instead of the today() function. Date conversion should be avoided as it will loose date properties and hence sometimes conversion may result in wrong information. For all user interface-related situations strFmt or date2Str should be used with a value of -1 for all formatting-related parameters. This will allow users to use this information in the format specified in regional settings. Care should also be taken that string variables storing converted date information are sufficiently long. Label Standards It is highly recommended that any user-interface text is defined using labels. This will ensure many advantages during translation. A few label file standards to ensure the true benefits of the label file system are as follows: The location of label files should be the most generalized one i.e. extended data type (EDT). In some cases an existing EDT cannot be used only because of the difference in label text. In such cases a new EDT should be created by extending the existing EDT. In such cases other alternatives may also be available (e.g. label change at the field) but the rule of thumb is to use the label at the most general place. The label files should not be duplicated i.e. two label files should not exist for the same text. AOT Object Standards The AOT object standards are specific to a particular AOT element. Broadly we can classify AOT elements as follows: Data Dictionary Extended data type Base Enum Tables Feature keys Table collection Classes Forms Reports Jobs Menu items Data Dictionary This is a group of AOT objects including the items mentioned in the previous section. The best practices for tables can further be divided into best practices for the fields, field groups, indexes, table relations, delete actions, and methods. Extended Data Type The EDT plays a great role as it is the basic entity of GUI elements. The following are a few basic best practices related to extended data types. All date and date format-related properties should be set to Auto. Help text should not be same as the label property. Help text is supposed to be more descriptive and should be able to explain why and/or how. An EDT name must be a real-world name, prefixed with module (if it belongs to one module only). Base Enum The following are a few basic best practices related to Base Enum: The Enum name should be an indication of either the few possible values or type of values. For example DiscountType, OpenClose, etc. Display length property should be set to auto so that in every language the full name can be displayed. Help and label properties must have some value. Help and label properties should not have the same value. Tables Many of the best practices for tables come under the scope of performance optimization, database design standards, etc. and hence those standards have been discussed elsewhere. Some of the standards not discussed are discussed here. The table name may consist of the following valuable information: Prefix: Module name such as Cust for Account Payable, Sales for Account Receivables Infix: Logical description of the content Post fix: Type of data e.g. Trans (for transactions), Jour (Journals), Line (table containing detailed information about a particular record in header table), Table (primary main tables), Group, Parameters, Setup, or module name to which the table belongs Label is a mandatory property and tables must be labelled using Label ID only. The text value of Label ID must be unique in all languages supported. If a table belongs to one of the four types Parameter, Group, Main, or WorksheetHeader, then it must have an associated form to maintain the table records. This form should have a name identical to its display menu item (used to start this form) and like the table name. formRef is the property of a table for the name of the associated form. Title Field 1 and Title Field 2 should be mentioned: TitleField1: The key field for the records in the table. This should be a descriptive title, if the key is information for the user. TitleField2: The description for the records in the table. Fields Most of the properties for the fields are inherited from extended data types; however, it is not mandatory to use some or all inherited values for such properties. Here are a few guidelines: Name: Should be like the corresponding EDT name but if named separately, it should be logical. The fields used as key should be postfixed as ID e.g. CustId, ItemId, etc. HelpText: This is a mandatory property and inherited from the corresponding EDT. Since Help Text needs to be customized as per the different uses ofthe same EDT, Help text can be modified at any field but the following arethe guidelines: The help text property should not be same as the label property. Label is also a mandatory property, which is inherited from EDT. If a value is set here, it should be different from the value on EDT. Every field that is either the primary key or one of the key mandatory properties must be set to Yes. Before considering memo or container type fields, it should be kept in mind that they add time to application and database fetch, they inhibit array fetching, and these types of fields cannot be used in where expressions. Field Group The field group is a group of fields shown in the user interface. Dynamics AX has some standard groups (e.g. Identification, Administration, Address, Dimension, Setup, Misc, etc.), while other can be created. The fields that logically belong together can be placed in one field group while the Misc field group can be used to group fields that do not fit in any other field group. The dimension field group must have a single kind of field Dimension. The field groups should have the same kind of grouping at the database and form or reports to improve caching and hence the performance. Delete Actions The database integrity is one of the key principles in Relational Database Management System (RDBMS). The delete action should be used on every relation between two tables. The following are key best practices for delete actions. Use a delete action on every relation between two tables. Use table delete actions instead of writing code to specify whether deletes are restricted or cascaded. Dynamics AX has three types of delete actions; selection of one will solely depend upon the custom requirements. Table Methods The tables in Dynamics AX have several properties such as delete, validateDelete, etc. and hence Dynamics AX recommends that you should not write methods or X++ code to implement something that can be done just by setting property values. Dynamics AX recommends using inbuilt table methods for those custom requirements that cannot be met with table properties settings. Some of the table methods are mandatory to implement e.g. find and exists methods. Classes The classes have a peculiarity that they may have both a back end (database) and front end (GUI). The front interface should be easy to use and at the same time as secure as possible. The implementation details of the class should always be hidden from the user and hence use of private or protected methods is recommended. The back-end methods are highly secure, standardized, and reliable and hence use of private or protected methods is recommended in prescribed design patterns. The design patterns depend upon the type of class. Classes can be categorized in the following categories: Real object Action class Supporting class The following are a few common best practices related to declaration: Object member variables must only be used to hold the state of the object i.e. variables for which values should be kept between and outside instance method calls. Use of global variables must be minimized. Unused variables must be cleaned up; a tool available at Add-Ins | Best Practices | Check Variables can be used to know the unused variables. Constants used in more than one method in a class (or in subclass) should be declared during class declaration. There is a rich set of best practices for classes and the Best Practices for Microsoft Dynamics AX Development released by Microsoft would be good read. Forms The forms are in the presentation tier in any three-tier architecture system. Most of them are related to look and feel or layout. Some other best practices for forms revolve around the following characteristics: Use of Intellimorph maximally No forced date or time format No forced layout such as fixed width for label, position control for GUI controls, etc. Use of label files for GUI text Forms having minimal coding Avoid Coding on Forms The basic concept of three-tier architecture is that forms should be used only for the presentation tier and hence no other code such as business logic should be there on forms. The code placed on forms also reduces their reusability and the ease of further customization; e.g. if you want to develop an enterprise portal, the code written on forms will have to be written again in classes or table methods, etc., which will make the implementation complex. Another example may be when you want to 'COM enable' your business logic; form code related to business logic will make your life almost impossible. Any code (other than presentation logic) written on forms imposes limitation on performance as call between two different layers increase slowing the performance and hence code on forms should be avoided as much as possible. In cases where avoiding code on forms is not possible the guidelines summarized in the following table should be used for writing code on forms. Place to Write Code Guidelines Form level When code is related to whole form When code is related to multiple data sources Editor or Display methods (only those that are not related to any data source) Data source Data source-related Edit or Display methods Code related only to the data source that cannot be effectively placed in a table method Controls When it is strictly related to the controls Use of IntelliMorph Maximally Due to a user's locale or preferred format a form may be presented in a different language and/or a different date, time, or currency format. Dynamics AX best practices recommend Auto as the value for the display properties related to the following: Date Currency Time Language Number format (such as decimal operator, separator, etc.) Label size Form size The rule of thumb is to keep the various properties as Auto or default value, which will help IntelliMorph to function maximally. For further details about best practices readers are recommended to go through the Developers Guide for Best Practices. Reports The peculiar fact about the reports is that they are output media where the external environment such as paper size, user's configuration about the locale or language, font size, etc. matters. Dynamics AX recommends using 'Auto Design' to develop the report as these kinds of reports can change the layout according to external environmental variables. Another way to develop a report in Dynamics AX is 'Generated Design'; this type of design is recommended only when strict report layout is required. A few such examples may be regulatory reports, accounts reports, etc. Summary In this two part article we discussed various areas where quality could be improved by adopting best practices. We also discussed various best practices, theory behind best practices, and how to adopt these best practices, i.e. with practical tips.
Read more
  • 0
  • 0
  • 9945
article-image-jboss-perspective
Packt
23 Oct 2009
4 min read
Save for later

JBoss AS Perspective

Packt
23 Oct 2009
4 min read
As you know, Eclipse offers an ingenious system of perspectives that helps us to switch between different technologies and to keep the main-screen as clean as possible. Every perspective is made of a set of components that can be added/removed by the user. These components are known as views. The JBoss AS Perspective has a set of specific views as follows: JBoss Server View Project Archives View Console View Properties View For launching the JBoss AS Perspective (or any other perspective), follow these two simple steps: From the Window menu, select Open Perspective | Other article. In the Open Perspective window, select the JBoss AS option and click on OK button (as shown in the following screenshot). If everything works fine, you should see the JBoss AS perspective as shown in the following screenshot: If any of these views is not available by default in your JBoss AS perspective, then you can add it manually by selecting from the Window menu the Show View | Other option. In the Show View window (shown in the following screenshot), you just select the desired view and click on the OK button. JBoss Server View This view contains a simple toolbar known as JBoss Server View Toolbar and two panels that separate the list of servers (top part) from the list of additional information about the selected server (bottom part). Note that the quantity of additional information is directly related to the server type. Top part of JBoss Server View In the top part of the JBoss Server View, we can see a list of our servers, their states, and if they are running or if they have stopped. Starting the JBoss AS The simplest ways to start our JBoss AS server are: Select the JBoss 4.2 Server from the server list and click the Start the server button from the JBoss Server View Toolbar (as shown in the following screenshot). Select the JBoss 4.2 Server from the server list and right-click on it. From the context menu, select the Start option (as shown in the following screenshot). In both cases, a detailed evolution of the startup process will be displayed in the Console View, as you can see in the following screenshot. Stopping the JBoss AS The simplest ways to stop JBoss AS server are: Select the JBoss 4.2 Server from the server list and click the Stop the server button from the JBoss Server View Toolbar. Select the JBoss 4.2 Server from the server list and right-click on it. From the context menu, select the Stop option. In both cases, a detailed evolution of the stopping process will be displayed in the Console View, as you can see in the following screenshot. Additional operations on JBoss AS Beside Start and Stop operations, JBoss Server View allows us to: Add a new server (the New Server option from the contextual menu) Remove an existing server (the Delete option from the contextual menu) Start the server in debug mode (first button on the JBoss Server View Toolbar) Start the server in profiling mode (third button on the JBoss Server View Toolbar) Publish to the server or synching the publish information between the server and the workspace (the Publish option from the contextual menu or the last button on the JBoss Server View Toolbar) Discard all publish state and republish from scratch (the Clean option from the contextual menu) Twiddle server (the Twiddle Server option from the contextual menu) Edit launch configuration (the Edit Launch Configuration option from the contextual menu as shown in the following screenshot). Add/remove projects (the Add and Remove Projects option from the contextual menu) Double-click the server name and modify parts of that server in the Server Editor—if you have a username and a password to start the server, then you can specify those credentials here (as shown in the following screenshot). Twiddle is a JMX library that comes with JBoss, and it is used to access (any) variables that are exposed via the JBoss JMX interfaces. Server publish status A server may have one of the following statuses: Synchronized: Allows you to see if changes are sync (as shown in the follo wing screenshot) Publishing: Allows you to see if changes are being updated Republish: Allows you to see if changes are waiting
Read more
  • 0
  • 0
  • 1799

article-image-chatroom-application-using-dwr-java-framework
Packt
23 Oct 2009
19 min read
Save for later

Chatroom Application using DWR Java Framework

Packt
23 Oct 2009
19 min read
Starting the Project and Configuration We start by creating a new project for our chat room, with the project name DWRChatRoom. We also need to add the dwr.jar file to the lib directory and enable DWR in the web.xml file. The following is the source code of the dwr.xml file. <?xml ver sion="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd"> <dwr> <allow> <create creator="new" javascript="Login"> <param name="class" value="chatroom.Login" /> </create> <create creator="new" javascript="ChatRoomDatabase"> <param name="class" value="chatroom.ChatRoomDatabase" /> </create> </allow> </dwr> The source code for web.xml is as follows: <?xml ver sion="1.0" encoding="UTF-8"?> <web-app xsi_schemaLocation="http://java. sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_ 5.xsd" id="WebApp_ID" version="2.5"> <display-name>DWRChatRoom</display-name> <servlet> <display-name>DWR Servlet</display-name> <servlet-name>dwr-invoker</servlet-name> <servlet-class> org.directwebremoting.servlet.DwrServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list></web-app> Developing the User Interface The next step we do is to create files for presentation: style sheet and HTML/JSP files. The style sheet, loginFailed.html, and index.jsp files are required for the application. The source code of the style sheet is as follows: body{margin:0;padding:0;line-height: 1.5em;}b{font-size: 110%;}em{color: red;}#topsection{background: #EAEAEA;height: 90px; /*Height of top section*/}#topsection h1{margin: 0;padding-top: 15px;}#contentwrapper{float: left;width: 100%;}#contentcolumn{margin-left: 200px; /*Set left margin to LeftColumnWidth*/}#leftcolumn{float: left;width: 200px; /*Width of left column*/margin-left: -100%;background: #C8FC98;}#footer{clear: left;width: 100%;background: black;color: #FFF;text-align: center;padding: 4px 0;}#footer a{color: #FFFF80;}.innertube{margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/margin-top: 0;} Our first page is the login page. It is located in the WebContent directory and it is named index.jsp. The source code for the page is given as follows: <%@ page language="java" contentType="text/html; charset=ISO-8859-1"    pageEncoding="ISO-8859-1"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Book Authoring</title><script type='text/javascript' src='/DWRChatroom/dwr/interface/Login.js'></script><script type='text/javascript' src='/DWRChatroom/dwr/engine.js'></script><script type='text/javascript' src='/DWRChatroom/dwr/util.js'></script>  <script type="text/javascript">function login(){  var userNameInput=dwr.util.byId('userName');  var userName=userNameInput.value;  Login.doLogin(userName,loginResult);}function loginResult(newPage){  window.location.href=newPage;}</script></head><body><h1>Book Authoring Sample</h1><table cellpadding="0" cellspacing="0"><tr><td>User name:</td><td><input id="userName" type="text" size="30"></td></tr><tr><td>&nbsp;</td><td><input type="button" value="Login" onclick="login();return false;"></td></tr></table></body></html> The login screen uses the DWR functionality to process the user login (the Java classes are presented after the web pages). The loginResults function opens either the failure page or the main page based on the result of the login operation. If the login was unsuccessful, a very simple loginFailed.html page is shown to the user, the source code for which is as follows: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html;                                         charset=ISO-8859-1"><title>Login failed</title></head><body><h2>Login failed.</h2></body></html> The main page, mainpage.jsp, includes all the client-side logic of our ChatRoom application. The source code for the page is as follows: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en" xml_lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Chatroom</title><link href="styles.css" rel="stylesheet" type="text/css" /><%   if (session.getAttribute("username") == null         || session.getAttribute("username").equals("")) {      //if not logged in and trying to access this page      //do nothing, browser shows empty page      return;   }%><script type='text/javascript' src='/DWRChatRoom/dwr/interface/Login.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/interface/ChatRoomDatabase.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/engine.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/util.js'></script>  <script type="text/javascript">dwr.engine.setActiveReverseAjax(true);function logout(){  Login.doLogout(showLoginScreen);}function showLoginScreen(){  window.location.href='index.jsp';}function showUsersOnline(){  var cellFuncs = [          function(user) {             return '<i>'+user+'</i>';          }          ];    Login.getUsersOnline({    callback:function(users)     {      dwr.util.removeAllRows('usersOnline');      dwr.util.addRows( "usersOnline",users, cellFuncs,                                    { escapeHtml:false });    }    });}function getPreviousMessages(){    ChatRoomDatabase.getChatContent({    callback:function(messages)     {      var chatArea=dwr.util.byId('chatArea');      var html="";      for(index in messages)      {         var msg=messages[index];         html+=msg;      }      chatArea.innerHTML=html;      var chatAreaHeight = chatArea.scrollHeight;      chatArea.scrollTop = chatAreaHeight;    }    });}function newMessage(message){  var chatArea=dwr.util.byId('chatArea');  var oldMessages=chatArea.innerHTML;  chatArea.innerHTML=oldMessages+message;    var chatAreaHeight = chatArea.scrollHeight;  chatArea.scrollTop = chatAreaHeight;}function sendMessageIfEnter(event){  if(event.keyCode == 13)  {    sendMessage();  }}function sendMessage(){    var message=dwr.util.byId('messageText');    var messageText=message.value;    ChatRoomDatabase.postMessage(messageText);    message.value='';}</script></head><body onload="showUsersOnline();"><div id="maincontainer"><div id="topsection"><div class="innertube"><h1>Chatroom</h1><h4>Welcome <i><%=(String) session.getAttribute("username")%></i></h4></div></div><div id="contentwrapper"><div id="contentcolumn"><div id="chatArea" style="width: 600px; height: 300px; overflow: auto"></div><div id="inputArea"><h4>Send message</h4><input id="messageText" type="text" size="50"  onkeyup="sendMessageIfEnter(event);"><input type="button" value="Send msg"                                                      onclick="sendMessage();"></div></div></div><div id="leftcolumn"><div class="innertube"><table cellpadding="0" cellspacing="0">  <thead>    <tr>      <td><b>Users online</b></td>    </tr>  </thead>  <tbody id="usersOnline">  </tbody></table><input id="logoutButton" type="button" value="Logout"  onclick="logout();return false;"></div></div><div id="footer">Stylesheet by <a  href="http://www.dynamicdrive.com/style/">Dynamic Drive CSSLibrary</a></div></div><script type="text/javascript">getPreviousMessages();</script></body></html> The first chat-room-specific JavaScript function is getPreviousMessages(). This function is called at the end of mainpage.jsp, and it retrieves previous chat messages for this chat room. The newMessage() function is called by the server-side Java code when a new message is posted to the chat room. The function also scrolls the chat area automatically to show the latest message. The sendMessageIfEnter() and sendMessage() functions are used to send user messages to the server. There is the input field for the message text in the HTML code, and the sendMessageIfEnter() function listens to onkeyup events in the input field. If the user presses enter, the sendMessage() function is called to send the message to the server. The HTML code includes the chat area of specified size and with automatic scrolling. Developing the Java Code There are several Java classes in the application. The Login class handles the user login and logout and also keeps track of the logged-in users. The source code of the Login class is as follows: package chatroom;import java.util.Collection;import java.util.List;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.directwebremoting.ScriptSession;import org.directwebremoting.ServerContext;import org.directwebremoting.ServerContextFactory;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;import org.directwebremoting.proxy.ScriptProxy;public class Login {   public Login() {   }      public String doLogin(String userName) {      UserDatabase userDb=UserDatabase.getInstance();      if(!userDb.isUserLogged(userName)) {         userDb.login(userName);         WebContext webContext= WebContextFactory.get();         HttpServletRequest request = webContext.getHttpServletRequest();         HttpSession session=request.getSession();         session.setAttribute("username", userName);         String scriptId = webContext.getScriptSession().getId();         session.setAttribute("scriptSessionId", scriptId);         updateUsersOnline();         return "mainpage.jsp";      }      else {         return "loginFailed.html";      }   }      public void doLogout() {      try {         WebContext ctx = WebContextFactory.get();         HttpServletRequest request = ctx.getHttpServletRequest();         HttpSession session = request.getSession();         Util util = new Util();         String userName = util.getCurrentUserName(session);         UserDatabase.getInstance().logout(userName);         session.removeAttribute("username");         session.removeAttribute("scriptSessionId");         session.invalidate();      } catch (Exception e) {         System.out.println(e.toString());      }      updateUsersOnline();   }      private void updateUsersOnline() {      WebContext webContext= WebContextFactory.get();      ServletContext servletContext = webContext.getServletContext();      ServerContext serverContext = ServerContextFactory.get(servletContext);      webContext.getScriptSessionsByPage("");      String contextPath = servletContext.getContextPath();      if (contextPath != null) {         Collection<ScriptSession> sessions =                            serverContext.getScriptSessionsByPage                                            (contextPath + "/mainpage.jsp");         ScriptProxy proxy = new ScriptProxy(sessions);         proxy.addFunctionCall("showUsersOnline");      }   }      public List<String> getUsersOnline() {      UserDatabase userDb=UserDatabase.getInstance();      return userDb.getLoggedInUsers();   }} The following is the source code of the UserDatabase class package chatroom;import java.util.List;import java.util.Vector;//this class holds currently logged in users//there is no persistencepublic class UserDatabase {      private static UserDatabase userDatabase=new UserDatabase();      private List<String> loggedInUsers=new Vector<String>();      private UserDatabase() {}      public static UserDatabase getInstance() {      return userDatabase;   }      public List<String> getLoggedInUsers() {      return loggedInUsers;   }      public boolean isUserLogged(String userName) {      return loggedInUsers.contains(userName);    }      public void login(String userName) {      loggedInUsers.add(userName);   }      public void logout(String userName) {      loggedInUsers.remove(userName);   }} The Util class is used by the Login class, and it provides helper methods for the sample application. The source code for the Util class is as follows: package chatroom;import java.util.Hashtable;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;public class Util {      public Util() {         }      public String getCurrentUserName() {      //get user name from session      WebContext ctx = WebContextFactory.get();      HttpServletRequest request = ctx.getHttpServletRequest();      HttpSession session=request.getSession();      return getCurrentUserName(session);   }   public String getCurrentUserName(HttpSession session) {      String userName=(String)session.getAttribute("username");      return userName;   }} The logic for the server-side chat room functionality is in the ChatRoomDatabase class. The source code for the ChatRoomDatabase is as follows: package chatroom;import java.util.Collection;import java.util.Date;import java.util.List;import java.util.Vector;import javax.servlet.ServletContext;import org.directwebremoting.ScriptSession;import org.directwebremoting.ServerContext;import org.directwebremoting.ServerContextFactory;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;import org.directwebremoting.proxy.ScriptProxy;public class ChatRoomDatabase {   private static List<String> chatContent = new Vector<String>();   public ChatRoomDatabase() {   }   public void postMessage(String message) {      String user = (new Util()).getCurrentUserName();      if (user != null) {         Date time = new Date();         StringBuffer sb = new StringBuffer();         sb.append(time.toString());         sb.append(" <b><i>");         sb.append(user);         sb.append("</i></b>:  ");         sb.append(message);         sb.append("<br/>");         String newMessage=sb.toString();         chatContent.add(newMessage);         postNewMessage(newMessage);      }   }   public List<String> getChatContent() {      return chatContent;   }   private ScriptProxy getScriptProxyForSessions() {      WebContext webContext = WebContextFactory.get();      ServletContext servletContext = webContext.getServletContext();      ServerContext serverContext = ServerContextFactory.get(servletContext);      webContext.getScriptSessionsByPage("");      String contextPath = servletContext.getContextPath();      if (contextPath != null) {         Collection<ScriptSession> sessions = serverContext               .getScriptSessionsByPage(contextPath + "/mainpage.jsp");         ScriptProxy proxy = new ScriptProxy(sessions);         return proxy;      }      return null;   }   public void postNewMessage(String newMessage) {      ScriptProxy proxy = getScriptProxyForSessions();      if (proxy != null) {         proxy.addFunctionCall("newMessage",newMessage);      }   }} The Chatroom code is surprisingly simple. The chat content is stored in a Vector of Strings. The getChatContent()method just returns the chat content Vector to the browser. The postMessage()method is called when the user sends a new chat message. The method verifies whether the user is logged in, and adds the current time and username to the chat message and then appends the message to the chat content. The method also calls the postNewMessage() method that is used to show new chat content to all logged-in users. Note that the postMessage() method does not return any value. We let DWR and reverse AJAX functionality show the chat message to all users, including the user who sent the message. The getScriptProxyForSessions() and postNewMessage() methods use reverse AJAX to update the chat areas of all logged-in users with the new message. And that is it! The chat room sample is very straightforward and basic functionality is already in place, and the application is ready for further development. Testing the Chat We test the chat room application with three users: Smith, Brown, and Jones. We have given some screenshots of a typical scenario in a chat room here. Both Smith and Brown log into the system and exchange some messages. Both users see empty chat rooms when they log in and start chatting. The empty area that is above the send message input field is reserved for chat content. Smith and Brown exchange some messages as is seen in the following screenshot: The third user, Jones, joins the chat and sees all the previous messages in the chat room. Jones then exchanges some messages with Smith and Brown. Smith and Brown log out from the system leaving Jones alone in the chat room (until she also logs out). This is visible in the following screenshot: Summary This sample application showed how to use DWR in a chat room application. This application makes it clear that DWR makes development of these kind of collaborative applications very easy. DWR itself does not even play a big part in the applications. DWR is just a transparent feature of the application. So developers can concentrate on the actual project and aspects such as persistence of data and a neat user interface, instead of the low-level details of AJAX.    
Read more
  • 0
  • 0
  • 2726

article-image-ejb-3-security
Packt
23 Oct 2009
15 min read
Save for later

EJB 3 Security

Packt
23 Oct 2009
15 min read
Authentication and authorization in Java EE Container Security There are two aspects covered by Java EE container security: authentication and authorization. Authentication is the process of verifying that users are who they claim to be. Typically this is performed by the user providing credentials such as a password. Authorization, or access control, is the process of restricting operations to specific users or categories of users. The EJB specification provides two kinds of authorization: declarative and programmatic, as we shall see later in the article. The Java EE security model introduces a few concepts common to both authentication and authorization. A principal is an entity that we wish to authenticate. The format of a principal is application-specific but an example is a username. A role is a logical grouping of principals. For example, we can have administrator, manager, and employee roles. The scope over which a common security policy applies is known as a security domain, or realm. Authentication For authentication, every Java EE compliant application server provides the Java Authentication and Authorization Service (JAAS) API. JAAS supports any underlying security system. So we have a common API regardless of whether authentication is username/password verification against a database, iris or fingerprint recognition for example. The JAAS API is fairly low level and most application servers provide authentication mechanisms at a higher level of abstraction. These authentication mechanisms are application-server specific however. We will not cover JAAS any further here, but look at authentication as provided by the GlassFish application server. GlassFish Authentication There are three actors we need to define on the GlassFish application server for authentication purposes: users, groups, and realms. A user is an entity that we wish to authenticate. A user is synonymous with a principal. A group is a logical grouping of users and is not the same as a role. A group's scope is global to the application server. A role is a logical grouping of users whose scope is limited to a specific application. Of course for some applications we may decide that roles are identical to groups. For other applications we need some mechanism for mapping the roles onto groups. We shall see how this is done later. A realm, as we have seen, is the scope over which a common security policy applies. GlassFish provides three kinds of realms: file, certificate, and admin-realm. The file realm stores user, group, and realm credentials in a file named keyfile. This file is stored within the application server file system. A file realm is used by web clients using http or EJB application clients. The certificate realm stores a digital certificate and is used for authenticating web clients using https. The admin-realm is similar to the file realm and is used for storing administrator credentials. GlassFish comes pre-configured with a default file realm named file. We can add, edit, and delete users, groups, and realms using the GlassFish administrator console. We can also use the create-file-user option of the asadmin command line utility. To add a user named scott to a group named bankemployee, in the file realm, we would use the command: <target name="create-file-user"> <exec executable="${glassfish.home}/bin/asadmin" failonerror="true" vmlauncher="false"> <arg line="create-file-user --user admin --passwordfile userpassword --groups bankemployee scott"/> </exec> </target> --user specifies the GlassFish administrator username, admin in our example. --passwordfile specifies the name of the file containing password entries. In our example this file is userpassword. Users, other than GlassFish administrators, are identified by AS_ADMIN_USERPASSWORD. In our example the content of the userpassword file is: AS_ADMIN_USERPASSWORD=xyz This indicates that the user's password is xyz. --groups specifies the groups associated with this user (there may be more than one group). In our example there is just one group, named bankemployee. Multiple groups are colon delineated. For example if the user belongs to both the bankemployee and bankcustomer groups, we would specify: --groups bankemployee:bankcustomer The final entry is the operand which specifies the name of the user to be created. In our example this is scott. There is a corresponding asadmin delete-file-user option to remove a user from the file realm. Mapping Roles to Groups The Java EE specification specifies that there must be a mechanism for mapping local application specific roles to global roles on the application server. Local roles are used by an EJB for authorization purposes. The actual mapping mechanism is application server specific. As we have seen in the case of GlassFish, the global application server roles are called groups. In GlassFish, local roles are referred to simply as roles. Suppose we want to map an employee role to the bankemployee group. We would need to create a GlassFish specific deployment descriptor, sun-ejb-jar.xml, with the following element: <security-role-mapping> <role-name>employee</role-name> <group-name>bankemployee</group-name> </security-role-mapping> We also need to access the configuration-security screen in the administrator console. We then disable the Default Principal To Role Mapping flag. If the flag is enabled then the default is to map a group onto a role with the same name. So the bankemployee group will be mapped to the bankemployee role. We can leave the default values for the other properties on the configuration-security screen. Many of these features are for advanced use where third party security products can be plugged in or security properties customized. Consequently we will give only a brief description of these properties here. Security Manager: This refers to the JVM security manager which performs code-based security checks. If the security manager is disabled GlassFish will have better performance. However, even if the security manager is disabled, GlassFish still enforces standard Java EE authentication/authorization. Audit Logging: If this is enabled, GlassFish will provide an audit trail of all authentication and authorization decisions through audit modules. Audit modules provide information on incoming requests, outgoing responses and whether authorization was granted or denied. Audit logging applies for web-tier and ejb-tier authentication and authorization. A default audit module is provided but custom audit modules can also be created. Default Realm: This is the default realm used for authentication. Applications use this realm unless they specify a different realm in their deployment descriptor. The default value is file. Other possible values are admin-realm and certificate. We discussed GlassFish realms in the previous section. Default Principal: This is the user name used by GlassFish at run time if no principal is provided. Normally this is not required so the property can be left blank. Default Principal Password: This is the password of the default principal. JACC: This is the class name of a JACC (Java Authorization Contract for Containers) provider. This enables the GlassFish administrator to set up third-party plug in modules conforming to the JACC standard to perform authorization. Audit Modules: If we have created custom modules to perform audit logging, we would select from this list. Mapped Principal Class: This is only applicable when Default Principal to Role Mapping is enabled. The mapped principal class is used to customize the java.security.Principal implementation class used in the default principal to role mapping. If no value is entered, the com.sun.enterprise.deployment.Group implementation of java.security.Principal is used. Authenticating an EJB Application Client Suppose we want to invoke an EJB, BankServiceBean, from an application client. We also want the application client container to authenticate the client. There are a number of steps we first need to take which are application server specific. We will assume that all roles will have the same name as the corresponding application server groups. In the case of GlassFish we need to use the administrator console and enable Default Principal To Role Mapping. Next we need to define a group named bankemployee with one or more associated users. An EJB application client needs to use IOR (Interoperable Object Reference) authentication. The IOR protocol was originally created for CORBA (Common Object Request Broker Architecture) but all Java EE compliant containers support IOR. An EJB deployed on one Java EE compliant vendor may be invoked by a client deployed on another Java EE compliant vendor. Security interoperability between these vendors is achieved using the IOR protocol. In our case the client and target EJB both happen to be deployed on the same vendor, but we still use IOR for propagating security details from the application client container to the EJB container. IORs are configured in vendor specific XML files rather than the standard ejb-jar.xml file. In the case of GlassFish, this is done within the <ior-security-config> element within the sun-ejb-jar.xml deployment descriptor file. We also need to specify the invoked EJB, BankServiceBean, in the deployment descriptor. An example of the sun-ejb-jar.xml deployment descriptor is shown below: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD       Application Server 9.0 EJB 3.0//EN"       "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd"> <sun-ejb-jar>   <enterprise-beans>     <ejb>       <ejb-name>BankServiceBean</ejb-name>         <ior-security-config>           <as-context>              <auth-method>USERNAME_PASSWORD</auth-method>              <realm>default</realm>              <required>true</required>           </as-context>         </ior-security-config>     </ejb>   </enterprise-beans> </sun-ejb-jar> The as in <as-context> stands for the IOR authentication service. This specifies authentication mechanism details. The <auth-method> element specifies the authentication method. This is set to USERNAME_PASSWORD which is the only value for an application client. The <realm> element specifies the realm in which the client is authenticated. The <required> element specifies whether the above authentication method is required to be used for client authentication. When creating the corresponding EJB JAR file, the sun-ejb-jar.xml file should be included in the META-INF directory, as follows: <target name="package-ejb" depends="compile">     <jar jarfile="${build.dir}/BankService.jar">         <fileset dir="${build.dir}">              <include name="ejb30/session/**" />                           <include name="ejb30/entity/**" />               </fileset>               <metainf dir="${config.dir}">             <include name="persistence.xml" />                          <include name="sun-ejb-jar.xml" />         </metainf>     </jar> </target> As soon as we run the application client, GlassFish will prompt with a username and password form, as follows: If we reply with the username scott and password xyz the program will run. If we run the application with an invalid username or password we will get the following error message: javax.ejb.EJBException: nested exception is: java.rmi.AccessException: CORBA NO_PERMISSION 9998 ..... EJB Authorization Authorization, or access control, is the process of restricting operations to specific roles. In contrast with authentication, EJB authorization is completely application server independent. The EJB specification provides two kinds of authorization: declarative and programmatic. With declarative authorization all security checks are performed by the container. An EJB's security requirements are declared using annotations or deployment descriptors. With programmatic authorization security checks are hard-coded in the EJBs code using API calls. However, even with programmatic authorization the container is still responsible for authentication and for assigning roles to principals. Declarative Authorization As an example, consider the BankServiceBean stateless session bean with methods findCustomer(), addCustomer() and updateCustomer(): package ejb30.session; import javax.ejb.Stateless; import javax.persistence.EntityManager; import ejb30.entity.Customer; import javax.persistence.PersistenceContext; import javax.annotation.security.RolesAllowed; import javax.annotation.security.PermitAll; import java.util.*; @Stateless @RolesAllowed("bankemployee") public class BankServiceBean implements BankService { @PersistenceContext(unitName="BankService") private EntityManager em; private Customer cust; @PermitAll public Customer findCustomer(int custId) { return ((Customer) em.find(Customer.class, custId)); } public void addCustomer(int custId, String firstName, String lastName) { cust = new Customer(); cust.setId(custId); cust.setFirstName(firstName); cust.setLastName(lastName); em.persist(cust); } public void updateCustomer(Customer cust) { Customer mergedCust = em.merge(cust); } } We have prefixed the bean class with the annotation: @RolesAllowed("bankemployee") This specifies the roles allowed to access any of the bean's method. So only users belonging to the bankemployee role may access the addCustomer() and updateCustomer() methods. More than one role can be specified by means of a brace delineated list, as follows: @RolesAllowed({"bankemployee", "bankcustomer"}) We can also prefix a method with @RolesAllowed, in which case the method annotation will override the class annotation. The @PermitAll annotation allows unrestricted access to a method, overriding any class level @RolesAllowed annotation. As with EJB 3 in general, we can use deployment descriptors as alternatives to the @RolesAllowed and @PermitAll annotations. Denying Authorization Suppose we want to deny all users access to the BankServiceBean.updateCustomer() method. We can do this using the @DenyAll annotation: @DenyAll public void updateCustomer(Customer cust) { Customer mergedCust = em.merge(cust); } Of course if you have access to source code you could simply delete the method in question rather than using @DenyAll. However suppose you do not have access to the source code and have received the EJB from a third party. If you in turn do not want your clients accessing a given method then you would need to use the <exclude-list> element in the ejb-jar.xml deployment descriptor: <?xml version="1.0" encoding="UTF-8"?> <ejb-jar version="3.0"                         xsi_schemaLocation="http://java.sun.com/xml/ns/javaee             http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"> <enterprise-beans> <session> <ejb-name>BankServiceBean</ejb-name> </session> </enterprise-beans> <assembly-descriptor> <exclude-list><method> <ejb-name>BankServiceBean</ejb-name> <method-name>updateCustomer</method-name></method></exclude-list> </assembly-descriptor> </ejb-jar> EJB Security Propagation Suppose a client with an associated role invokes, for example, EJB A. If EJB A then invokes, for example, EJB B then by default the client's role is propagated to EJB B. However, you can specify with the @RunAs annotation that all methods of an EJB execute under a specific role. For example, suppose the addCustomer() method in the BankServiceBean EJB invokes the addAuditMessage() method of the AuditServiceBean EJB: @Stateless @RolesAllowed("bankemployee") public class BankServiceBean implements BankService { private @EJB AuditService audit; ....      public void addCustomer(int custId, String firstName,                                                          String lastName) {              cust = new Customer();              cust.setId(custId);              cust.setFirstName(firstName);              cust.setLastName(lastName);              em.persist(cust);              audit.addAuditMessage(1, "customer add attempt");      }      ... } Note that only a client with an associated role of bankemployee can invoke addCustomer(). If we prefix the AuditServiceBean class declaration with @RunAs("bankauditor") then the container will run any method in AuditServiceBean as the bankauditor role, regardless of the role which invokes the method. Note that the @RunAs annotation is applied only at the class level, @RunAs cannot be applied at the method level. @Stateless @RunAs("bankauditor") public class AuditServiceBean implements AuditService { @PersistenceContext(unitName="BankService") private EntityManager em; @TransactionAttribute( TransactionAttributeType.REQUIRES_NEW) public void addAuditMessage (int auditId, String message) { Audit audit = new Audit(); audit.setId(auditId); audit.setMessage(message); em.persist(audit); } } Programmatic Authorization With programmatic authorization the bean rather than the container controls authorization. The javax.ejb.SessionContext object provides two methods which support programmatic authorization: getCallerPrincipal() and isCallerInRole(). The getCallerPrincipal() method returns a java.security.Principal object. This object represents the caller, or principal, invoking the EJB. We can then use the Principal.getName() method to obtain the name of the principal. We have done this in the addAccount() method of the BankServiceBean as follows: Principal cp = ctx.getCallerPrincipal(); System.out.println("getname:" + cp.getName()); The isCallerInRole() method checks whether the principal belongs to a given role. For example, the code fragment below checks if the principal belongs to the bankcustomer role. If the principal does not belong to the bankcustomer role, we only persist the account if the balance is less than 99. if (ctx.isCallerInRole("bankcustomer")) {     em.persist(ac); } else if (balance < 99) {            em.persist(ac);   } When using the isCallerInRole() method, we need to declare all the security role names used in the EJB code using the class level @DeclareRoles annotation: @DeclareRoles({"bankemployee", "bankcustomer"}) The code below shows the BankServiceBean EJB with all the programmatic authorization code described in this section: package ejb30.session; import javax.ejb.Stateless; import javax.persistence.EntityManager; import ejb30.entity.Account; import javax.persistence.PersistenceContext; import javax.annotation.security.RolesAllowed; import java.security.Principal; import javax.annotation.Resource; import javax.ejb.SessionContext; import javax.annotation.security.DeclareRoles; import java.util.*; @Stateless @DeclareRoles({"bankemployee", "bankcustomer"}) public class BankServiceBean implements BankService { @PersistenceContext(unitName="BankService") private EntityManager em; private Account ac; @Resource SessionContext ctx; @RolesAllowed({"bankemployee", "bankcustomer"}) public void addAccount(int accountId, double balance, String accountType) { ac = new Account(); ac.setId(accountId); ac.setBalance(balance); ac.setAccountType(accountType); Principal cp = ctx.getCallerPrincipal(); System.out.println("getname:" + cp.getName()); if (ctx.isCallerInRole("bankcustomer")) { em.persist(ac); } else if (balance < 99) { em.persist(ac); } } ..... } Where we have a choice declarative authorization is preferable to programmatic authorization. Declarative authorization avoids having to mix business code with security management code. We can change a bean's security policy by simply changing an annotation or deployment descriptor instead of modifying the logic of a business method. However, some security rules, such as the example above of only persisting an account within a balance limit, can only be handled by programmatic authorization. Declarative security is based only on the principal and the method being invoked, whereas programmatic security can take state into consideration. Because an EJB is typically invoked from the web-tier by a servlet, JSP page or JSF component, we will briefly mention Java EE web container security. The web-tier and EJB tier share the same security model. So the web-tier security model is based on the same concepts of principals, roles and realms.
Read more
  • 0
  • 0
  • 4478
article-image-integrating-twitter-and-youtube-mediawiki
Packt
23 Oct 2009
5 min read
Save for later

Integrating Twitter and YouTube with MediaWiki

Packt
23 Oct 2009
5 min read
Twitter in MediaWiki Twitter (http://www.twitter.com) is a micro-blogging service that allows users to convey the world (or at least the small portion of it on Twitter) what they are doing, in messages of 140 characters or less. It is possible to embed these messages in external websites, which is what we will be doing for JazzMeet. We can use the updates to inform our wiki's visitors of the latest JazzMeet being held across the world, and they can send a response to the JazzMeet Twitter account. Shorter Links Because Twitter only allows posts of up to 140 characters, many Twitter usersmake use of URL-shortening services such as Tiny URL (http://tinyurl.com), and notlong (http://notlong.com) to turn long web addresses into short, more manageable URLs. Tiny URL assigns a random URL such as http://tinyurl.com/3ut9p4, while notlong allows you to pick a free sub-domain to redirect to your chosen address, such as http://asgkasdgadg.notlong.com. Twitter automatically shortens web addresses in your posts. Creating a Twitter Account Creating a Twitter account is quite easy. Just fill in the username, password, and email address fields, and submit the registration form, once you have read and accepted the terms and conditions. If your chosen username is free, your account is created instantly. Once your account has been created, you can change the settings such as your display name and your profile's background image, to help blur the distinction between your website and your Twitter profile. Colors can be specified as "hex" values under the Design tab of your Twitter account's settings section. The following color codes change the link colors to our JazzMeet's palette of browns and reds: As you can see in the screenshot, JazzMeet's Twitter profile now looks a little more like the JazzMeet wiki. By doing this, the visitors catching up with JazzMeet's events on Twitter will not be confused by a sudden change in color scheme:   Embedding Twitter Feeds in MediaWiki Twitter provides a few ways to embed your latest posts in to your own website(s); simply log in and go to http://www.twitter.com/badges. Flash: With this option you can show just your posts, or your posts and your friends' most recent posts on Twitter. HTML and JavaScript: You can configure the code to show between 1 and 20 of your most recent Twitter posts. As JazzMeet isn't really the sort of wiki the visitors would expect to find on Flash, we will be using the HTML and JavaScript version. You are provided with the necessary code to embed in your website or wiki. We will add it to the JazzMeet skin template, as we want it to be displayed on every page of our wiki, just beneath our sponsor links. Refer to the following code: <div id="twitter_div"><h2 class="twitter-title">Twitter Updates</h2><ul id="twitter_update_list"></ul></div><script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script><script type="text/javascript" src="http://twitter.com/statuses/user_timeline/jazzmeet.json?callback=twitterCallback2&count=5"></script> The JavaScript given at the bottom of the code can be moved just above the </body> tag of your wiki's skin template. This will help your wiki to load other important elements of your wiki before the Twitter status. You will need to replace "jazzmeet" in the code with your own Twitter username, otherwise you will receive JazzMeet's Twitter updates, and not your own. It is important to leave the unordered list of ID twitter_update_list as it is, as this is the element the JavaScript code looks for to insert a list item containing each of your twitter messages in the page. Styling Twitter's HTML We need to style the Twitter HTML by adding some CSS to change the colors and style of the Twitter status code: #twitter_div {background: #FFF;border: 3px #BEB798 solid;color: #BEB798;margin: 0;padding: 5px;width: 165px;}#twitter_div a {color: #8D1425 !important;}ul#twitter_update_list {list-style-type: none;margin: 0;padding: 0;}#twitter_update_list li {color: #38230C;display: block;}h2.twitter-title {color: #BEB798;font-size: 100%;} There are only a few CSS IDs and classes that need to be taken care of. They are as follows: #twitter_div is the element that contains the Twitter feeds. #twitter_update_list is the ID applied to the unordered list. Styling this affects how your Twitter feeds are displayed. .twitter-title is the class applied to the Twitter feed's heading (which you can remove, if necessary). Our wiki's skin for JazzMeet now has JazzMeet's Twitter feed embedded in the righthand column, allowing visitors to keep up-to-date with the latest JazzMeet news. Inserting Twitter as Page Content Media Wiki does not allow JavaScript to be embedded in a page via the "edit" function, so you won't be able to insert a Twitter status feed directly in a page unless it is in the template itself. Even if you inserted the relevant JavaScript links into your MediaWiki skin template, they are relevant only for one Twitter profile ("jazzmeet", in our case).  
Read more
  • 0
  • 0
  • 8266

article-image-class-less-objects-javascript
Packt
23 Oct 2009
7 min read
Save for later

Class-less Objects in JavaScript

Packt
23 Oct 2009
7 min read
JavaScript Objects When you think about a JavaScript object, think a hash. That's all there is to objects - they are just collections of name-value pairs, where the values can be anything including other objects and functions. When an object's property is a function, you can also call it a method. This is an empty object: var myobj = {}; Now you can start adding some meaningful functionality to this object: myobj.name = "My precious";myobj.getName = function() {return this.name}; Note a few things here: this inside a method refers to the current object, as expected you can add/tweak/remove properties at any time, not only during creation Another way to create an object and add properties/methods to it at the same time, is like this: var another = { name: 'My other precious', getName: function() { return this.name; }}; This syntax is the so-called object literal notation - you wrap everything in curly braces { and } and separate the properties inside the object with a comma. Key:value pairs are separated by colons. This syntax is not the only way to create objects though. Constructor Functions Another way to create a JavaScript object is by using a constructor function. Here's an example of a constructor function: function ShinyObject(name) { this.name = name; this.getName = function() { return this.name; }} Now creating an object is much more Java-like: var my = new ShinyObject('ring');var myname = my.getName(); // "ring" There is no difference in the syntax for creating a constructor function as opposed to any other function, the difference is in the usage. If you invoke a function with new, it creates and returns an object and, via this, you have access to modifying the object before you return it. By convention though, constructor functions are named with a capital letter to distinguish visually from normal functions and methods. So which way is better - object literal or constructor function? Well, that depends on your specific task. For example, if you need to create many different, yet similar objects, then the class-like constructors may be the right choice. But if your object is more of a one-off singleton, then object literal is definitely simpler and shorter. OK then, so since there are no classes, how about inheritance? Before we get there, here comes a little surprise - in JavaScript, functions are actually objects. (Actually in JavaScript pretty much everything is an object, with the exception of the few primitive data types - string, boolean, number and undefined. Functions are objects, arrays are objects, even null is an object. Furthermore, the primitive data types can also be converted and used as objects, so for example "string".length is valid.) Function Objects and Prototype Property In JavaScript, functions are objects. They can be assigned to variables, you can add properties and methods to them and so on. Here's an example of a function: var myfunc = function(param) { alert(param);}; This is pretty much the same as: function myfunc(param) { alertparam);} No matter how you create the function, you end up with a myfunc object and you can access its properties and methods. alert(myfunc.length); // alerts 1, the number of parametersalert(myfunc.toString()); // alerts the source code of the function One of the interesting properties that every function object has is the prototype property. As soon as you create a function, it automatically gets a prototype property which points to an empty object. Of course, you can modify the properties of that empty object. alert(typeof myfunc.prototype); // alerts "object"myfunc.prototype.test = 1; // completely OK to do so The question is, how is this prototype thing useful? It's used only when you invoke a function as a constructor to create objects. When you do so, the objects automatically get a secret link to the prototype's properties and can access them as their own properties. Confusing? Let's see an example. A new function: function ShinyObject(name) { this.name = name;} Augmenting the prototype property of the function with some functionality: ShinyObject.prototype.getName = function() { return this.name;}; Using the function as a constructor function to create an object: var iphone = new ShinyObject('my precious');iphone.getName(); // returns "my precious" As you can see the new objects automatically get access to the prototype's properties. And when something is getting functionality "for free", this starts to smell like code reusability and inheritance.   Inheritance via Prototype Now let's see how you can use the prototype to implement inheritance. Here's a constructor function which will be the parent: function NormalObject() { this.name = 'normal'; this.getName = function() { return this.name; };} Now a second constructor: function PreciousObject(){ this.shiny = true; this.round = true;} Now the inheritance part: PreciousObject.prototype = new NormalObject(); Voila! Now you can create precious objects and they'll get all the functionality of the normal objects: var crystal_ball = new PreciousObject();crystal_ball.name = 'Ball, Crystal Ball.';alert(crystal_ball.round); // truealert(crystal_ball.getName()); // "Ball, Crystal Ball." Notice how we needed to create an object with new and assign it to the prototype, because the prototype is just an object. It's not like one constructor function inherited from another, in essence we inherited from an object. JavaScript doesn't have classes that inherit from other classes, here objects inherit from other objects. If you have several constructor functions that will inherit NormalObject objects, you may create new NormalObject() every time, but it's not necessary. Even the whole NormalObject constructor may not be needed. Another way to do the same would be to create one (singleton) normal object and use it as a base for the other objects. var normal = { name: 'normal', getName: function() { return this.name; }}; Then the PreciousObject can inherit like this: PreciousObject.prototype = normal; Inheritance by Copying Properties Since inheritance is all about reusing code, yet another way to implement it is to simply copy properties. Imagine you have these objects: var shiny = { shiny: true, round: true};var normal = { name: 'name me', getName: function() { return this.name; }}; How can shiny get normal's properties? Here's a simple extend() function that loops through and copies properties: function extend(parent, child) { for (var i in parent) { child[i] = parent[i]; }}extend(normal, shiny); // inheritshiny.getName(); // "name me" Now this property copying may look like overhead and not performing too well, but truth is, for many tasks it's just fine. You can also see that this is an easy way to implement mixins and multiple inheritance. Crockford's beget Object Douglas Crockford, a JavaScript guru and creator of JSON, suggests this interesting begetObject() way of implementing inheritance: function begetObject(o) { function F() {} F.prototype = o; return new F();} Here you create a temp constructor so you can use the prototype functionality, the idea is that you create a new object, but instead of starting fresh, you inherit some functionality from another, already existing, object. Parent object: var normal = { name: 'name me', getName: function() { return this.name; }}; A new object inheriting from the parent: var shiny = begetObject(normal); Augment the new object with more functionality: shiny.round = true;shiny.preciousness = true; YUI's extend() Let's wrap up with yet another way to implement inheritance, which is probably the closest to Java, because in this method, it looks like a constructor function inherits from another constructor function, hence it looks a bit like a class inheriting from a class. This method is used in the popular YUI JavaScript library (Yahoo! User Interface) and here's a little simplified version: function extend(Child, Parent) { var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F();} With this method you pass two constructor functions and the first (the child) gets all the properties and methods of the second (the parent) via the prototype property. Summary Let's quickly summarize what we just learned about JavaScript: there are no classes objects inherit from objects object literal notation var o = {}; constructor functions provide Java-like syntax var o = new Object(); functions are objects all function objects have a prototype property And finally, there are dozens of ways to implement inheritance, you can pick and choose depending on your task at hand, personal preferences, team preferences, mood or the current phase of the Moon.  
Read more
  • 0
  • 0
  • 2601
Modal Close icon
Modal Close icon