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

How-To Tutorials

7019 Articles
article-image-basic-dijit-knowledge-dojo
Packt
22 Oct 2009
7 min read
Save for later

Basic Dijit Knowledge in Dojo

Packt
22 Oct 2009
7 min read
All Dijits can be subclassed to change parts of their behavior, and then used as the original Dijits, or you can create your own Dijits from scratch and include existing Dijits (Forms, buttons, calendars, and so on) in a hierarchical manner. All Dijits can be created in either of the following two ways: Using the dojoType markup property inside selected tags in the HTML page. Programmatic creation inside any JavaScript. For instance, if you want to have a ColorPalette in your page, you can write the following: <div dojoType="dijit.ColorPalette"></div> But you also need to load the required Dojo packages, which consist of the ColorPalette and any other things it needs. This is generally done in a script statement in the <head> part of the HTML page, along with any CSS resources and the djConfig declaration. So a complete example would look like this: <html> <head> <title>ColorPalette</title> <style> @import "dojo-1.1b1/dojo/resources/dojo.css"; @import "dojo-1.1b1/dijit/themes/tundra/tundra.css"; </style> <script type="text/javascript"> djConfig= { parseOnLoad: true } </script> <script type="text/javascript" src="dojo-1.1b1/dojo/dojo.js"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.ColorPalette"); </script> </head> <body class=”tundra”> <div dojoType="dijit.ColorPalette"></div> </body> </html> Obviously, this shows a simple color palette, which can be told to call a function when a choice has been made. But if we start from the top, I've chosen to include two CSS files in the <style> tag. The first one, dojo.css, is a reset.css, which gives lists, table elements, and various other things their defaults. The file itself is quite small and well commented. The second file is called tundra.css and is a wrapper around lots of other stylesheets; some are generic for the theme it represents, but most are specific for widgets or widget families. The two ways to create Dijits So putting a Dojo widget in your page is very simple. If you would want the ColorPalette dynamically in a script instead, remove the highlighted line just before the closing body tag and instead write the following: <script> new dijit.ColorPalette({}, dojo.byId('myPalette')); </script> This seems fairly easy, but what's up with the empty object literal ( {} ) as the first argument? Well, as some Dijits take few arguments and others more, all arguments to a Dijit get stuffed into the first argument and the others, the last argument is (if needed) the DOM node which the Dijit shall replace with its own content somewhere in the page. The default is, for all Dijits, that if we only give one argument to the constructor, this will be taken as the DOM node where the Dijit is to be created. Let's see how to create a more complex Dijit in our page, a NumberSpinner. This will create a NumberSpinner that is set at the value '200' and which has '500' as a maximum, showing no decimals. To create this NumberSpinner dynamically, we would write the following: <input type="text" name="date1" value="2008-12-30" dojoType="dijit.form.DateTextBox"/> One rather peculiar feature of markup-instantiation of Dijits is that you can use almost any kind of tag for the Dijit. The Dijit will replace the element with its own template when it is initialized. Certain Dijits work in a more complicated fashion and do not replace child nodes of the element where they're defined, but wrap them instead. However, each Dijit has support for template HTML which will be inserted, with variable substitutions whenever that Dijit is put in the page. This is a very powerful feature, since when you start creating your own widgets, you will have an excellent system in place already which constrains where things will be put and how they are called. This means that when you finish your super-complicated graph drawing widget and your client or boss wants three more just like it on the same page, you just slap up three more tags which have the dojoType defining your widget. How do I find my widget? You already know that you can use dojo.byId('foo') as a shorter version of document.getElementById('foo'). If you still think that dojo.byId is too long, you can create a shorthand function like this: var $ = dojo.byId; And then use $('foo') instead of dojo.byId for simple DOM node lookup. But Dijits also seem to have an id. Are those the same as the ids of the DOM node they reside in or what? Well, the answer is both yes and no. All created Dijit widgets have a unique id. That id can be the same string as the id that defines the DOM node where they're created, but it doesn't have to be. Suppose that you create a Dijit like this: <div id='foo' dojoType='dijit._Calendar'></div> The created Dijit will have the same Dijit id as the id of the DOM node it was created in, because no others were given. But can you define another id for the widget than for its DOM node? Sure thing. There's a magic attribute called widgetId. So we could do the following: <div id='foo' dojoType='dijit._Calendar' widgetId='bar'></div> This would give the widget the id of 'bar'. But, really, what is the point? Why would we care the widget / Dijit has some kind of obscure id? All we really need is the DOM node, right? Not at all. Sure, you might want to reach out and do bad things to the DOM node of a widget, but that object will not be the widget and have none of its functions. If you want to grab hold of a widget instance after it is created, you need to know its widget id, so you can call the functions defined in the widget. So it's almost its entire reason to exist! So how do I get hold of a widget obejct now that I have its id? By using dijit.byId(). These two functions look pretty similar, so here is a clear and easy to find (when browsing the book) explanation: dojo.byId(): Returns the DOM node for the given id. dijit.byId(): Returns the widget object for the given widget id. Just one more thing. What happens if we create a widget and don't give either a DOM or widget id? Does the created widget still get an id? How do we get at it? Yes, the widget will get a generated id, if we write the following: <div dojoType='dijit._Calendar'></div> The widget will get a widget id like this: dijit__Calendar_0. The id will be the string of the file or namespace path down to the .js file which declares the widget, with / exchanged to _, and with a static widget counter attached to the end.
Read more
  • 0
  • 0
  • 3249

article-image-soap-and-php-5
Packt
22 Oct 2009
16 min read
Save for later

SOAP and PHP 5

Packt
22 Oct 2009
16 min read
SOAP SOAP, formerly known as Simple Object Access Protocol (until the acronym was dropped in version 1.2), came around shortly after XML-RPC was released. It was created by a group of developers with backing from Microsoft. Interestingly, the creator of XML-RPC, David Winer, was also one of the primary contributors to SOAP. Winer released XML-RPC before SOAP, when it became apparent to him that though SOAP was still a way away from being completed, there was an immediate need for some sort of web service protocol. Like XML-RPC, SOAP is an XML-based web service protocol. SOAP, however, satisfies a lot of the shortcomings of XML-RPC: namely the lack of user-defined data types, better character set support, and rudimentary security. It is quite simply, a more powerful and flexible protocol than REST or XML-RPC. Unfortunately, sacrifices come with that power. SOAP is a much more complex and rigid protocol. For example, even though SOAP can stand alone, it is much more useful when you use another XML-based standard, called Web Services Descriptor Language (WSDL), in conjunction with it. Therefore, in order to be proficient with SOAP, you should also be proficient with WSDL. The most-levied criticism of SOAP is that it is overly complex. Indeed, SOAP is not simple. It is long and verbose. You need to know how namespaces work in XML. SOAP can rely heavily on other standards. This is true for most implementations of SOAP, including Microsoft Live Search, which we will be looking at. The most common external specifications used by a SOAP-based service is WSDL to describe its available services, and that, in turn, usually relies on XML Schema Data (XSD) to describe its data types. In order to "know" SOAP, it would be extremely useful to have some knowledge of WSDL and XSD. This will allow one to figure out how to use the majority of SOAP services. We are going to take a "need to know" approach when looking at SOAP. Microsoft Live Search's SOAP API uses WSDL and XSD, so we will take a look at SOAP with the other two in mind. We will limit our discussion on how to gather information about the web service that you, as a web service consumer, would need and how to write SOAP requests using PHP 5 against it. Even though this article will just introduce you to the core necessities of SOAP, there is a lot of information and detail. SOAP is very meticulous and you have to keep track of a fair amount of things. Do not be discouraged, take notes if you have to, and be patient. All three, SOAP, WSD, and XSD are maintained by the W3C. All three specifications are available for your perusal. The official SOAP specification is located at http://www.w3.org/TR/soap/. WSDL specification is located at http://www.w3.org/TR/wsdl. Finally, the recommended XSD specification can be found at http://www.w3.org/XML/Schema. Web Services Descriptor Language (WSDL) With XML Schema Data (XSD) Out of all the drawbacks of XML-RPC and REST, there is one that is prominent. Both of these protocols rely heavily on good documentation by the service provider in order to use them. Lacking this, you really do not know what operations are available to you, what parameters you need to pass in order to use them, and what you should expect to get back. Even worse, an XML-RPC or REST service may be poorly or inaccurately documented and give you inaccurate or unexpected results. SOAP addresses this by relying on another XML standard called WSDL to set the rules on which web service methods are available, how parameters should be passed, and what data type might be returned. A service's WSDL document, basically, is an XML version of the documentation. If a SOAP-based service is bound to a WSDL document, and most of them are, requests and responses must adhere to the rules set in the WSDL document, otherwise a fault will occur. WSDL is an acronym for a technical language. When referring to a specific web service's WSDL document, people commonly refer to the document as "the WSDL" even though that is grammatically incorrect. Being XML-based, this allows clients to automatically discover everything about the functionality of the web service. Human-readable documentation is technically not required for a SOAP service that uses a WSDL document, though it is still highly recommended. Let's take a look at the structure of a WSDL document and how we can use it to figure out what is available to us in a SOAP-based web service. Out of all three specifications that we're going to look at in relationship to SOAP, WSDL is the most ethereal. Both supporters and detractors often call writing WSDL documents a black art. As we go through this, I will stress the main points and just briefly note other uses or exceptions. Basic WSDL Structure Beginning with a root definitions element, WSDL documents follow this basic structure:     <definitions>        <types>        …        </types>        <message>        …        </message>        <portType>        …        </portType>        <binding>        …        </binding>    </definitions> As you can see, in addition to the definitions element, there are four main sections to a WSDL document: types, message, portType, and binding. Let's take a look at these in further detail. Google used to provide a SOAP service for their web search engine. However, this service is now deprecated, and no new developer API keys are given out. This is unfortunate because the service was simple enough to learn SOAP quickly, but complex enough to get a thorough exposure to SOAP. Luckily, the service itself is still working and the WSDL is still available. As we go through WSDL elements, we will look at the Google SOAP Search WSDL and Microsoft Live Search API WSDL documents for examples. These are available at http://api.google.com/GoogleSearch.wsdl and http://soap.search.msn.com/webservices.asmx?wsdl respectively. definitions Element This is the root element of a WSDL document. If the WSDL relies on other specifications, their namespace declarations would be made here. Let's take a look at Google's WSDL's definition tag:     <definitions name="GoogleSearch"        targetNamespace="urn:GoogleSearch"                                                > The more common ones you'll run across are xsd for schema namespace, wsdl for the WSDL framework itself, and soap and soapenc for SOAP bindings. As these namespaces refer to W3C standards, you will run across them regardless of the web service implementation. Note that some searches use an equally common prefix, xs, for XML Schema. tns is another common namespace. It means "this namespace" and is a convention used to refer to the WSDL itself. types Element In a WSDL document, data types used by requests and responses need to be explicitly declared and defined. The textbook answer that you'll find is that the types element is where this is done. In theory, this is true. In practice, this is mostly true. The types element is used only for special data types. To achieve platform neutrality, WSDL defaults to, and most implementations use, XSD to describe its data types. In XSD, many basic data types are already included and do not need to be declared. Common Built-in XSD Data Types Time Date Boolean String Base64Binary Float Double Integer Byte For a complete list, see the recommendation on XSD data types at http://www.w3.org/TR/xmlschema-2/. If the web service utilizes nothing more than these built-in data types, there is no need to have special data types, and thus, types will be empty. So, the data types will just be referred to later, when we define the parameters. There are three occasions where data types would be defined here: If you want a special data type that is based on a built-in data type. Most commonly this is a built-in, whose value is restricted in some way. These are known as simple types. If the data type is an object, it is known as a complex type in XSD, and must be declared. An array, which can be described as a hybrid of the former two. Let's take a look at some examples of what we will encounter in the types element. Simple Type Sometimes, you need to restrict or refine a value of a built-in data type. For example, in a hospital's patient database, it would be ludicrous to have the length of a field called Age to be more than three digits. To add such a restriction in the SOAP world, you would have to define Age here in the types section as a new type. Simple types must be based on an existing built-in type. They cannot have children or properties like complex types. Generally, a simple type is defined with the simpleType element, the name as an attribute, followed by the restriction or definition. If the simple type is a restriction, the built-in data type that it is based on, is defined in the base attribute of the restriction element. For example, a restriction for an age can look like this:     <xsd:simpleType name="Age">        <xsd:restriction base="xsd:integer">            <xsd:totalDigits value="3" />        </xsd:restriction>    </xsd:simpleType> Children elements of restriction define what is acceptable for the value. totalDigits is used to restrict a value based on the character length. A table of common restrictions follows: Restriction Use Applicable In enumeration Specifies a list of acceptable values. All except boolean fractionDigits Defines the number of decimal places allowed. Integers length Defines the exact number of characters allowed. Strings and all binaries maxExclusive/ maxInclusive Defines the maximum value allowed. If Exclusive is used, value cannot be equal to the definition. If Inclusive, can be equal to, but not greater than, this definition. All numeric and dates minLength/ maxLength Defines the minimum and maximum number of characters or list items allowed. Strings and all binaries minExclusive/ minInclusive Defines the minimum value allowed. If Exclusive is used, value cannot be equal to the definition. If Inclusive, can be equal to, but not less than, this definition. All numeric and dates pattern A regular expression defining the allowed values. All totalDigits Defines the maximum number of digits allowed. Integers whiteSpace Defines how tabs, spaces, and line breaks are handled. Can be preserve (no changes), replace (tabs and line breaks are converted to spaces) or collapse (multiple spaces, tabs, and line breaks are converted to one space. Strings and all binaries A practical example of a restriction can be found in the MSN Search Web Service WSDL. Look at the section that defines SafeSearchOptions.     <xsd:simpleType name="SafeSearchOptions">        <xsd:restriction base="xsd:string">            <xsd:enumeration value="Moderate" />            <xsd:enumeration value="Strict" />            <xsd:enumeration value="Off" />    </xsd:restriction> </xsd:simpleType> In this example, the SafeSearchOptions data type is based on a string data type. Unlike a regular string, however, the value that SafeSearchOptions takes is restricted by the restriction element. In this case, the several enumeration elements that follow. SafeSearchOptions can only be what is given in this enumeration list. That is, SafeSearchOptions can only have a value of "Moderate", "Strict", or "Off". Restrictions are not the only reason to use a simple type. There can also be two other elements in place of restrictions. The first is a list. If an element is a list, it means that the value passed to it is a list of space-separated values. A list is defined with the list element followed by an attribute named itemType, which defines the allowed data type. For example, this example specifies an attribute named listOfValues, which comprises all integers.     <xsd:simpleType name="listOfValues">        <xsd:list itemType="xsd:integer" />    </xsd:simpleType> The second is a union. Unions are basically a combination of two or more restrictions. This gives you a greater ability to fine-tune the allowed value. Back to our age example, if our service was for a hospital's pediatrics ward that admits only those under 18 years old, we can restrict the value with a union.     <xsd:simpleType name="Age">        <xsd:union>            <xsd:simpleType>                <xsd:restriction base="decimal">                        <xsd:minInclusive value="0" />                </xsd:restriction>            </xsd:simpleType>            <xsd:simpleType>                <xsd:restriction base="decimal">                        <xsd:maxExclusive value="18" />                </xsd:restriction>            </xsd:simpleType>        </xsd:union>    </xsd:simpleType> Finally, it is important to note that while simple types are, especially in the case of WSDLs, used mainly in the definition of elements, they can be used anywhere that requires the definition of a number. For example, you may sometimes see an attribute being defined and a simple type structure being used to restrict the value. Complex Type Generically, a complex type is anything that can have multiple elements or attributes. This is opposed to a simple type, which can have only one element. A complex type is represented by the element complexType in the WSDL. The most common use for complex types is as a carrier for objects in SOAP transactions. In other words, to pass an object to a SOAP service, it needs to be serialized into an XSD complex type in the message. The purpose of a complexType element is to explicitly define what other data types make up the complex type. Let's take a look at a piece of Google's WSDL for an example:     <xsd:complexType name="ResultElement">        <xsd:all>            <xsd:element name="summary" type="xsd:string"/>            <xsd:element name="URL" type="xsd:string"/>            <xsd:element name="snippet" type="xsd:string"/>            <xsd:element name="title" type="xsd:string"/>            <xsd:element name="cachedSize" type="xsd:string"/>            <xsd:element name=                        "relatedInformationPresent" type="xsd:boolean"/>            <xsd:element name="hostName" type="xsd:string"/>            <xsd:element name=                        "directoryCategory" type="typens:DirectoryCategory"/>            <xsd:element name="directoryTitle" type="xsd:string"/>        </xsd:all>    </xsd:complexType> First thing to notice is how the xsd: namespace is used throughout types. This denotes that these elements and attributes are part of the XSD specification. In this example, a data type called ResultElement is defined. We don't exactly know what it is used for right now, but we know that it exists. An element tag denotes complex type's equivalent to an object property. The first property of it is summary, and the type attribute tells us that it is a string, as are most properties of ResultElement. One exception is relatedInformationPresent, which is a Boolean. Another exception is directoryCategory. This has a data type of DirectoryCategory. The namespace used in the type attribute is typens. This tells us that it is not an XSD data type. To find out what it is, we'll have to look for the namespace declaration that declared typens.
Read more
  • 0
  • 0
  • 5329

