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

How-To Tutorials

7019 Articles
article-image-podcasting-linux-command-line-tools-and-audacity
Packt
22 Oct 2009
5 min read
Save for later

Podcasting with Linux Command Line Tools and Audacity

Packt
22 Oct 2009
5 min read
Introduction Recording a good podcast is as much about good voice training and delivery, as much as it is about the technology used to record it. As with other things, you only get better with practice. In this article we will use Linux command line tools and optionally Audacity to create a quick, no-frills podcast with a background music track. The only other GUI-based tool we will manipulate, will be the ALSA Mixer. The mixer has a command-line interface too, but the GUI is intuitive and quicker. The emphasis is on quick turnaround. If you are the type that attaches a quick voice message to an e-mail for impact, ("We simply must get this done by Friday!!") then the podcast creation method outlined here should appeal to you. If you are new to podcasting and audio mixer setups, the next few sections might be tedious. But towards the end of this article, we will see how quickly one can run down these steps so that you spend more time recording your message than wrestling with technology or complicated screens. The Recording Setup A stereo headset with a microphone works best for making or listening to podcasts; but do not despair if you have a desktop microphone and a pair of speakers. You can always upgrade your setup later. For now just make sure that the sound from the speakers does not directly reach the microphone and cause feedback. Place the microphone towards the lower right of your mouth as you speak, away from your nose. This avoids breathing sounds getting captured. Minimizing ambient noise by choosing a quieter time of the day is also a good idea. Recording Tips All through the recording and mixing process, there are a couple of things to keep in mind. First, stay above the noise floor. The signal should be recorded high enough to stay above the background noise and hiss. If your audio signals are like little, beautiful flowers growing in a grassy field, make sure their stalks are tall enough to tower over the field. Else you would lose the flowers in the prickly grass just as your audio signal would be lost in the background hiss and noise. Second, stay below the clipping or overload level of the audio channels. If your audio channels were like open water canals, then overloading them past the clipping limit would have a similar undesirable effect on your audio experience as a canal overflowing its banks -- puddles around your feet or a jarring quality to your sound. Since sound level is a dynamic quantity, record your audio at a level of around 80% keeping some margin (or headroom) against clipping. Setting up the Audio Mixer Connections An audio mixer application helps us record our podcast by allowing us to mix various signal sources in the right proportion. You can bring up the sound mixer from the Linux start menu by getting into the Sound and Video category. To those who are new to the red and green lights of the Linux ALSA mixer, let us run a quick intro. There are audio signal sources and there are destinations. An audio mixer allows you to route one or more sources after adjusting their relative levels to one or more destinations and achieve your project goal. The project goal might be listening to music -- the destination in this case being a pair of headphones or speakers; or it might be a recording device, say, to capture a podcast as we will do presently. Once the ALSA mixer or Kmix is up, select the Output tab. Make sure the Master output channel as well as the PCM channel is switched on (click over the green lights so they turn on) and their gains -- the slider positions -- are at the maximum. Briefly, go the Switches tab and click over the LED indicator to switch on the 'Mix Mono'. We will use this mixing switch to mix the microphone (voice) and the CD (background score) signals to both the monitoring and the recording channels. You can optionally select the 'Mic Boost' switch but experiment with your microphone to check if you indeed need it. Now, go to the Input tab. The two input sources that interest us are the 'Mic' or microphone for our voice and the CD for our background music score. We need to mix these two signal sources in the right proportion and deliver them to the Capture device. Turn on the green LEDs for the 'Mic' and 'CD' sources ensuring that their outputs feed into the 'Mono Mix' and also to your monitoring headphones or speakers. That way you get to listen to what is being recorded. All other input sources should be off (their corresponding green LEDs should be off). Lastly, turn on the red LED under the Capture slider on the Input tab ensuring that the 'Mix Mono' output gets connected to the recording channel.
Read more
  • 0
  • 0
  • 27058

Packt
22 Oct 2009
8 min read
Save for later

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

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

article-image-google-earth-google-maps-and-your-photos-tutorial
Packt
22 Oct 2009
38 min read
Save for later

Google Earth, Google Maps and Your Photos: a Tutorial

