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

How-To Tutorials

7019 Articles
article-image-jboss-jbpm-concepts-and-jbpm-process-definition-language-jpdl
Packt
22 Oct 2009
6 min read
Save for later

JBoss jBPM Concepts and jBPM Process Definition Language (jPDL)

Packt
22 Oct 2009
6 min read
JBoss jBPM Concepts JBoss jBPM is built around the concept of waiting. That may sound strange given that software is usually about getting things done, but in this case there is a very good reason for waiting. Real-life business processes cut across an organization, involve numerous humans and multiple systems, and happen over a period of time. In regular software, the code that makes up the system is normally built to "do all these tasks as soon as possible". This wouldn't work for a business process, as the people who need to take part in the process won't always want or be able to "do their task now". The software needs some way of waiting, until the process actor is ready to do their activity. Then once they have done their activity, the software needs to know what is the next activity in the chain and then wait for the next process actor to get round to doing their bit. The orchestration of this sequence of "wait, work, wait, work" is handled by the JBoss jBPM engine. The jBPM engine looks up our process definition and works out which way it should direct us through the process. We know the "process definition" better as our graphical process map. jBPM Process Definition Language—jPDL We will introduce the key terms and concepts here to get the ball rolling. We won't linger too long over the definitions, as the best way to fix the terminology in the brain is to see it used in context. At this point, we will introduce some core terminologies for a better understanding. The visual process map in the Designer is an example of what the JBoss jBPM project calls "Graph Oriented Programming". Instead of programming our software in code, we are programming our software using a visual process map: referred to as a "directed graph". This directed graph is also defined in the XML representation of the process we saw in the Source view. The graph plus the XML is a notation set, which is properly called jPDL, the "jBPM Process Definition Language". A process definition specified in jPDL is composed of "nodes", "transitions", and "actions", which together describe how an "instance" of the process should traverse the directed graph. During execution of the process, as the instance moves through the directed graph, it carries through a "token", which is a pointer to the node of the graph at which the instance is currently waiting. A "signal" tells the token which "transition" it should take from the node: signals specify which path to take through the process. Let's break this down a little bit with some more detail. Nodes A node in jPDL is modeled visually as a box, and hence looks very similar to the activity box we are used to from our workflow and activity flow diagrams. The concept of "nodes" does subtly differ from that of activities, however. In designing jPDL, the jBPM team have logically separated the idea of waiting for the result of an action from that of doing an action. They believe that the term "activity" blurs the line between these two ideas, which causes problems when trying to implement the logic behind a business process management system. For example, both "Seek approval" and "Record approval" would be modeled as activities on an activity flow diagram, but the former would be described as a "state" and the latter as an "action" in jPDL: the state element represents the concept of waiting for the action to happen, moving the graph to the next state. "Node" is therefore synonymous with "state" in jPDL. "Actions" are bits of code that can be added by a developer to tell the business process management system to perform an action that needs to be done by the system: for example, recording the approval of a holiday request in a database. Actions aren't mapped visually, but are recorded in the XML view of the process definition. We'll cover actions a bit later. There are different types of node, and they are used to accomplish different things. Let's quickly go through them so we know how they are used. Tasks A task node represents a task that is to be performed by humans. If we model a task node on our graph, it will result in a task being added to the task list of the person assigned to that task, when the process is executed. The process instance will wait for the person to complete that task and hand back the outcome of the task to the node. State A state node simply tells the process instance to wait, and in contrast to a task node, it doesn't create a task in anybody's task list. A state node would normally be used to model the behavior of waiting for an external system to provide a response. This would typically be done in combination with an Action, which we'll talk about soon. The process instance will resume execution when a signal comes back from the external system. Forks and Joins We can model concurrent paths of execution in jPDL using forks and joins. For example, the changes we made to our model to design our To Be process can be modeled using forks and joins to represent the parallel running of activities. We use a Fork to split the path of execution up, and then join it back together using a Join: the process instance will wait at the Join until the parallel tasks on both sides are completed. The instance can't move on until both chains of activities are finished. jBPM creates multiple child tokens related to the parent token for each path of execution. Decision In modeling our process in jBPM, there are two distinct types of decision with which we need to concern ourselves. Firstly, there is the case where the process definition itself needs to make a decision, based on data at its disposal, and secondly, where a decision made by a human or an external system is an input to the process definition. Where the process definition itself will make the decision, we can use a decision node in the model. Where the outcome of the decision is simply input into the process definition at run time, we should use a state node with multiple exiting transitions representing the possible outcomes of the decision.
Read more
  • 0
  • 1
  • 3308

article-image-data-processing-using-derived-column-and-aggregate-data-transformations
Packt
22 Oct 2009
3 min read
Save for later

Data Processing using Derived Column and Aggregate Data Transformations

Packt
22 Oct 2009
3 min read
Details of Data Processing: This package accomplishes the following: Connect to the SQL Server 2005 and access the MyNorthwind (a copy of the Northwind) database. A Data Reader Source will extract data using the following query: Select orderID, quantity, UnitPrice from [Order details] A Derived Column data transformation will add a column to the data flow which contains a combination of data from two other columns. A Conditional Split transformation divides the data flow into two flows based on a certain value in the derived column. The rows that satisfies the condition are captured in a recordset destination. The rest of the flow (bad data) gets routed to the next processor, the Aggregate Transformation. The Aggregate transformation orders the data coming into it showing group averages of the derived column. This grouped data then gets into a recordset destination. Although the final data ends up in recordset destinations, they can also be persisted to other destinations such as Data Reader, OLEDB and File system. Implementation in the Visual Studio 2005 Designer Before going into the details of the data processing let us take a look at the building blocks from the VS 2005 Toolbox that can be used to implement it and the interconnections between the building blocks. In addition to the data flow controls three data viewers are also inserted to stop and inspect the data before it goes any further. Data Extraction The data is extracted from MyNorthwind database on the SQL Server 2005. While configuring the Data Reader, you make use of a Connection Manager. The details of this Connection Manager is shown in its editor as in the next figure. The connection uses the SqlClient Data Provider. The SQL Server is a default installation with the name [.] and as it is set for SQL Server authentication username and password are required. The database connection is chosen from the drop-down as shown. The connectivity test can be performed and it now allows the data reader to extract data from the database. The Data Reader is added to the design surface by double clicking the control in the Toolbox. The Data Reader uses the connection manager to access the SQL Server as you see in the next figure in its Connection Manager's tab. The Data Reader's Property shows some of the other configuration details made by the other tabs in the above editor. In particular it shows the query used in extracting the data. It extracts three columns from the Order Details table in the MyNorthwind database and provides this to the next component in the data processing implementation.    
Read more
  • 0
  • 0
  • 4429

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-search-engine-optimization-joomla
Packt
22 Oct 2009
8 min read
Save for later

Search Engine Optimization in Joomla!