article-image-using-lists-and-tables-mediawiki
Packt
22 Oct 2009
6 min read
Save for later

Using Lists and Tables with MediaWiki

Packt
22 Oct 2009
6 min read
Using Lists with MediaWiki The three types of lists available in HTML—unordered lists, ordered lists, and definition lists—are also available in MediaWiki. In MediaWiki, we can use both HTML and wiki syntax for creating lists. We will explore both techniques in this article. Unordered List Creating unordered lists in MediaWiki is very simple. In order to create an unordered list in MediaWiki using wiki syntax, keep the following rules in mind: Use the asterisk (*) sign at the beginning of each line for creating a list element. The number of asterisks you add before the line will indicate the level of list element in the unordered list. For example, ** will indicate a second-level list element, while *** will indicate a third-level list element, and so on. In order to restart an unordered list, put a wiki line break (an empty line) at the end of the list. Then you can start another list using *. Let's open a new page and write the following content in order to create an unordered list: * Ghost Directory - North America:** United States of America.*** Florida.*** New York.**** Long Island**** Manhattan**** Cooney Island*** New Jersey*** Michigan* Ghost Directory - Europe:** United Kingdom*** Liverpool*** Fulham** Ireland** Finland** SwedenOther directories.* Bangladesh* India. Now let's click on Save page to see the unordered lists that we have created: Now let us see how to create the same list using HTML syntax: <ul><li>Ghost Directory - North America :   <ul><li>United States of America.      <ul><li> Florida.            <li> New York.            <ul><li>Long Island                   <li>Manhattan                   <li>Cooney Island            </ul>            <li> New Jersey            <li> Michigan      </ul>   </ul></ul><ul><li> Ghost Directory - Europe:      <ul><li> United Kingdom            <ul><li>Liverpool                   <li>Fulham            </ul>       <li>Ireland <li>Finland <li>Sweden </ul></ul>Other directories.<ul><li> Bangladesh <li> India.</ul> From the previous two examples we see that the wiki syntax definitely gives us a less hard time generating the unordered list. Ordered List The basic difference between unordered and ordered lists is that while we see only bullets for unordered lists, in an ordered list we will see numbers like 1,2... etc. In order to create an ordered list in MediaWiki using wiki syntax, keep the following rules in mind: Use the hash (#) sign for creating each list element. The number of hashes you add before the line will indicate the level of list element in the ordered list. For example, ## will indicate a second-level list element, ### will indicate a third-level list element, and so on. In order to restart an ordered list, put a blank line at the end of the list. Then you can then start another list using #. Now look at the following example in MediaWiki to create an ordered list: In order to submit your story for the Monthly Haunted story contest, you have to follow the guidelines below:Stories can have the following Categories# Novel# Short Story# Real life story# ArticlesHere are the writing guidelines# Basic Guidelines## Story must be within 1200 words.## Computer Typed:### Font size: 12 pt### Paragraph: double line break### Font Name: Times New Roman## Well formatted with a front page## Front page content:### Story name### Author Name### Submission Date### Category### Author Email Address# All entries must be submitted before 1st October, 2006# For any query, contact storyteller@haunted.com Click on Save page to see the ordered list, which appears as shown below: Now if the same example is created with HTML tags, we will see that the wiki syntax is much easier to apply than HTML syntax. However, there still are some places where we have to use HTML instead of wiki syntax. Take this example: we have a list of ghost sighting for the last 100 years starting from early 1900s. We want to show the sightings sequentially using the years rather than 1, 2, 3, etc. In MediaWiki all ordered lists start from 1, and we cannot define any attribute for wiki syntax. Hence it is not possible for us to start with predefined numbering. Maybe future MediaWiki versions will have something to accommodate this feature. So let's see how we can perform the task with HTML: Here is the list of ghost sightings in the last 100 years <ol start=1905> <li> Ghosts Sighted in Year 1905 <ol><li>3rd January: Ghost of ancient Mariner sighted at Port City, Florida, USA <li>10th January: Ghost of a Little girl sighted at a village in Ireland <li>5th May: A werewolf sighted in a mountain region of Colorado. <li>25th December: A Christmas ghost sighted in Texas </ol> <li> Ghosts Sighted in Year 1906 <ol><li> 3 sightings have been reported but details about place and time are not available. </ol> <li> Ghosts Sighted in Year 1907 <ol><li>3rd January: Ghost of ancient Mariner sighted again after 2 years at Port City, Florida, USA <li>11th June: Ghost of a Mathematician sighted at an old valley, Texas </ol> </ol> <ol start=1937> <li> Ghosts Sighted in Year 1937 <ol><li>January, First Vampire existence found in United Kingdom <li>April, A sailor ghost was sighted on a ship bound to USA from UK <li> July, The sailor ghost again sighted on a ship bound to USA from UK - it was named Atlantic Nightmare. </ol> </ol> Click on Save page to see the output as shown in the following screenshot: So, from the previous example, we see that it's better to use HTML tags in special cases, where wiki syntax is not of much help. This is the reason why MediaWiki allows the use of HTML tags for formatting.
Read more
  • 0
  • 0
  • 5933

article-image-building-jsfejb3-applications
Packt
22 Oct 2009
15 min read
Save for later

Building JSF/EJB3 Applications

Packt
22 Oct 2009
15 min read
Building JSF/EJB3 Applications This practical article shows you how to create a simple data-driven application using JSF and EJB3 technologies. The article also shows you how to effectively use NetBeans IDE when building enterprise applications. What We Are Going to Build The sample application we are building throughout the article is very straightforward. It offers just a few pages. When you click the Ask us a question link on the welcomeJSF.jsp page, you will be taken to the following page, on which you can submit a question:     Once you’re done with your question, you click the Submit button. As a result, the application persist your question along with your email in the database. The next page will look like this:     The web tier of the application is build using the JavaServer Faces technology, while EJB is used to implement the database-related code. Software You Need to Follow the Article Exercise To build the sample discussed here, you will need the following software components installed on your computer: Java Standard Development Kit (JDK) 5.0 or higher Sun Java System Application Server Platform Edition 9 MySQL NetBeans IDE 5.5 Setting Up the Database The first step in building our application is to set up the database to interact with. In fact, you could choose any database you like to be the application’s backend database. For the purpose of this article, though, we will discuss how to use MySQL. To keep things simple, let’s create a questions table that contains just three columns, outlined in the following table: Column Type Description trackno INTEGER AUTO_INCREMENT PRIMARY KEY Stores a track number generated automatically when a row is inserted. user_email VARCHAR(50) NOT NULL   question VARCHAR(2000) NOT NULL   Of course, a real-world questions table would contain a few more columns, for example, dateOfSubmission containing the date and time of submitting the question. To create the questions table, you first have to create a database and grant the required privileges to the user with which you are going to connect to that database. For example, you might create database my_db and user usr identified by password pswd. To do this, you should issue the following SQL commands from MySQL Command Line Client:   CREATE DATABASE my_db; GRANT CREATE, DROP, SELECT, INSERT, UPDATE, DELETE ON my_db.* TO 'usr'@'localhost' IDENTIFIED BY 'pswd'; In order to use the newly created database for subsequent statements, you should issue the following statement:   USE my_db   Finally, create the questions table in the database as follows:   CREATE TABLE questions(      trackno INTEGER AUTO_INCREMENT PRIMARY KEY,      user_email VARCHAR(50) NOT NULL,      question  VARCHAR(2000) NOT NULL ) ENGINE = InnoDB;     Once you’re done, you have the database with the questions table required to store incoming users’ questions. Setting Up a Data Source for Your MySQL Database Since the application we are going to build will interact with MySQL, you need to have installed an appropriate MySQL driver on your application server. For example, you might want to install MySQL Connector/J, which is the official JDBC driver for MySQL. You can pick up this software from the "downloads" page of the MySQL AB website at http://mysql.org/downloads/. Install the driver on your GlassFish application server as follows: Unpack the downloaded archive containing the driver to any directory on your machine Add mysql-connector-java-xxx-bin.jar to the CLASSPATH environment variable Make sure that your GlassFish application server is up and running Launch the Application Server Admin Console by pointing your browser at http://localhost:4848/ Within the Common Tasks frame, find and double-click the ResourcesJDBCNew Connection Pool node On the New Connection Pool page, click the New… button The first step of the New Connection Pool master, set the fields as shown in the following table: Setting Value Name jdbc/mysqlPool Resource type javax.sql.DataSource Database Vendor mysql   Click Next to move on to the second page of the master On the second page of New Connection Pool, set the properties to reflect your database settings, like that shown in the following table: Name Value databaseName my_db serverName localhost port 3306 user usr password pswd   Once you are done with setting the properties, click Finish. The newly created jdbc/mysqlPool connection pool should appear on the list. To check it, you should click its link to open it in a window, and then click the Ping button. If everything is okay, you should see a message telling you Ping succeeded Creating the Project The next step is to create an application project with NetBeans. To do this, follow the steps below: Choose File/New project and then choose the EnterpriseEnterprise Application template for the project. Click Next On the Name and Location page of the master, specify the name for the project: JSF_EJB_App. Also make sure that Create EJB Module and Create Web Application Module are checked. And click Finish As a result, NetBeans generates a new enterprise application in a standard project, containing actually two projects: an EJB module project and Web application project. In this particular example, you will use the first project for EJBs and the second one for JSF pages. Creating Entity Beans and Persistent Unit You create entity beans and the persistent unit in the EJB module project—in this example this is the JSF_EJB_App-ejb project. In fact, the sample discussed here will contain the only entity bean: Question. You might automatically generate it and then edit as needed. To generate it with NetBeans, follow the steps below: Make sure that your Sun Java System Application Server is up and running In the Project window, right click JSF_EJB_App-ejb project, and then choose New/Entity Classes From Database. As a result, you’ll be prompted to connect to your Sun Java System Application Server. Do it by entering appropriate credentials. In the New Entity Classes from Database window, select jdbc/mysqlPool from the Data Source combobox. If you recall from the Setting up a Data Source for your MySQL database section discussed earlier in this article, jdbc/mysqlPool is a JDBC connection pool created on your application server In the Connect dialog appeared, you’ll be prompted to connect to your MySQL database. Enter password pswd, set the Remember password during this session checkbox, and then click OK In the Available Tables listbox, choose questions, and click Add button to move it to the Selected Tables listbox. After that, click Next On the next page of the New Entity Classes from Database master, fill up the Package field. For example, you might choose the following name: myappejb.entities. And change the class name from Questions to Question in the Class Names box. Next, click the Create Persistent Unit button In the Create Persistent Unit window, just click the Create button, leaving default values of the fields In the New Entity Classes from Database dialog, click Finish As a result, NetBeans will generate the Question entity class, which you should edit so that the resultant class looks like the following:   package myappejb.entities; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "questions") public class Question implements Serializable { @Id @Column(name = "trackno") private Integer trackno; @Column(name = "user_email", nullable = false) private String userEmail; @Column(name = "question", nullable = false) private String question; public Question() { } public Integer getTrackno() { return this.trackno; } public void setTrackno(Integer trackno) { this.trackno = trackno; } public String getUserEmail() { return this.userEmail; } public void setUserEmail(String userEmail) { this.userEmail = userEmail; } public String getQuestion() { return this.question; } public void setQuestion(String question) { this.question = question; } }     Once you’re done, make sure to save all the changes made by choosing File/Save All. Having the above code in hand, you might of course do without first generating the Question entity from the database, but simply create an empty Java file in the myappejb.entities package, and then insert the above code there. Then you could separately create the persistent unit. However, the idea behind building the Question entity with the master here is to show how you can quickly get a required piece of code to be then edited as needed, rather than creating it from scratch. Creating Session Beans To finish with the JSF_EJB_App-ejb project, let’s proceed to creating the session bean that will be used by the web tier. In particular, you need to create the QuestionSessionBean session bean that will be responsible for persisting the data a user enters on the askquestion page. To generate the bean’s frame with a master, follow the steps below: In the Project window, right click JSF_EJB_App-ejb project, and then choose New/Session Bean In the New Session Bean window, enter EJB name: QuestionSessionBean. Then specify the package: myappejb.ejb. Make sure that the Session Type is set to Stateless and Create Interface is set to Remote. Click Finish As a result, NetBeans should generate two Java files: QuestionSessionBean.java and QuestionSessionRemote.java. You should modify QuestionSessionBean.java so that it contains the following code:   package myappejb.ejb; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceUnit; import javax.transaction.UserTransaction; import myappejb.entities.Question; @Stateless <b>@TransactionManagement(TransactionManagementType.BEAN)</b> public class QuestionSessionBean implements myappejb.ejb.QuestionSessionRemote { /** Creates a new instance of QuestionSessionBean */ public QuestionSessionBean() { } @Resource private UserTransaction utx; @PersistenceUnit(unitName = "JSF_EJB_App-ejbPU") private EntityManagerFactory emf; private EntityManager getEntityManager() { return emf.createEntityManager(); } public void save(Question question) throws Exception { EntityManager em = getEntityManager(); try { utx.begin(); em.joinTransaction(); em.persist(question); utx.commit(); } catch (Exception ex) { try { utx.rollback(); throw new Exception(ex.getLocalizedMessage()); } catch (Exception e) { throw new Exception(e.getLocalizedMessage()); } } finally { em.close(); } } }   Next, modify the QuestionSessionRemote.java so that it looks like this:   package myappejb.ejb; import javax.ejb.Remote; import myappejb.entities.Question; @Remote public interface QuestionSessionRemote { void save(Question question) throws Exception; }   Choose File/Save All to save the changes made. That’s it. You just finished with your EJB module project. Adding JSF Framework to the Project Now that you have the entity and session beans created, let’s switch to the JSF_EJB_App-war project, where you’re building the web tier for the application.Before you can proceed to building JSF pages, you need to add the JavaServer Faces framework to the JSF_EJB_App-war project. To do this, follow the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose Properties In the Project Properties window, select Frameworks from Categories, and click Add button. As a result, the Add a Framework dialog should appear In the Add a Framework dialog, choose JavaServer Faces and click OK Then click OK in the Project Properties dialog As a result, NetBeans adds the JavaServer Faces framework to the JSF_EJB_App-war project. Now if you extend the Configuration Files folder under the JSF_EJB_App-war project node in the Project window, you should see, among other configuration files, faces-config.xml there. Also notice the appearance of the welcomeJSF.jsp page in the Web Pages folder Creating JSF Managed Beans The next step is to create managed beans whose methods will be called from within the JSF pages. In this particular example, you need to create only one such bean: let’s call it QuestionController. This can be achieved by following the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose New/Empty Java File In the New Empty Java File window, enter QuestionController as the class name and enter myappjsf.jsf in the Package field. Then, click Finish In the generated empty java file, insert the following code:   package myappjsf.jsf; import javax.ejb.EJB; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import myappejb.entities.Question; import myappejb.ejb.QuestionSessionBean; public class QuestionController { @EJB private QuestionSessionBean sbean; private Question question; public QuestionController() { } public Question getQuestion() { return question; } public void setQuestion(Question question) { this.question = question; } public String createSetup() { this.question = new Question(); this.question.setTrackno(null); return "question_create"; } public String create() { try { Integer trck = sbean.save(question); addSuccessMessage("Your question was successfully submitted."); } catch (Exception ex) { addErrorMessage(ex.getLocalizedMessage()); } return "created"; } public static void addErrorMessage(String msg) { FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg); FacesContext fc = FacesContext.getCurrentInstance(); fc.addMessage(null, facesMsg); } public static void addSuccessMessage(String msg) { FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); FacesContext fc = FacesContext.getCurrentInstance(); fc.addMessage("successInfo", facesMsg); } }   Next, you need to add information about the newly created JSF managed bean to the faces-config.xml configuration file automatically generated when adding the JSF framework to the project. Find this file in the following folder: JSF_EJB_App-warWeb PagesWEB-INF in the Project window, and then insert the following tag between the and tags:   <managed-bean> <managed-bean-name>questionJSFBean</managed-bean-name> <managed-bean-class>myappjsf.jsf.QuestionController</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>   Finally, make sure to choose File/Save All to save the changes made in faces-config.xml as well as in QuestionController.java. Creating JSF Pages To keep things simple, you create just one more JSF page: askquestion.jsp, where a user can submit a question. First, though, let’s modify the welcomeJSF.jsp page so that you can use it to move on to askquestion.jsp and then return to, once a question has been submitted. To achieve this, modify welcomeJSF.jsp as follows:   <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <!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=UTF-8"> <title>JSP Page</title> </head> <body> <f:view> <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/> <h:form> <h1><h:outputText value="Ask us a question" /></h1> <h:commandLink action="#{questionJSFBean.createSetup}" value="New question"/> <br> </h:form> </f:view> </body> </html> Now you can move on and create askquestion.jsp. To do this, follow the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose New/JSP In the New JSP File window, enter askquestion as the name for the page, and click Finish Modify the newly created askquestion.jsp so that it finally looks like this:   <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <html>     <head>         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />         <title>New Question</title>     </head>     <body>         <f:view>             <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>             <h1>Your question, please!</h1>             <h:form>                 <h:panelGrid columns="2">                     <h:outputText value="Your Email:"/>                     <h:inputText id="userEmail" value= "#{questionJSFBean.question.userEmail}" title="Your Email" />                     <h:outputText value="Your Question:"/>                     <h:inputTextarea id="question" value= "#{questionJSFBean.question.question}"  title="Your Question" rows ="5" cols="35" />                 </h:panelGrid>                 <h:commandLink action="#{questionJSFBean.create}" value="Create"/>                 <br>                 <a href="/JSF_EJB_App-war/index.jsp">Back to index</a>             </h:form>         </f:view>     </body> </html>   The next step is to set page navigation. Turning back to the faces-config.xml configuration file, insert the following code there.   <navigation-rule> <navigation-case> <from-outcome>question_create</from-outcome> <to-view-id>/askquestion.jsp</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <navigation-case> <from-outcome>created</from-outcome> <to-view-id>/welcomeJSF.jsp</to-view-id> </navigation-case> </navigation-rule> Make sure that the above tags are within the <faces-config> and </faces-config> root tags. Check It You are ready now to check the application you just created. To do this, right-click JSF_EJB_App-ejb project in the Project window and choose Deploy Project. After the JSF_EJB_App-ejb project is successfully deployed, right click the JSF_EJB_App-war project and choose Run Project. As a result, the newly created application will run in a browser. As mentioned earlier, the application contains very few pages, actually three ones. For testing purposes, you can submit a question, and then check the questions database table to make sure that everything went as planned. Summary Both JSF and EJB 3 are popular technologies when it comes to building enterprise applications. This simple example illustrates how you can use these technologies together in a complementary way.
Read more
  • 0
  • 0
  • 3251

article-image-working-report-builder-microsoft-sql-server-2008-part-2
Packt
22 Oct 2009
3 min read
Save for later

Working with the Report Builder in Microsoft SQL Server 2008: Part 2

Packt
22 Oct 2009
3 min read
Enabling and reviewing My Reports As described in Part 1 the My Reports folder needs to be enabled in order to use the folder or display it in the Open Report dialogue. The RC0 version had a documentation bug which has been rectified (https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=366413) Getting ready In order to enable the My Reports folder you need to carry out a few tasks. This will require authentication and working with the SQL Server Management Studio. These tasks are listed here: Make sure the Report Server has started. Make sure you have adequate permissions to access the Servers. Open the Microsoft SQL Server Management Studio as described previously. Connect to the Reporting Services after making sure you have started the Reporting Services. Right-click the Report Server node. General Execution History Logging Security Advanced The Server Properties window is displayed with a navigation list on the left consisting of the following: In the General page the name, version, edition, authentication mode, and URL of Reporting Service is displayed. Download of an ActiveX Client Print control is enabled by default. In order to work with Report Builder effectively and provide a My Reports folder for each user, you need to place a check mark for the check box Enable a My Reports folder for each user. The My Reports feature has been turned on as shown in the next screenshot. In the Execution page there is choice for report timeout execution, with the default set such that the report execution expires after 1800 seconds. In the History page there is choice between keeping an unlimited number of snapshots in the report history (default) or to limit the copies allowing you to specify how many to be kept. In the Logging page, report execution logging is enabled and the log entries older than 60 days are removed by default. This can be changed if desired. In the Security page, both Windows integrated security for report data sources and ad hoc report executions are enabled by default. The Advanced page shows several more items including the ones described thus far as shown in the next figure. In the General page enable the My Reports feature by placing a check mark. Click on the Advanced list item in the left. The Advanced page is displayed as shown: Now expand the Security node of Reporting Services and you will see that the My Reports role is present in the list of roles as shown. This is also added to the ReportServer database. The description of everything that a user with the assignment My Reports role can do is as follows: May publish reports and linked reports, manage folders, reports, and resources in a users My Reports folder. Now bring up Report Builder 2.0 by clicking Start | All Programs | Microsoft SQL Server 2008 Report Builder | Report Builder 2.0. Report Builder 2.0 is displayed. Click on Office Button | Open. The Open Report dialogue appears as shown. When the report Server is offline, the default location is My Documents, like Microsoft products Excel and MS Access. Choose the Recent sites and Servers. The Report server that is active should get displayed here as shown: Highlight the Server URL and click Open. All the folders and files on the server become accessible as shown: Open the Report Manager by providing its URL address. Verify that a My Reports folder is created for the user (current user). There could be slight differences in the look of the interface depending on whether you are using the RTM or the final version of SQL Server 2008 Enterprise edition.
Read more
  • 0
  • 0
  • 2596

article-image-visual-studio-2008-test-types
Packt
22 Oct 2009
15 min read
Save for later

Visual Studio 2008 Test Types

Packt
22 Oct 2009
15 min read
Software testing in Visual Studio Team System 2008 Before going into the details of the actual testing using Visual Studio 2008, we need to understand the different tools provided by Visual Studio Team System (VSTS) and their usage. Once we understand the tools usage, then we should be able to perform different types of testing using VSTS. As we go along creating a number of different tests, we will encounter difficulty in managing the test similar to the code and its different versions during application development. There are different features such as the Test List Editor and Test View and the Team Foundation Server (TFS) for managing and maintaining all the tests created using VSTS. Using this Test List Editor, we can group similar tests, create number of lists, add, or delete tests from the list. The other aspect of this article is to see the different file types getting created in Visual Studio during testing. Most of these files are in XML format, which get created automatically whenever the corresponding test is created. The tools such as the Team Explorer, Code Coverage, Test View, and Test Results are not new to Visual Studio 2008 but actually available since Visual Studio 2005. While we go through the windows and their purposes, we can check the IDE and the tools integration into Visual Studio 2008. Testing as part of Software Development Life Cycle The main objective of testing is to find the defects early in the SDLC. If the defect is found early, then the cost will be less, but if the defect is found during production or implementation stage, then the cost will be higher. Moreover, testing is carried out to assure the quality and reliability of the software. In order to find the defect earlier, the testing activities should start early, that is, in the Requirement phase of SDLC and continue till the end of SDLC. In the Coding phase, various testing activities takes place. Based on the design, the developers start coding the modules. Static and dynamic testing is carried out by the developers. Code reviews and code walkthroughs are also conducted. Once the coding is completed, then comes the Validation phase, where different phases or forms of testing are performed. Unit Testing: This is the first stage of testing in SDLC. This is performed by the developer to check whether the developed code meets the stated requirements. If there are any defects, the developer logs them against the code and fixes the code. The code is retested and then moved to the testers after confirming the code without any defects for the piece of functionality. This phase identifies a lot of defects and also reduces the cost and time involved in testing the application and fixing the code. Integration Testing: This testing is carried out between two or more modules or functions together with the intent of finding interface defects between them. This testing is completed as a part of unit or functional testing, and sometimes becomes its own standalone test phase. On a larger level, integration testing can involve putting together groups of modules and functions with the goal of completing and verifying that the system meets the system requirements. Defects found are logged and later fixed by the developers. There are different ways of integration testing such as top-down testing and bottom-up testing: The Top-Down approach is followed to test the highest level of components and integrate first to test the high-level logic and the flow. The low-level components are tested later. The Bottom-Up approach is the exact opposite of the top-down approach. In this case, the low-level functionalities are tested and integrated first and then the high-level functionalities are tested. The disadvantage in this approach is that the high-level or the most complex functionalities are tested later. The Umbrella approach uses both the top-down and bottom-up patterns. The inputs for functions are integrated in the bottom-up approach and then the outputs for the functions are integrated in the top-down approach. System Testing: It compares the system specifications against the actual system. The system test design is derived from the system design documents and is used in this phase. Sometimes, system testing is automated using testing tools. Once all the modules are integrated, several errors may arise. Testing done at this stage is called system testing. Defects found in this testing are logged and fixed by the developers. Regression Testing: This is not mentioned in the testing phase, but is carried out once the defects are fixed by the developers. The main objective of this type of testing is to determine if bug fixes have been successful and have not created any new problems. Also, this type of testing is done to ensure that no degradation of baseline functionality has occurred and to check if any new functionality was introduced in the software. Types of testing Visual Studio provides a range of testing types and tools for software applications. Following are some of those types: Unit test Manual test Web test Load test Stress test Performance test Capacity Planning test Generic test Ordered test In addition to these types, there are additional tools provided to manage, order the listing, and execute tests created in Visual Studio. Some of these are the Test View, Test List Editor, and the Test Results window. We will look at these testing tools and the supporting tools for managing the testing in Visual Studio 2008 in detail later. Unit test As soon as the developer finishes the code, the developer wants to know if it is producing the expected result before getting into any more detailed testing or handing over the component to the tester. The type of testing performed by the developers to test their own code is called Unit testing. Visual Studio has great support for Unit testing. The main goal of the unit testing is to isolate each piece of the code or individual functionality and test if the method is returning the expected result for different set of parameter values. It is extremely important to run unit tests to catch the defects in the early stage. The methods generated by the automated unit testing tool call the methods in the classes from the source code and test the output of each of the methods by comparing them with the expected values. The unit test tool produces a separate set of test code for the source. Using the test code we can pass the parameter values to the method and test the value returned by the method, and then compare them with the expected result. Unit testing code can be easily created by using the code generation feature, which creates the testing source code for the source application code. The generated unit testing code will contain several attributes to identify the Test Class, Test Method, and Test Project. These attributes are assigned when the unit test code gets generated from the original source code. Then using this code, the developer has to change the values and assert methods to compare the expected result from these methods. The Unit test class is similar to the other classes in any other project. The good thing here is that we can create new test classes by inheriting the base test class. The base test class will contain the common or reusable testing methods. This is the new Unit testing feature which helps us reduce the code and reuse the existing test classes. Whenever any code change occurs, it is easy to figure out the fault with the help of Unit tests, rerun those tests, and check whether the code is giving the intended output. This is to verify the code change the developer has made and to confirm that it is not affecting the other parts of the application. All the methods and classes generated for the automated unit testing are inherited from the namespace Microsoft.VisualStudio.TestTools.UnitTesting. Manual test Manual testing is the oldest and the simplest type of testing, but yet very crucial for software testing. It requires a tester to run all the tests without any automation tool. It helps us to validate whether the application meets various standards defined for effective and efficient accessibility and usage. Manual testing comes to play in the following scenarios: There is not enough budget for automation. The tests are more complicated, or are too difficult to be converted into automated tests. The tests are going to be executed only once. There is not enough time to automate the tests. Automated tests would be time-consuming to create and run. Manual tests can be created either using a Word document or Text format in Visual Studio 2008. This is a form of describing the test steps that should be performed by the tester. The step should also mention the expected result out of testing the step. Web tests Web tests are used for testing the functionality of the web page, web application, web site, web services, and a combination of all these. Web tests can be created by recording the interactions that are performed in the browser. These can be played back to test the web application. Web tests are normally a series of HTTP requests (GET/POST). Web tests can be used for testing the application performance as well as for stress testing. During HTTP requests, the web test takes care of testing the web page redirects, validations, viewstate information, authentication, and JavaScript executions. There are different validation rules and extraction rules used in web testing. The validation rules are used for validating the form field names, texts, and tags in the requested web page. We can validate the results or values against the expected result as per business needs. These validation rules are also used for checking the time taken for the HTTP request. At some point in time, we need to extract the data returned by the web pages. We may need the data for future use, or we may have to collect the data for testing purposes. In this case, we have to use the extraction rules for extracting the data returned by the page requested. Using this process, we can extract the form fields, texts, or values in the web page and store it in the web test context or collection. Web tests cannot be performed only with the existence of a web page. We need some data to be populated from the database or some other source to test the web page functionality and performance. There is a data binding mechanism used in Web test, which is used for providing the data required for the requested page. We can bind the data from a database or any other data source. For example, the web page would be a reporting page that might require some query string parameters as well as the data to be shown in the page according to the parameters passed. To provide data for all these data-driven testing, we have to use the concept of data binding with the data source. Web tests can be classified into Simple Web tests and Coded Web tests. Both these are supported by VSTS. Simple Web tests are very simple to create and execute. It executes on its own as per the recording. Once the test is started, there won't be any intervention. The disadvantage is that it is not conditional. It's a series of valid flow of events. Coded Web tests are bit more complex, but provide a lot of flexibility. For example, if we need some conditional execution of tests based on some values then we have to depend on this coded web test. These tests are created using either C# or Visual Basic code. Using the generated code we can control the flow of test events. But the disadvantage is its high complexity and maintenance cost. Load test Load testing is a method of testing used in different types of testing. The important thing with Load testing is that it is about performance. This type of testing is conducted with other types of testing, which means that it can be performed along with either Web testing or Unit testing. The main purpose of load testing is to identify the performance of application based on different scenarios. Most of the time, we can predict the performance of the application that we develop, if it is running on one machine or a desktop. But in the case of web applications such as online ordering systems, we know the estimated maximum number of users, but do not know the connection speeds and location from where the users will access the web site. For such scenarios, the web application should support all the end users with good performance irrespective of the system they use, their Internet connection, the place, and the tool they use to access the web site. So before we release this web site to the customers or the end users, we should check the performance of the application so that it can support the mass end user group. This is where load testing will be very useful in testing the application along with Web test or Unit test. When a Web test is added to a Load test, it will simulate multiple users opening simultaneous connections to the same web application and making multiple HTTP requests. Load testing in Visual Studio comes with lots of properties which can be set to test the web application with different browsers, different user profiles, light loads, and heavy loads. Results of different tests can be saved in a repository to compare the set of results and improve their performance. In case of client server and multi-tier applications, we will be having a lot of components which will reside in the server and serve the client requests. To get the performance of these components, we have to make use of a Load test with a set of Unit tests. One good example would be to test the data access service component that calls a stored procedure in the backend database and returns the results to the application that is using this service. Load tests can be run either from the local machine or by submitting to a rig, which is a group of computers used for simulating the tests remotely. A rig consists of a single controller and one or more agents. Load tests can be used in different scenarios of testing: Stress testing: This checks the functionality of the application under heavy load. The resource provided to the application could vary based on the input file size or the size of the data set, for example, uploading a file which is more than 50MB in size. Smoke testing: This checks if the application performs well for a short duration with a light load. Performance testing: This checks the responsiveness and throughput of the application with different loads. Capacity Planning test: This checks the application performance with various capacities. Ordered test As we know, there are different types of testing required to build quality software. We take care of running all these tests for the applications we develop. But we also have an order in which to execute all these different tests. For example, we do the unit testing first, then the integration test, then the smoke test, and then we go for the functional test. We can order the execution of these tests using Visual Studio. Another example would be to test the configurations for the application before actually testing the functionality of the application. If we don't order the test, we would never know whether the end result is correct or not. Sometimes, the tests will not go through successfully if the tests are not run in order. Ordering of tests is done using the Test View window in Visual Studio. We can list all the available tests in the Test View and choose the tests in the same order using different options provided by Visual Studio and then run the tests. Visual Studio will take care of running the tests in the same order we have chosen in the list. So once we are able to run the test successfully in an order, we can also expect the same ordering in getting the results. Visual Studio provides the results of all the tests in a single row in the Test Results window. Actually, this single row result will contain the results of all the tests run in the order. We can just double-click the single row result to get the details of each tests run in the ordered test. Ordered test is the best way of controlling the tests and running the tests in an order. Generic test We have seen different types and ways of testing the applications using VSTS. There are situations where we might end up having other applications for testing, which are not developed using Visual Studio. We might have only the executables or binaries for those applications. But we may not have the supported testing tool for those applications. This is where we need the generic testing method. This is just a way of testing third-party applications using Visual Studio. Generic tests are used to wrap the existing tests. Once the wrapping is done, then it is just another test in VSTS. Using Visual Studio, we can collect the test results, and gather the code coverage data too. We can manage and run the generic tests in Visual Studio just like the others tests.
Read more
  • 0
  • 0
  • 7780
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-xen-virtualization-work-mysql-server-ruby-rails-and-subversion
Packt
22 Oct 2009
7 min read
Save for later

Xen Virtualization: Work with MySQL Server, Ruby on Rails, and Subversion

Packt
22 Oct 2009
7 min read
Base Appliance Image We will use an Ubuntu Feisty domain image as the base image for creating these appliances. This image should be made as sparse and small as possible, and free of any cruft. A completely stripped down version of Linux with only the bare necessities would be a great start. In this case, we will not need any graphical desktop environments, so we can completely eliminate software packages like the X11 and any window manager like Gnome or KDE. Once we have a base image, we can back it up and then start using it for creating Xen appliances. In this article we will use an Ubuntu Feisty domain as the base image. Once this domain image is ready we are going to update it and clean it up a little bit so it can be our base. Edit the sources list for apt and add in other repositories that we will need to get software packages we will need when creating these appliances. Update your list of software. This will connect to the apt repositories and get the latest list of packages. We will do the actual update in the next step. Upgrade the distribution to ensure that you have the latest versions of all the packages. Automatically clean the image so all unused packages are removed. This will ensure that the image stays free of cruft.   Now we have the base appliance image ready, we will use it to create some Xen appliances. You can make a backup of the original base image and every time you create an appliance you can use a copy as the starting point or template. The images are nothing but domU images, which are customized for running only specific applications. You start them up and run them like ay other Xen guest domains. MySQL Database Server MySQL is one of the most popular open-source databases in the world. It is a key component of the LAMP architecture – (Linux Apache MySQL and PHP). It is also very easy to get started with MySQL and is one of the key factors driving its adoption across the enterprise. In this section we will create a Xen appliance that will run a MySQL database server and also provide the ability to automatically backup the database on a given schedule. Time for Action – Create our first Xen appliance We will use our base Ubuntu Feisty domain image, and add MySQL and other needed software to it. Please ensure that you have updated your base image to the latest versions of the repositories and software packages before creating this appliance. Install mysql-server using apt. Once it is installed, Ubuntu will automatically start the database server. So before we make our other changes, stop MySQL. Edit the /etc/mysql/my.cnf and comment out the line for the bind-address parameter. This will ensure that MySQL will accept connections from external machines and not just the localhost. Start a mysql console session to test that everything is installed and working correctly. Next we will install the utility for doing the automated backups. In order to do that we will first need to install the wget utility for transferring files. This is not a part of the base Ubuntu Feisty installation. Download the automysqlbackup script from the website. Copy this script to wherever you like, maybe /opt. Create a link to this location so it’s easy to do future updates. # cp automysqlbackup.sh.2.5 /opt# ln -s automysqlbackup.sh.2.5 automysqlbackup.sh Edit the script and modify the parameters at the top of the script to match your environment. Here are the changes to be made in our case. # Username to access the MySQL server e.g. dbuserUSERNAME=pchaganti# Username to access the MySQL server e.g. passwordPASSWORD=password# Host name (or IP address) of MySQL server e.g localhostDBHOST=localhost# List of DBNAMES for Daily/Weekly Backup e.g. "DB1 DB2 DB3"DBNAMES="all"# Backup directory location e.g /backupsBACKUPDIR="/var/backup/mysql"# Mail setupMAILCONTENT="quiet" Schedule this backup script to be run daily by creating a crontab entry for it, in the following format. 45 5 * * * root  /opt/automysqlbackup.sh >/dev/null 2>&1 Now we have a MySQL database server with automatic daily backups as a nice reusable Xen appliance. What just happened? We created our first Xen appliance! It is running the open-source MySQL database server along with an automated backup of the database as per the given schedule. This image is essentially a domU image and it can be uploaded along with its configuration file to a repository somewhere, and can be used by anyone in the enterprise or elsewhere with their Xen server. You can either start up the domain manually as and when you need it or set it up to boot automatically when your xend server starts. Ruby on Rails Appliance Ruby on Rails is one of the hottest web development frameworks around. It is simple to use and you can use all the expressive power of the Ruby language. It provides a great feature set and has really put the Ruby language on the map. Ruby on Rails is gaining rapid adoption across the IT landscape and for a wide variety of web applications. In this section, we are going to create a Rails appliance that contains Ruby, Rails, and the Mongrel cluster for serving the Rails application and nginx web server for the static content. This appliance gives you a great starting point for your explorations into the world of Ruby on Rails and can be an excellent learning resource. Time for Action – Rails on Xen We will use our base Ubuntu Feisty domain image and add Rails and other needed software to it. Please ensure that you have updated your base image to the latest versions of the repositories and software packages before creating this appliance. Install the packages required for compiling software on an Ubuntu system. This is required as we will be compiling some native extensions. Once the image is done, you can always remove this package if you want to save space. Install Ruby and other packages that are needed for it. Download the RubyGems package from RubyForge. We will use this to install any Ruby libraries or packages that we will need, including Rails. Now install Rails. The first time when you run this command on a clean Ubuntu Feisty system, you will get the following error. Ignore this error and just run the command once again and it will work fine. This will install Rails and all of its dependencies. Create a new Rails application. This will create everything needed in a directory named xenbook. $ rails xenbook  Change into the directory of the application that we created in the previous step and start the server up. This will start Ruby’s built-in web server, webrick by default. Launch a web browser and navigate to the web page for our xenbook application. We have everything working for a simple Rails install. However, we are using webrick, which is a bit slow. So let’s install the Mongrel server and use it with Rails. We will actually install mongrel_cluster that will let us use a cluster of Mongrel processes for serving up our Rails application.
Read more
  • 0
  • 0
  • 2985

article-image-enterprise-javabeans
Packt
22 Oct 2009
10 min read
Save for later

Enterprise JavaBeans

Packt
22 Oct 2009
10 min read
Readers familiar with previous versions of J2EE will notice that Entity Beans were not mentioned in the above paragraph. In Java EE 5, Entity Beans have been deprecated in favor of the Java Persistence API (JPA). Entity Beans are still supported for backwards compatibility; however, the preferred way of doing Object Relational Mapping with Java EE 5 is through JPA. Refer to Chapter 4 in the book Java EE 5 Development using GlassFish Application Server for a detailed discussion on JPA. Session Beans As we previously mentioned, session beans typically encapsulate business logic. In Java EE 5, only two artifacts need to be created in order to create a session bean: the bean itself, and a business interface. These artifacts need to be decorated with the proper annotations to let the EJB container know they are session beans. Previous versions of J2EE required application developers to create several artifacts in order to create a session bean. These artifacts included the bean itself, a local or remote interface (or both), a local home or a remote home interface (or both) and a deployment descriptor. As we shall see in this article, EJB development has been greatly simplified in Java EE 5. Simple Session Bean The following example illustrates a very simple session bean: package net.ensode.glassfishbook; import javax.ejb.Stateless; @Stateless public class SimpleSessionBean implements SimpleSession { private String message = "If you don't see this, it didn't work!"; public String getMessage() { return message; } } The @Stateless annotation lets the EJB container know that this class is a stateless session bean. There are two types of session beans, stateless and stateful. Before we explain the difference between these two types of session beans, we need to clarify how an instance of an EJB is provided to an EJB client application. When EJBs (both session beans and message-driven beans) are deployed, the EJB container creates a series of instances of each EJB. This is what is typically referred to as the EJB pool. When an EJB client application obtains an instance of an EJB, one of the instances in the pool is provided to this client application. The difference between stateful and stateless session beans is that stateful session beans maintain conversational state with the client, where stateless session beans do not. In simple terms, what this means is that when an EJB client application obtains an instance of a stateful session bean, the same instance of the EJB is provided for each method invocation, therefore, it is safe to modify any instance variables on a stateful session bean, as they will retain their value for the next method call. The EJB container may provide any instance of an EJB in the pool when an EJB client application requests an instance of a stateless session bean. As we are not guaranteed the same instance for every method call, values set to any instance variables in a stateless session bean may be "lost" (they are not really lost; the modification is in another instance of the EJB in the pool). Other than being decorated with the @Stateless annotation, there is nothing special about this class. Notice that it implements an interface called SimpleSession. This interface is the bean's business interface. The SimpleSession interface is shown next: package net.ensode.glassfishbook; import javax.ejb.Remote; @Remote public interface SimpleSession { public String getMessage(); } The only peculiar thing about this interface is that it is decorated with the @Remoteannotation. This annotation indicates that this is a remote business interface . What this means is that the interface may be in a different JVM than the client application invoking it. Remote business interfaces may even be invoked across the network. Business interfaces may also be decorated with the @Local interface. This annotation indicates that the business interface is a local business interface. Local business interface implementations must be in the same JVM as the client application invoking their methods. As remote business interfaces can be invoked either from the same JVM or from a different JVM than the client application, at first glance, we might be tempted to make all of our business interfaces remote. Before doing so, we must be aware of the fact that the flexibility provided by remote business interfaces comes with a performance penalty, because method invocations are made under the assumption that they will be made across the network. As a matter of fact, most typical Java EE application consist of web applications acting as client applications for EJBs; in this case, the client application and the EJB are running on the same JVM, therefore, local interfaces are used a lot more frequently than remote business interfaces. Once we have compiled the session bean and its corresponding business interface,we need to place them in a JAR file and deploy them. Just as with WAR files, the easiest way to deploy an EJB JAR file is to copy it to [glassfish installationdirectory]/glassfish/domains/domain1/autodeploy. Now that we have seen the session bean and its corresponding business interface, let's take a look at a client sample application: package net.ensode.glassfishbook; import javax.ejb.EJB; public class SessionBeanClient { @EJB private static SimpleSession simpleSession; private void invokeSessionBeanMethods() { System.out.println(simpleSession.getMessage()); System.out.println("nSimpleSession is of type: " + simpleSession.getClass().getName()); } public static void main(String[] args) { new SessionBeanClient().invokeSessionBeanMethods(); } } The above code simply declares an instance variable of type net.ensode.SimpleSession, which is the business interface for our session bean. The instance variable is decorated with the @EJB annotation; this annotation lets the EJB container know that this variable is a business interface for a session bean. The EJB container then injects an implementation of the business interface for the client code to use. As our client is a stand-alone application (as opposed to a Java EE artifact such as a WAR file) in order for it to be able to access code deployed in the server, it must be placed in a JAR file and executed through the appclient utility. This utility can be found at [glassfish installation directory]/glassfish/bin/. Assuming this path is in the PATH environment variable, and assuming we placed our client code in a JAR file called simplesessionbeanclient.jar, we would execute the above client code by typing the following command in the command line: appclient -client simplesessionbeanclient.jar Executing the above command results in the following console output: If you don't see this, it didn't work! SimpleSession is of type: net.ensode.glassfishbook._SimpleSession_Wrapper which is the output of the SessionBeanClient class. The first line of output is simply the return value of the getMessage() method we implemented in the session bean. The second line of output displays the fully qualified class name of the class implementing the business interface. Notice that the class name is not the fully qualified name of the session bean we wrote; instead, what is actually provided is an implementation of the business interface created behind the scenes by the EJB container. A More Realistic Example In the previous section, we saw a very simple, "Hello world" type of example. In this section, we will show a more realistic example. Session beans are frequently used as Data Access Objects (DAOs). Sometimes, they are used as a wrapper for JDBC calls, other times they are used to wrap calls to obtain or modify JPA entities. In this section, we will take the latter approach. The following example illustrates how to implement the DAO design pattern in asession bean. Before looking at the bean implementation, let's look at the business interface corresponding to it: package net.ensode.glassfishbook; import javax.ejb.Remote; @Remote public interface CustomerDao { public void saveCustomer(Customer customer); public Customer getCustomer(Long customerId); public void deleteCustomer(Customer customer); } As we can see, the above is a remote interface implementing three methods; thesaveCustomer() method saves customer data to the database, the getCustomer()method obtains data for a customer from the database, and the deleteCustomer() method deletes customer data from the database. Let's now take a look at the session bean implementing the above business interface. As we are about to see, there are some differences between the way JPA code is implemented in a session bean versus in a plain old Java object. package net.ensode.glassfishbook; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.sql.DataSource; @Stateless public class CustomerDaoBean implements CustomerDao { @PersistenceContext private EntityManager entityManager; @Resource(name = "jdbc/__CustomerDBPool") private DataSource dataSource; public void saveCustomer(Customer customer) { if (customer.getCustomerId() == null) { saveNewCustomer(customer); } else { updateCustomer(customer); } } private void saveNewCustomer(Customer customer) { customer.setCustomerId(getNewCustomerId()); entityManager.persist(customer); } private void updateCustomer(Customer customer) { entityManager.merge(customer); } public Customer getCustomer(Long customerId) { Customer customer; customer = entityManager.find(Customer.class, customerId); return customer; } public void deleteCustomer(Customer customer) { entityManager.remove(customer); } private Long getNewCustomerId() { Connection connection; Long newCustomerId = null; try { connection = dataSource.getConnection(); PreparedStatement preparedStatement = connection .prepareStatement( "select max(customer_id)+1 as new_customer_id " + "from customers"); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet != null && resultSet.next()) { newCustomerId = resultSet.getLong("new_customer_id"); } connection.close(); } catch (SQLException e) { e.printStackTrace(); } return newCustomerId; } } The first difference we should notice is that an instance of javax.persistence. EntityManager is directly injected into the session bean. In previous JPA examples,we had to inject an instance of javax.persistence.EntityManagerFactory, then use the injected EntityManagerFactory instance to obtain an instance of EntityManager. The reason we had to do this was that our previous examples were not thread safe. What this means is that potentially the same code could be executed concurrently by more than one user. As EntityManager is not designed to be used concurrently by more than one thread, we used an EntityManagerFactory instance to provide each thread with its own instance of EntityManager. Since the EJB container assigns a session bean to a single client at time, session beans are inherently thread safe, therefore, we can inject an instance of EntityManager directly into a session bean. The next difference between this session bean and previous JPA examples is that in previous examples, JPA calls were wrapped between calls to UserTransaction.begin() and UserTransaction.commit(). The reason we had to do this is because JPA calls are required to be in wrapped in a transaction, if they are not in a transaction, most JPA calls will throw a TransactionRequiredException. The reason we don't have to explicitly wrap JPA calls in a transaction as in previous examples is because session bean methods are implicitly transactional; there is nothing we need to do to make them that way. This default behavior is what is known as Container-Managed Transactions. Container-Managed Transactions are discussed in detail later in this article. When a JPA entity is retrieved in one transaction and updated in a different transaction, the EntityManager.merge() method needs to be invoked to update the data in the database. Invoking EntityManager.persist() in this case will result in a "Cannot persist detached object" exception.
Read more
  • 0
  • 0
  • 2635