Packt
22 Oct 2009
38 min read
Introduction A scholar who never travels but stays at home is not worthy to be accounted a scholar. From my youth on I had the ambition to travel, but could not afford to wander over the three hundred counties of Korea, much less the whole world. So, carrying out an ancient practise, I drew a geographical atlas. And while gazing at it for long stretches at a time I feel as though I was carrying out my ambition . . . Morning and evening while bending over my small study table, I meditate on it and play with it and there in one vast panorama are the districts, the prefectures and the four seas, and endless stretches of thousands of miles. WON HAK-SAENG Korean Student Preface to his untitled manuscript atlas of China during the Ming Dynasty, dated 1721. To say that maps are important is an understatement almost as big as the world itself. Maps quite literally connect us to the world in which we all live, and by extension, they link us to one another. The oldest preserved maps date back nearly 4500 years. In addition to connecting us to our past, they chart much of human progress and expose the relationships among people through time. Unfortunately, as a work of humankind, maps share many of the same shortcomings of all human endeavors. They are to some degree inaccurate and they reflect the bias of the map maker. Advancements in technology help to address the former issue, and offer us the opportunity to resist the latter. To the extent that it's possible for all of us to participate in the map making, the bias of a select few becomes less meaningful. Google Earth  and Google Maps  are two applications that allow each of us to assert our own place in the world and contribute our own unique perspective. I can think of no better way to accomplish this than by combining maps and photography. Photos reveal much about who we are, the places we have been, the people with whom we have shared those experiences, and the significant events in our lives. Pinning our photos to a map allows us to see them in their proper geographic context, a valuable way to explore and share them with friends and family. Photos can reveal the true character of a place, and afford others the opportunity to experience these destinations, perhaps faraway and unreachable for some of us, from the perspective of someone who has actually been there. In this tutorial I'll show you how to 'pin' your photos using Google Earth and Google Maps. Both applications are free, and available for Windows, Mac OS X, and Linux. In the case of Google Earth there are requirements associated with installing and running what is a local application. Google Maps has its own requirements: primary among them a compatible web browser (the highly regarded FireFox is recommended). In Google Earth, your photos show up on the map within the application complete with titles, descriptions, and other relevant information. You can choose to share your photos with everyone, only people you know, or even reserve them strictly for yourself. Google Maps offers the flexibility to present maps outside of a traditional application. For example you can embed a map on a webpage pinpointing the location of one particular photo, or mapping a collection of photos to present along with a photo gallery, or even collecting all of your digital photos together on one dynamic map. Over the course of a short couple of articles we'll cover everything you need to take advantage of both applications. I've put together two scripts to help us accomplish that goal. The first is a Perl script that works through your photos and generates a file in the proper format with all of the data necessary to include those photos in Google Earth. The second is a short bit of Javascript that works with the first file and builds a dynamic Google Map of those same photos. Both scripts are available for you to download, after which you are free to use them as is, or modify them to suit your own projects. I've purposefully kept the code as simple as possible to make them accessible to the widest audience, even those of you reading this who may be new to programming or unfamiliar with Perl, Javascript or both. I've taken care to comment the code generously so that everything is plainly obvious. I'm hopeful that you will be surprised at just how simple it is. There a couple of preliminary topics to examine briefly before we go any further. In the preceding paragraph I mentioned that the result of the first of our two scripts is a 'file in the proper format...'. This file, or more to the point the file format, is a very important part of the project. KML  (Keyhole Markup Language) is a fairly simple XML-based format that can be considered the native "language" of Google Earth. That description begs the question, 'What is XML?'. To oversimplify, because even a cursory discussion of XML is outside of the scope of this article, XML  (Extensible Markup Language) is an open data format (in contrast to proprietary formats) which allows us to present information in such way that we communicate not only the data itself, but also descriptive information about the data and the relationships among elements of the data. One of the technical terms that applies is 'metalanguage', which approximately translates to mean a language that makes it possible to describe other languages. If you're unfamiliar with the concept, it may be difficult to grasp at first or it may not seem impressive. However, metalanguages, and specifically XML, are an important innovation (I don't mean to suggest that it's a new concept. In fact XML has roots that are quite old, relative to the brief history of computing). These metalanguages make it possible for us to imbue data with meaning such that software can make use of that data. Let's look at an example taken from the Wikipedia entry for KML. <?xml version="1.0" encoding="UTF-8"?> <kml > <Placemark>  <description>New York City</description>  <name>New York City</name>  <Point>  <coordinates>-74.006393,40.714172,0</coordinates>  </Point> </Placemark> </kml>   Ignore all of the pro forma stuff before and after the <Placemark> tags and you might be able to guess what this bit of data represents. More importantly, a computer can be made to understand what it represents in some sense. Without the tags and structure, "New York City" is just a string, i.e. a sequence of characters. Considering the tags we can see that we're dealing with a place, (a Placemark), and that "New York City" is the name of this place (and in this example also its description). With all of this formal structure, programs can be made to roughly understand the concept of a Placemark, which is a useful thing for a mapping application. Let's think about this for a moment. There are a very large number of recognizable places on the planet, and a provably infinite number of strings. Given a block of text, how could a computer be made to identify a place from, for example the scientific name of a particular flower, or a person's name? It would be extremely difficult. We could try to create a database of every recognizable place and have the program check the database every time it encounters a string. That assumes it's possible to agree on a 'complete list of every place', which is almost certainly untrue. Keep in mind that we could be talking about informal places that are significant only to a small number of people or even a single person, e.g. 'the park where, as a child, I first learned to fly a kite'. It would be a very long list if we were going to include these sorts of places, and incredibly time-consuming to search. Relying on the structure of the fragment above, we can easily write a program that can identify 'New York City' as the name of a place, or for that matter 'The park where I first learned to fly a kite'. In fact, I could write a program that pulls all of the place names from a file like this, along with a description, and a pair of coordinate points for each, and includes them on a map. That's exactly what we're going to do. KML makes it possible. If I haven't made it clear, the structural bits of the file must be standardized. KML supports a limited set of elements (e.g. 'Placemark' is a supported element, as are 'Point' and 'coordinates'), and all of the elements used in a file must adhere to the standard for it to be considered valid. The second point we need to address before we begin is, appropriately enough... where to begin? Lewis Carroll famously tells us to "Begin at the beginning and go on till you come to the end: then stop."  Of course, Mr. Carroll  was writing a book at the time. If "Alice's Adventures in Wonderland" were an article, he might have had different advice. From the beginning to the end there is a lot of ground to cover. We're going to start somewhere further along, and make up the difference with the following assumptions. For the purposes of this discussion, I am going to assume that you have: Perl Access to Phil Harvey's excellent ExifTool , a Perl library and command-line application for reading, writing, and editing metadata in images (among other file types). We will be using this library in our first script A publicly accessible web server. Google requires the use of an API key  by which it can monitor the use of its map services. Google must be able to validate your key, and so your site must be publicly available. Note that this a requirement for Google Maps only Photos, preferably in a photo management application. Essentially, all you need is an app capable of generating both thumbnails and reduced size copies of your original photos . An app that can export a nice gallery for use on the web is even better Coordinate data as part of the EXIF metadata  embedded in your photos. If that sounds unfamiliar to you, then most likely you will have to take some additional steps before you can make use of this tutorial. I'm not aware of any digital cameras that automatically include this information at the time the photo is created. There are devices that can be used in combination with digital cameras, and there are a number of ways that you can 'tag' your photos with geographic data much the same way you would add keywords and other annotations. Let's begin!   Part 1: Google Earth Section 1: Introduction to Part 1 Time to begin the project in earnest. As I've already mentioned we'll spend the first half of this tutorial looking at Google Earth and putting together a Perl script whichthat, given a collection of geotagged photos, will build a set of KML files so that we can browse our photos in Google Earth. These same files will serve as the data source for our Google Maps application later on. Section 2: Some Advice Before We Begin Take your time to make sure you understand each topic before you move on to the next. Think of this as the first step in debugging your completed code. If you go slowly enough that you are to be able to identify aspects of the project that you don't quite understand, then you'll have some idea where to start looking for problems should things not go as expected. Furthermore, going slowly will give you the opportunity to identify those parts that you may want to modify to better fit the script to your own needs. If this is new to you, follow along as faithfully as possible with what I do here the first time through. Feel free to make notes for yourself as you go, but making changes on the first pass may make it difficult for you to catch back on to the narrative and piece together a functional script. After you have a working solution, it will be a simple matter to implement changes one at a time until you have something that works for you. Following this approach it will be easy to identify the silly mistakes that tend to creep in once you start making changes. There is also the issue of trust. This is probably the first time we're meeting each other, in which case you should have some doubt that my code works properly to begin with. If you minimize the number of changes you make, you can confirm that this works for you before blaming yourself or your changes for my mistakes. I will tell you up front that I'm building this project myself as we go. You can be certain at least that it functions as described for me as of the date attached to the article. I realize that this is quite different from being certain that the project will work for you, but at least it's something. The entirety of my project is available for you to download. You are free to use all of it for any legal purpose whatsoever,  including my photos in addition to all of the code, icons, etc. This is so you have some samples to use before you involve your own content. I don't promise that they are the most beautiful images you have ever seen, but they are all decent photos and properly annotated with the necessary metadata, including geographic tags. Section 3: Photos, Metadata and ExifTool To begin, we must have a clear understanding of what the Perl script will require from us. Essentially, we need to provide it with a selection of annotated image files, and information about how to reference those files. A simple folder of files is sufficient, and will be convenient for us, both as the programmer and end user. The script will be capable of negotiating nested folders, and if a directory contains both images and other file types, non-image types will be ignored. Typically, after a day of taking photos I'll have 100 to 200 that I want to keep. I delete the rest immediately after offloading them from the camera. For the files that are left, I preserve the original grouping, keeping all of the files together in a single folder. I place this folder of images in an appropriate location according to a scheme that serves to keep my complete collection of photos neatly organized. These are my digital 'negatives'. I handle all subsequent organization, editing, enhancements, and annotations within my photo management application. I use Apple Inc.'s Aperture; but there are many others that do the job equally well. Annotating your photos is well worth the investment of time and effort, but it's important that you have some strategy in mind so that you don't create meaningless tags that are difficult to use to your advantage. For the purposes of this project the tags we'll need are quite limited, which means that going forward we will be able to continue adding photos to our maps with a reasonable amount of work. The annotations we need are: Caption Latitude Longitude Image Date * Location/Sub-Location City Province/State Country Name Event People ImageWidth * ImageHeight * * Values for these Exif tags are generated by your camera. Note that these are labels used in Aperture, and are not necessarily consistent from one application to the next. Some of them are more likely than others to be used reliably. 'City' for example should be dependable, while the labels 'People', 'Events', and 'Location', among others, are more likely to differ. One explanation for these variations is that the meaning of these fields are more open to interpretation. Location, for example, is likely to be used to narrow down the area where the photo was taken within a particular city, but it is left to the person who is annotating the photo to decide that the field should name a specific street address, an informal place (e.g. 'home' or 'school'), or a larger area, for example a district or neighborhood. Fortunately things aren't so arbitrary as they seem. Each of these fields corresponds to a specific tag name that adheres to one of the common metadata formats (Exif1, IPTC2, XMP3, and there are others). These tag names are consistent as required by the standards. The trick is in determining the labels used in your application that correspond to the well-defined tag names. Our script relies on these metadata tags, so it is important that you know which fields to use in your application. This gives us an excuse to get acquainted with ExifTool4. From the project's website, we have this description of the application: ExifTool is a platform-independent Perl library plus a command-line application for reading, writing, and editing meta information in image, audio, and video files... ExifTool can seem a little intimidating at first. Just keep in mind that we will need to understand just a small part of it for this project, and then be happy that such a useful and flexible tool is freely available for you to use. The brief description above states in part that ExifTool is a Perl library and command line application that we can use to extract metadata from image files. With a single short command, we can have the app print all of the metadata contained in one of our image files. First, make sure ExifTool is installed. You can test for this by typing the name of the application at the command line. $ exiftool If it is installed, then running it with no options should prompt the tool to print its documentation. If this works, there will be more than one screen of text. You can page through it by pressing the spacebar. Press the 'q' key at any time to stop. If the tool is not installed, you will need to add it before continuing. See the appendix at the end of this tutorial for more information. Having confirmed that ExifTool is installed, typing the following command will result in a listing of the metadata for the named image: $ exiftool -f -s -g2 /path/image.jpg Where 'path' is an absolute path to image.jpg or a relative path from the current directory, and 'image.jpg' is the name of one of your tagged image files. We'll have more to say about ExifTool later, but because I believe that no tutorial should ask the reader to blindly enter commands as if they were magic incantations, I'll briefly describe each of the options used in the command above: -f, forces printing of tags even if their values are not found. This gives us a better idea about all of the available tag names, whether or not there are currently defined values for those tags. -s, prints tag names instead of descriptions. This is important for our purposes. We need to know the tag names so that we can request them in our Perl code. Descriptions, which are expanded, more human-readable forms of the same names obscure details we need. For example, compare the tag name 'GPSLatitude' to the description 'GPS Latitude'. We can use the tag name, but not the description to extract the latitude value from our files. -g2, organizes output by category. All location specific information is grouped together, as is all information related to the camera, date and time tags, etc.  You may feel, as I do, that this grouping makes it easier to examine the output. Also, this organization is more likely to reflect the grouping of field names used by your photo management application. If you prefer to save the output to a file, you can add ExifTool's -w option with a file extension. $ exiftool -f -s -g2 -w txt path/image.jpg This command will produce the same result but write the output to the file 'image.txt' in the current directory; again, where 'image.jpg' is the name of the image file. The -w option appends the named extension to the image file's basename, creates a new file with that name, and sets the new file as the destination for output. The tag names that correspond to the list of Aperture fields presented above are: metadata tag name Aperture field label Caption-Abstract Caption GPSLatitude Latitude GPSLongitude Longitude DateTimeOriginal Image Date Sub-location Location/Sub-Location City City Province-State Province/State Country-PrimaryLocationName Country Name FixtureIdentifier Event Contact People ImageWidth Pixel Width ImageHeight Pixel Height     Section 4: Making Photos Available to Google Earth We will use some of the metadata tags from our image files to locate our photos on the map (e.g. GPSLatitude, GPSLongitude), and others to describe the photos. For example, we will include the value of the People tag in the information window that accompanies each marker to identify friends and family who appear in the associated photo. Because we want to display and link to photos on the map, not just indicate their position, we need to include references to the location of our image files on a publicly accessible web server. You have some choice about how to do this, but for the implementation described here we will (1) Display a thumbnail in the info window of each map marker and (2) include a link to the details page for the image in a gallery created in our photo management app. When a visitor clicks on a map marker they will see a thumbnail photo along with other brief descriptive information. Clicking a link included as part of the description will open the viewer's web browser to a page displaying a large size image and additional details. Furthermore, because the page is part of a gallery, viewers can jump to an index page and step forward and back through the complete collection. This is a complementary way to browse our photos. Taking this one step further, we could add a comments section to the gallery pages or replace the gallery altogether, instead choosing to display each photo as a weblog post for example. The structure of the gallery created from my photo app is as follows... / (the root of the gallery directory) index.html large-1.html large-2.html large-3.html ... large-n.html assets/ css/ img/ catalog/ pictures/ picture-1.jpg picture-2.jpg picture-3.jpg ... picture-n.jpg thumbnails/ thumb-1.jpg thumb-2.jpg thumb-3.jpg ... thumb-n.jpg The application creates a root directory containing the complete gallery. Assuming we do not want to make any manual changes to the finished site, publishing is as easy as copying the entire directory to a location within the web server's document root. assets/: Is a subfolder containing files related to the theme itself. We don't need to concern ourselves with this sub-directory. catalog/: Contains a single catalog.plist file which is specific to Aperture and not relevant to this discussion. pictures/: Contains the large size images included on the detail gallery pages. thumbnails/: This subfolder contains the thumbnail images corresponding to the large size images in pictures/. Finally, there are a number of files at the root of the gallery. These include index pages and files named 'large-n.html', where n is a number starting at 1 and increasing sequentially e.g. large-1.html, large-2.html, large-3.html, ... The index files are the index pages of our gallery. The number of index pages generated will be dictated by the number of image files in the gallery, as well as the gallery's layout and design. index.html is always the first gallery page. The large-n.html files are the details pages of our gallery. Each page features an individual photo with links to the previous and next photos in sequence and a link back to the index. You can see the gallery I have created for this tutorial here: http://robreed.net/photos/tutorial_gallery/ If you take the time to look through the gallery, maybe you can appreciate the value of viewing these photos on a map. Web-based photo galleries like this one are nice enough, but the photos are more interesting when viewed in some meaningful context. There are a couple of things to notice about this gallery. Firstly, picture-1.jpg, thumb-1.jpg, and large-1.html all refer to the same image. So if we pick one of the three files we can easily predict the names of the other two. This relationship will be useful when it comes to writing our script. There is another important issue I need to call to your attention because it will not be apparent from looking only at the gallery structure. Aperture has renamed all of my photos in the process of exporting them. The name of the original file from which picture-1.jpg was generated (as well as large-1.html and thumb-1.jpg) is 'IMG_0277.JPG', which is the filename produced by my camera. Because I want to link to these gallery files, not my original photos which will stay safely tucked away on a local drive, I must run the script against the photos in the gallery. I cannot run it against the original image files because the filenames referenced in the output are unrelated to the files in the gallery. If my photo management app provided me the option of preserving the original filenames for the corresponding photos in the gallery, then I could run the script against the original image files or the gallery photos because all of the filenames would be consistent, but this is not the case. I don't have a problem as long as I run the script on the exported photos. However, if I'm running the script against the photos in the web gallery, either the pictures or thumbnail images must contain the same metadata as the original image files. Aperture preserves the metadata in both. Your application may not. A simple, dependable way to confirm that the metadata is present in the gallery files is to run ExifTool first against the original file and then the same photo in the pictures/ and thumbnails/ directories in the gallery. If ExifTool reports identical metadata, then you will have no trouble using one of pictures/ or thumbnails/ as your source directory. If the metadata is not present or not complete in the gallery files, you may need to use the script on your original image files. As has already been explained, this isn't a problem unless the gallery produces filenames that are inconsistent with the original filenames, as Aperture does. In this case you have a problem. You won't be able to run the script on the original image files because of the naming issue or on the gallery photos because they don't contain metadata. Make sure that you understand this point. If you find yourself in this situation, then your best bet is to generate files to use with your maps from your original photos in some other way, bypassing your photo management app's web gallery features altogether in favor of a solution that preserves the filenames, the metadata, or both. There is another option which involves setting up a relationship between the names of the original files and the gallery filenames. This tutorial does not include details about how to set up this association. Finally, keep in mind that though we've looked at the structure of a gallery generated by Aperture, virtually all photo management apps produce galleries with a similar structure. Regardless of the application used, you should find: A group of html files including index and details pages A folder of large size image files A folder of thumbnails Once you have identified the structure used by your application, as we have done here, it will be a simple task to translate these instructions. Section 5: Referencing Files Over the Internet Now we can talk about how to reference these files and gallery pages so that we can create a script to generate a KML file that includes these references. When we identify a file over the internet, it is not enough to use the filename, e.g. 'thumb-1.jpg', or even the absolute and relative path to the file on the local computer. In fact these paths are most likely not valid as far as your web server is concerned. Instead we need to know how to reference our files such that they can be accessed over the global internet, and the web more specifically. In other words, we need to be able to generate a URL (Uniform Resource Locator) which unambiguously describes the location of our files. The formal details of exactly what comprises a URL5; are more complicated than may be obvious at first, but most of us are familiar with the typical URL, like this one: http://www.ietf.org/rfc/rfc1630.txt which describes the location of a document titled "Universal Resource Identifiers in WWW" that just so happens to define the formal details of what comprises a URL. http://www.ietf.org This portion of the address is enough to describe the location of a particular web server over the public internet. In fact it does a little more than just specify the location of a machine. The http:// portion is called the scheme and it identifies a particular protocol (i.e. a set of rules governing communication) and a related application, namely the web. What I just said isn't quite correct; at one time, HTTP was used exclusively by the web, but that's no longer true. Many internet-based applications use the protocol because the popularity of the web ensures that data sent via HTTP isn't blocked or otherwise disrupted. You may not be accustomed to thinking of it as such, but the web itself is a highly-distributed, network-based application. /rfc/ This portion of the address specifies a directory on the server. It is equivalent to an absolute path on your local computer. The leading forward slash is the root of the web server's public document directory. Assuming no trickiness on the part of the server, all content lives under the document root. This tells us that rfc/ is a sub-directory contained within the document root. Though this directory happens to be located immediately under the root, this certainly need not be the case. In fact these paths can get quite long. We have now discussed all of the URL except for: rfc1630.txt which is the name of a specific file. The filename is no different than the filenames on your local computer. Let's manually construct a path to one of the large-n.html pages of the gallery we have created. The address of my server is robreed.net, so I know that the beginning of my URL will be: http://robreed.net I keep all of my galleries together within a photos/ directory, which is contained in the document root. http://robreed.net/photos/ Within photos/, each gallery is given its own folder. The name of the folder I have created for this tutorial is 'tutorial_gallery'. Putting this all together, the following URL brings me to the root of my photo gallery: http://robreed.net/photos/tutorial_gallery/ We've already gone over the directory structure of the gallery, so it should make sense you to that when referring to the 'large-1.html' detail page, the complete URL will be: http://robreed.net/photos/tutorial_gallery/large-1.html the URL of the image that corresponds to that detail page is: http://robreed.net/photos/tutorial_gallery/pictures/picture-1.jpg and the thumbnail can be found at: http://robreed.net/photos/tutorial_gallery/thumbnails/thumb-1.jpg Notice that the address of the gallery is shared among all of these resources. Also, notice that resources of each type (e.g. the large images, thumbnails, and html pages) share a more specific address with files of that same type. If we use the term 'base address' to refer to the shared portions of these URLs, then we can talk about several significant base addresses: The gallery base address: http://robreed.net/photos/tutorial_gallery/ The html pages base address: http://robreed.net/photos/tutorial_gallery/ The images base address: http://robreed.net/photos/tutorial_gallery/pictures/ The thumbnails base address: http://robreed.net/photos/tutorial_gallery/thumbnails/ Note that given the structure of this particular gallery, the html pages base address and the gallery base address are identical. This need not be the case, and may not be for the gallery produced by your application. We can hard-code the base addresses into our script. For each photo, we need only append the associated filename to construct valid URLs to any of these resources. As the script runs, it will have access to the name of the file that it is currently evaluating, and so it will be a simple matter to generate the references we need as we go. At this point we have discussed almost everything we need to put together our script. We have: Created a gallery at our server, which includes our photos with metadata in tow Identified all of the metadata tags we need to extract from our photos with the script and the corresponding field names in our photo management application Determined all of the base addresses we need to generate references to our image files Section 6: KML The last thing we need to understand is the format of the KML files we want to produce. We've already looked at a fragment of KML. The full details can be found on Google's KML documentation pages , which include samples, tutorials and a complete reference for the format. A quick look at the reference is enough to see that the language includes many elements and attributes, the majority of which we will not be including in our files. That statement correctly implies it is not necessary for every KML file to include all elements and attributes. The converse however is not true, which is to say that every element and attribute contained in any KML file must be a part of the standard. A small subset of KML will get us most, if not all, of what you will typically see in Google Earth from other applications. Many of the features we will not be using deal with aspects of the language that are either: Not relevant to this project, e.g. ground overlays (GroundOverlay) which "draw an image overlay draped onto the terrain" Minute details for which the default values are sensible There is no need to feel shortchanged because we are covering only a subset of the language. With the basic structure in place and a solid understanding of how to script the generation of KML, you will be able to extend the project to include any of the other components of the language as you see fit. The structure of our KML file is as follows:  1.    <?xml version="1.0" encoding="UTF-8"?> 2.    <kml > 3.        <Document> 4.            <Folder> 5.                <name>$folder_name</name> 6.                <description>$folder_description</description> 7.                <Placemark> 8.                    <name>$placemark_name</name> 9.                    <Snippet maxLines="1"> 10.                        $placemark_snippet 11.                    </Snippet> 12.                    <description><![CDATA[ 13.                        $placemark_description 14.                    ]]></description> 15.                    <Point> 16.                        <coordinates>$longitude,$latitude </coordinates> 17.                    </Point> 18.                </Placemark> 19.            </Folder> 20.        </Document> 21.    </kml> Line 1: XML header Every valid KML file must start with this line and nothing else is allowed to appear before it. As I've already mentioned, KML is an XML-based language and XML requires this header. Line 2: Namespace declaration More specifically this is the KML namespace declaration, and it is another formality. The value of the >Line 3: <Document> is a container element representing the KML file itself. If we do not explicitly name the document by including a name element then Google Earth will use the name of the KML file as the Document element <name>. The Document container will appear on the Google Earth 'Sidebar' within the 'Places' panel. Optionally we can control whether the container is closed or open by default. (This setting can be toggled in Google Earth using a typical disclosure triangle.) There are many other elements and attributes that can be applied to the Document element. Refer to the KML Reference for the full details. Line 4: <Folder> is another container element. The files we produce will include a single <Folder> containing all of our Placemarks, where each Placemark represents a single image. We could create multiple Folder elements to group our Placemarks according to some significant criteria. Think of the Folder element as being similar to your operating system's concept of a folder. At this point, note the structure of the fragment. The majority of it is contained within the Folder element. Folder, in turn, is an element of Document which is itself within the <kml> container. It should make sense that everything in the file that is considered part of the language must be contained within the kml element. From the KML reference: A Folder is used to arrange other Features hierarchically (Folders, Placemarks, NetworkLinks, or Overlays). A Feature is visible only if it and all its ancestors are visible. Line 5: The name element identifies an object, in this case the Folder object. The text that appears between the name tags can be any plain text that will serve as an appropriate label.   Line 6: <description> is any text that seems to adequately describe the object. The description element supports both plain text and a subset of HTML. We'll consider issues related to using HTML in <description> at the discussion of Placemark, lines 12 - 14. Lines 7 - 17 define a <Placemark> element. Note that Placemark contains a number of elements that also appear in Folder, including <name> (line 8), and <description> (lines 12 - 14). These elements serve the same purpose for Placemark as they do for the Folder element, but of course they refer to a different object. I've said that <description> can include a subset of HTML in addition to plain text. Under XML, some characters have special meaning. You may need to use these characters as part of the HTML included in your descriptions. Angle brackets (<, >) for example surround tag names in HTML, but serve a similar purpose in XML. When they are used strictly as part of the content, we want the XML parser to ignore these characters. We can accomplish this a few different ways: We can use entity references, either numeric character references or character entity references, to indicate that the symbol appears as part of the data and should not be treated as part of the syntax of the language. The character '<', which is required to include an image as part of the description (something we will be doing), (e.g. <img src=... />) can safely be included as the character entity reference '&lt;' or the numeric character reference '&#60'. The character entity references may be easier to remember and recognize on sight but are limited to the small subset of characters for which they have been defined. The numeric references on the other hand can specify any ASCII character. Of the two types, numeric character references should be preferred. There are also Unicode entity references which can specify any character at all. In the simple case of embedding short bits of HTML in KML descriptions, we can avoid the complication of these references altogether by enclosing the entire description in a CDATA6 element, which instructs the XML parser to ignore any special characters that appear until the end of the block set off by the CDATA tags. Notice the string '<![CDATA[' immediately after the opening <description> tag within <Placemark>, and the string ]]> immediately before the closing </description> tag. If we simply place all of our HTML and plain text between those two strings, it will all be ignored by the parser and we are not required to deal with special characters individually. This is how we'll handle the issue. Lines 9 - 11: <Snippet> The KML reference does a good job of clearly describing this element. From the KML reference: In Google Earth, this description is displayed in the Places panel under the name of the feature. If a Snippet is not supplied, the first two lines of the <description> are used. In Google Earth, if a Placemark contains both a description and a Snippet, the <Snippet> appears beneath the Placemark in the Places panel, and the <description> appears in the Placemark's description balloon. This tag does not support HTML markup. <Snippet> has a maxLines attribute, an integer that specifies the maximum number of lines to display. Default for maxLines is 2. Notice that in the block above at line 9, I have included a 'maxLines' attribute with a value of 1. Of course, you are free to substitute your own value for maxLines, or you can omit the attribute entirely to use the default value. The only element we have yet to review is <Point>, and again we need only look to the official reference for a nice description. From the KML reference: A geographic location defined by longitude, latitude, and (optional) altitude. When a Point is contained by a Placemark, the point itself determines the position of the Placemark's name and icon. <Point> in turn contains the element <coordinates> which is required. From the KML reference: A single tuple consisting of floating point values for longitude, latitude, and altitude (in that order). The reference also informs us that altitude is optional, and in fact we will not be generating altitude values. Finally the reference warns: Do not include spaces between the three values that describe a coordinate. This seems like an easy mistake to make. We'll need to be careful to avoid it. There will be a number of <Placemark> elements, one for each of our images. The question is how to handle these elements. The answer is that we'll treat KML as a 'fill in the blanks' style template. All of the structural and syntactic bits will be hard-coded, e.g. the XML header, namespace declaration, all of the element and attribute labels, and even the whitespace, which is not strictly required but will make it much easier for us to inspect the resulting files in a text editor. These components will form our template. The blanks are all of the text and html values of the various elements and attributes. We will use variables as place-holders everywhere we need dynamic data, i.e. values that change from one file to the next or one execution of the script to the next. Take a look at the strings I've used in the block above. $folder_name, $folder_description, $placemark_name, etc. For those of you unfamiliar with Perl, these are all valid variable names chosen to indicate where the variables slot into the structure. These are the same names used in the source file distributed with the tutorial. Section 7: Introduction to the Code At this point, having discussed every aspect of the project, we can succinctly describe how to write the code. We'll do this in 3 stages of increasing granularity. Firstly, we'll finish this tutorial with a natural language walk-through of the execution of the script. Secondly, if you look at the source file included with the project, you will notice immediately that comments dominate the code. Because instruction is as important an objective as the actual operation of the script, I use comments in the source to provide a running narration. For those of you who find this superabundant level of commenting a distraction, I'm distributing a second copy of the source file with much of the comments removed. Finally, there is the code itself. After all, source code is nothing more than a rigorously formal set of instructions that describe how to complete a task. Most programs, including this one, are a matter of transforming input in one form to output in another. In this very ge
Read more
  • 0
  • 0
  • 8682