Packt
22 Oct 2009
8 min read
What is SEO? Search-engine optimization, or SEO, refers to the process of preparing your website to be spidered, indexed, and ranked by the major search engines so that when Internet users search for your keywords, your website will appear on their results page. Proper search engine optimization is a crucial step to ensure success and should be undertaken with care and diligence. It should also be noted that SEO is an interdisciplinary concern, combining web design functions with marketing and promotional concerns. If aimed properly, SEO would be a powerful weapon in your arsenal. Proper SEO is: Optimizing META data Optimizing page titles Optimizing page content Selecting proper keywords Testing your optimizations Promoting link popularity Using standards-compliant HTML Optimizing image ALT tags Using a logical website structure Validating your content Proper SEO isn't: Keyword spamming Hidden text Cloaking content Link-farming Excessive content or site duplication Paying for questionable links Structural Optimization Optimizing your site's actual structure and presentation is the most immediate approach to SEO. Since these factors are under the immediate control of the webmaster, they represent a foundational approach to the SEO problem. Once you've optimized your site's structural components, you can optimize the promotional aspects of SEO, which we'll discuss momentarily. Items That Search Engines Look for in Your Site's Content It's important to remember that today's search engine rankings are determined by highly sophisticated algorithms. Trying to stay one step ahead of the major engines with bad tactics is not only a very bad idea, but also a waste of time. Well written content will win repeatedly. Giving the search engine robots a well prepared sitepage contributes in promoting your site. Three items that many search engine robots look for are: Relevant page titles to your content Relevant keywords and descriptions (META tags) Relevant, keyword-rich content, presented in clean and valid HTML Take a note of the recurring theme—"relevancy". If your site is relevant in terms of what the user is looking for, you will achieve respectable search engine rankings without any additional promotion. However, this is not a place to stop, as search engines correlate your site's standings among your peers and competitors by evaluating certain external factors. External Views of Your Site by Search Engines Search giant, Google, likes to describe its proprietary algorithm, known as PageRankTM, by discussing how the external factors can accurately define your site's relevancy, when considered along with your site's actual content. Most search engines today follow this formula in determining link popularity. Some popular items that are used to measure are: How many websites link to yours Where they link in your content What words are used in the actual link text (i.e. the description of the page) The topical relevancy of the sites that link to your site The power of web search lies in the search engine's ability to provide accurate and relevant results that someone can quickly use to find the information they seek. More importantly, the other end of the search process guarantees that the visitors we draw from search engines are truly after the information or services we provide. Another way to look at it would be it's the right message, but the wrong person. Thus we see that our interests, the interests of the search engines, and the interests of web surfers actually coincide! If we tune our content properly, and connect our content with similarly relevant content, we can expect to be rewarded with targeted traffic eager to devour our information and buy our services. If we try to deceive the search engines, or common people, we deceive ourselves. It's that simple. Optimizing META Data Metadata is the data about the data. It's the section where you define what a search engine should expect to find on your page. If you've never taken note of META tags before, then take a brief tour of the Web and view the source code of several websites. You'll see how this data is organized, primarily into descriptions and keyword listings. Joomla! provides functionality for modifying and dynamically generating META tags, in the Site | Global Configuration | Metadata dialog, as well as within individual articles via the META tab on the right-hand panel. This is where the dynamic aspect of metadata becomes important—your main page will have certain needs for proper META optimization and your individual Joomla! content articles will require special tuning to make the best of their potential. This is accomplished though key words and phrases scattered through out the text. Keep in mind that each search engine is different; however keeping ratio of about 3 to 1 for keywords and META (keyword) in the top 1/3rd of the page is a decent rule of thumb. Using the Site | Global Configuration | Metadata dialog, is pretty straight forward.You can enter descriptions, keywords and key phrases that are pertinent to your siteon a global level. You should select the META keywords based on the keywords appearing in your content with the greatest frequency. Be honest and use META keywords that actually appear in your content. Search engines penalize you for over use of keywords, known as keyword stuffing. Title Optimization What's in the actual title of your page? The keywords you insert into your site and article's titles play a huge role in successful search engine optimization. As with META tags, the key is to insert frequently-used, but not stuffed, keywords into your title, which correlate the relevancy of the site's title (what we say about our site)with the metadata (how we describe what it's about) and the actual content, which is indisputably "what the website is about". Content Optimization Writing clear content that uses pertinent language in our intended message or service is the key to content optimization. In your content, include naturally-written, keyword-rich content. This will tie into your META tags, title description and other portions of your site to help you achieve content relevance and thus higher search engine rankings. One note of caution—while we use our best keywords frequently within our text; we should not cram these words into our content. So don't be afraid to break out the thesaurus and include some alternative words and descriptions! Good content SEO is about achieving a balance between what the search engines see, and what your readers expect on arrival. Keyword Research and Optimization Researching our keywords not only gives us an idea of how our competitors are optimizing their websites, but also gives us a treasure-trove of alternative keywords that we can use to further optimize our own sites. There are several online tools that can give us an idea of what keywords are most typically searched for, and how the end-users phrase their searches. This provides avital two-way pathway into the visitor's minds, showing not only how they reach the products and information they seek, but also how they perceive those items. You can find a listing of free keyword research tools at:http://www.joomlawarrior.com. For our example, we'll use Google's freely available keyword suggestion tool for its AdWords program, and use Joomla! itself as our intended optimization candidate.See http://www.google.com/adwords for the keyword tool. The following example will demonstrate the AdWords tool and how it helps you determine good keywords for your site. Entering joomla into Google's keyword suggestion tool yields the following display: The three key pieces of information as seen in the previous figure, which help us inmaking a decision about keywords, are as follows: Keywords: This column indicates the keyword whose Search Volume and Advertiser Competition we want to check. Advertiser Competition: This is graphical indicator of how many ads are in rotation for this keyword. Search Volume: Graphical indication of how many people in the world are searching this keyword for a product or service. As we see from the example, when we search for the keyword joomla we see a lower Advertiser Competition than content management system, but a higher SearchVolume. If we then examine open source we see a heavy Advertiser Competition, but the same Search Volume as joomla. What this means is that if we advertise in the crowded keyword space—"open source", we can expect a lot of competition. Changing our keyword to Joomla! would give us less competition and about the same Search Volume. If we advertise something related to Joomla! then that would be the best choice. However, if we were advertising a tool for open source, we would want to spend our money on the keyword "open source". The last take away from this is if we are selling a joomla template, you see from the figure that there isn't much competition (at the time thiswas taken), but a healthy amount of Search Volume.
Read more
  • 0
  • 0
  • 2232

article-image-textures-blender
Packt
22 Oct 2009
10 min read
Save for later

Textures in Blender

Packt
22 Oct 2009
10 min read
Procedural Textures vs. Bitmap Textures Blender has basically two types of textures, which are procedural textures and bitmap textures. Each one has both positive and negative points. Which one is the best will depend on your project needs. Procedural: This kind of texture is generated by the software at rendering time, just like vector lines. This means that it won't depend on any type of image file. The best thing about this type of texture is that it is resolution independent, so we can set the texture to be rendered with high resolutions with minimum loss of quality. The negative point about this kind of texture is that it's harder to get realistic textures with it. Bitmap: To use this kind of texture, we will need an image file, such as a JPEG, PNG, or TGA file. The good thing about these textures is that we can achieve very realistic materials with it quickly. On the other hand, we must find the texture file before using it. And there is more. If you are creating a high resolution render, the texture file must be big. Texture Library Do you remember the way we organized materials? We can do exactly the same thing about textures. Besides setting names and storing the Blender files to import and use again later, collecting bitmap textures is another important point. Even if you don't start right away, it's important to know where to look for textures. So here is a small list of websites that provides free texture download. http://www.blender-textures.org http://www.cgtextures.com http://blender-archi.tuxfamily.org/textures Applying Textures To use a texture, we must apply a material to an object, and then use the texture with this material. We always use the texture inside a material. For instance, to make a plane that simulates a marble floor, we have to use a texture and set up how the surface will react to light and texture, which can give the surface a proper look of marble using any texture. To do that, we must use the texture panel, which is located right next to the materials button. We can use a keyboard shortcut to open this panel: just hit F6. There is a way to add a texture in the material panel as well, with a menu called Texture. The best way to get all the options is to add the texture on the texture panel. On this panel, we will be able to see a lot of buttons, which represent the texture channels. Each one of these channels can hold a texture. The final texture will be a mix of all the channels. If we have a texture at channel 1 and another texture at channel 2, these textures will be blended and represented in the material. Before adding a new texture, we must select a channel by clicking over one of them. Usually the first channel is selected, but if you want to use another one, just click on the channel. When the channel is selected, just click the Add New button to add a new texture. The texture controls are very similar to the material controls. We can set a name for the texture at the top, or erase it if we don't want it anymore. With the selector, we can choose a previously created texture too—just click and select. Now comes the fun part. Having added a texture, we have to choose a texture type. To do that, we click on the texture type combo box. There are a lot of textures, but most of them are procedural textures and we won't use them much. The only texture type that isn't procedural is the image type. We can use textures like Clouds and Wood to create some effects and give surfaces a more complex look, or even create a grass texture with some dirt on it. But most times, the texture type that we will be using will be the Image type. Each texture has its own set of parameters to determine how it will look in the object. If we add a Wood texture, it will show the configuration parameters at the right. If we choose as texture type Clouds, the parameters showed at the right will be completely different. With the image texture type it's not different, this kind of texture has its own type of setup. This is the control panel: To show how to set up a texture, let's use an image file that represents a wood floor and a plane. We can apply the texture to this plane and set up how it's going to look, testing all the parameters. The first thing to do is assign a material to the plane, and add a texture to this material. We choose as texture type the Image option. It will show the configuration options for this kind of texture. To apply the image as a texture to the plane, just click on the Load button, situated on the Image menu. When we hit this button, we will be able to select the image file. Locate the image file and the texture will be applied. If we want to have more control over how this texture is organized and placed on the plane, we need to learn how the controls work. Every time you make any changes to the setup of a texture, these changes will be shown in the preview window; use it a lot to make good changes. Here is a list of what some of the buttons can do for the texture: UseAlpha: If the texture has an alpha channel, we have to press this button for Blender calculate the channel. An image has an alpha channel when some kind of transparency is stored in the image. For instance, a .png file with transparent background has an alpha channel. We can use this to create a texture with a logo, for a bottle, or to add an image of a tree or person to a plane. Rot90: With this option we can rotate the texture by 90 degrees. Repeat: Every texture must be distributed on the object surface, and repeating the texture in lines and columns is the default way to do that. Extended: If this button is pressed, the texture will be adjusted to fit all the object surface area. Clip: With this option, the texture will be cropped and we will be able to show only a part of it. To adjust which parts of the texture will be displayed, use the Min/Max X/Y options. Xrepeat / Yrepeat: This option determines how many times a texture is repeated, with the repeat option turned on. Normal Map: If the texture will be used to create Normal Maps, press this button. These are textures used to change the face normals of an object. Still: With this button selected, we can determine that the image used as texture is a still image. This option is marked by default. Movie: If you have to use a movie file as texture, press this button. This is very useful if we need to make something like a theatre projection screen or a tv screen. Sequence: We can use a sequence of images as texture too; just press this button. It works the same ways as with a movie file. There are a few more parameters, like the Reload button. If your texture file suffers any kind of change, we must press this button for the changes get accepted by Blender. The X button can erase this texture; use it if you need to select another image file. When we add a texture to any material, an external link is created with this file. This link can be absolute or relative. When we add a texture called "wood.png", which is located at the root of your main hard disk, like C:, a link to this texture will be created like this: "c:wood.png", so every time you open this file, the software will look for that file at that exact place. This is an absolute link, but we can use a relative link as well. For instance, when we add a texture located in the same folder as our scene, a relative link will be created. Every time we use an absolute link and we have to move the ".blend" file to another computer, the texture file must go with it. To imbue the image file with the .blend, just press the icon of gift package. To save all the textures used in a scene, just access the file menu and use the Pack Data option. It will make all the texture files embedded with the source blend file. Mapping Every time we add a texture to any object, we must choose a mapping type to set up how the texture will be applied to the object. For instance, if we have a wall and apply a wood texture, it must be placed like wallpaper. But for cylindrical or spherical objects, or even walls, we have to set up in a way that makes the texture adaptable to the topology of the surface, to avoid effects such as a stretched texture. To set this up, we use the mapping options, which are located on the Map Input menu. On this menu, we can choose between four basic mapping types which are Cube, Sphere, Flat, and Tube. If you have a wall, choose the option that matches the topology type with the model. In this case, the best choice is the Cube. Another important option here is the UV button, which allows us to use another very powerful type of texturing, based on UV Mapping. Normal Map This is a special and useful type of texture, that can change the normals of surfaces. If we have a floor and a texture of ceramic tiles, the surface can be represented with smaller details of that tiling, using this kind of a map. It's almost like modeling the tiles. But everything is created using just a normal map. To use this kind of texture, we must turn on the Nor button on the Map To menu. When this button is turned on, we can set up the Nor slider to determine the intensity of the normal displacement. It works based on the pixel color of the texture. With white pixels, the normals are not affected, and with black pixels, the normals are fully translated. If you want to optimize the normal mapping, using a special texture is much recommended. Some texture libraries even have this type of normal maps ready for use. They can be called bump maps too. Here is an example of how we can use them. We take a stone texture and a tiled texture with a white background and black lines. The stone texture is applied to the floor, and the tiled texture is used to create a tiling for the floor. The setup for that is really simple. Just apply the texture at a lower channel, and turn off the Col button for this channel. Turn on the Nor button, and this texture will affect only the normals and not the material color. Any image can be used as a normal map, but we will always get better results with a greyscale image prepared to be used as a normal map. Now, just set up the Nor intensity with the slider, and see the render. Turn on positive and turn on negativeSome of the buttons on the Map To menu can be turned on with positive and negative values. For instance, the Nor option can be turned on with one click. If we click on it again, the Nor text will turn yellow. This means that the Nor is inverted with negative values. Some other buttons may present the same option.
Read more
  • 0
  • 0
  • 26810

article-image-migration-apache-lighttpd
Packt
22 Oct 2009
7 min read
Save for later

Migration from Apache to Lighttpd

Packt
22 Oct 2009
7 min read
Now starting from a working Apache installation, what can Lighttpd offer us? Improved performance for most cases (as in more hits per second) Reduced CPU time and memory usage Improved security Of course, the move to Lighttpd is not a small one, especially if our Apache configuration makes use of its many features. Systems tied into Apache as a module may make the move hard or even impossible without porting the module to a Lighttpd module or moving the functionality into CGI programs, if possible. We can ease the pain by moving in small steps. The following descriptions assume that we have one Apache instance running on one hardware instance. But we can scale the method by repeating it for every hardware instance. When not to migrateBefore we start this journey, we need to know that our hardware and operating systems support Lighttpd, that we have root access (or access to someone who has), and that the system has enough space for another Lighttpd installation (yes, I know, Lighttpd should reduce space concerns, but I have seen Apache installations munching away entire RAID arrays). Probably, this only makes sense if we plan on moving a big percentage of traffic to Lighttpd. We also might make extensive use of Apache module, which means a complete migration would involve finding or writing suitable substitutes for Lighttpd. Adding Lighttpd to the Mix Install Lighttpd on the system that Apache runs on. Find an unused port (refer to a port scanner if needed) to set server.port to. For example, if port 4080 is unused on our system, we would look for server.port in our Lighttpd configuration and change it to: server.port = 4080 If we want to use SSL, we should change all occurrences of the port 443 to another free port, say 4443. We assume our Apache is answering requests on HTTP port 80. Now let's use this Lighttpd instance as a proxy for our Apache by adding the following configuration: server.modules = (#..."mod_proxy",#...)#...proxy.server = ("" => ( # proxy everythinghost => "127.0.0.1" # localhostport => "80")) This tells our Lighttpd to proxy all requests to the server that answers on localhost, port 80, which happens to be our Apache server. Now, when we start our Lighttpd and point our browser to http://localhost:4080/, we should be able to see the same thing that our Apache is returning. What is a proxy?A Proxy stands in front of another object, simulating the object by relaying all requests to it. A proxy can change requests on the fly, filter requests, and so on. In our case, Lighttpd is the web server to the outside, whilst Apache will still get all requests as usual. Excursion: mod_proxy mod_proxy is the module that allows Lighttpd to relay requests to another web server. It is not to be confused with mod_proxy_core (of Lighttpd 1.5.0), which provides a basis for other interfaces such as CGI. Usually, we want to proxy only a specific subset of requests, for example, we might want to proxy requests for Java server pages to a Tomcat server. This could be done with the following proxy directive: proxy.server = (".jsp" => ( host => "127.0.0.1", port => "8080" )# given our tomcat is on port 8080) Thus the tomcat server only serves JSPs, which is what it was built to do, whilst our Lighttpd does the rest. Or we might have another server which we want to include in our Web presence at some given directory: proxy.server = ("/somepath" => ( host => "127.0.0.1", port => "8080" )) Assuming the server is on port 8080, this will do the trick. Now http://localhost/somepath/index.html will be the same as http://localhost:8080/index.html. Reducing Apache Load Note that as most Lighttpd directives, proxy.server can be moved into a selector, thereby reducing its reach. This way, we can reduce the set of files Apache will have to touch in a phased manner. For example, YouTube™ uses Lighttpd to serve the videos. Usually, we want to make Lighttpd serve static files such as images, CSS, and JavaScript, leaving Apache to serve the dynamically generated pages. Now, we have two options: we can either filter the extensions we want Apache to handle, or we can filter the addresses we want Lighttpd to serve without asking Apache. Actually, the first can be done in two ways. Assuming we want to give all addresses ending with .cgi and .php to Apache, we could either use the matching of proxy.server: proxy.server = (".cgi" => ( host = "127.0.0.1", port = "8080" ),".php" => ( host = "127.0.0.1", port = "8080" )) or match by selector: $HTTP['url'] =~ "(.cgi|.php)$" {proxy.server = ( "" => ( host = "127.0.0.1", port = "8080" ) )} The second way also allows negative filtering and filtering by regexp — just use !~ instead of =~. mod_perl, mod_php, and mod_python There are no Lighttpd modules to embed scripting languages into Lighttpd (with the exception of mod_magnet, which embeds Lua) because this is simply not the Lighttpd way of doing things. Instead, we have the CGI, SCGI, and FastCGI interfaces to outsource this work to the respective interpreters. Most mod_perl scripts are easily converted to FastCGI using CGI::Fast. Usually, our mod_perl script will look a lot like the following script: use CGI;my $q = CGI->new;initialize(); # this might need to be done only onceprocess_query($q); # this should be done per requestprint response($q); # this, too Using the easiest way to convert to FastCGI: use CGI:Fast # instead of CGIwhile (my $q = CGI:Fast->new) { # get requests in a while-loopinitialize();process_query($q);print response($q);} If this runs, we may try to put the initialize() call outside of the loop to make our script run even faster than under mod_perl. However, this is just the basic case. There are mod_perl scripts that manipulate the Apache core or use special hooks, so these scripts can get a little more complicated to migrate. Migrating from mod_php to php-fcgi is easier — we do not need to change the scripts, just the configuration. This means that we do not get the benefits of an obvious request loop, but we can work around that by setting some global variables only if they are not already set. The security benefit is obvious. Even for Apache, there are some alternatives to mod_php, which try to provide more security, often with bad performance implications. mod_python can be a little more complicated, because Apache calls out to the python functions directly, converting form fields to function arguments on the fly. If we are lucky, our python scripts could implement the WSGI (Web Server Gateway Interface). In this case, we can just use a WSGI-FastCGI wrapper. Looking on the Web, I already found two: one standalone (http://svn.saddi.com/py-lib/trunk/fcgi.py), and one, a part of the PEAK project (http://peak.telecommunity.com/DevCenter/FrontPage). Otherwise, python usually has excellent support for SCGI. As with mod_perl, there are some internals that have to be moved into the configuration (for example dynamic 404 pages, the directive for this is server.error-handler-405, which can also point to a CGI script). However, for basic scripts, we can use SCGI (either from http://www.mems-exchange.org/software/scgi/ or as a python-only version from http://www.cherokee-project.com/download/pyscgi/). We also need to change import cgi to import scgi and change CGIHandler and CGIServer to SCGIHandler and SCGIServer, respectively.
Read more
  • 0
  • 0
  • 7421
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-debugging-ajax-using-microsoft-ajax-library-internet-explorer-and-mozilla-firefox
Packt
22 Oct 2009
8 min read
Save for later

Debugging AJAX using Microsoft AJAX Library, Internet Explorer and Mozilla Firefox

Packt
22 Oct 2009
8 min read
AJAX Debugging Overview Unfortunately, today’s tools for client-side debugging and tracing aren’t as evolved as their server-side counterparts. For example, things such as capturing ongoing communication traffic between the client and the server, or client-side debugging, aren’t usually supported by today’s IDEs (Integrated Development Environments) such as Microsoft Visual Studio 2005. The next version of Visual Studio (code-named Orcas at the time of writing) promises a lot of improvements in this area: Improved IntelliSense technology with support for JavaScript code, which provides coding hints based on specially-formatted comments in the code Breakpoints in inline JavaScript code These are only the most important new coming features; there are others as well. For more information we suggest that you browse and keep an eye on Scott Guthrie’s blog at http://weblogs.asp.net/scottgu/, the JScript blog at http://blogs.msdn.com/jscript/, Bertrand Le Roy’s blog at http://weblogs.asp.net/bleroy/. Until this new edition of Visual Studio is released, we can rely on third-party tools that can do a very good job at helping us develop our AJAX applications. You’ll find a number of tools for Internet Explorer and Mozilla Firefox for this purpose. Debugging and Tracing with Microsoft AJAX Library The common practices for debugging JavaScript code are: Putting alert messages throughout the code to get notified about the values of the variables Logging tracing messages in a <div> element While the first option is straightforward, the second option offers a centralized place for storing different messages and could be considered more appropriate. Nevertheless both options can come in quite handy depending on the circumstances. Microsoft AJAX Library offers the Sys.Debug object that has a series of methods that you can use for debugging and tracing. The diagram of this class is presented in figure below. The Debug class As we can easily see in the diagram, Sys.Debug offers the most common features that we can find also in other languages: assert(), trace(), traceDump(), fail(), and clearTrace(). assert(), trace(), and fail() automatically send the messages to the debugging console of the browser. To see the messages in IE you need to have the Web Development Helper, and for Firefox you need the Firebug plugin. Both of these tools are presented later in this article. Internally assert() calls fail() if the expression evaluates to false. fail() simply logs the message passed in by assert to the debugging console. trace() offers an interesting feature beside logging to the debugging console: it offers the possibility to log the trace message in a <textarea> element with the ID TraceConsole. If such an element is found, trace() will log this message in this element too. The clearTrace() function simply clears the TraceConsole element, if found. The traceDump() function traces all the information about an object including its properties. Internally this function uses the trace() function so that we can have the information logged in the browser’s debugging console, and in the TraceConsole element (if it exists). MicrosoftAjax.debug.js You might have wondered why the Microsoft AJAX Library comes with both release and debug version of the JavaScript file. The major features of the debug version of the library files are:  The script is nicely formatted. The names of variables are not obfuscated. The script contains code comments. Some of the functions have the optional summary data that will be used by Visual Studio “Orcas” for code auto-completion. The script outputs debugging-friendly information. Parameters are validated. Once the development stage is finished, you can switch your application to the release version of the script (MicrosoftAjax.js), which is smaller and doesn’t contain the debugging features presented above. Perhaps the most interesting features of the debug version are the last two: debugging-friendly information and parameter validation. Anonymous Functions vs. Pseudo-Named Functions We will explain these two concepts by taking a look at how different functions are defined in the debug and release version of the library. The debug version of the library contains: function Sys$_Debug$assert(condition, message, displayCaller) {   ...}Sys._Debug.prototype = {  assert: Sys$_Debug$assert,  ...} and: String.format = function String$format(format, args) {...} In the release version of the library we have: Sys._Debug.prototype = {  assert: function(c, a, b) {  ...} and: String.format = function() {...} In the release version, we have methods that are anonymous functions. This means that within a debugger stack trace the method name will read JScript anonymous function. This is not very useful for debugging purposes, is it? Call Stack showing anonymous functions However, the debug version of the library uses the dollar-syntax to provide alias names for our functions: String$format for String.format and Sys$Debug$assert for Sys.Debug.assert. When using the debug version of the file, the stack trace would look like: Call Stack showing named functions We can still notice some anonymous functions as they are the result of creating callback or delegate functions. The example shows two different ways of coding:  In the debug version, the function is declared outside the prototype and then referenced in the prototype declaration. In the release version, the declaration is done directly where the function is declared (outside or inside the prototype). Parameters Validation Another interesting feature that has not been documented in the Microsoft AJAX Library documentation is that of parameters validation. Type safety is one of the typical problems when it comes to using JavaScript. Although the dynamic type features are really useful, sometimes we might really want to make sure that a parameter or object is of a certain type. To check the data type of an object, you can try converting the object to the desired type, or using the methods defined by Type. Fortunately the Microsoft AJAX Library has a function that does the dirty work for us: Function._validateParams(). The class diagram in figure below shows the _validateParameter() and _validateParams() methods of the Function class. The Function class The Function._validateParams() function, even if it is declared as private (by convention, using the leading underscore), can be used by our scripts as it is used throughout the debug version of the Microsoft AJAX Library. Here’s an example of using this function: function Sys$_Debug$fail(message) {/// <param name="message" type="String" mayBeNull="true"></param>   var e = Function._validateParams(arguments,          [ {name: "message", type: String, mayBeNull: true} ]);   if (e) throw e; This shows how the parameter for the fail() function is validated as a String. We can also see the additional code comments inside the function, which are meant to be used by the IntelliSense feature in Visual Studio “Orcas” to check for the correctness of the parameter types. While the first parameter of _validateParams() represents an array of parameters to be checked, the second parameter is an array of JSON objects describing the validation rules for the array of parameters. Each JSON object contains a validation rule for a parameter. The JSON object is a dictionary of keys and values. The list of keys that can be used is described in the table that follows. Key Description name The name of the parameter type The allowed type for this parameter (ex: String, Array, Function, Sys.Component, etc.) mayBeNull Boolean value indicating whether this parameter can be passed as null or not domElement Boolean value indicating whether this parameter is a DOM element or not integer Boolean value indicating whether this parameter should have an integer value or not optional Boolean value indicating whether this parameter is optional or not parameterArray Boolean value indicating whether this parameter should be an Array or not elementType The allowed type for each element of an array (type must be Array) elementMayBeNull Boolean value indicating whether an array element could have null or not (type must be Array) elementDomElement Boolean value indicating whether each element of an array is a DOM element (type must be Array) elementInteger Boolean value indicating whether each element of an array should have an integer value (type must be Array) The function returns an error message if the parameters don’t validate and the error is typically thrown like this: if (e) throw e; This exception could be caught and the appropriate measures taken programmatically. If the exception is not caught, the error will pop up in the debugging console of the browser.
Read more
  • 0
  • 0
  • 3121

article-image-identifying-key-elements-joomla-template-design
Packt
22 Oct 2009
6 min read
Save for later

Identifying Key Elements for Joomla! Template Design

Packt
22 Oct 2009
6 min read
The Joomla! Template When you install Joomla!, it comes with one or two built-in templates. In my version 1.0.8 installation, MadeYourWeb by Mark Hinse and rhuk_solarflare_ii by rhuk, are the two available. If you have a different version, you may have different templates available to you. We'll use the rhuk_solarflare_ii template to review the basic parts of a Joomla! template that you'll need to think about as you create your visual design. First, let's look at the following figure to see how our basic template affects the Joomla! PHP output: What Your XHTML does to the template layout. You'll recall that the PHP code for the footer, sitename, pathway, and MainBody are not module position slots. These functions load in the required information that helps Joomla! to run, display standard footer information, and load the actual site content from the Joomla! MySQL databases. Top, left, and right are module position slots, which can be assigned site modules. Site modules are what contain navigation links, form elements, and Joomla! status information that will be displayed to your visitors such as: Who's Online or Who's Logged In. You can assign site modules to any of the module position slots and even load multiple site modules into these position slots by assigning an ascending numerical order to them. You do this in the Module Manager [Site] by going to Modules | Site Modules in the administration panel. Site Modules panel in Joomla!'s admin panel. As shown in the following figure, you can assign up to 50 module position slots to place in your template layout. Go to Site | Template Manager | Module Positions to view the standard module positions Joomla! provides. Module Positions panel in Joomla's admin panel. Now that we have a deeper understanding of how the template, module position slots, and site modules work, let's take a look at how these three elements come together through the rhuk_solar_flare_ii template. The module position slot name is on the left, the content module name is on the right, and the assigned order, if any, is underneath. Example of modules assigned to Module Positions Using this example, you can now start thinking of how you're going to construct your template design. Let's move on to creating your design. Considerations to be Made First off, let's get to the most important consideration What modules will be used in your site? Thus, what modules do you need to design for? Go through your Joomla! installation and review all the modules your site will be using. There's the obvious top menu, main menu, and user menus, but will you be displaying the login form or a poll? If so, do you want to change their display? Will your site be displaying banners? Will your site require any special or add-on modules or components such as an image gallery or shopping cart? Make a list of each module or special component that your site will be displaying and take special note of their elements: Do they have headers or special text areas? Would you like anything to be highlighted with a background image? Do the modules have items that should be standard buttons or icons? All these things should be included in your list. When you begin work on your design in Photoshop, you'll want to compare your mock-up against your module checklist and make sure you've designed for all your modules. Refining the Wheel The next consideration is whether you are going to work from an existing template or from scratch? The more you work with Joomla! and learn all its quirks, the more you'll see that sometimes starting from scratch is best. However, while being a CSS and XHTML “wiz” is awesome, you don't always need to reinvent the wheel! Take a look at what happens to the standard rhuk template when all we do is change the color scheme and fonts. rhuk_solarflare_ii template with CSS changes to color and fonts Now, check out what happens in the following figure when we change the graphics. rhuk_solarflare_ii template with image changes And last, see what happens in the following figure when we use the Module Manager to swap module placements around. rhuk_solarflare_ii template with module swaps By thinking of this design in terms of leveraging the existing rhuk_solarflar_ii template, we effectively created a whole new template and module layout which is completely unique. And we only had to minimally edit the CSS to get it to work. Everything else was done in the Joomla! admin panel without touching any code. If you're going to work from an existing template, it's best to review that template's HTML output (right-click or Alt-click and chose View Source) and pull the image names from each page that you'll be replacing with your own images. It's also helpful to go through that template's image directory and just note each image: which ones you're going to change, leave alone, re-size, and so on as you work with your design mock-up. Make sure to note the specific file names that are going to be overwritten in your module check list so that you have them handy when it is time to export your image slices. So, when is it best to start from scratch? It's up to your site's specific needs. For instance, the Joomla! in-built templates comes with use tables to hold their layout structure together. If you want an all semantic, valid XHTML markup with CSS layout, you'll need to create it yourself from scratch. Whichever road you take, as you continue to design and build Joomla! templates, you'll find over time that you have your own “master” template—files you've generated or got to know so well—you understand how all their parts work together. You'll see how applying any new modules or components will affect the files and how they should be incorporated. It will become easy for you to work with this favorite or “master” template and easily massage it into any new creation you can imagine.  
Read more
  • 0
  • 0
  • 1756

article-image-filtering-microsoft-dynamics-nav
Packt
22 Oct 2009
3 min read
Save for later

Filtering in Microsoft® Dynamics™ NAV

Packt
22 Oct 2009
3 min read
Filtering As mentioned earlier, filtering is one of the very powerful tools within NAV C/AL. Filtering is the application of defined limits on the data to be considered in a process (to learn more about Data types in NAV, visit here). Filter structures can be applied in at least three different ways, depending on the design of the process. The first way is for the developer to fully define the filter structure and the value of the filter. This might be done in a report designed to show only information on a selected group of customers, for example those with an open Balance on Account. The Customer table would be filtered to report only customers who have an Outstanding Balance greater than zero. The second way is for the developer to define the filter structure, but allow the user to fill in the specific value to be applied. This approach would be appropriate in an accounting report that was to be tied to specific accounting periods. The user would be allowed to define what period(s) were to be considered for each report run. The third way is the ad hoc definition of a filter structure and value by the user. This approach is often used for general analysis of ledger data where the developer wants to give the user total flexibility in how they slice and dice the available data. It is quite common within the standard NAV applications and in the course of enhancements to use a combination of the different filtering types. For example, the report just mentioned that lists only customers with an open Balance on Account (via a developer-defined filter) could also allow the user to define additional filter criteria. Perhaps, the user wants to see only Euro currency-based customers, so they would filter on the Customer Currency Code field. Filters are an integral part of FlowFields and FlowFilters, two of the three Field Classes. These are very flexible and powerful tools, which allow the NAV designer to create forms, reports, and other processes that can be used by the user under a wide variety of circumstances for various purposes. In most systems, user inquiries (forms and reports) and processes need to be quite specific to different data types and ranges. The NAV C/AL toolset allows you to create relatively generic user inquiries and processes and then allow the user to apply filtering to fit their specific needs. Defining Filter Syntax and Values Let us go over some common ways in which we can define filter values and syntax. Remember, when you apply a filter, you will only view or process records where the filtered data field satisfies the limits defined by the filter. Equality and inequalityeither an equal (=) sign or no sign filters for data "equal to" the filter value. Data Type - description Example Filters Integer =200 Integer 200 Text Chicago Text " (two single quote marks)         a greater than (>) sign filters for data greater than the filter value Data Type - description Example Filters Integer >200 Date >10/06/07 Decimal >450.50         a less than (<) sign filters for data less than the filter value Data Type - description Example Filters Integer <150 Date <10/07/07
Read more
  • 0
  • 0
  • 3091

article-image-digitally-signing-and-verifying-messages-web-services-part-2
Packt
22 Oct 2009
4 min read
Save for later

Digitally Signing and Verifying Messages in Web Services ( part 2 )

Packt
22 Oct 2009
4 min read
Signature Verification by Oracle WSM Oracle Web Services Manager can actually validate the signature in the incoming i.e. request SOAP message. By using Oracle WSM to validate the signature, organizations can actually centralize the policy enforcement and also the public key management. As organizations deploy more web services that are accessed by other divisions and business partners, managing the signature verification process might become tedious, as with each new consumer, the certificate information should be maintained. Oracle WSM can address such issues by centralizing those operations. This section  will describe how to configure Oracle WSM policy to validate the signature of the SOAP request message. In order to view the policy, you can click on Policy Management and then Manage Policies. This will bring you to the screen with the gateway information and a hyperlink for policies (see the following screen capture).   You can then click on Policies to see all the policies and you will see theVerifyAndSign policy too that is created by default. A default policy is attached to the service. We can now click Edit to edit the  policy. When you click Edit, you will see the policy steps as shown in the  following screenshot. In this section, we want to configure the Request pipeline to validate the signature of the incoming SOAP message. In order to validate the signature, click Add Step Below to add the Verify Signature policy step as shown in the following screenshot. Once you click OK, the verify signature policy step is added, but that policy step should be configured. If you click on the Configure button on the verify signature policy step, it will take you to the screen where you can configure the verify signature policy information as shown in the following screen capture. In the previous screenshot, I configured Verify Signature policy steps with: Location of the key store Key store type as PKCS12 Password of the key store Public key alias in the key store Set Remove Signatures to true to remove the digital signature after the signature validation Enforce Signing is set to true to make sure that the incoming requests are signed In order to generate a PKCS12 key store from certifcate that is installed already in Microsoft certifcate services, you should frst export the certifcate (with or without private key) and then import that certifcate in FireFox (Advanced option) and then export back to PKCS12. Once the verify signature policy has been configured and saved (Commit Policy), the policy would enforce that any request for the time service with the particular service ID be digitally signed. Signature Generation by Oracle WSM In the last section, we discussed how to digitally sign a web service request by Microsoft .NET application and how to validate the signature by Oracle WSM. In this section, we will discuss how to digitally sign the web service response message. In the earlier section, we discussed how to register the service and how to attach the verify signature policy step to the request pipeline. In order to digitally sign the response message, the response pipeline of the policy should be modified to include the sign message policy step. The policy with the request pipeline that is already configured to verify signature would look like: Now we have to add the step in the Response pipeline to actually sign the response message. In order to add the policy step, click on Add Step Below and then select the Sign Message policy step. Once the Sign Message policy step is added, it can then be configured, as shown in the following screenshot, to include the appropriate key store location for the public key to digitally sign the message. In the previous figure, the location of the key store that has the private key, along with the Keystore password, alias and part of message to be signed are specified. Once the policy is created, it would look like: In the previous screenshot, the Response pipeline has two log steps—one to log the message before digitally signing and one to log the message after digitally signing the message. In this sample, we are using the same WSEQuickStartServer certificate to sign the message. Once the policy is saved, the response message will be digitally signed. The client application (Microsoft .NET) can be configured to validate the signature.
Read more
  • 0
  • 0
  • 1866
article-image-module-development-joomla
Packt
22 Oct 2009
4 min read
Save for later

Module Development in Joomla

Packt
22 Oct 2009
4 min read
Introduction Modules in Joomla can be used to fetch and display data almost anywhere on a page in a website.In this article, we will cover the following topics on module development. Registering the module in the database Getting and setting parameters Centralizing data access and output using helper classes Selecting display options using layouts Displaying the latest reviews Displaying a random review We will assume that we have a table in our database called jos_modules with the following fields title, ordering, position, published, module, showtitle, and params. We will also assume that we have a website that reviews different restaurants. However, visitors have to go to the component to see the reviews. We would be developing a module so that we could pull the content directly from the reviews and display them. Registering the Module in the Database As with the component, we will have to register the module in the database so that it can be referenced in the back end and used effectively. Entering a record into the jos_modules table will take care of this. Open your database console and enter the following query: INSERT INTO jos_modules (title, ordering, position, published, module, showtitle, params) VALUES ('Restaurant Reviews', 1, 'left', 1, 'mod_reviews', 1, 'style=simplenitems=3nrandom=1'); If you're using phpMyAdmin, enter the fields as in the following screen: If you refresh the front end right after entering the record in jos_modules, you'll notice that the module doesn't appear, even though the published column is set to 1. To fix this, go to Extensions | Module Manager in the back end and click the Restaurants Reviews link. Under Menu Assignment, select All and click Save. In the front end, the left-hand side of your front page should look similar to the following: Creating and Configuring a Basic Module Modules are both simple and flexible. You can create a module that simply outputs static text or one that queries remote databases for things like weather reports. Although you can create rather complex modules, they're best suited for displaying data and simple forms. You will not typically use a module for complex record or session management; you can do this through a component or plug-in instead. To create the module for our reviews, we will have to create a directory mod_reviews under /modules. We will also need to create the mod_reviews.php file inside mod_reviews. To start, we'll create a basic module that displays links to the most recent reviews. In the mod_reviews.php file, add the following code: <?php defined('_JEXEC') or die('Restricted access'); $items = $params->get('items', 1); $db =& JFactory::getDBO(); $query = "SELECT id, name FROM #__reviews WHERE published = '1' ORDER BY review_date DESC"; $db->setQuery( $query, 0, $items ); $rows = $db->loadObjectList(); foreach($rows as $row) { echo '<a href="' . JRoute::_('index.php?option=com_reviews&id=' . $row->id . '&task=view') . '">' . $row->name . '</a><br />'; } ?> When you save the file and refresh the homepage, your module should look similar to the following: When the module is loaded, the $params object is pulled into scope and can be used to get and set the parameters. When we added the row into jos_modules, the params column contained three values: one for items (set to 3), one for style (set to simple), and another for random (set to 1). We set $items to the parameter items using the get() member function, defaulting to 1 if no value exists. If desired, you can use the member function set($name, $value) to override or add a parameter for your module. After getting a database object reference, we write a query to select the id and name form jos_reviews and order reverse chronologically by the published date. We use the second and third parameters of setQuery() to generate a LIMIT clause that is automatically added to the query. This ensures that the correct syntax is used for the database type. Once the query is built, we load all the relevant database rows, go through them, and provide a link to each review.
Read more
  • 0
  • 0
  • 2996

article-image-obtaining-alfresco-web-content-management-wcm
Packt
22 Oct 2009
11 min read
Save for later

Obtaining Alfresco Web Content Management (WCM)

Packt
22 Oct 2009
11 min read
You must obtain and install an additional download to enable Alfresco WCM functionality. The download includes a new Spring bean configuration file, a standalone Tomcat instance pre-configured with JARs, and server settings that allow a separate Tomcat instance (which is called the virtualization server) to run web applications stored in Alfresco WCM web folders. This capability is used when content managers "preview" an asset or a website. Just as in the core Alfresco server, you can either build the WCM distribution from source or obtain a binary distribution. Step-by-Step: Installing Alfresco WCM If you are building from source, the source code for Alfresco WCM is included with the source code for the rest of the product. Once the source code is checked out, all you have to do is run the distribute Ant task as follows: ant -f continuous.xml distribute After several minutes, the WCM distribution will be placed in the build|dist directory of your source code's root directory. Alternatively, if you are using binaries, download the binary distribution of the Alfresco WCM extension. Where you get it depends on whether you are running Labs or Enterprise. The Labs version is available for download from http://www.alfresco.com. The Enterprise version can be downloaded from the customer or partner site using the credentials provided by your Alfresco representative. Regardless of whether you chose source or binary, you should now have an Alfresco WCM archive. For example, the Labs edition for Linux is named alfresco-labs-wcm-3b.tar.gz. To complete the installation, follow these steps: Expand the archive into any directory that makes sense to you. For example, on my machine I use |usr|local|bin|alfresco-labs-3.0-wcm. Copy the wcm-bootstrap-context.xml file to the Alfresco server's extension directory ($TOMCAT_HOME|shared|classes|alfresco|extension). Edit the startup script (virtual_alf.sh) to ensure that the APPSERVER variable is pointing to the virtual-tomcat directory in the location to which you expanded the archive. Using the example from the previous step, the APPSERVER variable would be: APPSERVER=|usr|local|bin|alfresco-labs-3.0-wcm|virtual-tomcat Start the virtual server by running: |virtual_alf.sh start</i> Start the Alfresco server (or restart it if it was already running). You now have Alfresco with Alfresco WCM up and running. You'll test it out in the next section, but you can do a smoke test by logging in to the web client and confirming that you see the Web Projects folder under Company Home. Creating Web Projects A web project is a collection of assets, settings, and deployment targets that make up a website or a part of a website. Web projects are stored in web project folders, which are regular folders with a bunch of web project metadata. The number of web project folders you use to represent a site, or whether multiple sites are contained within a single web project folder is completely up to you. There is no "right way" that works for everybody. Permissions are one factor. The ability to set permissions stops at the website. Therefore, if you have multiple groups that maintain a site that are concerned with the ability of one to change the other's files, your only remedy is to split the site across web project folders. Web form and workflow sharing is another thing to think about. As you'll soon learn, workflows and web forms are defined globally, and then selectively chosen and configured by each site. Once made available to a web project, they are available to the entire web project. For example, you can't restrict the use of a web form to only a subset of the users of a particular site. SomeCo has chosen the approach of using one web project folder to manage the entire SomeCo.com website. Step-by-Step: Creating the SomeCo Web Project The first thing you need to do is create a new web project folder for the SomeCo website. Initially, you don't need to worry about web forms, deployment targets, or workflows. The goal is simply to create the web project and import the contents of the website. To create the initial SomeCo web project, follow these steps: Log in as admin. Go to Web Projects under Company Home. Click Create, and then Create Web Project. Specify the name of the web project as SomeCo Corporate Site. Specify the DNS name as someco-site. Click Next for the remaining steps, taking all defaults. You'll come back later and configure some of these settings. On the summary page, click Finish. You now have a web project folder for the SomeCo corporate site. Click SomeCo Corporate Site. You should see one Staging Sandbox and one User Sandbox. Click the Browse Website button for the User Sandbox. Now you can import SomeCo's existing website into the web project folder. Click Create, and then Bulk Import. Navigate to the "web-site" project in your Eclipse workspace. Assuming you've already run Ant for this project, there should be a ZIP file in the build folder called someco-web-site.zip. Select the file. Alfresco will import the ZIP into your User Sandbox. What Just Happened You just created a new web project folder for SomeCo's corporate website. But upon creation of a web project folder, there is no website to manage. This is a big disappointment for some people. The most crestfallen are those who didn't realize that Alfresco is a "decoupled" content management system—it has no frontend framework and no "default" website like "coupled" content management systems such as Drupal. This will change in the 3.0 releases as Alfresco introduces its new set of clients. But for now, it's up to you to give Alfresco a website to manage. You just happened to have a start on the SomeCo website sitting in your Eclipse workspace. Alfresco knows how to import WAR and ZIP files, which is a convenient way to migrate the website into Alfresco for the first time. Because web project sandboxes are mountable via CIFS, simply copying the website into the sandbox via CIFS is another way to go. The difference between the two approaches is that the WAR/ZIP import can only happen once. The import action complains if an archive contains nodes that already exist in the repository. If you haven't already done so, take a look at the contents of your sandbox. You should see index.html in the root of your User Sandbox and a someco folder that contains additional folders for CSS, images, JavaScript, and so on. The HTML file in the root is the same index.html file you deployed to the Alfresco web application in order to implement the AJAX ratings widget. Click the preview icon. (Am I the only one who thinks it looks eerily similar to the Turkish nazar talisman used to ward off the "evil eye"?) You should see the index page in a new tab or window. The list of Whitepapers won't be displayed. That's because the page is running in the context of the virtualization server, which is a different domain than your Alfresco server. Therefore, it is subject to the cross-domain restriction, which will be addressed later. Playing Nicely in the Sandbox Go back to the root of your web project folder. The link in the breadcrumb trail is likely to be the fastest way to navigate back. Click the Browse Website link in the Staging Sandbox. It's empty. If you were to invite another user to this website, his/her sandbox would be empty as well. Sandboxes are used to isolate changes each content owner makes, while still providing him/her the full context of the website. The Staging Sandbox represents your live website. Or in source code control terms, it is the HEAD of your site. It is assumed that whatever is in the Staging Sandbox can be safely deployed to the live website at any time. It is currently empty because you have not yet submitted any content to staging. Let's go ahead and do that now. If you click the Modified Items link in the User Sandbox, you'll see the index.html file and the someco folder. You could submit these individually. But you want everything to go to staging, so click Submit All: Provide a label and a description such as initial population and click OK. It is safe to ignore the warning that a suitable workflow was not found. That's expected because you haven't configured a workflow for this web project yet. Now the files have been submitted to staging. Here are some things to notice: If you click the Preview Website link in the Staging Sandbox, you'll see the website just as you did in the User Sandbox earlier. If you browse the website in the Staging Sandbox, you'll see the same files currently shown when you browse the website in your User Sandbox. A snapshot of the site was automatically taken when the files were committed and is listed under Recent Snapshots: Inviting Users To get a feel for how sandboxes work, invite one or more users to the web project (Actions, Invite Web Project Users). The following table describes the out of the box web project roles:   WCM User Role Can do these things Content Contributor Create and submit new content; but cannot edit or delete existing content Content Reviewer Create, edit, and submit new content; but cannot delete existing content Content Collaborator See all sandboxes, but only have full control over their own Create, edit, and submit new content; but cannot delete existing content Edit web project settings Content Manager See and modify content in all sandboxes; exert full control over all content See and deploy snapshots and manage deployment reports Edit web project settings Invite new users to the web project Delete the web project and individual sandboxes You'll notice that each new user gets his/her own sandbox, and that the sandbox automatically contains everything that is currently in staging. If a user makes a change to his/her sandbox, it is only visible within their sandbox until they commit the change to staging. If this is done, everyone else sees the change immediately. Unlike some content management and source code control systems, there is no need for other users to do an "update" or a "get latest" to copy the latest changes from staging into their sandbox. It is important to note that Alfresco will not merge conflicts. When a user makes a change to a file in his/her sandbox, it will be locked in all other sandboxes to prevent conflicts. If you were to customize Alfresco to disable locking, the last change would win. Alfresco would not warn you of the conflict. The Alfresco admin user and any user with Content Manager Access can see (and work within) all User Sandboxes. Everyone else sees only their own sandboxes. Mounting Sandboxes via CIFS All sandboxes are individually mountable via CIFS. In fact, in staging, each snapshot is individually mountable. This gives content owners the flexibility to continue managing content in their sandbox using the tools they are familiar with. The procedure for mounting a sandbox is identical to that of mounting the regular repository via CIFS, except that you use "AVM" as the mount point instead of "Alfresco". One difference between mounting the AVM repository through CIFS and mounting the DM repository is that the AVM repository directory structure is more complicated. For example, the path to the root of admin's sandbox in the SomeCo site is: |someco-site--admin|HEAD|DATA|www|avm_webapps|ROOT The first part of the path, someco-site, is the DNS name you assigned when you set up the web project. The admin string indicates which User Sandbox we are looking at. If you wanted to mount to the Staging Sandbox, the first part of the path would be someco-site without --admin. The next part of the path, HEAD, specifies the latest-and-greatest version of the website. Alternatively, you could mount a specific snapshot like this: |someco-site--admin|VERSION|v2|DATA|www|avm_webapps|ROOT As you might expect, the normal permissions apply. Users who aren't able to see another user's sandbox in the web client won't be able to do so through CIFS.
Read more
  • 0
  • 0
  • 2307

article-image-custom-types-documentum
Packt
22 Oct 2009
4 min read
Save for later

Custom Types in Documentum

Packt
22 Oct 2009
4 min read
Custom Types Documentum provides a large number of built-in object types that support the functionality of the platform. Some object types are general purpose and can be used for business purposes as well. However, all possible business needs can neither be anticipated nor supported by default. Therefore, Documentum allows creation of new object types, which are called custom types. This article addresses creation and management of custom types. Before reading this article, it would be helpful to know about Objects and Types, since the majority of the concepts pertaining to object types apply here as well. Some concepts are explained here. Managing Custom Types A user-defined object type is called a custom type and the user-defined properties are called custom properties. Properties are also known as attributes. Custom types can be created, modified, and removed as long as certain rules are followed. This section describes the detail around managing custom types. Creating a Custom Type A custom type can be created using Documentum Application Builder (DAB), using Documentum Administrator (DA), or using DQL/API scripts. DAB is the most commonly used application for creating custom types since it fully supports the data dictionary (see Data Dictionary later in this article) and it has a Graphical User Interface (GUI) specifically designed for creating and managing custom types. Further, DAB can also be used for packaging the types into a DocApp. The following screenshot shows the DAB screen for creating and updating a custom type: DA provides basic support for managing custom types. For example, DA does not provide an interface for defining value assistance for a property. The following screenshot shows the screen for creating and updating custom types in DA: Creating a custom type is a privileged operation and only the users with following privileges can do so: Create Type Sysadmin Superuser        The user creating the type becomes the owner of the type. A custom type can extend an existing type through inheritance (see Type Hierarchy in Documentum). A new custom type can have an existing custom type or one of the sets of Documentum object types as its supertype. The most common supertype for a new custom type for representing documents is dm_document. It is also possible to create a custom type without a supertype. Such a type is called a NULL type. Only a user with Superuser privilege can create a NULL type. A NULL type is useful for storing data that does not need the usual object management features such as versioning. There are several built-in types that are NULL types such as dm_user, dm_session, and dm_alias_set. If a custom type is intended to only store non-versionable data, a NULL type may be appropriate for this purpose. Recall that any given type uses up to two tables (one for single-valued properties and one for repeating) of its own for storing non-inherited properties of its objects. There are additional views for retrieving all the properties together. The following key information is needed or captured in DAB when creating a new custom type:   Info Description Name Name of the type. A type name must be unique (caseinsensitive) in the repository and can be up to 27 characterslong. The additional constraints on the type name are that itcannot contain a space or punctuation nor can it be same asany DQL reserved word, such as SELECT or WHERE. Further, it cannot start with dm_, dmi, dmr_, a number, space, or a single quote. It is recommended that a custom prefix be used for custom type names to distinguish them from the other types. Creator The user creating the type. Supertype The supertype of the new type. This can be NULL. Label User-friendly version of the name, for display purposes in Documentum client applications. Default Lifecycle A lifecycle that can be attached to a document of this type, without identifying the lifecycle explicitly. Default Storage Area A storage area identifies where the content files are stored for objects. The default storage area identifies where the content files for objects of this type will be stored by default. Default Permission Set The default permission set is used when the default ACL mode for the Content Server is set to Type. In this case, a new object of this type gets this permission set. Template Document One or more template documents can be created for the type, which are available to users when they are creating a new object of this type. The template documents are stored in the Templates cabinet in Documentum repository.
Read more
  • 0
  • 0
  • 5481
article-image-creating-analysis-services-cube-visual-studio-2008-part-1
Packt
22 Oct 2009
4 min read
Save for later

Creating an Analysis Services Cube with Visual Studio 2008 - Part 1

Packt
22 Oct 2009
4 min read
  Reviewing Jayaram's other OLAP related articles may greatly help in understanding this article. Installing SQL Server Analysis Services SQL Server Analysis Services (SSAS) gets installed during the SQL Server 2008 (February 2008 CTP) installation. At that time the Service Accounts for the various components are also set up as shown in this screen shot taken during a typical installation. For full details review the following article on SQL Server 2008 installation. The Analysis Services is also configured during the same installation as shown displaying the default directories for Data, log file, backup etc. Starting and Stopping the SSAS The Analysis Services can be started and stopped from the Services in the local machine which can be accessed from All Programs | Control Panel | Administrative Tools | Services. Connecting to SSAS from SQL Server Management Studio File | Connect Object Explorer... in SQL Server Management Studio allows you to access the UI shown below where you can provide login information and get connected to the Analysis Services as shown. Out of the box, the SSAS comes up with a simple folder structure as shown. It does not come with databases. You may create a new database (this is not to be confused with databases on the Database Engine of SQL Server 2008). The database you create here will have the same folder structure as the Analysis Services Project folder structure when you start with VS 2008. Creating an Analysis Services Project in VS 2008 File | New | Project... opens the New Project window. Choose Business Intelligence Projects and from the Visual Studio installed templates choose Analysis Services Project. Change the default name of project to Nwind2008. This creates an empty project with a number of folders as shown. Although this is an empty structure you can deploy it on the server. To deploy right click with Nwind2008 highlighted and choose to deploy. After the processing is successfully completed you will see that Nwind 2008 is now available on the localhost. Adding a Data Source Right click on Data Sources folder and this will display the menu item New Data Source... as shown. Click on New Data Source... to open the Data Source Wizard as shown in the next figure. Read carefully the instructions on this page. In particular note that in order to change features of the data source you need to call up the next wizard - The Data Source View Wizard. Click on the Next button. This opens the page "Select how to define the connection" of the wizard as shown in the next figure. Here you can either create a data source based on an existing connection or use a new connection, or create a data source based on another object. The window also displays the existing connections under Data Connections and for each highlighted connection displays the properties on the right side. The New... button allows you to create a new connection by guiding you with more interactive windows. Click on Hodentek2.Northwind (<Server Name>.<database name>) (this will be different in your case) choose this data source and click on the Next button. This opens the Impersonation Page of the Data Source Wizard as shown with all text boxes empty, but with the Windows user name and password as default choice. Northwind database is not installed when you install SQL Server 2008. You may follow the procedure described in these articles to bring the Northwind database to SQL server 2008. Copying a Database from SQL Server 2005 to SQL Server 2008 using the Copy Database Wizard and Moving a Database from SQL Server 2005 to SQL Server 2008 in Three Steps. Change it to Use the service account and click on the Next button. This displays the Completing the Wizard page as shown where a Data source name and its connection information are displayed. Click on the Finish button. This adds the chosen data source to the Data Sources folder as shown. Northwind.ds is the file that is added and any changes to the source can be made by double clicking this file and applying the changes.  
Read more
  • 0
  • 0
  • 5380

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
Modal Close icon
Modal Close icon