article-image-using-object-oriented-approach-implementing-php-classes-interact-oracle
Packt
22 Oct 2009
8 min read
Save for later

Using An Object Oriented Approach for Implementing PHP Classes to Interact with Oracle

Packt
22 Oct 2009
8 min read
Before you start developing object-oriented solutions with PHP 5, it is important to understand that its object model provides more features than PHP 4's object model. Like most object-oriented languages, PHP 5 allows the developer to take advantage of interfaces, abstract classes, private/public/protected access modifiers, static members and methods, exception handling, and other features that were not available in PHP 4. But perhaps the most important thing to note about the object-oriented improvements of PHP 5 is that objects are now referenced byhandle, and not by value. Building Blocks of Applications As you no doubt know, the fundamental building block in any object-oriented language is a structure called a class. A class is a template for an object. It describes the data and behavior of its instances (objects). During run time, an application can create as many instances of a single class as necessary. The following diagram conceptually depicts the structure of a class. You might find it handy to think of an object-oriented application as a building made of blocks, where classes are those blocks. However, it is important to note that all blocks in this case are exchangeable. What this means is that if you are not satisfied with the implementation of a certain class, you can use a relevant class that has the same Application Programming Interface (API) but a different implementation instead. This allows you to increase the reusability and maintainability of your application, without increasing the complexity. The intent of the example discussed in this section is to illustrate how you can rewrite the implementation of a class so that this doesn't require a change in the existing code that employs this class. In particular, you'll see how a custom PHP 4 class designed to interact with Oracle can be rewritten to use the new object-oriented features available in PHP 5. Creating a Custom PHP Class from Scratch To proceed with the example, you first need to create a PHP 4 class interacting with Oracle. Consider the following dbConn4 class: <?php //File: dbConn4.php class dbConn4 { var $user; var $pswd; var $db; var $conn; var $query; var $row; var $exec_mode; function dbConn4($user, $pswd, $db, $exec_mode= OCI_COMMIT_ON_SUCCESS) { $this->user = $user; $this->pswd = $pswd; $this->db = $db; $this->exec_mode = $exec_mode; $this->GetConn (); } function GetConn() { if(!$this->conn = OCILogon($this->user, $this->pswd, $this->db)) { $err = OCIError(); trigger_error('Failed to establish a connection: ' . $err['message']); } } function query($sql) { if(!$this->query = OCIParse($this->conn, $sql)) { $err = OCIError($this->conn); trigger_error('Failed to parse SQL query: ' . $err['message']); return false; } else if(!OCIExecute($this->query, $this->exec_mode)) { $err = OCIError($this->query); trigger_error('Failed to execute SQL query: ' . $err['message']); return false; } return true; } function fetch() { if(!OCIFetchInto($this->query, $this->row, OCI_ASSOC)) { return false; } return $this->row; } } ?> In the above script, to define a class, you use the class keyword followed by the class name. Then, within curly braces, you define class properties and methods. Since this class is designed to work under both PHP 4 and PHP 5, all the class properties are defined with the var keyword. Declaring a property with var makes it publicly readable and writable. In PHP 5, you would use the public keyword instead. In PHP 4, you define the class constructor as a function with the same name as the class itself. This still works in PHP 5 for backward compatibility. However, in PHP 5, it's recommended that you use __construct as the constructor name. In the above example, the class constructor is used to set the member variables of a class instance to the values passed to the constructor as parameters. Note the use of the self-referencing variable $this that is used here to access the member variables of the current class instance. Within class methods, you can use $this, the special variable that points to the current instance of a class. This variable is created automatically during the execution of any object's method and can be used to access both member variables of the current instance and its methods. Then, you call the GetConn method from within the constructor to obtain a connection to the database. You reference the method using the $this variable. In this example, the GetConn method is supposed to be called from within the constructor only. In PHP 5, you would declare this method as private. To obtain a connection to the database in this example, you use the OCILogon function. In PHP 5, you would use the oci_connect function instead. The query method defined here takes an SQL string as the parameter and then parses and executes the query. It returns true on success or false on failure. This method is supposed to be called from outside an object. So, in PHP 5, you would declare it as public. Finally, you define the fetch method. You will call this method to fetch the results retrieved by a SELECT statement that has been executed with the query method. Testing the Newly Created Class Once written, the dbConn4 class discussed in the preceding section can be used in applications in order to establish a connection to an Oracle database and then issue queries against it as needed. To see this class in action, you might use the following PHP script. Assuming that you have saved the dbConn4 class as the dbConn4.php file, save the following script as select.php: <?php //File: select.php require_once 'dbConn4.php'; require_once 'hrCred.php'; $db = new dbConn4($user, $pswd, $conn); $sql="SELECT FIRST_NAME, LAST_NAME FROM employees"; if($db->query($sql)){ print 'Employee Names: ' . '<br />'; while ($row = $db->fetch()) { print $row['FIRST_NAME'] . '&nbsp;'; print $row['LAST_NAME'] . '<br />'; } } ?> The above select.php script employs the employees table from the hr/hr demonstration schema. So, before you can execute this script, you must create the hrCred.php file that contains all the information required to establish a connection to your Oracle database using the HR account. The hrCred.php file should look as shown below (note that the connection string may vary depending on your configuration): <?php //File: hrCred.php $user="hr"; $pswd="hr"; $conn="(DESCRIPTION= (ADDRESS_LIST= (ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)) ) (CONNECT_DATA=(SID=orcl)(SERVER=DEDICATED)) )"; ?> Once you have created the hrCred.php script, you can execute the select.php script. As a result, it should output the names of employees from the employees table in the hr/hr demonstration schema. Taking Advantage of PHP 5's Object-Oriented Features Turning back to the dbConn4 class, you may have noticed that it was written for PHP 4. Of course, it still can be used in new applications written for PHP 5. However, to take advantage of the new object-oriented features available in PHP 5, you might want to rewrite this class as follows: <?php //File: dbConn5.php class dbConn5 { private $user; private $pswd; private $db; private $conn; private $query; private $row; private $exec_mode; public function __construct($user, $pswd, $db, $exec_mode= OCI_COMMIT_ON_SUCCESS) { $this->user = $user; $this->pswd = $pswd; $this->db = $db; $this->exec_mode = $exec_mode; $this->GetConn(); } private function GetConn() { if(!$this->conn = oci_connect($this->user, $this->pswd, $this->db)) { $err = oci_error(); trigger_error('Failed to establish a connection: ' . $err['message']); } } public function query($sql) { if(!$this->query = oci_parse($this->conn, $sql)) { $err = oci_error($this->conn); trigger_error('Failed to execute SQL query: ' . $err['message']); return false; } else if(!oci_execute($this->query, $this->exec_mode)) { $err = oci_error($this->query); trigger_error('Failed to execute SQL query: ' . $err['message']); return false; } return true; } public function fetch() { if($this->row=oci_fetch_assoc($this->query)){ return $this->row; } else { return false; } } } ?> As you can see, the implementation of the class has been improved to conform to the new standards of PHP 5. For instance, the above class takes advantage of encapsulation that is accomplished in PHP 5—like most other object-oriented languages—by means of access modifiers, namely public, protected, and private. The idea behind encapsulation is to enable the developer to design the classes that reveal only the important members and methods and hide the internals. For instance, the GetConn method in the dbConn5 class is declared with the private modifier because this method is supposed to be called only from inside the constructor when a new instance of the class is initialized; therefore, there is no need to allow client code to access this method directly. Since the implementation of the newly created dbConn5 class is different from the one used in dbConn4, you may be asking yourself: "Does that mean we need to rewrite the client code that uses the dbConn4 class as well?" The answer is obvious: you don't need to rewrite client code that uses the dbConn4 class since you have neither changed the Application Programming Interface (API) of the class nor,more importantly, its functionality. Thus, all you need to do in order to make the select.php script work with dbConn5 is simply replace all the references to dbConn4 with references to dbConn5 throughout the script.
Read more
  • 0
  • 0
  • 7001