article-image-creating-analysis-services-cube-visual-studio-2008-part-2
Packt
22 Oct 2009
2 min read
Save for later

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

Packt
22 Oct 2009
2 min read
Reviewing Jayaram's other OLAP related articles may greatly help in understanding this article. Creating a New Cube The folder structure for the project developed in Part 1 is shown in the next figure. The Northwind.ds data source and the Northwind.dsv data source view were configured in Part 1. There are no pre-existing cubes in Nwind2008. Right click the Cubes folder and from the drop-down menu you can create a new Cube. Click on New Cube... menu item. This opens the Cube Wizard welcome window as shown. Click on the Next button. This opens the Select Creation Method page of the wizard as shown. There are three options and the default is used for this article. Click on the Next button. This opens the Select Measure Groups tables. At least one table must be chosen to continue. There is even the option of asking for a suggestion. Click on the Suggest button at the top. The program goes through the motions and comes up with two tables as candidates for Measures group, the Products table and the Order Details table. You will see check marks appearing for these two tables. Accept the suggested tables for measures and click on the Next button. This opens the Select Measures window where you can choose measures that you want to include in the Cube as shown. Uncheck the ID related items in the Products table and click on the Next button. This brings up the Select New Dimensions window as shown in the next figure. Here also one could choose the needed items. For this article the default is accepted. Click on the Next button. This takes you to the Completing the Wizard window which shows your Cube contents in a tree view as shown. Now click on the Finish button. This creates the Cube as shown in the Solution Explorer. Now you will see additional tabs open up for the Northwind.cube as shown. Using these tabs you can look at more details. These are outside the scope of this article. Also separate windows gets displayed for Cube's Measures and Dimensions as shown. Also, the Data Source View of the Cube with the relationships between the Dimensions and Measures gets displayed as shown.    
Read more
  • 0
  • 0
  • 4200

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-professional-plone-development-foreword-alexander-limi
Packt
22 Oct 2009
9 min read
Save for later

Professional Plone Development: Foreword by Alexander Limi

Packt
22 Oct 2009
9 min read
  Foreword by Alexander Limi, co-founder of Plone It's always fascinating how life throws you a loop now and then that changes your future in a profound way—and you don't realize it at the time. As I sit here almost six years after the Plone project started, it seems like a good time to reflect on how the last years changed everything, and some of the background of why you are holding this book in your hands—because the story about the Plone community is at least as remarkable as the software itself. It all started out in a very classic way—I had just discovered Zope and Python, and wanted to build a simple web application to teach myself how they worked. This was back in 1999, when Zope was still a new, unproven technology, and had more than a few rough spots. I have never been a programmer, but Python made it all seem so simple that I couldn't resist trying to build a simple web application with it. After reading what I could find of documentation at the time, I couldn't quite figure it out—so I ended up in the online Zope chat rooms to see if I could get any help with building my web application. Little did I know that what happened that evening would change my life in a significant way. I met Alan Runyan online, and after trying to assist me, we ended up talking about music instead. We also reached the conclusion that I should focus on what I was passionate about—instead of coding, I wanted to build great user interfaces and make things easy to use. Alan wanted to provide the plumbing to make the system work. For some reason, it just clicked at that point, and we collaborated online and obsessed over the details of the system for months. External factors were probably decisive here too: I was without a job, and my girlfriend had left me a few months prior; Alan had just given up his job as a Java programmer at a failed dot-com company and decided to start his own company doing Python instead—so we both ended up pouring every living hour into the project, and moving at a break-neck pace towards getting the initial version out. We ended up getting a release ready just before the EuroPython Conference in 2002, and this was actually the first time I met Alan in person. We had been working on Plone for the past year just using email and IRC chat—two technologies that are still cornerstones of Plone project communication. I still remember the delight in discovering that we had excellent communication in person as well. What happened next was somewhat surreal for people new to this whole thing: we were sitting in the audience in the "State of Zope" talk held by Paul Everitt. He got to the part of his talk where he called attention to people and projects that he was especially impressed with. When he called out our names and talked about how much he liked Plone—which at this point was still mostly the effort of a handful of people—it made us feel like we were really onto something. This was our defining moment. For those of you who don't know Paul, he is one of the founders of Zope Corporation, and would go on to become our most tireless and hard-working supporter. He got involved in all the important steps that would follow—he put a solid legal and marketing story in place and helped create the Plone Foundation—and did some great storytelling along the way. There is no way to properly express how much Paul has meant to us personally—and to Plone—five years later. His role was crucial in the story of Plone's success, and the project would not be where it is now without him. Looking back, it sounds a bit like the classic romanticized start-up stories of Silicon Valley, except that we didn't start a company together. We chose to start two separate companies—in hindsight a very good decision. It never ceases to amaze me how much of an impact the project has had since. We are now an open-source community of hundreds of companies doing Plone development, training, and support. In just the past month, large companies like Novell and Akamai—as well as government agencies like the CIA, and NGOs like Oxfam—have revealed that they are using Plone for their web content management, and more will follow. The Plone Network site, plone.net, lists over 150 companies that offer Plone services, and the entire ecosystem is estimated to have revenues in the hundreds of millions of US dollars annually. This year's Plone Conference in Naples, Italy is expected to draw over 300 developers and users from around the world. Not bad for a system that was conceived and created by a handful of people standing on the shoulders of the giants of the Zope and Python communities. But the real story here is about an amazing community of people—individuals and organizations, large and small—all coming together to create the best content management system on the planet. We meet in the most unlikely locations—from ancient castles and mountain-tops in Austria, to the archipelagos and fjords of Norway, the sandy beaches of Brazil, and the busy corporate offices of Google in Silicon Valley. These events are at the core of the Plone experience, and developers nurture deep friendships within the community. I can say without a doubt that these are the smartest, kindest, most amazing people I have ever had the pleasure to work with. One of those people is Martin Aspeli, whose book you are reading right now. Even though we're originally from the same country, we didn't meet that way. Martin was at the time—and still is—living in London. He had contributed some code to one of our community projects a few months prior, and suggested that we should meet up when he was visiting his parents in Oslo, Norway. It was a cold and dark winter evening when we met at the train station—and ended up talking about how to improve Plone and the community process at a nearby café. I knew there and then that Martin would become an important part of the Plone project. Fast-forward a few years, and Martin has risen to become one of Plone's most important and respected—not to mention prolific—developers. He has architected and built several core components of the Plone 3 release; he has been one of the leaders on the documentation team, as well as an active guide in Plone's help forums. He also manages to fit in a day job at one of the "big four" consulting companies in the world. On top of all this, he was secretly working on a book to coincide with the Plone 3.0 release—which you are now the lucky owner of. This brings me to why this book is so unique, and why we are lucky to have Martin as part of our community. In the fast-paced world of open-source development—and Plone in particular—we have never had the chance to have a book that was entirely up-to-date on all subjects. There have been several great books in the past, but Martin has raised the bar further—by using the writing of a book to inform the development of Plone. If something didn't make sense, or was deemed too complex for the problem it was trying to solve—he would update that part of Plone so that it could be explained in simpler terms. It made the book better, and it has certainly made Plone better. Another thing that sets Martin's book apart is his unparalleled ability to explain advanced and powerful concepts in a very accessible way. He has years of experience developing with Plone and answering questions on the support forums, and is one of the most patient and eloquent writers around. He doesn't give up until you know exactly what's going on. But maybe more than anything, this book is unique in its scope. Martin takes you through every step from installing Plone, through professional development practices, unit tests, how to think about your application, and even through some common, non-trivial tasks like setting up external caching proxies like Varnish and authentication mechanisms like LDAP. In sum, this book teaches you how to be an independent and skillful Plone developer, capable of running your own company—if that is your goal—or provide scalable, maintainable services for your existing organization. Five years ago, I certainly wouldn't have imagined sitting here, jet-lagged and happy in Barcelona this Sunday morning after wrapping up a workshop to improve the multilingual components in Plone. Nor would I have expected to live halfway across the world in San Francisco and work for Google, and still have time to lead Plone into the future. Speaking of which, how does the future of Plone look like in 2007? Web development is now in a state we could only have dreamt about five years ago—and the rise of numerous great Python web frameworks, and even non-Python solutions like Ruby on Rails has made it possible for the Plone community to focus on what it excels at: content and document management, multilingual content, and solving real problems for real companies—and having fun in the process. Before these frameworks existed, people would often try to do things with Plone that it was not built or designed to do—and we are very happy that solutions now exist that cater to these audiences, so we can focus on our core expertise. Choice is good, and you should use the right tool for the job at hand. We are lucky to have Martin, and so are you. Enjoy the book, and I look forward to seeing you in our help forums, chat rooms, or at one of the many Plone conferences and workshops around the world. — Alexander Limi, Barcelona, July 2007 http://limi.net Alexander Limi co-founded the Plone project with Alan Runyan, and continues to play a key role in the Plone community. He is Plone's main user interface developer, and currently works as a user interaction designer at Google in California.
Read more
  • 0
  • 0
  • 5525
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-resource-oriented-clients-rest-principles
Packt
22 Oct 2009
8 min read
Save for later

Resource-Oriented Clients with REST Principles