article-image-qmail-quickstarter-virtualization
Packt
22 Oct 2009
6 min read
Save for later

Qmail Quickstarter: Virtualization

Packt
22 Oct 2009
6 min read
Generic Virtualization Framework The most straightforward mail handling in qmail is used for what are known as the local domains: those listed in the file. The users for these domains are all the same, and are typically the users defined in control/locals/etc/passwd, though they can be defined in users/assign as well (discussed in the Non-Virtual Non-System Users section). Qmail, however, has another sense in which an email can be local, which is to assign a domain to a user (or, more accurately, to a prefix). This feature is configured with the control/virtualdomains file. Power of the virtualdomains File The virtualdomains file is one of the most powerful, useful, and stunningly simple mechanisms for configuring qmail. Virtual domains and even virtual users can be created, independently of one another, and assigned to controlling users. Virtual domains are fully independent, and as they are assigned to users (or, more accurately, prefixes) they can be in different UNIX protection domains if desired. This file can also define virtual users and similarly assign them to controlling users. This file thus makes it both possible and easy to intercept specific addresses and do something special with them. Perhaps surprisingly for the power this file wields, the control/virtualdomains file is only slightly more complicated than similar control files, such as control/locals. Rather than a list of domains, the virtualdomains file is a list of patterns and their associated prefixes. The entries are of the form: matching-pattern: prefix Only one prefix is associated with each pattern. The matching pattern can be one of the following three things: a domain (that follows the same wildcarding semantics used in the control/rcpthosts file), an email address, or an empty string. The empty string is considered to match anything. An email address matches any message addressed to that email address, and a domain matches any message addressed to a user in that domain. If there are multiple possible matches, the longest match is used. Emails that match patterns listed in the control/virtualdomains file are considered to be local emails, similar to those addressed to domains in the control/locals file. Messages that match patterns in the virtualdomains file must first undergo a simple modification before delivery. While messages are prepared for delivery, if they have an envelope destination address that matches a pattern in the virtualdomains file, that destination address is prepended with the matching pattern's associated prefix. This turns the original local part of the address into an extension of the prepended user. In this way, a domain can be mapped to a user, giving that user full control over the mailboxes (or users) within that domain. The virtualdomains file can also be used to define exceptions to the matching rules, if the prefix is blank. It is important to note that the control/virtualdomains file is considered after the control/locals file, which means that if an email is addressed to a domain listed in locals, the virtualdomains file will not apply. Also, virtualdomains rewriting occurs before the mail is given to qmail-lspawn for delivery. This sounds complex, but is easy to understand with an example. Basic Virtual Domains An example virtualdomains file that demonstrates most of the file's features is as follows: example.com:foo.example.com:foo-bartwo.example.com:bazwaldo@domain.com:quxdomain.com::garply Presuming that the users mentioned i.e. foo, baz, qux, and garply are the only local users on this system; these lines cause the following results:      The first line matches any address ending in @example.com, such as user@example.com. Such a destination address will be rewritten as foo-user@example.com, ensuring that the email's delivery will be controlled by the local user named foo.      Messages addressed to user@something.example.com do not match the first line but do match the second line, and so will be delivered as if they had been addressed to foo-bar-user@something.example.com.      Because the virtualdomains file is used in a longest match wins manner, the third line (not the second) will match messages addressed to user@two.example.com. This destination will be rewritten asbaz-user@two.example.com and baz will control the delivery of such messages.      The fourth line specifies that email addressed to waldo@domain.com will be instead delivered as if it had been addressed to qux-waldo@domain.com. The qux user will control that delivery.      The fifth line specifies that any domain.com email—other than waldo@domain.com—should be treated as if had been listed in the domain.comcontrol/locals file.      Finally, the sixth line specifies that all other email will be rewritten and delivered to the local garply user. For example, email addressed to someone@somewhere.org will be rewritten as garply-someone@somewhere.org and delivery will be attempted locally. In this example, the foo user is essentially in charge of the entirety of the example.com domains. Users that are specific to example.com are defined by creating appropriately named .qmail files in foo's home directory. For example, to establish the standard postmaster@example.com address, foo would create a file named .qmail-postmaster in its home directory, containing the instructions for delivering postmaster's email. The foo user could also establish a address by creating a file named foo@example.com.qmail-foo in his or her home directory. In this way, once the example.com mapping has been established, the foo user can set up and maintain the users in the example.com domain without ever requiring further permission from or contact with the system administrator. It is worth pointing out that precisely who controls what can get more complex if real usernames have extension separator characters (a hyphen, by default) in them. For example, if the address postmaster@example.com is rewritten to be foo-postmaster@example.com, it is typically delivered according to the instructions in ~foo/.qmail-postmaster or, if that file does not exist, ~foo/.qmail-default. However, if there is a user named foo-postmaster, that user will receive email addressed to postmaster@example.com. If a .qmail file (such as ~foo/.qmail-postmaster) cannot be located for a given extension address (such as foo-postmaster@example.com), the alias user's directory is checked for .qmail files. Specifically, .qmail-foo-postmaster, .qmail-foo-default, and .qmail-default. If none of these files exist, the message is considered undeliverable and is bounced. Note that during delivery of such an email, the standard environment variables are defined per the rewritten destination rather than per the original address. For example, if a message addressed to postmaster@example.com is delivered using the example configuration, the affected environment variables will be defined as follows (assuming foo's home directory is /home/foo):   Environment Variable Content for Virtual Domain Delivery Content for Normal Delivery RECIPIENT foo-postmaster@example.com postmaster@example.com USER foo-postmaster postmaster LOCAL foo postmaster HOME /home/foo /home/postmaster HOST example.com example.com HOST2 example example HOST3 example example HOST4 example example EXT postmaster      
Read more
  • 0
  • 0
  • 3505
article-image-enhancing-user-interface-ajax
Packt
22 Oct 2009
32 min read
Save for later

Enhancing the User Interface with Ajax

Packt
22 Oct 2009
32 min read
Since our project is a Web 2.0 application, it should be heavily focused on the user experience. The success of our application depends on getting users to post and share content on it. Therefore, the user interface of our application is one of our major concerns. This article will improve the interface of our application by introducing Ajax features, making it more user-friendly and interactive. Ajax and Its Advantages Ajax, which stands for Asynchronous JavaScript and XML, consists of the following technologies: HTML and CSS for structuring and styling information. JavaScript for accessing and manipulating information dynamically. XMLHttpRequest, which is an object provided by modern browsers for exchanging data with the server without reloading the current web page. A format for transferring data between the client and server. XML is sometimes used, but it could be HTML, plain text, or a JavaScript-based format called JSON. Ajax technologies let code on the client-side exchange data with the server behind the scenes, without having to reload the entire page each time the user makes a request. By using Ajax, web developers are able to increase the interactivity and usability of web pages. Ajax offers the following advantages when implemented in the right places: Better user experience. With Ajax, the user can do a lot without refreshing the page, which brings web applications closer to regular desktop applications. Better performance. By exchanging only the required data with the server, Ajax saves bandwidth and increases the application's speed. There are numerous examples of web applications that use Ajax. Google Maps and Gmail are perhaps two of the most prominent examples. In fact, these two applications played an important role in spreading the adoption of Ajax, because of the success that they enjoyed. What sets Gmail from other web mail services is its user interface, which enables users to manage their emails interactively without waiting for a page reload after every action. This creates a better user experience and makes Gmail feel like a responsive and feature-rich application rather than a simple web site. This article explains how to use Ajax with Django so as to make our application more responsive and user friendly. We are going to implement three of the most common Ajax features found in web applications today. But before that, we will learn about the benefits of using an Ajax framework as opposed to working with raw JavaScript functions. Using an Ajax Framework in Django In this section we will choose and install an Ajax framework in our application. This step isn't entirely necessary when using Ajax in Django, but it can greatly simplify working with Ajax. There are many advantages to using an Ajax framework: JavaScript implementations vary from browser to browser. Some browsers provide more complete and feature-rich implementations, whereas others contain implementations that are incomplete or don't adhere to standards. Without an Ajax framework, the developer must keep track of browser support for the JavaScript features that they are using, and work around the limitations that are present in some browser implementations of JavaScript. On the other hand, when using an Ajax framework, the framework takes care of this for us; it abstracts access to the JavaScript implementation and deals with the differences and quirks of JavaScript across browsers. This way, we concentrate on developing features instead of worrying about browser differences and limitations. The standard set of JavaScript functions and classes is a bit lacking for fully fledged web application development. Various common tasks require many lines of code even though they could have been wrapped in simple functions. Therefore, even if you decide not to use an Ajax framework, you will find yourself having to write a library of functions that encapsulates JavaScript facilities and makes them more usable. But why reinvent the wheel when there are many excellent Open Source libraries already available? Ajax frameworks available on the market today range from comprehensive solutions that provide server-side and client-side components to light-weight client-side libraries that simplify working with JavaScript. Given that we are already using Django on the server-side, we only want a client-side framework. In addition, the framework should be easy to integrate with Django without requiring additional dependencies. And finally, it is preferable to pick a light and fast framework. There are many excellent frameworks that fulfil our requirements, such as Prototype, the Yahoo! UI Library and jQuery. I have worked with them all and they are all great. But for our application, I'm going to pick jQuery, because it's the lightest of the three. It also enjoys a very active development community and a wide range of plugins. If you already have experience with another framework, you can continue using it during this article. It is true that you will have to adapt the JavaScript code in this article to your framework, but Django code on the server-side will remain the same no matter which framework you choose. Now that you know the benefits of using an Ajax framework, we will move to installing jQuery into our project. Downloading and Installing jQuery One of the advantages of jQuery is that it consists of a single light-weight file. To download it, head to http://jquery.com/ and choose the latest version (1.2.3 at the time of writing). You will find two choices: Uncompressed version: This is the standard version that I recommend you to use during development. You will get a .js file with the library's code in it. Compressed version: You will also get a .js file if you download this version. However, the code will look obfuscated. jQuery developers produce this version by applying many operations on the uncompressed .js file to reduce its size, such as removing white spaces and renaming variables, as well as many other techniques. This version is useful when you deploy your application, because it offers exactly the same features as the uncompressed one, but with a smaller file size. I recommend the uncompressed version during development because you may want to look into jQuery's code and see how a particular method works. However, the two versions offer exactly the same set of features, and switching from one to another is just a matter of replacing one file. Once you have the jquery-xxx.js file (where xxx is the version number), rename it to jquery.js and copy it to the site_media directory of our project (Remember that this directory holds static files which are not Python code). Next, you will have to include this file in the base template of our site. This will make jQuery available to all of our project pages. To do so, open templates/base.html and add the highlighted code to the head section in it: <head> <title>Django Bookmarks | {% block title %}{% endblock %}</title> <link rel="stylesheet" href="/site_media/style.css"type="text/css" /> <script type="text/javascript"src="/site_media/jquery.js"></script></head> To add your own JavaScript code to an HTML page, you can either put the code in a separate .js file and link it to the HTML page by using the script tag as above, or write the code directly in the body of a script tag: <script type="text/javascript"> // JavaScript code goes here.</script> The first method, however, is recommended over the second one, because it helps keep the source tree organized by putting HTML and JavaScript code in different files. Since we are going to write our own .js files during this article, we need a way to link .js files to templates without having to edit base.html every time. We will do this by creating a template block in the head section of the base.html template. When a particular page wants to include its own JavaScript code, this block may be overridden to add the relevant script tag to the page. We will call this block external, because it is used to link external files to pages. Open templates/base.html and modify its head section as follows: <head> <title>Django Bookmarks | {% block title %}{% endblock %}</title> <link rel="stylesheet" href="/site_media/style.css" type="text/css"/> <script type="text/javascript" src="/site_media/jquery.js"> </script> {% block external %}{% endblock %}</head> And we have finished. From now on, when a view wants to use some JavaScript code, it can link a JavaScript file to its template by overriding the external template block. Before we start to implement Ajax enhancements in our project, let's go through a quick introduction to the jQuery framework. The jQuery JavaScript Framework jQuery is a library of JavaScript functions that facilitates interacting with HTML documents and manipulating them. The library is designed to reduce the time and effort spent on writing code and achieving cross-browser compatibility, while at the same time taking full advantage of what JavaScript offers to build interactive and responsive web applications. The general workflow of using jQuery consists of two steps: Select an HTML element or a group of elements to work on. Apply a jQuery method to the selected group Element Selectors jQuery provides a simple approach to select elements; it works by passing a CSS selector string to a function called $. Here are some examples to illustrate the usage of this function: If you want to select all anchor (<a>) elements on a page, you can use the following function call: $("a") If you want to select anchor elements which have the .title CSS class, use $("a.title") To select an element whose ID is #nav, you can use $("#nav") To select all list item (<li>) elements inside #nav, use $("#nav li") And so on. The $() function constructs and returns a jQuery object. After that, you can call methods on this object to interact with the selected HTML elements. jQuery Methods jQuery offers a variety of methods to manipulate HTML documents. You can hide or show elements, attach event handlers to events, modify CSS properties, manipulate the page structure and, most importantly, perform Ajax requests. Before we go through some of the most important methods, I highly recommend using the Firefox web browser and an extension called Firebug to experiment with jQuery. This extension provides a JavaScript console that is very similar to the interactive Python console. With it, you can enter JavaScript statements and see their output directly without having to create and edit files. To obtain Firebug, go to http://www.getfirebug.com/, and click on the install link. Depending on the security settings of Firefox, you may need to approve the website as a safe source of extensions. If you do not want to use Firefox for any reason, Firebug's website offers a "lite" version of the extension for other browsers in the form of a JavaScript file. Download the file to the site_media directory, and then include it in the templates/base.html template as we did with jquery.js: <head> <title>Django Bookmarks | {% block title %}{% endblock %}</title> <link rel="stylesheet" href="/site_media/style.css" type="text/css"/> <script type="text/javascript" src="/site_media/firebug.js"> </script> <script type="text/javascript" src="/site_media/jquery.js"> </script> {% block external %}{% endblock %}</head> To experiment with the methods outlined in this section, launch the development server and navigate to the application's main page. Open the Firebug console by pressing F12, and try selecting elements and manipulating them. Hiding and Showing Elements Let's start with something simple. To hide an element on the page, call the hide() method on it. To show it again, call the show() method. For example, try this on the navigation menu of your application: >>> $("#nav").hide()>>> $("#nav").show() You can also animate the element while hiding and showing it. Try the fadeOut(), fadeIn(), slideUp() or slideDown() methods to see two of these animated effects. Of course, these methods (like all other jQuery methods) also work if you select more than one element at once. For example, if you open your user page and enter the following method call into the Firebug console, all of the tags will disappear: >>> $('.tags').slideUp() Accessing CSS Properties and HTML Attributes Next, we will learn how to change CSS properties of elements. jQuery offers a method called css() for performing CSS operations. If you call this method with a CSS property name passed as a string, it returns the value of this property: >>> $("#nav").css("display") Result: "block" If you pass a second argument to this method, it sets the specified CSS property of the selected element to the additional argument: >>> $("#nav").css("font-size", "0.8em") Result: <div id="nav" style="font-size: 0.8em;"> In fact, you can manipulate any HTML attribute and not just CSS properties. To do so, use the attr() method which works in a similar way to css(). Calling it with an attribute name returns the attribute value, whereas calling it with an attribute name/value pair sets the attribute to the passed value. To test this, go to the bookmark submission form and enter the following into the console: >>> $("input").attr("size", "48") Results: <input id="id_url" type="text" size="48" name="url"> <input id="id_title" type="text" size="48" name="title"> <input id="id_tags" type="text" size="48" name="tags"> (Output may slightly differ depending on the versions of Firefox and Firebug). This will change the sizes of all input elements on the page at once to 48. In addition, there are shortcut methods to get and set commonly used attributes, such as val() which returns the value of an input field when called without arguments, and sets this value to an argument if you pass one. There is also html() which controls the HTML code inside an element. Finally, there are two methods that can be used to attach or detach a CSS class to an element; they are called addClass() and removeClass(). A third method is provided to toggle a CSS class, and it is called toggleClass(). All of these class methods take the name of the class to be changed as a parameter. Manipulating HTML Documents Now that you are comfortable with manipulating HTML elements, let's see how to add new elements or remove existing elements. To insert HTML code before an element, use the before() method, and to insert code after an element, use the after() method. Notice how jQuery methods are well-named and very easy to remember! Let's test these methods by inserting parentheses around tag lists on the user page. Open your user page and enter the following in the Firebug console: >>> $(".tags").before("<strong>(</strong>")>>> $(".tags").after("<strong>)</strong>") You can pass any string you want to - before() or after() - the string may contain plain text, one HTML element or more. These methods offer a very flexible way to dynamically add HTML elements to an HTML document. If you want to remove an element, use the remove() method. For example: $("#nav").remove() Not only does this method hide the element, it also removes it completely from the document tree. If you try to select the element again after using the remove() method, you will get an empty set: >>> $("#nav") Result: [] Of course, this only removes the elements from the current instance of the page. If you reload the page, the elements will appear again. Traversing the Document Tree Although CSS selectors offer a very powerful way to select elements, there are times when you want to traverse the document tree starting from a particular element. For this, jQuery provides several methods. The parent() method returns the parent of the currently selected element. The children() method returns all the immediate children of the selected element. Finally, the find() method returns all the descendants of the currently selected element. All of these methods take an optional CSS selector string to limit the result to elements that match the selector. For example, $("#nav").find ("li") returns all the <li> descendants of #nav. If you want to access an individual element of a group, use the get() method which takes the index of the element as a parameter. $("li").get(0) for example returns the first <li> element out of the selected group. Handling Events Next, we will learn about event handlers. An event handler is a JavaScript function that is invoked when a particular event happens, for example, when a button is clicked or a form is submitted. jQuery provides a large set of methods to attach handlers to events; events of particular interest in our application are mouse clicks and form submissions. To handle the event of clicking on an element, we select this element and call the click() method on it. This method takes an event handler function as a parameter. Let's try this using the Firebug console. Open the main page of the application, and insert a button after the welcome message: >>> $("p").after("<button id="test-button">Click me!</button>") (Notice that we had to escape the quotations in the strings passed to the after() method.) If you try to click this button, nothing will happen, so let's attach an event handler to it: >>> $("#test-button").click(function () { alert("You clicked me!"); }) Now, when you click the button, a message box will appear. How did this work? The argument that we passed to click() may look a bit complicated, so let's examine it again: function () { alert("You clicked me!"); } This appears to be a function declaration but without a function name. Indeed, this construct creates what is called an anonymous function in JavaScript terminology, and it is used when you need to create a function on the fly and pass it as an argument to another function. We could have avoided using anonymous functions and declared the event handler as a regular function: >>> function handler() { alert("You clicked me!"); }>>> $("#test-button").click(handler) The above code achieves the same effect, but the first one is more concise and compact. I highly recommend you to get used to anonymous functions in JavaScript (if you are not already), as I'm sure you will appreciate this construct and find it more readable after using it for a while. Handling form submissions is very similar to handling mouse clicks. First, you select the form, and then you call the submit() method on it and pass the handler as an argument. We will use this method many times while adding Ajax features to our project in later sections. Sending Ajax Requests Before we finish this section, let's talk about Ajax requests. jQuery provides many ways to send Ajax requests to the server. There is, for example, the load() method which takes a URL and loads the page at this URL into the selected element. There are also methods for sending GET or POST requests, and receiving the results. We will examine these methods in more depth while implementing Ajax features in our project. What Next? This wraps up our quick introduction to jQuery. The information provided in this section will be enough to continue with this article, and once you finish the article, you will be able to implement many interesting Ajax features on your own. But please keep in mind that this jQuery introduction is only the tip of the iceberg. If you want a comprehensive treatment of the jQuery framework, I highly recommend the book "Learning jQuery" from Packt Publishing, as it covers jQuery in much more detail. You can find out more about the book at: http://www.packtpub.com/jQuery Implementing Live Searching of Bookmarks We will start introducing Ajax into our application by implementing live searching. The idea behind this feature is simple: when the user types a few keywords into a text field and clicks search, a script works behind the scenes to fetch search results and present them on the same page. The search page does not reload, thus saving bandwidth, and providing a better and more responsive user experience. Before we start implementing this, we need to keep in mind an important rule while working with Ajax: write your application so that it works without Ajax, and then introduce Ajax to it. If you do so, you ensure that everyone will be able to use your application, including users who don't have JavaScript enabled and those who use browsers without Ajax support. Implementing Searching So before we work with Ajax, let's write a simple view that searches bookmarks by title. First of all, we need to create a search form, so open bookmarks/forms.py and add the following class to it: class SearchForm(forms.Form): query = forms.CharField( label='Enter a keyword to search for', widget=forms.TextInput(attrs={'size': 32})) As you can see, it's a pretty straightforward form class with only one text field. This field will be used by the user to enter search keywords. Next, let's create a view for searching. Open bookmarks/views.py and enter the following code into it: def search_page(request): form = SearchForm() bookmarks = [] show_results = False if request.GET.has_key('query'): show_results = True query = request.GET['query'].strip() if query: form = SearchForm({'query' : query}) bookmarks = Bookmark.objects.filter (title__icontains=query)[:10] variables = RequestContext(request, { 'form': form, 'bookmarks': bookmarks, 'show_results': show_results, 'show_tags': True, 'show_user': True })return render_to_response('search.html', variables) Apart from a couple of method calls, the view should be very easy to understand. We first initialize three variables, form which holds the search form, bookmarks which holds the bookmarks that we will display in the search results, and show_results which is a Boolean flag. We use this flag to distinguish between two cases: The search page was requested without a search query. In this case, we shouldn't display any search results, not even a "No bookmarks found" message. The search page was requested with a search query. In this case, we display the search results, or a "No bookmarks found" message if the query does not match any bookmarks. We need the show_results flag because the bookmarks variable alone is not enough to distinguish between the above two cases. bookmarks will empty when the search page is requested without a query, and it will also be empty when the query does not match any bookmarks. Next, we check whether a query was sent by calling the has_key method on the request.GET dictionary: if request.GET.has_key('query'): show_results = True query = request.GET['query'].strip() if query: form = SearchForm({'query' : query}) bookmarks = Bookmark.objects.filter(title__icontains=query)[:10] We use GET instead of POST here because the search form does not create or change data; it merely queries the database, and the general rule is to use GET with forms that query the database, and POST with forms that create, change or delete records from the database. If a query was submitted by the user, we set show_results to True and call strip() on the query string to ensure that it contains non-whitespace characters before we proceed with searching. If this is indeed the case, we bind the form to the query and retrieve a list of bookmarks that contain the query in their title. Searching is done by using a method called filter in Bookmark.objects. This is the first time that we have used this method; you can think of it as the equivalent of a SELECT statements in Django models. It receives the search criteria in its arguments and returns search results. The name of each argument must adhere to the following naming convention: field__operator Note that field and operator are separated by two underscores: field is the name of the field that we want to search by and operator is the lookup method that we want to use. Here is a list of the commonly-used operators: exact: The value of the argument is an exact match of the field. contains: The field contains the value of the argument. startswith: The field starts with the value of the argument. lt: The field is less than the value of the argument. gt: The field is greater than the value of the argument. Also, there are case-insensitive versions of the first three operators: iexact, icontains and istartswith. After this explanation of the filter method, let's get back to our search view. We use the icontains operator to get a list of bookmarks that match the query and retrieve the first ten items using Python's list slicing syntax. Finally we pass all the variables to a template called search.html to render the search page. Now create the search.html template in the templates directory with the following content: {% extends "base.html" %}{% block title %}Search Bookmarks{% endblock %}{% block head %}Search Bookmarks{% endblock %}{% block content %}<form id="search-form" method="get" action="."> {{ form.as_p }} <input type="submit" value="search" /></form><div id="search-results"> {% if show_results %} {% include 'bookmark_list.html' %} {% endif %}</div>{% endblock %} The template consists of familiar aspects that we have used before. We build the results list by including the bookmark_list.html like we did when building the user and tag pages. We gave the search form an ID, and rendered the search results in a div identified by another ID so that we can interact with them using JavaScript later. Notice how many times the include template tag saved us from writing additional code? It also lets us modify the look of the bookmarks list by editing a single file. This Django template feature is indeed very helpful in organizing and managing templates. Before you test the new view, add an entry for it in urls.py: urlpatterns = patterns('', # Browsing (r'^$', main_page), (r'^user/(w+)/$', user_page), (r'^tag/([^s]+)/$', tag_page), (r'^tag/$', tag_cloud_page), (r'^search/$', search_page),) Now test the search view by navigating to http://127.0.0.1:8000/search/ and experiment with it. You can also add a link to it in the navigation menu if you want; edit templates/base.html and add the highlighted code: <div id="nav"> <a href="/">home</a> | {% if user.is_authenticated %} <a href="/save/">submit</a> | <a href="/search/">search</a> | <a href="/user/{{ user.username }}/"> {{ user.username }}</a> | <a href="/logout/">logout</a> {% else %} <a href="/login/">login</a> | <a href="/register/">register</a> {% endif %}</div> We now have a functional (albeit very basic) search page. Thanks to our modular code, the task will turn out to be much simpler than it may seem. Implementing Live Searching To implement live searching, we need to do two things: Intercept and handle the event of submitting the search form. This can be done using the submit() method of jQuery. Use Ajax to load the search results in the back scenes, and insert them into the page. This can be done using the load() method of jQuery as we will see next. jQuery offers a method called load() that retrieves a page from the server and inserts its contents into the selected element. In its simplest form, the function takes the URL of the remote page to be loaded as a parameter. First of all, let's modify our search view a little so that it only returns search results without the rest of the search page when it receives an additional GET variable called ajax. We do so to enable JavaScript code on the client-side to easily retrieve search results without the rest of the search page HTML. This can be done by simply using the bookmark_list.html template instead of search.html when request.GET contains the key ajax. Open bookmarks/views.py and modify search_page (towards the end) so that it becomes as follows: def search_page(request): [...] variables = RequestContext(request, { 'form': form, 'bookmarks': bookmarks, 'show_results': show_results, 'show_tags': True, 'show_user': True }) if request.GET.has_key('ajax'): return render_to_response('bookmark_list.html', variables) else: return render_to_response('search.html', variables) Next, create a file called search.js in the site_media directory and link it to templates/search.html like this: {% extends "base.html" %}{% block external %} <script type="text/javascript" src="/site_media/search.js"> </script>{% endblock %}{% block title %}Search Bookmarks{% endblock %}{% block head %}Search Bookmarks{% endblock %}[...] Now for the fun part! Let's create a function that loads search results and inserts them into the corresponding div. Write the following code into site_media/search.js: function search_submit() { var query = $("#id_query").val(); $("#search-results").load( "/search/?ajax&query=" + encodeURIComponent(query) ); return false;} Let's go through this function line by line: The function first gets the query string from the text field using the val() method. We use the load() method to get search results from the search_page view, and insert the search results into the #search-results div. The request URL is constructed by first calling encodeURIComponent on query, which works exactly like the urlencode filter we used in Django templates. Calling this function is important to ensure that the constructed URL remains valid even if the user enters special characters into the text field such as &. After escaping query, we concatenate it with /search/?ajax&query=. This URL invokes the search_page view and passes the GET variables ajax and query to it. The view returns search results, and the load() method in turn loads the results into the #search-results div. We return false from the function to tell the browser not to submit the form after calling our handler. If we don't return false in the function, the browser will continue to submit the form as usual, and we don't want that. One little detail remains; where and when to attach search_submit to the submit event of the search form? A rule of a thumb when writing JavaScript is that we cannot manipulate elements in the document tree before the document finishes loading. Therefore, our function must be invoked as soon as the search page is loaded. Fortunately for us, jQuery provides a method to execute a function when the HTML document is loaded. Let's utilize it by appending the following code to site_media/search.js: $(document).ready(function () { $("#search-form").submit(search_submit);}); $(document) selects the document element of the current page. Notice that there are no quotations around document; it's a variable provided by the browser, not a string. ready() is a method that takes a function and executes it as soon as the selected element finishes loading. So in effect, we are telling jQuery to execute the passed function as soon as the HTML document is loaded. We pass an anonymous function to the ready() method; this function simply binds search_submit to the submit event of the form #search-form. That's it. We've implemented live searching with less than fifteen lines of code. To test the new functionality, navigate to http://127.0.0.1:8000/search/, submit queries, and notice how the results are displayed without reloading the page: The information covered in this section can be applied to any form that needs to be processed in the back scenes without reloading the page. You can, for example, create a comment form with a preview button that loads the preview in the same page without reloading. In the next section, we will enhance the user page to let users edit their bookmarks in place, without navigating away from the user page. Editing Bookmarks in Place Editing of posted content is a very common task in web sites. It's usually implemented by offering an edit link next to content. When clicked, this link takes the user to a form located on another page where content can be edited. When the user submits the form, they are redirected back to the content page. Imagine, on the other hand, that you could edit content without navigating away from the content page. When you click edit, the content is replaced with a form. When you submit the form, it disappears and the updated content appears in its place. Everything happens on the same page; edit form rendering and submission are done using JavaScript and Ajax. Wouldn't such a workflow be more intuitive and responsive? The technique described above is called in-place editing. It is now finding its way into web applications and becoming more common. We will implement this feature in our application by letting the user edit their bookmarks in place on the user page. Since our application doesn't support the editing of bookmarks yet, we will implement this first, and then modify the editing procedure to work in place. Implementing Bookmark Editing We already have most of the parts that are needed to implement bookmark editing. This was easy to do thanks to the get_or_create method provided by data models. This little detail greatly simplifies the implementation of bookmark editing. Here is what we need to do: We pass the URL of the bookmark that we want to edit as a GET variable named url to the bookmark_save_page view. We modify bookmark_save_page so that it populates the fields of the bookmark form if it receives the GET variable. The form is populated with the data of the bookmark that corresponds to the passed URL. When the populated form is submitted, the bookmark will be updated as we explained earlier, because it will look like the user submitted the same URL another time. Before we implement the technique described above, let's reduce the size of bookmark_save_page by moving the part that saves a bookmark to a separate function. We will call this function _bookmark_save. The underscore at the beginning of the name tells Python not to import this function when the views module is imported. The function expects a request and a valid form object as parameters; it saves a bookmark out of the form data, and returns this bookmark. Open bookmarks/views.py and create the following function; you can cut and paste the code from bookmark_save_page if you like, as we are not making any changes to it except for the return statement at the end. def _bookmark_save(request, form): # Create or get link. link, dummy = Link.objects.get_or_create(url=form.clean_data['url']) # Create or get bookmark. bookmark, created = Bookmark.objects.get_or_create( user=request.user, link=link ) # Update bookmark title. bookmark.title = form.clean_data['title'] # If the bookmark is being updated, clear old tag list. if not created: bookmark.tag_set.clear() # Create new tag list. tag_names = form.clean_data['tags'].split() for tag_name in tag_names: tag, dummy = Tag.objects.get_or_create(name=tag_name) bookmark.tag_set.add(tag)# Save bookmark to database and return it.bookmark.save()return bookmark Now in the same file, replace the code that you removed from bookmark_save_page with a call to _bookmark_save: @login_requireddef bookmark_save_page(request): if request.method == 'POST': form = BookmarkSaveForm(request.POST) if form.is_valid(): bookmark = _bookmark_save(request, form) return HttpResponseRedirect( '/user/%s/' % request.user.username )else: form = BookmarkSaveForm()variables = RequestContext(request, { 'form': form})return render_to_response('bookmark_save.html', variables) The current logic in bookmark_save_page works like this: if there is POST data:Validate and save bookmark.Redirect to user page.else:Create an empty form.Render page. To implement bookmark editing, we need to slightly modify the logic as follows: if there is POST data: Validate and save bookmark. Redirect to user page.else if there is a URL in GET data: Create a form an populate it with the URL's bookmark.else: Create an empty form.Render page. Let's translate the above pseudo code into Python. Modify bookmark_save_page in bookmarks/views.py so that it looks like the following (new code is highlighted): from django.core.exceptions import ObjectDoesNotExist@login_requireddef bookmark_save_page(request): if request.method == 'POST': form = BookmarkSaveForm(request.POST) if form.is_valid(): bookmark = _bookmark_save(request, form) return HttpResponseRedirect( '/user/%s/' % request.user.username ) elif request.GET.has_key('url'): url = request.GET['url'] title = '' tags = '' try: link = Link.objects.get(url=url) bookmark = Bookmark.objects.get( link=link, user=request.user ) title = bookmark.title tags = ' '.join( tag.name for tag in bookmark.tag_set.all() ) except ObjectDoesNotExist: pass form = BookmarkSaveForm({ 'url': url, 'title': title, 'tags': tags }) else: form = BookmarkSaveForm() variables = RequestContext(request, { 'form': form }) return render_to_response('bookmark_save.html', variables) This new section of the code first checks whether a GET variable called url exists. If this is the case, it loads the corresponding Link and Bookmark objects of this URL, and binds all the data to a bookmark saving form. You may wonder why we load the Link and Bookmark objects in a try-except construct that silently ignores exceptions. Indeed, it's perfectly valid to raise an Http404 exception if no bookmark was found for the requested URL. But our code chooses to only populate the URL field in this situation, leaving the title and tags fields empty.
Read more
  • 0
  • 0
  • 11304

Packt
22 Oct 2009
8 min read
Save for later

Working with Rails – ActiveRecord, Migrations, Models, Scaffolding, and Database Completion

Packt
22 Oct 2009
8 min read
ActiveRecord, Migrations, and Models ActiveRecord is the ORM layer (see the section Connecting Rails to a Database in the previous article) used in Rails. It is used by controllers as a proxy to the database tables. What's really great about this is that it protects you against having to code SQL. Writing SQL is one of the least desirable aspects of developing with other web-centric languages (like PHP): having to manually build SQL statements, remembering to correctly escape quotes, and creating labyrinthine join statements to pull data from multiple tables. ActiveRecord does away with all of that (most of the time), instead presenting database tables through classes (a class which wraps around a database table is called a model) and instances of those classes (model instances). The best way to illustrate the beauty of ActiveRecord is to start using it. Model == Table The base concept in ActiveRecord is the model. Each model class is stored in the app/models directory inside your application, in its own file. So, if you have a model called Person, the file holding that model is in app/models/person.rb, and the class for that model, defined in that file, is called Person. Each model will usually correspond to a table in the database. The name of the database table is, by convention, the pluralized (in the English language), lower-case form of the model's class name. In the case of our Intranet application, the models are organized as follows: Table Model class File containing class definition (in app/models) people Person person.rb companies Company company.rb addresses Address address.rb We haven't built any of these yet, but we will shortly. Which Comes First: The Model or The Table? To get going with our application, we need to generate the tables to store data into, as shown in the previous section. It used to be at this point where we would reach for a MySQL client, and create the database tables using a SQL script. (This is typically how you would code a database for a PHP application.) However, things have moved on in the Rails world. The Rails developers came up with a pretty good (not perfect, but pretty good) mechanism for generating databases without the need for SQL: it's called migrations, and is a part of ActiveRecord. Migrations enable a developer to generate a database structure using a series of Ruby script files (each of which is an individual migration) to define database operations. The "operations" part of that last sentence is important: migrations are not just for creating tables, but also for dropping tables, altering them, and even adding data to them. It is this multi-faceted aspect of migrations which makes them useful, as they can effectively be used to version a database (in much the same way as Subversion can be used to version code). A team of developers can use migrations to keep their databases in sync: when a change to the database is made by one of the team and coded into a migration, the other developers can apply the same migration to their database, so they are all working with a consistent structure. When you run a migration, the Ruby script is converted into the SQL code appropriate to your database server and executed over the database connection. However, migrations don't work with every database adapter in Rails: check the Database Support section of the ActiveRecord::Migration documentation to find out whether your adapter is supported. At the time of writing, MySQL, PostgreSQL, SQLite, SQL Server, Sybase, and Oracle were all supported by migrations. Another way to check whether your database supports migrations is to run the following command in the console (the output shown below is the result of running this using the MySQL adapter): >> ActiveRecord::Base.connection.supports_migrations? => true We're going to use migrations to develop our database, so we'll be building the model first. The actual database table will be generated from a migration attached to the model. Building a Model with Migrations In this section, we're going to develop a series of migrations to recreate the database structure outlined in Chapter 2 of the book Ruby on Rails Enterprise Application Development: Plan, Program, Extend. First, we'll work on a model and migration for the people table. Rails has a generate script for generating a model and its migration. (This script is in the script directory, along with the other Rails built-in scripts.) The script builds the model, a base migration for the table, plus scripts for testing the model. Run it like this: $ ruby script/generate model Person exists app/models/  exists test/unit/    exists test/fixtures/    create app/models/person.rb    create test/unit/person_test.rb    create test/fixtures/people.yml    exists db/migrate    create db/migrate/001_create_people.rb Note that we passed the singular, uppercase version of the table name ("people" becomes "Person") to the generate script. This generates a Person model in the file app/models/person.rb; and a corresponding migration for a people table (db/ migrate/001_create_people.rb). As you can see, the script enforces the naming conventions, which connects the table to the model. The migration name is important, as it contains sequencing information: the "001" part of the name indicates that running this migration will bring the database schema up to version 1; subsequent migrations will be numbered "002...", "003..." etc., each specifying the actions required to bring the database schema up to that version from the previous one. The next step is to edit the migration so that it will create the people table structure. At this point, we can return to Eclipse to do our editing. (Remember that you need to refresh the file list in Eclipse to see the files you just generated). Once, you have started Eclipse, open the file db/migrate/001_create_people.rb. It should look like this:     class CreatePeople < ActiveRecord::Migration        def self.up            create_table :people do |t|                # t.column :name, :string            end        end        def self.down            drop_table :people        end    end This is a migration class with two class methods, self.up and self.down. The self.up method is applied when migrating up one database version number: in this case, from version 0 to version 1. The self.down method is applied when moving down a version number (from version 1 to 0). You can leave self.down as it is, as it simply drops the database table. This migration's self.up method is going to add our new table using the create_table method, so this is the method we're going to edit in the next section. Ruby syntaxExplaining the full Ruby syntax is outside the scope of this book. For our purposes, it suffices to understand the most unusual parts. For example, in the create_table method call shown above:,     create_table :people do |t|        t.column :title, :string        ...    end The first unusual part of this is the block construct, a powerful technique for creating nameless functions. In the example code above, the block is initialized by the do keyword; this is followed by a list of parameters to the block (in this case, just t); and closed by the end keyword. The statements in-between the do and end keywords are run within the context of the block. Blocks are similar to lambda functions in Lisp or Python, providing a mechanism for passing a function as an argument to another function. In the case of the example, the method call create_table:people is passed to a block, which accepts a single argument, t; t has methods called on it within the body of the block. When create_table is called, the resulting table object is "yielded" to the block; effectively, the object is passed into the block as the argument t, and has its column method called multiple times. One other oddity is the symbol: that's what the words prefixed with a colon are. A symbol is the name of a variable. However, in much of Rails, it is used in contexts where it is functionally equivalent to a string, to make the code look more elegant. In fact, in migrations, strings can be used interchangeably with symbols.  
Read more
  • 0
  • 0
  • 5395

article-image-customer-management-joomla-and-virtuemart
Packt
22 Oct 2009
7 min read
Save for later

Customer Management in Joomla! and VirtueMart

Packt
22 Oct 2009
7 min read
Note that all VirtueMart customers must be registered with Joomla!. However, not all Joomla! users need to be the VirtueMart customers. Within the first few sections of this article, you will have a clear concept about user management in Joomla! and VirtueMart. Customer management Customer management in VirtueMart includes registering customers to the VirtueMart shop, assigning them to user groups for appropriate permission levels, managing fields in the registration form, viewing and editing customer information, and managing the user groups. Let's dive in to these activities in the following sections. Registration/Authentication of customers Joomla! has a very strong user registration and authentication system. One core component in Joomla! is com_users, which manages user registration and authentication in Joomla!. However, VirtueMart needs some extra information for customers. VirtueMart collects this information through its own customer registration process, and stores the information in separate tables in the database. The extra information required by VirtueMart is stored in a table named jos_vm_user_info, which is related to the jos_users table by the user id field. Usually, when a user registers to the Joomla! site, they also register with VirtueMart. This depends on some global settings. In the following sections, we are going to learn how to enable the user registration and authentication for VirtueMart. Revisiting registration settings We configure the registration settings from VirtueMart's administration panel Admin | Configuration | Global screen. There is a section titled User Registration Settings, which defines how the user registration will be handled: Ensure that your VirtueMart shop has been configured as shown in the screenshot above. The first field to configure is the User Registration Type. Selecting Normal Account Creation in this field creates both a Joomla! and VirtueMart account during user registration. For our example shop, we will be using this setting. Joomla!'s new user activation should be disabled when we are using VirtueMart. That means the Joomla! New account activation necessary? field should read No. Enabling VirtueMart login module There is a default module in Joomla! which is used for user registrations and login. When we are using this default Login Form (mod_login module), it does not collect information required by VirtueMart, and does not create customers in VirtueMart. By default, when published, the mod_login module looks like the following screenshot: As you see, registered users can log in to Joomla! through this form, recover their forgotten password by clicking on the Forgot your password? link, and create a new user account by clicking on the Create an account link. When a user clicks on the Create an account link, they get the form as shown in the following screenshot: We see that normal registration in Joomla! only requires four pieces of information: Name, Username, Email, and Password. It does not collect information needed in VirtueMart, such as billing and shipping address, to be a customer. Therefore, we need to disable the mod_login module and enable the mod_virtuemart_login module. We have already learned how to enable and disable a module in Joomla!. We have also learned how to install modules. By default, the mod_virtuemart_login module's title is VirtueMart Login. You may prefer to show this title as Login only. In that case, click on the VirtueMart Login link in the Module Name column. This brings the Module:[Edit] screen: In the Title field, type Login (or any other text you want to show as the title of this module). Make sure the module is enabled and position is set to left or right. Click  on the Save icon to save your settings. Now, browse to your site's front-page  (for example, http://localhost/bdosn/), and you will see the login form as shown in the following screenshot: As you can see, this module has the same functionalities as we saw in the mod_login module of Joomla!. Let us test the account creation in this module. Click on the Register link. It brings the following screen: The registration form has three main sections: Customer Information, Bill To Information, and Send Registration. At the end, there is the Send Registration button for submitting the form data. In the Customer Information section, type your email address, the desired username, and password. Confirm the password by typing it again in the Confirm password field. In the Bill To Information section, type the address details where bills are to be sent. In the entire form, required fields are marked with an asterisk (*). You must provide information for these required fields. In the Send Registration section, you need to agree to the Terms of Service. Click on the Terms of Service link to read it. Then, check the I agree to the Terms of Service checkbox and click on the Send Registration button to submit the form data: If you have provided all of the required information and submitted a unique  email address, the registration will be successful. On successful completion of registration, you get the following screen notification, and will be logged in to  the shop automatically: If you scroll down to the Login module, you will see that you are logged in and greeted by the store. You also see the User Menu in this screen: Both the User Menu and the Login modules contain a Logout button. Click on either of these buttons to log out from the Joomla! site. In fact, links in the User Menu module are for Joomla! only. Let us try the link Your Details. Click on the Your Details link, and you will see the information shown in the following screenshot: As you see in the screenshot above, you can change your full name, email, password, frontend language, and time zone. You cannot view any information regarding billing address, or other information of the customer. In fact, this information is for regular Joomla! users. We can only get full customer information by clicking on the Account Maintenance link in the Login module. Let us try it. Click on the Account Maintenance link, and it shows the following screenshot: The Account Maintenance screen has three sections: Account Information, Shipping Information, and Order Information. Click on the Account Information link to see what happens. It shows the following screen: This shows Customer Information and Bill To Information, which have been entered during user registration. The last section on this screen is the Bank Information, from where the customer can add bank account information. This section looks like the following screenshot: As you can see, from the Bank Account Info section, the customers can enter their bank account information including the account holder's name, account number, bank's sorting code number, bank's name, account type, and IBAN (International Bank Account Number). Entering this information is important when you are using  a Bank Account Debit payment method. Now, let us go back to the Account Maintenance screen and see the other sections. Click on the Shipping Information link, and you get the following screen: There is one default shipping address, which is the same as the billing address. The customers can create additional shipping addresses. For creating a new shipping address, click on the Add Address link. It shows the following screen:
Read more
  • 0
  • 0
  • 11449
article-image-deploying-net-based-applications-microsoft-windows-ce-enabled-smart-devices
Packt
22 Oct 2009
4 min read
Save for later

Deploying .NET-based Applications on to Microsoft Windows CE Enabled Smart Devices

Packt
22 Oct 2009
4 min read
Introducing Microsoft Windows Mobile There exist several types of smart devices in the market including Smart Phones, Pocket PCs, Pocket PC Phones, Tablet PCs, etc. Every smart device is installed with a mobile‑based operating system with respect to the features of the device. One of such operating systems is Microsoft Windows CE. Microsoft Windows CE is a small, embedded operating system (runs from ROM) that has a look and feel similar to Microsoft Windows 95/98. It includes scaled down versions of Microsoft Excel, Microsoft Word, Microsoft Internet Explorer, etc. Microsoft Windows Mobile (Windows Mobile in short) is a complete software platform built on Windows CE. Unlike Windows CE, the Windows Mobile for Smart Phone or Pocket PC operating systems is specifically designed for devices that require a specialized hardware configuration. The software includes standardized interfaces and applications that ensure compatibility across hardware designs. The Pocket PC is the best example device that gets equipped with Microsoft Windows Mobile operating system. The Pocket PC runs Windows CE as its core operating system. Pocket PCs come with mobile versions of Microsoft Office applications in addition to Microsoft Outlook Mobile. Though there are different Pocket PCs, many come with Wi-Fi to enable you to connect to the Internet when you are near to a wireless hotspot. You can compose email messages and send them wirelessly or by synchronizing with your desktop computer. A Pocket PC Phone is a bit different from an ordinary Pocket PC. You can do everything with a Pocket PC Phone that you can do with a Pocket PC, but with the addition of cellular phone capabilities. If you have a Pocket PC Phone, you can access the Internet through the GPRS service. A Smart Phone has phone capabilities and comes with a smaller set of applications. Though you can add third-party software titles to your Smart Phone, the smaller keypad and screen are designed to give you quick one-handed access to important data. A Smart Phone is a good choice for business users who need to check email, keep track of their calendars, and take voice notes. Microsoft.NET enables us to develop and deploy .NET applications on Microsoft Windows Mobile-enabled smart devices like Smart Phones, Pocket PCs, Tablet PCs, etc. To develop for either Smart Phones or Pocket PCs, we need not really buy those devices. We simply need to have smart device client extensions installed as a part of Visual Studio 2005 (which automatically installs .NET Compact Edition). When the extensions are installed, we are provided with few device emulators for developing and testing .NET-based mobile applications. However, for testing and production, it is recommended to have physical smart devices. The next section focuses on developing a simple Pocket PC application, which consumes the web service developed previously. Consuming a Web Service from Pocket PC Now, let us make use a web service for the Pocket PC. You need not have a physical Pocket PC in your hands to test it. We can simply use existing emulators available as part of Visual Studio 2005. The following are the steps: Open Visual Studio 2005 Environment    Go to File | New | Project.    Select and provide information as shown in the following figure:      Add a Web Reference for the web service you created.    Drag and drop a DataGrid on to the Pocket PC emulator as shown below:      Modify the existing code as follows: Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.DataGrid1.DataSource = (New EmpService.Service).getList.Tables(0) End SubEnd Class     Press F5, and select any Emulator for deployment. The output should look like the following: Conclusion We have seen the deployment of .NET-based application on to smart devices enabled with Microsoft Windows Mobile operating system.
Read more
  • 0
  • 0
  • 2906

article-image-python-ldap-applications-part-1-installing-and-configuring-python-ldap-library-and-bin
Packt
22 Oct 2009
16 min read
Save for later

Configuring and securing PYTHON LDAP Applications Part 1

Packt
22 Oct 2009
16 min read
This article mini-series by Matt Butcher will look at the Python application programmers interface (API) for the LDAP libraries, and using this API, we will connect to our OpenLDAP server and manipulate the directory information tree. More specifically, we will cover the following in this article series: Installing and configuring the Python-LDAP library. Binding to an LDAP directory. Comparing attributes between the client and server. Performing searches on the directory. Modifying the directory information tree with add, delete, and modify operations. Modifying directory passwords. Working with LDAP schemas. This first part will deal with installation and configuration of the Python-LDAP library. We will then see how the binding operation is performed. Installing Python-LDAP There are a couple of LDAP libraries available for Python, but the most popular is the Python-LDAP module, which (as with the PHP API) uses the OpenLDAP C library as a base for providing network access to an LDAP server. Like OpenLDAP, the Python-LDAP API is Open Source. It works on Linux, Windows, Mac OS X, BSD, and probably other UNIX operating systems as well (platforms that have both Python and OpenLDAP available). The source code is available at the official Python-LDAP website: http://python-ldap.sourceforge.net. Here pre-compiled binaries for many platforms are available, but we will install the version in the Ubuntu repository. Before installing Python-LDAP, you will need to have the Python scripting language installed. Typically, this is installed by default on Ubuntu (and on most flavors of Linux). Installing Python-LDAP requires only one command: $ sudo apt-get install python-ldap This will choose the module or modules that match the installed Python version. That is, if you are running Python 2.4 (the stable version, at the time of writing), this will install the python2.4-ldap package. The library, which consists of several Python packages, will be installed into /usr/lib/python2.4/site-packages/. In Ubuntu, there is no need to run further configuration in order to make use of the Python-LDAP library. We are ready to dive into the API. If you install by hand, either from source or from the binary packages, you may need to add the Python-LDAP library to your Python path. See the Python documentation for details. The Python-LDAP API is well documented. The documentation is available online at the official Python-LDAP website: http://python-ldap.sourceforge.net/docs.shtml. You may find it more convenient to download a copy of the documentation and use it locally. In previous versions of Ubuntu Python-LDAP documentation was available in the package python-ldap-doc, which could be installed with apt-get. Also, many of the Python-LDAP functions and objects have documentation strings that can be accessed from the Python interpreter like this: >>> print ldap.initialize.__doc__ Return LDAPObject instance by opening LDAP connection to LDAP host specified by LDAP URL Parameters: uri LDAP URL containing at least connection scheme and hostport, e.g. ldap://localhost:389 trace_level If non-zero a trace output of LDAP calls is generated. trace_file File object where to write the trace output to. Default is to use stdout. The documentation string usually contains a brief description of the function or object, and is a useful quick reference. A Quick Overview of the Python LDAP API Now that the package is installed, let's take a quick look at what was installed. The Python-LDAP package comes with nine different modules: ldap: This is the main LDAP module. It contains the functions  necessary for performing LDAP operations, such as binding, searching,  adding, and modifying. ldap.async: Python can do synchronous and asynchronous transactions.  This module provides utilities that are useful when performing asynchronous  operations. ldap.cidict: This contains the cidict class, which is a case-insensitive  dictionary. Although LDAP is case-insensitive when it comes to attribute  names, it is often necessary to perform case-insensitive operations on  dictionary keys. ldap.modlist: Utility functions for creating modification records (for  performing the LDAP modify operation) are in this package. ldap.filter: This module provides a couple of utility functions for  creating LDAP search filters. ldap.sasl: Python-LDAP's SASL support is partially contained in this  package. It is not documented in the online documentation, but there are  plenty of notes in the doc strings in this module. ldap.schema: This module contains classes that describe the subschema  subentry records. It can be used to access schema information. ldapurl: This module provides a class for generating and parsing LDAP  URLs. ldif: This module is used to parse or write LDIF-formatted LDAP records. Most of the commonly used LDAP features are in the ldap module, and we will be focused mainly on using that. Since many of the submodules have only a couple of functions, we will use them in passing but treat them as separate objects of discussion. A Note on the Python Examples The Python interpreter (python) can be run interactively. Running Python in an interactive mode can be very useful for discovery and debugging. Further, since it prints useful information directly to the console, it can be useful for demonstration purposes. In many of the examples below, the code is shown as it would be entered in the interactive shell. Here is an example: >>> h = "Hello World">>> h'Hello World'>>> print hHello World Lines that begin with >>> and ... are interpreter prompts (similar to $ in shell). Examples with the >>> are run in the interpreter interactively. Some code, however, will be typed into a file (as usual). This code will not have lines beginning with the interpreter prompt. They tend to look more like this: h = “Hello World”print h Most of the time, features are introduced using the interpreter, but lengthier examples are done in the form of a Python script. Where it might be confusing, I will explicitly say in the text which of the two methods I am using. Connecting and Binding to the Directory Now that we have the library installed, we are ready to use the API. The Python-LDAP API connects and binds in two stages. Initializing the LDAP system is done with the ldap.initialize() function. The initialize() method returns an LDAPObject object, which contains methods for performing LDAP operations and retrieving information about the LDAP connection and transactions. A basic initialization is done like this: >>> import ldap>>> con = ldap.initialize('ldap://localhost') The first line of this example imports the ldap module, that contains the initialize() method as well as the LDAPObject that we will make frequent use of. The second line initializes the LDAP code, and returns an LDAPObject that we will use to connect to the server. The initialize() function takes a simple LDAP URL (protocol://host:port) as a parameter. Sometimes, you may prefer to pass in simply host and port information. This can be done with the connect(host, port) function, that also returns an LDAPObject object. In addition, if you need to check or set any LDAP options, you should use the get_option() and set_option() functions before binding. For instance, we can set the connection to require a TLS certificate by setting the OPT_X_TLS_DEMAND option: >>> con.get_option(ldap.OPT_X_TLS_DEMAND)0>>> con.set_option(ldap.OPT_X_TLS_DEMAND, True)>>> con.get_option(ldap.OPT_X_TLS_DEMAND)1 A Safe Connection In most production environments, security is a major concern. As we have seen in previous chapters, one major component of security in network-based LDAP services is the use of SSL/TLS-based connections. There are two ways to get transport-layer security with the Python-LDAP module. The first is to connect to the LDAPS (LDAP over SSL) port. This is done by passing the correct parameter to the initialize() function. Instead of using the ldap:// protocol, which will make an unverified unencrypted connection to port 389, use an ldaps:// protocol, which will make an SSL connection to port 636 (you can specify alternate an alternate port by appending a colon (:) and then the port number to the end of the URL). Or, instead of using LDAPS, you can perform a Start TLS operation before binding to the server: >>> import ldap>>> con = ldap.initialize('ldap://localhost')>>> con.start_tls_s() Note that while the call to ldap.initialize() does not actually open a connection, the call to ldap.start_tls_s() does create a connection. Exceptions Connecting to an LDAP server may result in the raising of an exception, so in production code, it is best to wrap the connection attempt inside of a try/except block. Here is a fragment of a script: #!/usr/bin/env pythonimport ldap, sysserver = 'ldap://localhost'l = ldap.initialize(server)try: l.start_tls_s()except ldap.LDAPError, e: print e.message['info'] if type(e.message) == dict and e.message.has_key('desc'): print e.message['desc'] else: print e sys.exit() In the case above, if the start_tls_s() method results in an error, it will be caught. The except clause checks if the returned message is a dict (which it should always be), and also checks if it has the description ('desc') field. If so, it prints the description. Otherwise, it prints the entire message. There are a few dozen exceptions that the Python-LDAP library might raise, but all of them are subclasses of the LDAPError class, and can be caught by the line: except ldap.LDAPError, e: Within an LDAPError object, there is a dictionary, called message, which contains the 'info' and 'desc' fields. The 'info' field contains the information returned from the server, and the 'desc' field contains a description of the error. In general, it is best to use try/except blocks around LDAP operations in order to catch any errors that might occur during processing. Binding Once we have an LDAPObject instance, we can bind to the LDAP directory. The Python-LDAP API supports both simple and SASL binding methods, and there are five different bind methods: bind(): Takes three required parameters: a DN, a password (or credential, for SASL), and a string indicating what type of bind method to use. Currently, only ldap.AUTH_SIMPLE is supported. This is asynchronous. Example: con.bind(dn, pw, ldap.AUTH_SIMPLE) bind_s(): This one is same as above, but it is synchronous, and returns  information about the status of the bind. simple_bind(): This performs a simple bind. This has two optional  parameters: DN and password. If no parameter is specified, this will bind as  anonymous. This is asynchronous. simple_bind_s(): This is the synchronous version of the above. sasl_interactive_bind_s(): This performs an SASL bind, and it takes two parameters: an SASL identifier and an SASL authentication string. First, for many Python LDAP functions, including almost all of the LDAP operations, there are both synchronous and asynchronous versions. Synchronous versions, which will block until the server returns a result, have method names that end with _s. The other operations – those that do not end with _s – are asynchronous. An asynchronous message will begin an operation, and then return control to the program. The operation will continue in the background. It is the responsibility of the program to periodically check on the operation to see if it has been completed. Since they wait to return any results until the operation has been completed, synchronous methods will often have different return values than their asynchronous counterparts. Synchronized methods may return the results obtained from the server, or they may have void returns. Asynchronous methods, on the other hand, will always return a message identifier. This identifier can be used to access the results of the operation. Here's an example of the different results for the two different forms of simple bind. First, the synchronous bind: >>> dn = "uid=matt,ou=users,dc=example,dc=com">>> pw = "secret">>> con.simple_bind_s( dn, pw ) (97, [])>>> Notice that this method returns a tuple. Now, look at the asynchronous version: >>> con.simple_bind( dn, pw )8>>> con.result(8)(97, []) In this case, the simple_bind() method returned 8 – the message identification number for the result. We can use the result() method to fetch the resulting information. The result() method returns a two-item tuple, where the first item is the status code (97 means success), and the second is a list of messages from the server. In this case, the list is empty. Notes on Getting ResultsThere are two noteworthy caveats about fetching results. First, a particular result can only be fetched once. You cannot call result() with the same message ID multiple times. Second, you can execute multiple asynchronous operations without checking the results. The consequence of doing this is that all of the results will be stored until they are fetched. This consumes memory, and can lead to confusing results if result() or result( ldap.RES_ANY ) is called. Later in this chapter, we will see more sophisticated uses of synchronous and asynchronous methods, but for now we will continue looking at methods of binding. The bind() and bind_s() methods work the same way, but they require a third parameter, specifying which sort of authentication mechanism to use. Unfortunately, at the time of this writing, only the AUTH_SIMPLE form of binding (plain old simple bind) is supported by this mechanism: >>> con.bind_s( dn, pw, ldap.AUTH_SIMPLE ) (97, []) This performs a simple bind to the server. Exceptions A bind can fail for a number of reasons, the most common being that the connection failed (the CONNECT_ERROR exception) or authentication failed (INVALID_CREDENTIALS). In production code, it is a good idea to check for these exceptions using try/except blocks. By checking for them separately, you can distinguish between, say, authentication failures and other, more serious failures: l = ldap.initialize(server)try: #l.start_tls_s() l.bind_s(user_dn, user_pw)except ldap.INVALID_CREDENTIALS: print "Your username or password is incorrect." sys.exit()except ldap.LDAPError, e: if type(e.message) == dict and e.message.has_key('desc'): print e.message['desc'] else: print e sys.exit() In this case, if the failure is due to the user entering the wrong DN or password, a message to that effect is printed. Otherwise, the error description provided by the LDAP library is printed. SASL Interactive Binds SASL is a robust authentication mechanism, but the flexibility and adaptability of SASL comes at the cost of additional complexity. This additional complexity is evident in the Python-LDAP module. SASL binding is implemented differently than the other bind methods. First, there is no asynchronous version of the SASL bind method (not all thread safety issues have been worked out in this module, yet). Since the SASL code is not as stable as the rest of the API, you may want to stick to simple binding (with SSL/TLS protection) rather than rely upon SASL support. There is only one SASL binding method, sasl_interactive_bind_s(). This method takes two arguments. The first is a DN string. It is almost always left blank, since with SASL, we usually authenticate with some other identifier. The second argument is an sasl object (or a subclass of an sasl object). The sasl object contains a dictionary of information that the SASL subsystem uses to perform authentication. Each different SASL mechanism is implemented as a class that is a subclass of the sasl object. There are a handful of different subclasses that come with the Python-LDAP module, though you can create your own if you need support for a different mechanism. cram_md5: This class implements the CRAM-MD5 SASL mechanism. A new cram_md5 object can be created with a constructor that passes in the authentication ID, a password, and an optional authorization ID. digest_md5: This implements the DIGEST-MD5 SASL mechanism. Like  cram_md5(), this object can be constructed with an authentication ID, a  password, and an optional authorization ID. gssapi: This implements the GSSAPI mechanism, an its constructor has only the optional authorization ID. It is used to perform Kerberos V authentication. external: This implements the EXTERNAL SASL mechanism, that uses an underlying transport security mechanism (like SSL/TLS). Its constructor only takes the optional authorization ID. Our LDAP server is configured to allow DIGEST-MD5 SASL connections, so we will walk through an example of performing this sort of SASL authentication. >>> import ldap>>> import ldap.sasl>>> user_name = "matt">>> pw = "secret">>> >>> con = ldap.initialize("ldap://localhost")>>> auth_tokens = ldap.sasl.digest_md5( user_name, pw )>>> >>> con.sasl_interactive_bind_s( "", auth_tokens )0 To begin with, we import the ldap and ldap.sasl packages, and we store the user name and password information in a couple of variables. After initializing a connection, we need to create a new sasl object – on that will contain the information necessary to perform DIGEST-MD5 authentication. We do this by constructing a new digest_md5 object: >>> auth_tokens = ldap.sasl.digest_md5( user_name, pw ) Now, auth_tokens points to our new SASL object. Next, we need to bind. This is done with the sasl_interactive_bind_s() method of the LDAPObject: >>> con.sasl_interactive_bind_s( "", auth_tokens ) If a SASL interactive bind is successful, then this method will return an integer. Otherwise, an INVALID_CREDENTIALS exception will be raised: >>> auth_tokens = ldap.sasl.digest_md5( "foo", pw )>>> try:... con.sasl_interactive_bind_s( "", auth_tokens )... except ldap.INVALID_CREDENTIALS, e :... print e... {'info': 'SASL(-13): user not found: no secret in database', 'desc': 'Invalid credentials'} In this case, the user foo was not found in the SASL DB, and the SASL subsystem returned an error.
Read more
  • 1
  • 0
  • 34578
Modal Close icon
Modal Close icon