Packt
22 Oct 2009
8 min read
Designing Clients While designing the library service, the ultimate outcome was the mapping of business operations to URIs and HTTP verbs. The client design is governed by this mapping. Prior to service design, the problem statement was analyzed. For consuming the service and invoking the business operations of the service using clients, there needs to be some understanding of how the service intends to solve the problem. In other words, the service, by design, has already solved the problem. However, the semantics of the solution provided by the service needs to be understood by the developers implementing the clients. The semantics of the service is usually documented in terms of business operations and the relationships between those operations. And sometimes, the semantics are obvious. As an example, in the library system, a member returning a book must have already borrowed that book. Theborrow book operation precedes the return book operation. Client design must take these semantics into account. Resource Design Following is the URI and HTTP verb mapping for business operations of the library system: URI HTTP Method Collection Operation Business Operation /book GET books retrieve Get books /book POST books create Add book(s) /book/{book_id} GET books retrieve Get book data /member GET members retrieve Get members /member POST members create Add member(s) /member/{member_id} GET members retrieve Get member data /member/{member_id}/books GET members retrieve Get member borrowings /member/{member_id}/books/{book_id} POST members create Borrow book /member/{member_id}/books/{book_id} DELETE members delete Return book   When it comes to client design, the resource design is given, and is an input to the client design. When it comes to implementing clients, we have to adhere to the design given to us by the service designer. In this example, we designed the API given in the above table, so we are already familiar with the API. Sometimes, you may have to use an API designed by someone else, hence you would have to ensure that you have access to information such as: Resource URI formats HTTP methods involved with each resource URI The resource collection that is associated with the URI The nature of the operation to be executed combining the URI and the HTTP verb The business operation that maps the resource operation to the real world context Looking into the above resource design table, we can identify two resources, book and member. And we could understand some of the semantics associated with the business operations of the resources. Create, retrieve books Create, retrieve members Borrow book, list borrowed books and return book Book ID and member ID could be used to invoke operations specific to a particular book or member instance System Implementation In this section, we will use the techniques on client programming to consume the library service. These techniques include: Building requests using XML Sending requests with correct HTTP verbs using an HTTP client library like CURL Receiving XML responses and processing the received responses to extract information that we require from the response Retrieving Resource Information Here is the PHP source code to retrieve book information. <?php$url = 'http://localhost/rest/04/library/book.php';$client = curl_init($url);curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);$response = curl_exec($client);curl_close($client);$xml = simplexml_load_string($response);foreach ($xml->book as $book) { echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";}?> The output generated is shown below As per the service design, all that is required is to send a GET request to the URL of the book resource. And as per the service semantics, we are expecting the response to be something similar to: <books> <book> <id>1</id> <name>Book1</name> <author>Auth1</author> <isbn>ISBN0001</isbn> </book> <book> <id>2</id> <name>Book2</name> <author>Auth2</author> <isbn>ISBN0002</isbn> </book></books> So in the client, we convert the response to an XML tree. $xml = simplexml_load_string($response); And generate the output that we desire from the client. In this case we print all the books. foreach ($xml->book as $book) { echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";} The output is: 1, Book1, Auth1, ISBN0001 2, Book2, Auth2, ISBN0002 Similarly, we could retrieve all the members with the following PHP script. <?php$url = 'http://localhost/rest/04/library/member.php';$client = curl_init($url);curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);$response = curl_exec($client);curl_close($client);$xml = simplexml_load_string($response);foreach ($xml->member as $member) { echo "$member->id, $member->first_name, $member->last_name <br/>n";}?> Next, retrieving books borrowed by a member. <?php$url = 'http://localhost/rest/04/library/member.php/1/books';$client = curl_init($url);curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);$response = curl_exec($client);curl_close($client);$xml = simplexml_load_string($response);foreach ($xml->book as $book) { echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";}?> Here we are retrieving the books borrowed by member with ID 1. Only the URL differs, the rest of the logic is the same. Creating Resources Books, members, and borrowings could be created using POST operations, as per the service design. The following PHP script creates new book. <?php$url = 'http://localhost/rest/04/library/book.php';$data = <<<XML<books> <book><name>Book3</name><author>Auth3</author><isbn>ISBN0003</isbn></book> <book><name>Book4</name><author>Auth4</author><isbn>ISBN0004</isbn></book></books>XML;$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);$response = curl_exec($ch);curl_close($ch);echo $response;?> When data is sent with POST verb to the URI of the book resource, the posted data would be used to create resource instances. Note that, in order to figure out the format of the XML message to be used, you have to look into the service operation documentation. This is where the knowledge on service semantics comes into play. Next is the PHP script to create members. <?php$url = 'http://localhost/rest/04/library/member.php';$data = <<<XML<members><member><first_name>Sam</first_name><last_name>Noel</last_name></member></members>XML;$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);$response = curl_exec($ch);curl_close($ch);echo $response;?> This script is very similar to the script that creates books. Only differences are the endpoint address and the XML payload used. The endpoint address refers to the location where the service is located. In the above script the endpoint address of the service is: $url = 'http://localhost/rest/04/library/member.php'; Next, borrowing a book can be done by posting to the member URI with the ID of the member borrowing the book, and the ID of the book being borrowed. <?php$url = 'http://localhost/rest/04/library/member.php/1/books/2';$data = <<<XMLXML;$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);$response = curl_exec($ch);curl_close($ch);echo $response;?> Note that, in the above sample, we are not posting any data to the URI. Hence the XML payload is empty: $data = <<<XMLXML; As per the REST architectural principles, we just send a POST request with all resource information on the URI itself. In this example, member with ID 1 is borrowing the book with ID 2. $url = 'http://localhost/rest/04/library/member.php/1/books/2'; One of the things to be noted in the client scripts is that we have used hard coded URLs and parameter values. When you are using these scripts with an application that uses a Web-based user interface, those hard coded values need to be parameterized. And we send a POST request to this URL: curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data); Note that, even though the XML payload that we are sending to the service is empty, we still have to set the CURLOPT_POSTFIELDS option for CURL. This is because we have set CURLOPT_POST to true and the CRUL library mandates setting POST field option even when it is empty. This script would cause a book borrowing to be created on the server side. When the member.php script receives a request with the from /{member_id}/books/{book_id} with HTTP verb POST, it maps the request to borrow book business operation. So, the URL $url = 'http://localhost/rest/04/library/member.php/1/books/2'; means that member with ID 1 is borrowing the book with ID 2.
Read more
  • 0
  • 0
  • 3580

article-image-using-asterisk-pstn-gateway-openser
Packt
22 Oct 2009
4 min read
Save for later

Using Asterisk as a PSTN Gateway for OpenSER

Packt
22 Oct 2009
4 min read
Using Asterisk as a PSTN Gateway Step 1: Add the gateway address in the trusted table using SerMyAdmin: If desired or convenient, you can instead use the MySQL command line interface to achieve the same result. #mysql –u openser –p-- enter your mysql password --mysql> use openser;mysql> INSERT INTO trusted ( src_ip, proto, from_pattern )VALUES ( '10.1.30.22', 'any', '^sip:.*$'); The records above tell the OpenSER script to allow requests coming from the IP address 10.1.30.22 with any transport protocol, matching the regular expression ^sip:.*$. You can use the following command if you don't want to reload OpenSER. #openserctl fifo trusted_reload Step 2: Include your served domains in the domain table (if you have not done before). openserctl domain add sermyadmin.org You can also use SerMyAdmin to do this. Step 3: Include the user into the groups (local, ld, and int): #openserctl acl grant 1000@sermyadmin.org local#openserctl acl grant 1000@sermyadmin.org ld#openserctl acl grant 1000@sermyadmin.org int#openserctl acl grant 1001@sermyadmin.org local To use SerMyAdmin, just go to the screen below: Step 4: Configuring Asterisk as a gateway. Two very popular gateways for OpenSER are Asterisk and Cisco AS5300. Gateways from other manufacturers can be used too; check their documentation for instructions. Let's see how to configure a Cisco 2601 with two FXO interfaces and an Asterisk with an E1 PSTN card. WarningIt is important to prevent the direct sending of SIP packets to gateways. The SIP proxy should be in front of the gateway and a firewall should prevent users from sending SIP requests directly to the gateway. Step 5: Setting up the Asterisk Server or the Cisco Gateway. We will assume that the PSTN side of the Asterisk gateway is already configured. Now let's change the SIP configuration (sip.conf) of our gateway and its dial plan (extensions.conf). We will configure Asterisk to send to the proxy each call coming from the PSTN and vice versa. We are using the guest feature of the SIP channel on the Asterisk Server. Prior knowledge of Asterisk is required here. Below is the simplest configuration allowing Asterisk to communicate with OpenSER. Please, adapt this script to your topology. WarningAllow SIP packets to your asterisk server, coming only from your SIP server. Do not allow SIP packets coming from other destinations. You can use IP Tables to do this, consult a Linux security specialist, if you arein doubt. Asterisk Gateway (sip.conf) [general]context=sipincoming#calls incoming from the SIP proxy to be terminated in the PSTN lines[sipproxy]#calls incoming from the PSTN to be forwarded to clients behind the SIP#proxytype=peerhost=10.1.30.22Asterisk (extensions.conf)[general][globals][sipincoming]exten=>_[0-9].,1,Dial(Zap/g1/${EXTEN:1})exten=>_[0-9].,2,hangup()[sipoutgoing]# If you have a digital interface use the lines belowexten=_[0-9].,1,Answer()exten=_[0-9].,2,dial(SIP/${EXTEN}@sipproxy)exten=_[0-9].,3,Hangup()#If you have analog FXO interfaces use the lines below.exten=s,1,Answer()exten=s,2,dial(SIP/${EXTEN}@sipproxy)exten=s,3,Hangup() Cisco 2601 Gateway The following explanation could help, but prior knowledge of Cisco gateways is required to complete this configuration. The call routing on Cisco gateways is done by the instruction dial peer. Any call with the number called starting with 9 followed by any number (9T) is forwarded to the PSTN on the ports 1/0 or 1/1 as instructed by the dial peer voice 1 and 2 POTS lines (plain old telephone system). Called numbers starting from 1 to 9 with any number of digits following will be directed to the SIP proxy in the IP address 10.1.3.22 as instructed in the 'dial-peer voice 123 voip' line. voice class codec 1codec preference 2 g711ulaw!interface Ethernet0/0ip address 10.1.30.38 255.255.0.0half-duplex!ip classlessip route 0.0.0.0 0.0.0.0 10.1.0.1no ip http serverip pim bidir-enable!voice-port 1/0!voice-port 1/1!mgcp profile default!! The dial-peer pots commands will handle the calls coming from SIP !dial-peers. Any call matching 9 followed by any number of digits will be !forwarded to the PSTN with the 9 striped.dial-peer voice 1 potsdestination-pattern 9Tport 1/0!dial-peer voice 2 potsdestination-pattern 9T port1/1!!The dial-peer voip commands will handle the calls coming from the pots !dial peers (PSTN). You can prefix a number (80 in this example) and send the DID number ahead.!dial-peer voice 123 voip destination-pattern ....T prefix80 forward all session protocol sipv2 session target ipv4:10.1.30.22 dtmf-relay sip-notify Step 6: Test the configuration making and receiving calls. Summary In this article, we have seen how to configure and use the Cisco 2601 gateway and the Asterisk gateway for OpenSER to send calls to the PSTN.
Read more
  • 0
  • 0
  • 5230

article-image-testing-help-system-java-application
Packt
22 Oct 2009
6 min read
Save for later

Testing a HELP System in a Java Application

Packt
22 Oct 2009
6 min read
Introduction {literal}As more and more features get added to your software, the Help system for the software becomes extensive. It could probably contains hundreds of HTML files plus a similar number of images. We could always face the problems listed below. There could be broken links in the help index. Some files may not be listed in the index, therefore they can not be read by the customers. Some of the contextual help buttons could show the wrong topic. Some of the HTML files can contain broken links or incorrect image tags. Not all of the file titles would match their index entry. Another problem could occur when the user does a free text search of the help system. The result of such a search is a list of files, each represented by its title. In our system,  documents could have the title "untitled". In fact, the JavaHelp 2.0 System User's Guide contains the recommendation "To avoid confusion, ensure that the <TITLE> tag corresponds to the title used in the table of contents." Given that customers mostly use the Help system when they are already frustrated by our software, we should always see to it that such errors do not exist in our help system. To do this, we will write a tool, HelpGenerator, that generates some of the boilerplate XML in the help system and checks the HTML and index files for the problems listed above. We will also build tools for displaying and testing the contextual help. We've re-engineered and improved these tools and present them in this article. In this article we are assuming familiarity with the JavaHelp system. Documentation and sample code for JavaHelp can be found at: http://java.sun.com/products/javahelp. Overview A JavaHelp package consists of: A collection of HTML and image files containing the specific Help information to be displayed. A file defining the index of the Help topics. Each index item in the file consists of the text of the index entry and a string representing the target of the HTML file to be displayed for that index entry, for example: <index version="1.0"> <indexitem text="This is an example topic."target="Topic"> <indexitem text="This is an sub-topic."target="SubTopic"/> </indexitem></index> A file associating each target with its corresponding HTML file (or more generally, a URL)—the map file. Each map entry consists of the target name and the URL it is mapped to, for example: <map version="1.0"> <mapID target="Topic" url="Topic.html"/> <mapID target="SubTopic" url="SubTopic.html"/></map> A HelpSet file (by default HelpSet.hs) which specifies the names of the index and map files and the folder containing the search database. Our software will normally have a main menu item to activate the Help and, in addition, buttons or menu items on specific dialogs to activate a Help page for a particular topic, that is, "context-sensitive" Help. What Tests Do We Need?? At an overall structural level, we need to check: For each target referred to in the index file, is there a corresponding entry in the map file? In the previous example, the index file refers to targets called Topic and SubTopic. Are there entries for these targets in the map file? For each URL referred to in the map file, is that URL reachable? In the example above, do the files Topic.html and SubTopic.html exist? Are there HTML files in our help package which are never referred to? If a Help button or menu item on some dialog or window is activated, does the Help facility show the expected topic? If the Help search facility has been activated, do the expected search results show? That is, has the search database been built on the latest versions of our Help pages? At a lower level, we need to check the contents of each of the HTML files: Do the image tags in the files really point to images in our help system? Are there any broken links? Finally, we need to check that the contents of the files and the indexes are consistent Does the title of each help page match its index? To simplify these tests, we will follow a simple naming pattern as follows: We adopt the convention that the name of each HTML file should be in CamelCase format (conventional Java class name format) plus the .html extension. Also, we use this name, without the extension, as the target name. For example, the target named SubTopic will correspond to the file SubTopic.html. Furthermore, we assume that there is a single Java package containing all the required help files, namely, the HTML files, the image files, the index file, and the map file. Finally, we assume a fixed location for the Help search database. With this convention, we can now write a program that: Generates the list of available targets from the names of the HTML files. Checks that this list is consistent with the targets referred to in the index file. Checks that the index file is well-formed in that: It is a valid XML document. It has no blank index entries. It has no duplicate index entries. Each index entry refers to a unique target. Generates the map file, thereby guaranteeing that it will be consistent with the index file and the HTML files. The class HelpGenerator in the package jet.testtools.help does all this,and, if there are no inconsistencies found, it generates the map file. If an inconsistency or other error is found, an assertion will be raised. HelpGenerator also performs the consistency checks at the level of individual HTML files. Let's look at some examples. An HTML File That is Not Indexed Here is a simple help system with just three HTML files: The index file, HelpIndex.xml, only lists two of the HTML files: <index version="1.0"> <indexitem text="This is an example topic." target="ExampleTopic"> <indexitem text="This is an example sub-topic." target="ExampleSubTopic"/> </indexitem></index> When we run HelpGenerator over this system (we'll see how to do this later in this article), we get an assertion with the error messageThe Help file: TopicWithoutTarget.html was not referenced in the Index file: HelpIndex.xml.
Read more
  • 0
  • 0
  • 2795

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-enterprise-javabeans
Packt
22 Oct 2009
10 min read
Save for later

Enterprise JavaBeans

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

article-image-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-modeling-orchestration-and-choreography-service-oriented-architecture
Packt
22 Oct 2009
30 min read
Save for later

Modeling Orchestration and Choreography in Service Oriented Architecture

Packt
22 Oct 2009
30 min read
  Choreography versus Orchestration Choreography and orchestration, in an SOA context, pertain to the use of processes that span multiple participants, with message traffic moving in all directions according to a complex set of rules. Choreography and orchestration are attempts to coordinate or control all of this activity. They attack the problem by putting rigor on how message exchanges are represented, and by organizing the overall process using the right set of control flow patterns. Use cases in this area can be inter-organizational (for example, B2B commerce involving buyer, seller, and wholesaler), or intra-organizational if the organization is large enough and the participants act as separate organizations (for example, bank account processes spanning the front office, the back office, and the fraud department). By convention, choreography describes the global protocol governing how individual participants interact with one another. Each participant has its own process, but choreography is a master process that acts as a kind of traffic cop. Significantly, the choreography process does not actually run. It is not a central broker in the live message exchange, but merely a message exchange protocol. If the participants follow the protocol, the live exchange will run as smoothly as if there were a central broker. 'Traffic cop' is not exactly right then; choreography is more like a set of traffic rules. To mix metaphors, choreography teaches the participant processes how to dance as a group. The process for each participant is referred to as an orchestration process, whose principal job is to build a flow of control around (that is, to orchestrate) its interactions with partners. Orchestration processes are difficult to model, especially those faced with complex combinations of inbound events. If the process is subject to choreography, its structure can be derived from the choreography; in fact, as we'll see, there are tools that can generate skeletal orchestration processes from choreography definitions. The idea is simple: the choreography tells the complete story, so the participant can determine its role by isolating the parts in which it's involved. Not all orchestrations, alas, have a choreography to guide them (not all inter-organizational domains have a precise protocol defined). If the use case is sufficiently complex, the participant ought to create its own choreography anyway, not to share with its partners but simply to improve its own understanding of its orchestration. An orchestration process has public and private activities. The public activities are those that are required by the choreography. Private activities are there to meet internal requirements, but are not visible to partners. The next figure shows the public activities of the orchestration process for an energy retailer. The steps shown (for example, Send Request to Distributor) are those required by the enrollment choreography, in which the retailer is but one participant. The next figure shows the same process with private steps (for example, Update Account) included. In the figure, steps marked with a P are public steps. We examine the energy example in detail in this article. Web Services Choreography Description Language (WS-CDL) is the leading choreography language; Business Process Execution Language (BPEL) is the dominant process orchestration language. Although these XML-based languages feature a similar flow-oriented design style, only BPEL is meant to have an actual runtime platform: BPEL processes run; WS-CDL choreographies are protocols. BPEL is better known than WS-CDL in part because orchestration is more prevalent than choreography. BPEL's user community is much larger than WS-CDL's. Today, every company is building an SOA platform, and if they don't use BPEL as their SOA orchestration language, they use something similar. The user community for choreography consists of industry committees that publish protocols such as the enrollment and funds transfer choreographies we discuss in this article. Choreography might also work as part of a large organization's enterprise architecture, helping to sort out the communication of the organization's numerous systems. Few of these committees use WS-CDL to document their protocols anyway. Choreography is more often documented less formally using English descriptions, flowchart diagrams, and an XML message schema. Examples-Energy Enrollment and Email Bank Transfer The two examples from industry that showcase our technique for modeling choreography and orchestration are the enrollment of customers with retailers in a deregulated energy market and the procedure for transferring funds by email between two banks. In the energy market for a state or small country there are three parties: customers (who use electricity to power their homes), retailers (who sell electricity to customers), and the distributor (who supplies the electricity). Before deregulation, the distributor sold electricity directly to customers; there were no retailers back then. Deregulation introduced competition and broke up the distributor's monopoly. Customers can now buy electricity from one of many competing retailers. The distributor is now merely a supplier, having moved out of the retail sales business. When a customer enrolls with a retailer, the retailer uses the following protocol to complete the enrollment: The retailer submits the customer's request for enrollment to the distributor. The distributor responds in one of the three ways. If there is a problem with the request (for example, the customer has another enrollment in progress, or the customer has been flagged for fraud), the distributor sends a rejection to the retailer. If the request is valid and the customer is not currently enrolled with a retailer, the distributor sends an acceptance to the retailer. If the customer is currently enrolled with a competing retailer but intends to switch, the distributor sends a notice of pending switch to both the retailers. In the acceptance case, there is a 10-day waiting period during which the customer may cancel the enrollment. To cancel, the customer contacts the retailer, who forwards the cancellation request to the distributor. Assuming the customer does not cancel, at the end of the waiting period, the distributor sends a completion event to the retailer. The customer is now enrolled with the retailer. In the switch case, there is also a 10-day waiting period. To cancel, the customer contacts the initiating retailer (that is, the retailer to whom the customer is switching). The initiating retailer forwards the cancellation to the distributor, who then sends completion events to both retailers indicating that the customer will remain enrolled with the original retailer. Assuming the customer does not cancel, at the end of the waiting period, the distributor sends completion events to both retailers indicating that the customer is now enrolled with the initiating retailer. Email bank transfer is a protocol for wiring money by email. It works as follows: The person sending the money contacts his bank (the Sender bank), specifying from which account to draw the funds, how much money to send, and the name and email address of the recipient. The Sender bank sets aside the amount and sends an email to the recipient with instructions on how to complete the transfer. The Sender bank sets aside the amount and sends an email to the recipient with instructions on how to complete the transfer. The Recipient bank submits the transfer request to the Sender bank. The Sender bank accepts, and the funds are moved into the recipient's account, completing the transfer. At any point, either the sender or recipient may cancel the transfer, and the transaction is automatically canceled if not completed within 30 days. On cancellation, the funds are returned to the sender's account. (We assume both banks are members of the email transfer programme.) The following figure shows the most common scenarios in these examples: Modeling Choreography in BPMN In BPMN, two possible models for choreography are as follows: Invisible hub: Although choreography is fundamentally decentralized, we imagine there is a central hub through which all messages pass, and model the choreography as the process of that hub. Sum of parts: The public process of each participant (that is, the process containing steps required by the choreography, with private steps omitted) is drawn in a swim lane. Message flow (dashed lines) is used to show inter-participant communication. A sum-of-parts model for the enrollment choreography is shown in next figure. There are three swim lanes in the diagram: one for the distributor (referred to as Distributor), one for the initiating retailer (referred to as Retailer), and one for the current retailer (referred to as CurrentRetailer). Each lane contains the public process of the participant. The dashed arrows show the flow of messages between participants. The enrollment choreography is, according to this approach, the combination of the public processes of each participant plus the message flow that connects them. The choreography begins when the customer enrolls with the retailer (Cust Enrolls in the Retailer lane). The retailer then submits the enrollment request to the distributor by calling Dist.enroll. This call sends a message to the distributor, which triggers the event Enroll (the first step in the Distributor lane). The Distributor process is now underway, and it responds to the enrollment request either by rejecting the request, accepting it, or notifying the initiating retailer and the current retailer of a pending switch. The distributor rejects by calling Ret.reject, and, as the dashed line signifies, triggers the event Dist.reject in the retailer. The remaining steps are straightforward. The sum-of-parts method is intuitive, and variations on it can be found in business process literature (in the WSCI and BPMN specifications, for example). Sum-of-parts, however, has two disadvantages. First, the message flow creates an indecipherable clutter, making complex choreographies almost impossible to read; the swim lanes, for their part, use a lot of real estate. Aesthetics aside, sum-of-parts fails to present a global, consolidated view of the choreography. We grow bug-eyed trying to keep track of what each participant is doing. We are forced to watch each dancer rather than the group as a whole. The invisible-hub representation is comparatively compact. The next figure, which shows the enrollment choreography as a hub, has fewer steps than the sum-of-parts equivalent, and it makes do without lanes or dashed lines. The hub works as you would expect a hub to work: it listens for inbound events and routes them to their intended recipients. The act of receiving an event and sending it elsewhere is a single unit of work (shown in the figure as a rounded box with a dashed line), known as an interaction. The hub choreography represents the communication of its participants as a process of interactions. Before walking through this process, consider the following notational conventions: The event with a thin border (Ret.enroll(Dist)) is the process' start event. Events with a double-line border (for example, Dist.reject(Ret)) are intermediate events, which occur over the course of the process. Intermediate events can be used in three ways: for cancellation, for deferred choice, or simply to wait for the next message before continuing. The enrollment hub has examples of the latter two forms. We'll come back to cancellation while discussing the email transfer hub. Deferred choice, also known as an event pick, uses a diamond containing an inscribed star (known as an event-based gateway) with arrows leading to a set of intermediate events. The intent is to wait for one of those events to occur, execute its activities, and discard the remaining events. There are three deferred choices in the enrollment hub. The first occurs in three steps, and selects one of the three events: Dis.reject(Ret), Dist.accept(ret), or Dist.pendingSwitch(Ret, CurrRet). If, say, Dist.reject(Ret) occurs first, the activity Ret1.reject(Dist) is executed. The intermediate event Dist.switchCompleteCurrent(Ret, CurrRet) simply waits for something to happen before continuing. This event is sandwiched between the activities Dist.cancel(Ret) and Ret.switchCompleteCurrent, CurrRet.switchCompleteCurrent(Dist). Thus, when the first activity completes, that branch of the process waits for the event to occur before continuing with the second activity. Events have labels of the form Sender.msg (Recipients), meaning that the event received by the hub is a message from the sender bound for the specified recipients. (There must be at least one.) Thus, Dist.switchCompleteCurrent(Ret, CurrRet) is the message switchCompleteCurrent from the distributor (Dist) to both the initiating retailer (Ret) and the current retailer (CurrRet). Send tasks (rounded boxes with a straight border) are labeled Recipient.msg(Sender), meaning that hub is sending the specified message to the recipient and is indicating that the message originated with the specified sender. In Dist.enroll(Ret), for instance, the hub sends the message enroll to the distributor (Dist), and is indicating to the distributor that this message came from the retailer (Ret). If the event that preceded it specifies multiple recipients, the send task sends the message to each recipient. Each send counts as one interaction.Ret.pendingSwitch, CurrRet.pendingSwitch (Dist), for example, sends the message pendingSwitch to both the retailer (Ret) and the current retailer (CurrRet), and thus spans two interactions. A rounded box with a dashed border, known in BPMN as a group, pairs up an event and a send task. Thus, the grouping of Ret.enroll(Dist) and Dist.enroll(Ret) means that when the hub receives the message enroll from the retailer bound for the distributor, it sends that message to the distributor, indicating to the distributor that the message originated with the retailer. A group that contains multiple interactions has a label in the top-center of the dashed box indicating the number of interactions. The number of interactions is equal to the number of recipients. The enrollment hub diagram reads as follows: The choreography begins with the interaction in which the retailer sends an enrollment request to the distributor. For convenience, this interaction is labeled a in the figure. Exactly one of the three interactions can happen next: the distributor sends a rejection to the retailer (b); the distributor sends an acceptance to the retailer (c); or the distributor sends a notice of pending switch to both the initiating and current retailers (d). Exactly one of the two interactions can follow acceptance: the retailer sends a cancellation to the distributor e, or the distributor sends a completion event to the retailer (f). In the pending switch case, one of the two interactions follows the notice of pending switch: the initiating retailer sends a cancellation to the distributor (g); or the distributor sends a switch completion event to both the initiating and current retailers indicating that the current retailer won (h). If the switch is cancelled, the distributor sends a switch completion event to both retailers indicating that the initiating retailer won (i). The choreography has 12 interactions assembled in a process flow. (There are nine groups, but three of them have two interactions each.) Reading the diagram means spotting the 12 interactions and traversing the control flow that connects them. The email transfer choreography hub, shown in the next figure, is somewhat more complex. The email transfer hub reads as follows: The choreography begins when the sender submits the transfer request to the sender bank (a). The sender bank can reject the request (b), or accept it (c). The acceptance event in c is routed to both the sender and the recipient, and thus results in two interactions. The remainder of the hub process is a loop that continues until the transfer is completed. The loop is modeled as a BPMN embedded sub-process labeled Loop. The arched arrow pointing counter-clockwise in the bottom-center of the sub-process box denotes that this sub-process is iterative. In the first step of the loop, the recipient requests her bank to transfer the funds into his or her account (d). The recipient's bank either rejects (e) or accepts (f) the request. In the rejection case, the recipient's bank sends a rejection notice to the recipient. In the next iteration of the loop, the recipient can try again. In the acceptance case, the recipient's bank sends a transfer request to the sender's bank. The sender's bank can either accept (g) or reject (h) the request. In the acceptance case, the sender's bank sends a transferOK message to both the recipient's bank and the sender. The recipient's bank then notifies the recipient (i), and the choreography completes. (The Set Done task sets the loop's continuation condition to false, which causes the loop to exit and the hub process to complete.) In the rejection case, the sender's bank sends a rejectTransfer message to the recipient's bank, and the recipient's bank notifies the recipient of this (j). In the next iteration of the loop, the recipient can try again. While the loop is executing, any of the parties may cancel the request (k). The label in the event *.cancel (SenderBank) informs the hub to listen for a cancel message from any party—the * works as a wildcard—and to route that message to the sender's bank. The sender's bank, in turn, sends an abort message (l) to the sender, the recipient, and the recipient's bank (the bank into which the recipient is currently requesting the transfer). Interaction (k) is an example of a cancellation intermediate event; it terminates the loop and transition into a series of cancellation activities. Choreographies are not executable, as we discussed previously. A choreography is a protocol, a set of traffic laws. It is, emphatically, not a central hub through which all participant interactions flow. Our hub model is merely a specification of how the individual participants should communicate. There are countless senders, recipients, and banks in the world of email transfer, but there is no hub that helps them talk to each other. The invisible hub for email transfer is merely a model; it is every bit as hypothetical as the invisible hand of Adam Smith's free-market economy. The economy is self-powered, and does not require the intervention of a hand; email transfer goes on without a hub. Still, the BPMN hub model is more than an informative picture. As we'll see, it maps easily to WS-CDL, and it serves as the basis for the generation of participant stubs and a choreography 'protocol' tester. Our BPMN method is practical and built with implementation in mind. Choreography modeling is also a hot topic in the academic world. Useful papers in this arena include Inheritance of Interorganizational Workflows: How to agree to disagree without loosing control? (Wil van der Aalst," BETA Working Paper Series, BP46, Eindhoven University, http://is.tm.tue.nl/staff/wvdaalst/publications/p109.pdf) and 'Let's Dance' (servicechoreographies.com, http://sky.fit.qut.edu.au/~dumas/LetsDance/01-Overview.html). The Invisible Hub in BPEL BPEL is principally an orchestration language, as just discussed, but it can also be used to model invisible hub choreographies. The code shown in the next figure is a simplified version of an actual BPEL implementation of the enrollment hub. The mapping from the BPMN hub to this BPEL implementation is straightforward: The event that starts the choreography in BPMN (Ret.enroll(Dist)) is receive that creates the BPEL process instance, marked as Start Event in the figure. An intermediate event that simply waits for a message between activities (for example, Dist.switchCompleteCurrent (Ret, CurrRet) in the BPMN model) is a BPEL receive, such as the line marked Intermediate Event in the figure. Deferred choice is a BPEL pick. The events in the choice are onMessage handlers. For example, the deferred choice in the BPMN model of Dist.reject(Ret), Dist.accept(Ret) and Dist.pendingSwitch(Ret, CurrRet) is the pick marked as Deferred Choice in the figure. The handlers are the three onMessage blocks that sit underneath the pick. Send tasks are BPEL invoke activities. For example, Dist.enroll(Ret) in the BPMN representation becomes the invoke in the line marked Send Task in the figure. The set of partner links used in the BPEL process is the union of all sender and recipient participants in the hub. Many partner links are bidirectional: they can either call the BPEL process or the BPEL process can call the partner link. The three partner links in this example, which are referred to in each receive, invoke, and onMessage tag are Ret, Dist, and CurrRet. BPEL supports dynamic partner links (where the BPEL process determines the physical address of its partner service at runtime). The series of four steps marked Dynamic partner links in the figure provides an example. The initial receive is a message from the distributor intended for one of the two retailers (either the current or the initiating retailer). The invoke that follows sends the message to that retailer. The endpoint of that retailer is resolved at runtime, based on the contents of the receive message. The next receive is a message from the distributor intended for the second retailer, and the invoke that follows sends the message to that retailer, again resolving the endpoint at runtime. In the majority of BPEL processes, partner links are resolved at deployment time, but that approach does not work in scenarios like ours. An interaction in which the sender sends to N recipients is modeled in BPEL as N separate inbound events and invokes. The series of four steps discussed in the previous bullet (and marked with Send to Multiple in the figure) provides an example. These steps model the activity Dist.switchCompleteCurrent (Ret, CurrRet) from the BPMN hub. In the BPEL code, the effect of the distributor sending the message switchCompleteCurrent to both the initiating and current retailers is achieved by having the hub receive the message from the distributor twice (using a receive), in each case forwarding the message (using an invoke) to one of the retailers. Dynamic partner links are used to resolve the endpoint of the recipient. The figure maps lines of code in the BPEL hub to interaction groups in the BPMN model. The first two lines, for example, represent group A. The reader can easily verify the mapping for groups B to I. There are two advantages to having the hub model in BPEL form: BPEL's XML form is an alternative to the leading XML choreography representation, WS-CDL (discussed in the next section). If we require an XML representation of choreography, BPEL might be a better choice than WS-CDL, because it is more familiar and has broader tool support. The BPEL hub is executable! There are numerous BPEL runtime platforms that can run this process as an actual hub. Granted, choreographies are not meant to run as part of the live exchange of actual participants, but having an executable version enables two important types of testing, shown in the next figure: unit testing of the choreography itself, and protocol testing of a particular participant. In unit testing, we build a Test Harness, driven by scripted scenarios, that sends messages to the hub and compares responses received with those expected. In protocol testing, we build the public process of a participant (say the retailer), but point it to the hub rather than its actual partners. We can embellish the hub to use test scripts to control how it responds. Once we have tested all of the scenarios and verified that the participant behaves as required, we can point the participant process to the real partners and go live Choreography in WS-CDL with Pi4SOA The description of choreography in WS-CDL with P14SOA is as follows: Defining Roles and Relationships Web Services Choreography Description Language (WS-CDL) is a specification from the W3C (Web Services Choreography Description Language Version 1.0, http://www.w3.org/TR/ws-cdl-10) for building choreographies in XML form. Like our invisible hub model, WS-CDL takes the global view: a choreography is not the sum of the public processes of its participants, but a single control flow of interactions. The WS-CDL language is exceedingly rich and best learned by example. In this section, we study how the enrollment choreography is represented in WS-CDL. Rather than building the choreography's XML from scratch, we use a visual modelling tool known as pi4SOA. pi4SOA, an open-source implementation that plugs into Eclipse, is one of the few WS-CDL implementations available today. The first step in building a WS-CDL choreography is to define participants and their structural relationships. The following figure shows the enrollment choreography open in the Participants, Roles, and Relationships tab of the pi4SOA editor.   There are five participants (shown with building icons) in the figure: Distributor, Retailer, CurrentRetailer, Customer (to model a customer's interaction with a retailer), and DistributorBizCal (a subsystem of the distributor to model the management of business calendars for completion and switch periods). Each participant has a role of the same name (designated by a stick-man icon), and each role has a behavior named for its role: Distributor's behavior is DistributorBehavior, Retailer's behaviour is RetailerBehavior, and so on. In WS-CDL, a behavior is a web service interface, and a role is a group of behaviors. A role can have multiple behaviors and a participant can have multiple roles. In our case, each participant has one role and one participant. The lines connecting roles are called relationships. There are four relationships: RD is the relationship between Retailer and Distributor, CRD the relationship between CurrentRetailer and Distributor, RC the relationship between Retailer and Customer, and DInt the relationship between Distributor and DistributorBizCal. When two roles have a relationship, they can interact by calling each other's services. The next figure shows the Base Types tab of the choreography editor. To the participants, roles, and relationships defined above, we add four important elements: information types, tokens, token locators, and channel types. An information type is an XML data type (generally based on an XML schema) exchanged during interactions. A token is a field in an information type. A token locator defines how to extract—generally using an XPath expression—the token from the information type. Our choreography has one information type, called EnergyMsg with five tokens and token locators (custID, retailer, txID, currentRetailer, and reason). A channel type is an inbound communication endpoint for a role behavior. In the enrollment choreography, there are channels for the retailer, current retailer and distributor. Each channel type is configured for one-way asynchronous requests only. Hence, Retailer receives requests on its RetailerChannel; CurrentRetailer receives requests on its CurrentRetailerChannel; and Distributor receives requests on its DistributorChannel. Combining our definitions of relationships and channels, we have the following communication structure: In the relationship RD, Retailer sends to Distributor on DistributorChannel, and Distributor sends to Retailer on RetailerChannel   In the relationship CRD, Distributor sends to CurrentRetailer on CurrentRetailerChannel. (CurrentRetailer could also send to Distributor on DistributorChannel, but the use case does not require it.) In the relationship RC, Customer sends to Retailer on RetailerChannel. (Customer does not have a channel, so the reverse direction is not permitted.) In the relationship DInt, DistributorBizCal sends to Distributor on DistributorChannel. (DistributorBizCal does not have a channel, so the reverse direction is not permitted.) Building a Control Flow of Interactions The next figure shows the overall control flow that defines the behaviour of the choreography. There are three steps. The first, RequestC2R, is an interaction in which the Customer participant sends an enrollment request to the Retailer participant. The request has the information type EnrollmentMsg, and is sent on RetailerChannel as part of the RC relationship. In the interaction that follows, RequestR2D, the retailer forwards that request to the distributor; or, in the language of WS-CDL, Retailer sends the request with information type EnrollmentMsg on the DistributorChannel as part of the RD relationship. The step that follows, enrollmentResult, is a flow construct known as a choice. There are three possible outcomes of an enrollment request—acceptance, rejection, or a pending switch. The choice allows exactly one to occur. The next figure shows the acceptance and rejection paths; the switch path is omitted for brevity. The rejection path (housed in a sequence labelled rejectEnrollment) has one interaction, RejectD2R, in which the distributor sends a rejection message to the retailer. The more complicated acceptance path is housed in the sequence labelled newEnrollment, which begins with the interaction in which the distributor notifies the retailer that the enrollment is accepted (AcceptD2R). Next is a silent action, setCompletionTimer, in which the distributor sets a timer that expires at the end of the ten-day cancellation period. A silent action in WS-CDL is a private operation performed by a role. The acceptance path has a nested choice, labelled completionPeriod, which documents the two possible outcomes for an accepted enrolment: periodExpired is a sequence that specifies what happens when the ten-day timer expires, and cancel handles the case in which the customer cancels the enrollment during the cancellation period. Each path contains two interactions. In the periodExpired sequence, the periodExpired interaction (sent from DistributorBizCal to Distributor by the DInt relationship) notifies the distributor that time is up, whereupon the distributor sends a completion event to the retailer (CompleteD2R). In the cancel sequence, the customer cancels with the retailer (CancelC2R by the RC relationship), and the retailer, in turn, cancels with the distributor (CancelR2D by the RD relationship). The following is a snippet of the WS-CDL XML encoding of the enrollment choreography, covering the acceptance case only. For the sake of simplicity, numerous details are omitted: <package name="EnergyChoreo">   <choreography name="main" root="true">     <sequence>       <!-- Cust sends request to retailer -->       <interaction channelVariable="tns:retailerChannel"                    name="RequestC2R" operation="enroll">         <participate fromRoleTypeRef="tns:Customer"                      relationshipType="tns:RC" toRoleTypeRef="tns:Retailer"/>       </interaction>       <!-- Retailer sends request to distributor -->       <interaction channelVariable="tns:distributorChannel"                    name="RequestR2D" operation="enroll">         <participate fromRoleTypeRef="tns:Retailer"                relationshipType="tns:RD" toRoleTypeRef= "tns:Distributor"/>       </interaction>       <!-- Choose what comes next -->       <choice>         <!-- Path taken if distributor rejects -->         <sequence>           <!-- This is the interaction that heads the reject path -->             <interaction name="RejectD2R" operation="reject">             </interaction>         </sequence>         <!-- Path taken if distributor accepts -->         <sequence>           <!-- This is the interaction that heads the accept path -->             <interaction name="AcceptD2R" operation="accept">             </interaction>             <silentAction name="setCompletionTimer"                           roleType="tns:Distributor">             <choice>               <!-- Accept subpaths omitted -->             </choice>          </sequence>          <!-- Omitted: switch path -->       </choice>     </sequence>   </choreography> </package> The two key elements in this example are choice and interaction. They are mapped to our hub model as follows: A receive-send pair in the hub is a WS-CDL interaction. In WS-CDL, a relationship is defined between sender and recipient, and the recipient has a channel on which the sender sends the message. An example of this is the interaction shown in bold from the customer (fromRoleTypeRef="tns: Customer") to the retailer (toRoleTypeRef="tns:Retailer") on the RC relationship (relationshipType="tns:RC"). The event arrives on the retailer's channel (channelVariable="tns:retailerChannel"). A deferred choice in the hub is a choice structure in WS-CDL. Generally, a path in the choice is a sequence. The set of events from which we are choosing is the set of first interactions on each path. The main choice structure in the choreography, shown in bold, has two interactions from which to choose: acceptance and rejection interactions (also shown in bold). The interaction that actually occurs determines which path is taken.   Generating a BPEL Role Process In addition to producing conformant WS-CDL code, pi4SOA's capabilities include scenario testing and BPEL and Java endpoint generation. The BPEL generation feature is especially useful, as BPEL is a suitable implementation choice to build orchestration process of a given participant. Here, in pseudo-code, is the BPEL process that pi4SOA generates for the distributor: <process>   <sequence>     <receive operation="enroll" partnerLink="RD"              portType="DistributorBehavior"/>       <!-- Dist receives interaction -->     <switch name="enrollmentResult"> <!-- Dist choice is switch -->       <case condition="accepted">         <sequence>           <invoke operation="accept" partnerLink="RD"                   portType="RetailerBehavior"/> <!-- Dist is sender -->           <scope name="setCompletionTimer"/>           <pick name="completionPeriod">             <onMessage operation="periodExpired" partnerLink="DInt"                        portType="DistributorBehavior">               <sequence>                 <invoke operation="complete" partnerLink="RD"                         portType="RetailerBehavior"/>               </sequence>             </onMessage>             <onMessage operation="cancel" partnerLink="RD"                        portType="DistributorBehavior"/>           </pick>         </sequence>       </case>       <case condition="rejected ">         <invoke operation="reject" partnerLink="RD"                 portType="RetailerBehavior"/>       </case>       <case condition="switch">         <!-- omitted -->       </case>   </switch> </sequence> </process> Two salient features of this process are the mapping of interactions and the conversion of the WS-CDL choice to a BPEL switch as follows: An interaction in which the distributor is the sender is a BPEL invoke activity whose partner link is the WS-CDL relationship and whose port type is the recipient's behavior. The operation element in the invoke matches the one specified in the interaction. The invoke shown in bold, for example, which is sent to the retailer, has partner link RD, port type RetailerBehavior, and operation accept. An interaction in which the participant is the recipient is either a receive activity or an onMessage handler in a pick. The partner link is the name of the relationship, and port type is the participant's behavior. The operation element, as before, matches that specified in the interaction. The bolded receive in the BPEL sample is the enroll operation on the partner link RD and port type DistributorBehavior. The WS-CDL choice is a switch for the BPEL distributor process (as the bolded comment in the switch line indicates), because the distributor begins each path of the choice by sending a message. From the distributor's perspective, the choice represents its decision to reject the request, accept it, or initiate a pending switch. Each case in the switch handles one of these possibilities. The retailer, on the other hand, begins each path by waiting for an event from the distributor. From the retailer's point of view, the choice is a pick, as in the following snippet: <pick name="enrollmentResult"> <!-- For Ret, choice is a pick -->   <onMessage operation="accept" partnerLink="RD"              portType="RetailerBehavior">     <!-- code omitted -->   </onMessage>   <onMessage operation="reject" partnerLink="RD"              portType="RetailerBehavior" />   <onMessage operation="pendingSwitch" partnerLink="RD"              portType="RetailerBehavior" >     <!-- code omitted -->   </onMessage> </pick> We have only scratched the surface of WS-CDL. Other notable capabilities are state alignment, coordination, and channel passing. WS-CDL's supporters boast that their language has its foundations in the Pi Calculus, a mathematical scheme for describing concurrent processes and how they pass messages to each other. Robin Milner, the mathematician who devised the Pi Calculus, is an advisor to the WS-CDL working group. Sadly, WS-CDL has not gained much traction in the field. There are scant tools to build WS-CDL choreographies and, frankly, not many use cases that require choreography. Few people who practice SOA technology have even heard of this language. WS-CDL is winning the mathematics battle but losing the marketing war. Summary Choreography is the global protocol governing the interaction of SOA processes partnering to achieve some business ends. An orchestration process is a process whose principal job is to build a flow of control around its interactions with partners. WS-CDL is the dominant choreography standard. BPEL is the dominant orchestration standard. Both standards provide a way to build process flows in an XML form, though only BPEL processes are meant to actually execute. The modeling tool pi4SOA is ideal for building WS-CDL examples. Key WS-CDL elements are interaction (which corresponds to the receive-send pair in the invisible hub) and choice (a kind of deferred choice in the choreography's flow of control. pi4SOA generates skeletal BPEL code for each participant in the choreography.
Read more
  • 0
  • 0
  • 7700
article-image-linq-objects
Packt
22 Oct 2009
10 min read
Save for later

LINQ to Objects

Packt
22 Oct 2009
10 min read
Without LINQ, we would have to go through the values one-by-one and then find the required details. However, using LINQ we can directly query collections and filter the required values without using any looping. LINQ provides powerful filtering, ordering, and grouping capabilities that requires minimum coding. For example, if we want to find out the types stored in an assembly and then filter the required details, we can use LINQ to query the assembly details using System.Reflection classes. The System.Reflection namespace contains types that retrieve information about assemblies, modules, members, parameters, and other entities as collections are managed code, by examining their metadata. Also, files under a directory are a collection of objects that can be queried using LINQ. We shall see some of the examples for querying some collections. Array of Integers The following example shows an integer array that contains a set of integers. We can apply the LINQ queries on the array to fetch the required values.     int[] integers = { 1, 6, 2, 27, 10, 33, 12, 8, 14, 5 };       IEnumerable<int> twoDigits =       from numbers in integers       where numbers >= 10       select numbers;       Console.WriteLine("Integers > 10:");       foreach (var number in twoDigits)       {          Console.WriteLine(number);       } The integers variable contains an array of integers with different values. The variable twoDigits, which is of type IEnumerable, holds the query. To get the actual result, the query has to be executed. The actual query execution happens when the query variable is iterated through the foreach loop by calling GetEnumerator() to enumerate the result. Any variable of type IEnumerable<T>, can be enumerated using the foreach construct. Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T>, are called queryable types. All collections such as list, dictionary and other classes are queryable. There are some non-generic IEnumerable collections like ArrayList that can also be queried using LINQ. For that, we have to explicitly declare the type of the range variable to the specific type of the objects in the collection, as it is explained in the examples later in this article. The twoDigits variable will hold the query to fetch the values that are greater than or equal to 10. This is used for fetching the numbers one-by-one from the array. The foreach loop will execute the query and then loop through the values retrieved from the integer array, and write it to the console. This is an easy way of getting the required values from the collection. If we want only the first four values from a collection, we can apply the Take() query operator on the collection object. Following is an example which takes the  first four integers from the collection. The four integers in the resultant collection are displayed using the foreach method.    IEnumerable<int> firstFourNumbers = integers.Take(4);   Console.WriteLine("First 4 numbers:");   foreach (var num in firstFourNumbers)   {      Console.WriteLine(num);   } The opposite of Take() operator is Skip() operator, which is used to skip the number of items in the collection and retrieve the rest. The following example skips the first four items in the list and retrieves the remaining.    IEnumerable<int> skipFirstFourNumbers = integers.Skip(4);   Console.WriteLine("Skip first 4 numbers:");   foreach (var num in skipFirstFourNumbers)   {      Console.WriteLine(num);   } This example shows the way to take or skip the specified number of items from the collection. So what if we want to skip or take the items until we find a match in the list? We have operators to get this. They are TakeWhile() and SkipWhile(). For example, the following code shows how to get the list of numbers from the integers collection until 50 is found. TakeWhile() uses an expression to include the elements in the collection as long as the condition is true and it ignores the other elements in the list. This expression represents the condition to test the elements in the collection for the match.    int[] integers = { 1, 9, 5, 3, 7, 2, 11, 23, 50, 41, 6, 8 };   IEnmerable<int> takeWhileNumber = integers.TakeWhile(num =>      num.CompareTo(50) != 0);   Console.WriteLine("Take while number equals 50");   foreach (int num in takeWhileNumber)      {         Console.WriteLine(num.ToString());      } Similarly, we can skip the items in the collection using SkipWhile(). It uses an expression to bypass the elements in the collection as long as the condition is true. This expression is used to evaluate the condition for each element in the list. The output of the expression is boolean. If the expression returns false, the remaining elements in the collections are returned and the expression will not be executed for the other elements. The first occurrence of the return value as false will stop the expression for the other elements and returns the remaining elements. These operators will provide better results if used against ordered lists as the expression is ignored for the other elements once the first match is found.    IEnumerable<int> skipWhileNumber = integers.SkipWhile(num =>      num.CompareTo(50) != 0);   Console.WriteLine("Skip while number equals 50");   foreach (int num in skipWhileNumber)   {      Console.WriteLine(num.ToString());   } Collection of Objects In this section we will see how we can query a custom built objects collection. Let us take the Icecream object, and build the collection, then we can query the collection. This Icecream class in the following code contains different properties such as Name, Ingredients, TotalFat, and Cholesterol.     public class Icecream    {        public string Name { get; set; }        public string Ingredients { get; set; }        public string TotalFat { get; set; }        public string Cholesterol { get; set; }        public string TotalCarbohydrates { get; set; }        public string Protein { get; set; }        public double Price { get; set; }     } Now build the Icecreams list collection using the class defined perviously.     List<Icecream> icecreamsList = new List<Icecream>        {            new Icecream {Name="Chocolate Fudge Icecream", Ingredients="cream,                milk, mono and diglycerides...", Cholesterol="50mg",                Protein="4g", TotalCarbohydrates="35g", TotalFat="20g",                Price=10.5        },        new Icecream {Name="Vanilla Icecream", Ingredients="vanilla extract,            guar gum, cream...", Cholesterol="65mg", Protein="4g",            TotalCarbohydrates="26g", TotalFat="16g", Price=9.80 },            new Icecream {Name="Banana Split Icecream", Ingredients="Banana, guar            gum, cream...", Cholesterol="58mg", Protein="6g",            TotalCarbohydrates="24g", TotalFat="13g", Price=7.5 }        }; We have icecreamsList collection which contains three objects with values of the Icecream type. Now let us say we have to retrieve all the ice-creams that cost less. We can use a looping method, where we have to look at the price value of each object in the list one-by-one and then retrieve the objects that have less value for the Price property. Using LINQ, we can avoid looping through all the objects and its properties to find the required ones. We can use LINQ queries to find this out easily. Following is a query that fetches the ice-creams with low prices from the collection. The query uses the where condition, to do this. This is similar to relational database queries. The query gets executed when the variable of type IEnumerable is enumerated when referred to in the foreach loop.     List<Icecream> Icecreams = CreateIcecreamsList();    IEnumerable<Icecream> IcecreamsWithLessPrice =    from ice in Icecreams    where ice.Price < 10    select ice;    Console.WriteLine("Ice Creams with price less than 10:");    foreach (Icecream ice in IcecreamsWithLessPrice)    {        Console.WriteLine("{0} is {1}", ice.Name, ice.Price);     } As we used List<Icecream> objects, we can also use ArrayList to hold the objects, and a LINQ query can be used to retrieve the specific objects from the collection according to our need. For example, following is the code to add the same Icecreams objects to the ArrayList, as we did in the previous example.     ArrayList arrListIcecreams = new ArrayList();    arrListIcecreams.Add( new Icecream {Name="Chocolate Fudge Icecream",        Ingredients="cream, milk, mono and diglycerides...",        Cholesterol="50mg", Protein="4g", TotalCarbohydrates="35g",        TotalFat="20g", Price=10.5 });    arrListIcecreams.Add( new Icecream {Name="Vanilla Icecream",        Ingredients="vanilla extract, guar gum, cream...",        Cholesterol="65mg", Protein="4g", TotalCarbohydrates="26g",        TotalFat="16g", Price=9.80 });    arrListIcecreams.Add( new Icecream {Name="Banana Split Icecream",        Ingredients="Banana, guar gum, cream...", Cholesterol="58mg",        Protein="6g", TotalCarbohydrates="24g", TotalFat="13g", Price=7.5    }); Following is the query to fetch low priced ice-creams from the list.     var queryIcecreanList = from Icecream icecream in arrListIcecreams    where icecream.Price < 10    select icecream; Use the foreach loop, shown as follows, to display the price of the objects retrieved using the above query.     foreach (Icecream ice in queryIcecreanList)    Console.WriteLine("Icecream Price : " + ice.Price);
Read more
  • 0
  • 0
  • 2159

article-image-functional-testing-jmeter
Packt
22 Oct 2009
5 min read
Save for later

Functional Testing with JMeter

Packt
22 Oct 2009
5 min read
JMeter is a 100% pure Java desktop application. JMeter is found to be very useful and convenient in support of functional testing. Although JMeter is known more as a performance testing tool, functional testing elements can be integrated within the Test Plan, which was originally designed to support load testing. Many other load-testing tools provide little or none of this feature, restricting themselves to performance-testing purposes. Besides integrating functional-testing elements along with load-testing elements in the Test Plan, you can also create a Test Plan that runs these exclusively. In other words, aside from creating a Load Test Plan, JMeter also allows you to create a Functional Test Plan. This flexibility is certainly resource-efficient for the testing project. In this article by Emily H. Halili, we will give you a walkthrough on how to create a Test Plan as we incorporate and/or configure JMeter elements to support functional testing. Preparing for Functional Testing JMeter does not have a built-in browser, unlike many functional-test tools. It tests on the protocol layer, not the client layer (i.e. JavaScripts, applets, and many more.) and it does not render the page for viewing. Although, by default that embedded resources can be downloaded, rendering these in the Listener | View Results Tree may not yield a 100% browser-like rendering. In fact, it may not be able to render large HTML files at all. This makes it difficult to test the GUI of an application under testing. However, to compensate for these shortcomings, JMeter allows the tester to create assertions based on the tags and text of the page as the HTML file is received by the client. With some knowledge of HTML tags, you can test and verify any elements as you would expect them in the browser. It is unnecessary to select a specific workload time to perform a functional test. In fact, the application you want to test may even reside locally, with your own machine acting as the "localhost" server for your web application. For this article, we will limit ourselves to selected functional aspects of the page that we seek to verify or assert. Using JMeter Components We will create a Test Plan in order to demonstrate how we can configure the Test Plan to include functional testing capabilities. The modified Test Plan will include these scenarios: 1. Create Account —New Visitor creating an Account 2. Login User —User logging in to an Account Following these scenarios, we will simulate various entries and form submission as a request to a page is made, while checking the correct page response to these user entries. We will add assertions to the samples following these scenarios to verify the 'correctness' of a requested page. In this manner, we can see if the pages responded correctly to invalid data. For example, we would like to check that the page responded with the correct warning message when a user enters an invalid password, or whether a request returns the correct page. First of all, we will create a series of test cases following the various user actions in each scenario. The test cases may be designed as follows: CREATE ACCOUNT Test Steps Data Expected 1 Go to Home page. www.packtpub.com Home page loads and renders with no page error 2 Click Your Account link (top right). User action 1. Your Account page loads and renders with no page error.2. Logout link is not found. 3 No Password: - Enter email address in Email text field.- Click the Create Account and Continue button. email=EMAIL 1. Your Account page resets with Warning message-Please enter password.2. Logout link not found. 4 Short Password: - Enter email address in Email text field.- Enter password in Password text field.- Enter password in Confirm Password text field. - Click Create Account and Continue button. email=EMAILpassword=SHORT_PWD confirm password=SHORT_PWD 1. Your Account page resets with Warning message-Your password must be 8 characters or longer.2. Logout link is not found. 5 Unconfirmed Password: - Enter email address in Email text field.- Enter password in Password text field.- Enter password in Confirm Password text field. - Click Create Account and Continue button. email=EMAILpassword=VALID_PWDconfirm password=INVALID_PWD 1. Your Account page resets with Warning messagePassword does not match.2. Logout link is not found. 6 Register Valid User: - Enter email address in Email text field.- Enter password in Password text field.- Enter password in Confirm Password text field. - Click Create Account and Continue button. email=EMAILpassword=VALID_PWDconfirm password=VALID_PWD 1. Logout link is found.2. Page redirects to User Account page.3. Message found: You are registered as: e:<EMAIL>. 7 Click Logout link. User action 1. Logout link is NOT found.     LOGIN USER Test Steps Data Expected 1 Click Home page. User action 1. WELCOME tab is active. 2 Log in Wrong Password: - Enter email in Email text field- Enter password at Password text field.- Click Login button. email=EMAILpassword=INVALID_PWD 1. Logout link is NOT found.2. Page refreshes.3. Warning message-Sorry your password was incorrect appears. 3 Log in Non-Exist Account:- Enter email in Email text field.- Enter password in Password text field.- Click Login button. email=INVALID_EMAILpassword=INVALID_PWD 1. Logout link is NOT found.2. Page refreshes.3. Warning message-Sorry, this does not match any existing accounts. Please check your details and try again or open a new account below appears. 4 Log in Valid Account:- Enter email in Email text field.- Enter password in Password text field.- Click Login-button. email=EMAILpassword=VALID_PWD 1. Logout link is found.2. Page reloads.3. Login successful message-You are logged in as: appears. 5 Click Logout link. User action 1. Logout link is NOT found.    
Read more
  • 0
  • 3
  • 12881
Modal Close icon
Modal Close icon