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-user-input-validation-tapestry-5
Packt
16 Oct 2009
9 min read
Save for later

User Input Validation in Tapestry 5

Packt
16 Oct 2009
9 min read
Adding Validation to Components The Start page of the web application Celebrity Collector has a login form that expects the user to enter some values into its two fields. But, what if the user didn't enter anything and still clicked on the Log In button? Currently, the application will decide that the credentials are wrong and the user will be redirected to the Registration page, and receive an invitation to register. This logic does make some sense; but, it isn't the best line of action, as the button might have been pressed by mistake. These two fields, User Name and Password, are actually mandatory, and if no value was entered into them, then it should be considered an error. All we need to do for this is to add a required validator to every field, as seen in the following code: <tr> <td> <t:label t_for="userName"> Label for the first text box</t:label>: </td> <td> <input type="text" t_id="userName" t_type="TextField" t:label="User Name" t_validate="required"/> </td></tr><tr> <td> <t:label t_for="password"> The second label</t:label>: </td><td> <input type="text" t_id="password" t_label="Password" t:type="PasswordField" t_validate="required"/></td></tr> Just one additional attribute for each component, and let's see how this works now. Run the application, leave both fields empty and click on the Log In button. Here is what you should see: Both fields, including their labels, are clearly marked now as an error. We even have some kind of graphical marker for the problematic fields. However, one thing is missing—a clear explanation of what exactly went wrong. To display such a message, one more component needs to be added to the page. Modify the page template, as done here: <t:form t_id="loginForm"> <t:errors/> <table> The Errors component is very simple, but one important thing to remember is that it should be placed inside of the Form component, which in turn, surrounds the validated components. Let's run the application again and try to submit an empty form. Now the result should look like this: This kind of feedback doesn't leave any space for doubt, does it? If you see that the error messages are strongly misplaced to the left, it means that an error in the default.css file that comes with Tapestry distribution still hasn't been fixed. To override the faulty style, define it in our application's styles.css file like this: DIV.t-error LI{ margin-left: 20px;} Do not forget to make the stylesheet available to the page. I hope you will agree that the efforts we had to make to get user input validated are close to zero. But let's see what Tapestry has done in response to them: Every form component has a ValidationTracker object associated with it. It is provided automatically, we do not need to care about it. Basically, ValidationTracker is the place where any validation problems, if they happen, are recorded. As soon as we use the t:validate attribute for a component in the form, Tapestry will assign to that component one or more validators, the number and type of them will depend on the value of the t:validate attribute (more about this later). As soon as a validator decides that the value entered associated with the component is not valid, it records an error in the ValidationTracker. Again, this happens automatically. If there are any errors recorded in ValidationTracker, Tapestry will redisplay the form, decorating the fields with erroneous input and their labels appropriately. If there is an Errors component in the form, it will automatically display error messages for all the errors in ValidationTracker. The error messages for standard validators are provided by Tapestry while the name of the component to be mentioned in the message is taken from its label. A lot of very useful functionality comes with the framework and works for us "out of the box", without any configuration or set-up! Tapestry comes with a set of validators that should be sufficient for most needs. Let's have a more detailed look at how to use them. Validators The following validators come with the current distribution of Tapestry 5: Required—checks if the value of the validated component is not null or an empty string. MinLength—checks if the string (the value of the validated component) is not shorter than the specified length. You will see how to pass the length parameter to this validator shortly. MaxLength—same as above, but checks if the string is not too long. Min—ensures that the numeric value of the validated component is not less than the specified value, passed to the validator as a parameter. Max—as above, but ensures that the value does not exceed the specified limit. Regexp—checks if the string value fits the specified pattern. We can use several validators for one component. Let's see how all this works together. First of all, let's add another component to the Registration page template: <tr> <td><t:label t_for="age"/>:</td> <td><input type="text" t_type="textfield" t_id="age"/></td></tr> Also, add the corresponding property to the Registration page class, age, of type double. It could be an int indeed, but I want to show that the Min and Max validators can work with fractional numbers too. Besides, someone might decide to enter their age as 23.4567. This will be weird, but not against the laws. Finally, add an Errors component to the form at the Registration page, so that we can see error messages: <t:form t_id="registrationForm"> <t:errors/> <table> Now we can test all the available validators on one page. Let's specify the validation rules first: Both User Name and Password are required. Also, they should not be shorter than three characters and not longer than eight characters. Age is required, and it should not be less than five (change this number if you've got a prodigy in your family) and not more than 120 (as that would probably be a mistake). Email address is not required, but if entered, should match a common pattern. Here are the changes to the Registration page template that will implement the specified validation rules: <td> <input type="text" t_type="textfield" t_id="userName" t:validate="required,minlength=3,maxlength=8"/></td>...<td> <input type="text" t_type="passwordfield" t_id="password" t:validate="required,minlength=3,maxlength=8"/></td>...<td> <input type="text" t_type="textfield" t_id="age" t:validate="required,min=5,max=120"/></td>...<input type="text" t_type="textfield" t_id="email" t:validate="regexp"/> As you see, it is very easy to pass a parameter to a validator, like min=5 or maxlength=8. But, where do we specify a pattern for the Regexp validator? The answer is, in the message catalog. Let's add the following line to the app.properties file: email-regexp=^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$ This will serve as a regular expression for all Regexp validators applied to components with ID email throughout the application. Run the application, go to the Registration page and, try to submit the empty form. Here is what you should see: Looks all right, but the message for the age could be more sensible, something like You are too young! You should be at least 5 years old. We'll deal with this later. However for now, enter a very long username, only two characters for password and an age that is more than the upper limit, and see how the messages will change: Again, looks good, except for the message about age. Next, enter some valid values for User Name, Password and Age. Then click on the check box to subscribe to the newsletter. In the text box for email, enter some invalid value and click on Submit. Here is the result: Yes! The validation worked properly, but the error message is absolutely unacceptable. Let's deal with this, but first make sure that any valid email address will pass the validation.   Providing Custom Error Messages We can provide custom messages for validators in the application's (or page's) message catalog. For such messages we use keys that are made of the validated component's ID, the name of validator and the "message" postfix. Here is an example of what we could add to the app.properties file to change error messages for the Min and Max validators of the Age component as well as the message used for the email validation: email-regexp-message=Email address is not valid.age-min-message=You are too young! You should be at least 5 years old.age-max-message=People do not live that long! Still better, instead of hard-coding the required minimal age into the message, we could insert into the message the parameter that was passed to the Min validator (following the rules for java.text.Format), like this: age-min-message=You are too young! You should be at least %s years old. If you run the application now and submit an invalid value for age, the error message will be much better: You might want to make sure that the other error messages have changed too. We can now successfully validate values entered into separate fields, but what if the validity of the input depends on how two or more different values relate to each other? For example, at the Registration page we want two versions of password to be the same, and if they are not, this should be considered as an invalid input and reported appropriately. Before dealing with this problem however, we need to look more thoroughly at different events generated by the Form component.  
Read more
  • 0
  • 0
  • 4197

article-image-maintaining-optimizing-and-upgrading-your-site-drupal-6-part-2
Packt
16 Oct 2009
9 min read
Save for later

Maintaining, Optimizing and Upgrading Your Site in Drupal 6: Part 2

Packt
16 Oct 2009
9 min read
Maintaining content As you continue to add content to your web site, you will need to ensure that your content is properly moderated, that old content is removed, and that changes to web site content are tracked. Creating content revisions Good Eatin' Goal: Create revisions of content to ensure that you have a complete record of changes to your web site's content. Additional modules needed: None. Basic steps We have simply updated our pages as necessary to add new functionality and content. However, if you have many editors, content that changes frequently, a need to view the history of a page, or need the ability to easily return to an old version of a page, you will want to store multiple revisions of your pages. To do this, carry out the following steps: Edit the content for which you want to create a new revision. Make the changes as needed and, before saving, expand the Revision information section. Select the Create new revision option and enter a message describing the changes that you have made to the node. When you save the content, you will see a new tab called Revisions. Clicking on this tab will show you a list of all of the revisions that have been created for the page. If you would like to return to an older version of the page, you can click the revert link. Or, if you want to remove an older revision, you can click the delete link to get rid of it permanently. You can control which users have access to the revision system by using the Permissions Manager. Drupal allows you to control which users can: view revisions, revert revisions, and delete revisions. If you want to force users to always create new revisions when editing content, edit the content type and then expand the Workflow settings. Change the default options to select the Create new revision option. When editors change content, the Create new revision option will be selected by default, and they will not be able to change the option unless they have the administer nodes permission. If you want to approve all revisions before publication, you can deselect the Published checkbox. Comparing content revisions Good Eatin' Goal: Compare the text of two different revisions of a page. Additional modules needed: Diff (http://drupal.org/project/diff). Basic steps Although the built-in functionality for creating revisions in Drupal works perfectly well, it can be difficult to review the changes that were made in each revision. The Diff module makes comparing revisions very easy. Begin by installing and activating the Diff module. To use the Diff module, simply view the revisions for any page. You will notice that the Revisions list has changed to allow you to select the revisions to be compared. Select the revisions to compare and then click on the Show diff button. Drupal will then display information about the text that has been changed, added, or deleted. Moderate content Good Eatin' Goal: Find questionable or offensive content, and remove it from your site, easily. Additional modules needed: Modr8 (http://drupal.org/project/modr8). Basic steps An unfortunate side effect of having a web site on the Internet is that, at some point, a malicious user will attempt to post inappropriate content on your site. If your site is extremely busy, you may find yourself with a large amount of content to review and approve. The Modr8 module can help you manage the workload and can send emails to users letting them know when their content has been approved or rejected. Begin by installing and activating the Modr8 module. The settings for the Modr8 module can be accessed by selecting Site configuration and then Modr8, from the Administer menu. The basic settings control how often logs are removed. Alternatively, you can choose to keep the logs forever. You can also change the number of items in the moderation queue to be displayed at a time, as well as the default action for the content that requires moderation. You can also configure the email settings for the moderation queue, including the text of the emails, and whether or not emails should be sent to the user who posted the content when their content is approved and/or when their content is rejected. You can also choose to send an email if the moderator does not take action for the item and wants to send a note to the author. If you would like new content to be added to the moderation queue automatically, you can edit the content type and select the In moderation queue setting in the workflow section. To view the moderation queue, select Content management and then Moderated content, from the Administer menu. The moderation queue appears as follows: From this page, you can approve, delete, or defer action on any content that needs moderation. After you make your changes, click Save to complete your selections. You can also display a log of all the moderation actions, by clicking on Reports and then Content moderation log. The moderation log appears as follows: Allowing users to report questionable or offensive content. Good Eatin' Goal: Get feedback from users to learn what they find offensive so the objectionable content can be removed. Additional modules needed: Abuse (http://drupal.org/project/abuse). Basic steps In the last task, we reviewed methods that allowed you to moderate every piece of content that is added to the site. However, this can be a time-intensive task if the proportion of content that you receive that is questionable is low. If this is the case, you can allow your users to help you to moderate the content by using the Abuse module, to let them report items that they find offensive. This strategy has a couple of advantages. Firstly, you are freed from the maintenance of pre-approving all content before it is published. Secondly, it ensures that the content meets community standards, rather than placing you or your editors in charge of defining community standards. The Abuse module also has a Watchlist component that allows you to flag content as suspicious or banned, and automatically move them into a queue for review by an administrator. Begin by downloading and installing the Abuse and Watchlist modules, both of which are included in the Abuse installation. We will begin by editing the Watchlist settings, which can be accessed by selecting Site configuration and then Watchlist settings, from the Administer menu. You can include any words that you want to, in the Watch list and Filtered/banned word list, depending on your target audience and your site's needs; just make sure that you enter one word per line. Items on the Watch list can be viewed while they are in the review queue, and items on the Filtered/banned word list will be hidden until they are reviewed. You can also control which items are automatically added to the Watch list or banned list, based on the Watchlist word settings configured above. You can also force moderation for specific types if they are more prone to abuse. We can now modify the Abuse Moderation settings by selecting Site configuration and then Abuse Moderation settings, from the Administer menu. The first setting controls what content types are subject to abuse reports. The next section of controls how abuse tickets are to be handled by your moderators. If you have multiple moderators for your site, you can select the Abuse Assigned Moderators option. If you use this, you will also need to store the maximum number of items that have been flagged for abuse that are added to the moderator's queue. If moderators live in different time zones, you can set an hour of the day at which all moderation queues are cleared, so that items do not remain in the moderation queue for an overly-long period of time. Finally, you can configure the settings related to all of the items that have been flagged as abusive by a user. The Abuse threshold controls how many complaints must be registered for an item before it is moved into the moderation queue. 3 is a good number to start with, but you may want to increase or decrease the threshold depending on the needs of your site. You can edit the reasons for flagging an item for abuse by selecting Site configuration, then Abuse Moderation settings, and finally Abuse Moderation reasons, from the Administer menu. All available reasons will be listed on the page using a format similar to the example above. You can add new reasons, remove reasons, or change the text for reasons from this page. Before the abuse module is activated, you need to assign permissions to users, so that they can flag content for review. Content that has the abuse module activated will have a new Flag as offensive link added to it, as shown in the following screenshot: When the user clicks on the Flag as offensive link, he or she will be presented with a form where he or she can specify their contact information, and a reason why he or she believes that the content is offensive. Administrators can review content that has been flagged as offensive by clicking on Content management and then Moderate. The administrators can click on the Get More Tickets link to have additional items assigned to them. Once a ticket has been assigned to them, the administrator can view information about the user who submitted the content as well as the user who flagged the content, and choose what action to take for the content. The administrator can either allow the content, or remove the content from the web site. The administrator can also optionally send a warning to the user without further action.
Read more
  • 0
  • 0
  • 1795

article-image-feeds-facebook-applications
Packt
16 Oct 2009
7 min read
Save for later

Feeds in Facebook Applications

Packt
16 Oct 2009
7 min read
{literal} What Are Feeds? Feeds are the way to publish news in Facebook. As we have already mentioned before, there are two types of feeds in Facebook, News feed and Mini feed. News feed instantly tracks activities of a user's online friends, ranging from changes in relationship status to added photos to wall comments. Mini feed appears on individuals' profiles and highlights recent social activity. You can see your news feed right after you log in, and point your browser to http://www.facebook.com/home.php. It looks like the following, which is, in fact, my news feed. Mini feeds are seen in your profile page, displaying your recent activities and look like the following one: Only the last 10 entries are being displayed in the mini feed section of the profile page. But you can always see the complete list of mini feeds by going to http://www.facebook.com/minifeed.php. Also the mini feed of any user can be accessed from http://www.facebook.com/minifeed.php?id=userid. There is another close relation between news feed and mini feed. When applications publish a mini feed in your profile, it will also appear in your friend's news feed page. How to publish Feeds Facebook provides three APIs to publish mini feeds and news feeds. But these are restricted to call not more than 10 times for a particular user in a 48 hour cycle. This means you can publish a maximum of 10 feeds in a specific user's profile within 48 hours. The following three APIs help to publish feeds: feed_publishStoryToUser—this function publishes the story to the news feed of any user (limited to call once every 12 hours). feed_publishActionOfUser—this one publishes the story to a user's mini feed, and to his or her friend's news feed (limited to call 10 times in a rolling 48 hour slot). feed_publishTemplatizedAction—this one also publishes mini feeds and news feeds, but in an easier way (limited to call 10 times in a rolling 48 hour slot). You can test this API also from http://developers.facebook.com/tools.php?api, and by choosing Feed Preview Console, which will give you the following interface: And once you execute the sample, like the previous one, it will preview the sample of your feed. Sample application to play with Feeds Let's publish some news to our profile, and test how the functions actually work. In this section, we will develop a small application (RateBuddies) by which we will be able to send messages to our friends, and then publish our activities as a mini feed. The purpose of this application is to display friends list and rate them in different categories (Awesome, All Square, Loser, etc.). Here is the code of our application: index.php<?include_once("prepend.php"); //the Lib and key container?><div style="padding:20px;"><?if (!empty($_POST['friend_sel'])){ $friend = $_POST['friend_sel']; $rating = $_POST['rate']; $title = "<fb:name uid='{$fbuser}' useyou='false' /> just <a href='http://apps.facebook.com/ratebuddies/'>Rated</a> <fb:name uid='{$friend}' useyou='false' /> as a '{$rating}' "; $body = "Why not you also <a href='http://apps.facebook.com/ratebuddies/'>rate your friends</a>?";try{//now publish the story to user's mini feed and on his friend's news feed $facebook->api_client->feed_publishActionOfUser($title, $body, null, $null,null, null, null, null, null, null, 1); } catch(Exception $e) { //echo "Error when publishing feeds: "; echo $e->getMessage(); }}?> <h1>Welcome to RateBuddies, your gateway to rate your friends</h1> <div style="padding-top:10px;"> <form method="POST"> Seect a friend: <br/><br/> <fb:friend-selector uid="<?=$fbuser;?>" name="friendid" idname="friend_sel" /> <br/><br/><br/> And your friend is: <br/> <table> <tr> <td valign="middle"><input name="rate" type="radio" value="funny" /></td> <td valign="middle">Funny</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="hot tempered" /></td> <td valign="middle">Hot Tempered</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="awesome" /></td> <td valign="middle">Awesome</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="naughty professor" /></td> <td valign="middle">Naughty Professor</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="looser" /></td> <td valign="middle">Looser</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="empty veseel" /></td> <td valign="middle">Empty Vessel</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="foxy" /></td> <td valign="middle">Foxy</td> </tr> <tr> <td valign="middle"><input name="rate" type="radio" value="childish" /></td> <td valign="middle">Childish</td> </tr> </table> &nbsp; <input type="submit" value="Rate Buddy"/> </form> </div></div> index.php includes another file called prepend.php. In that file, we initialized the facebook api client using the API key and Secret key of the current application. It is a good practice to keep them in separate file because we need to use them throughout our application, in as many pages as we have. Here is the code of that file: prepend.php<?php// this defines some of your basic setupinclude 'client/facebook.php'; // the facebook API library// Get these from ?http://www.facebook.com/developers/apps.phphttp://www.facebook.com/developers/apps.php$api_key = 'your api key';//the api ket of this application$secret = 'your secret key'; //the secret key$facebook = new Facebook($api_key, $secret); //catch the exception that gets thrown if the cookie has an invalid session_key in it try { if (!$facebook->api_client->users_isAppAdded()) { $facebook->redirect($facebook->get_add_url()); } } catch (Exception $ex) { //this will clear cookies for your application and redirect them to a login prompt $facebook->set_user(null, null); $facebook->redirect($appcallbackurl); }?> The client is a standard Facebook REST API client, which is available directly from Facebook. If you are not sure about these API keys, then point your browser to http://www.facebook.com/developers/apps.php and collect the API key and secret key from there. Here is a screenshot of that page: Just collect your API key and Secret Key from this page, when you develop your own application. Now, when you point your browser to http://apps.facebooks.com/ratebuddies and successfully add that application, it will look like this: To see how this app works, type a friend in the box, Select a friend, and click on any rating such as Funny or Foxy. Then click on the Rate Buddy button. As soon as the page submits, open your profile page and you will see that it has published a mini feed in your profile.
Read more
  • 0
  • 0
  • 5373

article-image-human-readable-rules-drools-jboss-rules-50part-2
Packt
16 Oct 2009
5 min read
Save for later

Human-readable Rules with Drools JBoss Rules 5.0(Part 2)

Packt
16 Oct 2009
5 min read
Drools Agenda Before we talk about how to manage rule execution order, we have to understand Drools Agenda. When an object is inserted into the knowledge session, Drools tries to match this object with all of the possible rules. If a rule has all of its conditions met, its consequence can be executed. We say that a rule is activated. Drools records this event by placing this rule onto its agenda (it is a collection of activated rules). As you may imagine, many rules can be activated, and also deactivated, depending on what objects are in the rule session. After the fireAllRules method call, Drools picks one rule from the agenda and executes its consequence. It may or may not cause further activations or deactivations. This continues until the Drools Agenda is empty. The purpose of the agenda is to manage the execution order of rules. Methods for managing rule execution order The following are the methods for managing the rule execution order (from the user's perspective). They can be viewed as alternatives to ruleflow. All of them are defined as rule attributes. salience: This is the most basic one. Every rule has a salience value. By default it is set to 0. Rules with higher salience value will fire first. The problem with this approach is that it is hard to maintain. If we want to add new rule with some priority, we may have to shift the priorities of existing rules. It is often hard to figure out why a rule has certain salience, so we have to comment every salience value. It creates an invisible dependency on other rules. activation-group: This used to be called xor-group. When two or more rules with the same activation group are on the agenda, Drools will fire just one of them. agenda-group: Every rule has an agenda group. By default it is MAIN. However, it can be overridden. This allows us to partition Drools Agenda into multiple groups that can be executed separately. The figure above shows partitioned Agenda with activated rules. The matched rules are coming from left and going into Agenda. One rule is chosen from the Agenda at a time and then executed/fired. At runtime, we can programmatically set the active Agenda group (through the getAgenda().getAgendaGroup(String agendaGroup).setFocus() method of KnowledgeRuntime), or declaratively, by setting the rule attribute auto-focus to true. When a rule is activated and has this attribute set to true, the active agenda group is automatically changed to rule's agenda group. Drools maintains a stack of agenda groups. Whenever the focus is set to a different agenda group, Drools adds this group onto this stack. When there are no rules to fire in the current agenda group, Drools pops from the stack and sets the agenda group to the next one. Agenda groups are similar to ruleflow groups with the exception that ruleflow groups are not stacked. Note that only one instance of each of these attributes is allowed per rule (for example, a rule can only be in one ruleflow-group ; however, it can also define salience within that group). Ruleflow As we've already said, ruleflow can externalize the execution order from the rule definitions. Rules just define a ruleflow-group attribute, which is similar to agenda-group. It is then used to define the execution order. A simple ruleflow (in the example.rf file) is shown in the following screenshot: The preceding screenshot shows a ruleflow opened with the Drools Eclipse plugin. On the lefthand side are the components that can be used when building a ruleflow. On the righthand side is the ruleflow itself. It has a Start node which goes to ruleflow group called Group 1. After it finishes execution, an Action is executed, then the flow continues to another ruleflow group called Group 2, and finally it finishes at an End node. Ruleflow definitions are stored in a file with the .rf extension. This file has an XML format and defines the structure and layout for presentational purposes. Another useful rule attribute for managing which rules can be activated is lock-on-active. It is a special form of the no-loop attribute. It can be used in combination with ruleflow-group or agenda-group. If it is set to true, and an agenda/ruleflow group becomes active/focused, it discards any further activations for the rule until a different group becomes active. Please note that activations that are already on the agenda will be fired. A ruleflow consists of various nodes. Each node has a name, type, and other specific attributes. You can see and change these attributes by opening the standard Properties view in Eclipse while editing the ruleflow file. The basic node types are as follows: Start End Action RuleFlowGroup Split Join They are discussed in the following sections. Start It is the initial node. The flow begins here. Each ruleflow needs one start node. This node has no incoming connection—just one outgoing connection. End It is a terminal node. When execution reaches this node, the whole ruleflow is terminated (all of the active nodes are canceled). This node has one incoming connection and no outgoing connections. Action Used to execute some arbitrary block of code. It is similar to the rule consequence—it can reference global variables and can specify dialect. RuleFlowGroup This node will activate a ruleflow-group, as specified by its RuleFlowGroup attribute. It should match the value in ruleflow-group rule attribute.  
Read more
  • 0
  • 0
  • 5015

article-image-recording-calls-freepbx-25
Packt
16 Oct 2009
2 min read
Save for later

Recording Calls in FreePBX 2.5

Packt
16 Oct 2009
2 min read
Asterisk has a wonderful, built-in ability to record calls. No additional software is required to make this happen. When Asterisk records a call, both sides of the call are recorded and written out to a file for playback on a computer. Call recording is often performed in call centers to ensure call quality, or to keep calls for later review, should the need arise. Asterisk provides the ability to record all of the calls, or to selectively record calls. In this article, we will look the following:   General recording options Recording calls to extensions Recording calls to queues Recording calls to conferences Maintaining call recordings Before enabling call recording for your PBX, make sure that you are aware of the legalities surrounding call recordings and privacy laws. Call recordings are prohibited in certain places, unless the caller is told that the call will be recorded. For example, in the state of California all of the parties on the call must consent to the call being recorded before it begins. Playing back a message stating that the call is being recorded prior to the call being answered is considered a valid form of consent. Recording formats FreePBX allows calls to be recorded in the following formats: WAV WAV49 ULAW ALAW SLN GSM Each format has its own ratio of file size to recording quality, and certain formats will not play on all of the computers. A comparison between all of the  available formats is as follows:
Read more
  • 0
  • 0
  • 3484

article-image-competitive-service-and-contract-management-sap-business-one-implementation-part-2
Packt
16 Oct 2009
8 min read
Save for later

Competitive Service and Contract Management in SAP Business ONE Implementation: Part 2

Packt
16 Oct 2009
8 min read
In the first half of this 2-part article series, we looked at the service module so as to evaluate potential actions that are triggered, based on service-related information. We also introduced a concept which explained how to utilize the service module features to establish a guaranteed response time for customers. We also learnt about : Key terms - The common terminology related to service management were covered. Although nothing major , we went about learning what the terms entail with regards to the SAP system. Service module core functions – In this section, the available functions and features were put into perspective—what is available and how much we can expect from it.  You also learnt what service operations mean. Case study and your own project – The available features of the service module were implemented for the case study. By doing so, knowledge was provided to implement the service module in your own business. We also reviewed some guidelines which enabled you to translate the case study implementation into a set of activities for your own project. Let's begin with Service reports. Service reports The crucial element of each module is the information that can easily be extracted for reporting purposes. SAP provides a series of canned reports for the service module. The Service Calls report provides information about service call activities based on the selected criteria. You can filter this report by timeframe of service call creation and also by resolution time. Additional filter ranges are available for Customer Code, Handled By, Item, and also Queue ID. In addition, the report allows filtering by Problem Type, Priority, Call Type, Origin, Call Status, and Overdue Calls. You can see that there is a wide range of options to obtain information. It is important to note that reporting can utilize the information only if all of the data is properly collected using the SAP forms. In case no options are selected for filtering, the report defaults to select all of the available information. The following additional service reports are available and have almost identical filtering capabilities as the service calls report: Service Calls by Queue, Response Time by Assigned to, Average Closure Time. The Service Contracts report(seen below) helps you manage the status of all maintenance contracts. If you've ever had to manage maintenance contracts with customers, you will appreciate the ease of obtaining the information here. You can filter this report by Customer Code, Start Date Range, End Date Range and Termination Date Range. In addition, this report can be further filtered by Contract Type, Contract Status, and Service Type. The customer equipment card report allows information to be obtained about items sold to customers based on serial number tracking. Each serial number has its own contract with expiration which is usually based on the purchase date. This report is able to be filtered by customer and item code. In addition, a more global filter can be used such as item group. The Service Monitor report provides a more real-time view of the service pipeline. We already covered this report in the previous section. Finally, My Reports includes My Service Calls, My Open Service Calls, and My Overdue Service Calls. Those reports conveniently filter the information based on the current login name. Therefore, if you run the report, you will only see information that is relevant for you based on the login. Limitations I have already mentioned that you can look at SAP Business ONE as the operating system for your business. You can use industry add-ons to seamlessly transform the standard features into an industry solution that is specific to your requirements. Therefore, let's evaluate some add-ons I've worked with that are related to the service module—specifically, the Enprise Job Costing module and the solution from Navigator called ServiceONE. By looking at these add-ons, we can also learn the limitations of the standard service module. For example, since the Navigator promises to have all of the information available in one view, we realize that in SAP, we sometimes need to jump to different forms to get where we wanted to be initially. Let's further evaluate the features of these add-ons. The Enprise Job Costing solution introduces a web-based timesheet. This is an obvious feature that is not directly available in the SAP standard configuration. First, I will look at the Navigator solution and will then follow the Enprise offering. Often, there is more than one add-on providing industry-specific features. You then need to evaluate both solutions and decide which one best fi ts your requirements. Please note that I am presenting the add-on features to better define the limitations of the SAP Standard Business ONE features. Job Costing add-on by Enprise The Enprise Job Costing add-on is one of the first industry-specific solutions that gained widespread adoption as a standard for companies that required a detailed job costing solution. The advantage of this solution is that it is based on true expertise in the job costing area as it relates to the SAP service module. Let's look at a scenario that is very common for companies that work in the service industry and require what is known as job costing. However, I would first like to take the opportunity to explain job costing a bit. Job costing allows the profit and loss for specific services provided to be calculated. For example, if you have a company that sends out technicians to customer sites for performing equipment repairs, you need to make sure that the invoiced amount exceeds the cost you incur. The following workflow may be common in this environment: Serialized items are delivered to customers with each having a warranty contract that may or may not include services, parts, and replacements. Services may be performed on serialized items delivered by you or by another company. A service call may lead to a proposal (job) which will then be ordered. Technicians may use a timesheet to report the status and time. Timesheet entries must be possible via a mobile device or the Web. Furthermore, time entered needs to be approved before it is relevant for invoicing. A job may lead to subjobs that require unique management of related costs. As the number of jobs increase, you will require "work in progress" reporting. Estimating a job is crucial. Therefore, technicians need to be able to create estimates. It must then be possible to translate those estimates into orders and contracts. As services may require replacement parts, a feature is required that allows optimized picking of relevant items for a specific job. Complex jobs require milestone payments. This needs to be implemented in the contracts. The invoicing system needs to be integrated with the way services are completed. For example, milestone payments, fixed priced billing, and partial invoicing are common requirements in the service industry. The Enprise Job Costing add-on resides in its own menu item called Job Costing. As you can see below, the menu items are well defined and provide a quick overview of the available features. In addition, it is important to note that the features seamlessly appear within the SAP interface: By selecting the Job Entry form, the powerful features come to light. As you can see in the following screenshot, the form allows searching jobs based on Status,Type, Properties, Category, and Entered By. The resulting list is shown in the lower pane. We can use this interface to search for specific jobs, and then click on the Bulk Invoice button as highlighted in the screenshot. This automates the invoicing process based on a clear, uncluttered form. Please note that we do not need to jump between multiple forms. The Direct Time Entry form(seen below) is basically a timesheet. Therefore, technicians can use this to enter the time they spend on projects. Please note the buttons in the lower right that allow importing from the Web and also from an Excel clipboard. Enprise provides a web-based timesheet from which we can import data. However, it is important to note that we can also import from an Excel clipboard. This way, we can use the date that technicians entered in their laptops. The contract list provides a link where the Enprise-enhanced contract management surfaces: The contract management allows milestones for a contract. Each milestone to be established could lead to a milestone payment. In addition, we can directly jump to the related invoices by using the Show Invoices button: Enprise has adopted the concept of master data. For this purpose, the Job Master Data form was established. This is consistent with the SAP concept. Each job is defined and configured with specific parameters, which later drive the transactions that are based on this master data. For example, we can define the job parameters alongside a list of subjobs. In addition, documents can be attached as attachments: Advanced service functionality using ServiceONE by Navigator Navigator provides a wide range of valuable add-ons. Each add-on is valuable. However, the key advantage of Navigator is the comprehensive portfolio of add-ons the cover almost all aspects of SAP Business ONE. In particular, the fact that Navigator also provides a mobile solution, which connects handheld computers with SAP Business ONE, extends the reach of the available functionality beyond the boundaries of the SAP client interface. Therefore, a mobile field service does not need to use a web-based timesheet, but could directly interact using mobile devices. However, you may need to purchase another add-on to accomplish this.
Read more
  • 0
  • 0
  • 2641
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-displaying-sql-server-data-using-linq-data-source
Packt
16 Oct 2009
2 min read
Save for later

Displaying SQL Server Data using a Linq Data Source

Packt
16 Oct 2009
2 min read
Create web site project and add LinqDataSource control Open Visual Studio 2008 from its shortcut on the desktop. Click File | New | Web Site...(or Shift+Alt+N) to open the New Web Site window. Change the default name of the site to a name of your choice (herein LinqDemo)on your local web server as shown. Make sure you are creating a .NET Framework 3.5 web site as shown here. Drag and drop a LinqDataSource control from Toolbox|Data shown in the next figure on to the Default.aspx This creates an instance of the control LinqDataSource1 as shown. The figure also shows the smart tasks of this control as shown. Create a data context for the LinqDataSource control In order to use this control you also need to create a data context. Right click the localhost web site and choose Add New Item...to open the Add New Item - http://localhost/ LinqDemo window as shown. In the Visual Studio installed templates highlight Linq to SQL Classes. Change the default name from DataClasses.dbml to a name of your choosing. Herein MyDC.dbml. Click Add. This pops-up a Microsoft Visual Studio warning message as shown. The preferred location for this file is in the App_Code folder of your project as suggested here. Click on Yes. This adds a MyDC.dbml file to APP_Code folder as shown. MyDC.dbml consists of two components MyDC.dbml and MyDC.designer.vb to the App_Code folder as shown . Double click the MyDC.dbml node in the APP_Code folder. This opens the ObjectRelational Designer and the designer surface with two panes as shown. Read the instructions in the windows. In the left pane you can drag and drop items from the Server Explorer in Visual Studio to create the appropriate classes and in the right pane you can drag and drop stored procedures. In this article we will be looking at just creating classes from table objects.
Read more
  • 0
  • 0
  • 3888

article-image-creating-matrix-report-using-analysis-services-cube
Packt
16 Oct 2009
4 min read
Save for later

Creating a matrix report using the Analysis Services Cube

Packt
16 Oct 2009
4 min read
Reviewing Jayaram's other OLAP related articles may greatly help in understanding this article. Creating the CUBE will be essential to work with this hands-on. If you are already experienced and have an appropriate CUBE to work with you may directly go to the section on deriving a dataset. The CUBE used in this hands-on is a simple one. It does not even have a "Time" dimension although Microsoft in Visual Studio gives a warning that you should have one. However for the purposes of demonstration and doing the hands-on a CUBE without the "Time" dimension should be adequate. The two previous articles on creating a CUBE provide the necessary background for this article. Create a data source with a CUBE Create an Analysis Services Cube (herein called MyNwind.cube) using the TestNorthwind as the database. The Measures and Dimensions for this cube are as shown in the next figure. Start your Report Builder 2.0. Make sure you have started the reporting services using the Reporting Services Configuration Manager. In Report Builder 2.0 click on New | Data source... under Report Data. Provide the following information: Name: SrcCubeSelect connection type: Microsoft SQL Server Analysis ServicesConnection String: Data Source=Hodentek2SANGAM; Initial Catalog=NwindRTM Herein NwindRTM is the name of the Datasource in the Analysis Server. (Alternately you may build this source as shown). Click OK on the Data Source Properties window. Add a dataset to the report Right click on SrcCube and choose Add DataSet... In the Dataset Properties window make the following changes: Name: QryCubeData source: SrcCubeQuery Type: text Click on Query Designer... button. At first you will see only the Metadata of the cube displayed as in the left side of the next figure. Expand Customers, Orders, and Products in the dimensions and drop them on the list header in the bottom pane on the right hand side of the next figure. Drag and drop Freight from Orders under Measures as shown. For each of the dimensions using an operator create a filter expression as shown. For example, the Products included in the query range from Product IDs 3 to 9; the Customer ID (some specific ones are chosen), similarly theCategory ID (only those with ID's 2, 3, 4, and 5 are included in the query). The design of the query with these filtering choices is as shown in the previous figure. The filtering tool is very flexible and all the items namely Dimension, Hierarchy, Operator and Filter Expression can be designed in this interface using either drop-down pick lists choices or drop-downs with checkboxes as shown here. Run the query by clicking on the toolbar item (!) and review the results. Click OK on the Query Designer. The Dataset Properties window shows up with this query designed according to your choices in the query item window as shown. Close the Dataset Properties window. Report Design In Report Builder 2.0 click on New Table or Matrix wizard. In the Choose a dataset window accept the default and click Next. Drag and drop Customer_ID in the Row Groups drop area. Drag and drop Order_ID below Customer_ID in the Row Groups drop area. Drag and drop Product_ID in the Column Groups drop area. Drag and drop Freight into the Values drop area and click on Next. In the Choose the layout window accept Expand/collapse groups and choose the option Stepped, subtotal above. Click Next and choose some style (herein Ocean) and click Finish. The final report design is as shown here. Click Home | Run. The report gets displayed after processing as shown here. The orders from a particular customer have been expended in this view. Summary Report Builder 2.0 can used to author reports based on Analysis Services Cubes. The interface is very flexible and the Query Designer is very easy to use as shown in this article. If you have read this article you may be interested to view : Creating an Analysis Services Cube with Visual Studio 2008 - Part 1 Creating an Analysis Services Cube with Visual Studio 2008 - Part 2
Read more
  • 0
  • 0
  • 3698

article-image-windows-development-using-visual-studio-2008
Packt
16 Oct 2009
11 min read
Save for later

Windows Development Using Visual Studio 2008

Packt
16 Oct 2009
11 min read
Visual Studio Visual Studio is an environment for developing applications in Windows. It has a number of tools, such as an editor, compilers, linkers, a debugger, and a project manager. It also has several Wizards—tools designed for rapid development. The Wizard you will first encounter is the Application Wizard. It generates code for an Application Framework. The idea is that we use the Application Wizard to design a skeleton application that is later completed with more application-specific code. There is no real magic about wizards, all they do is generate the skeleton code. We could write the code ourselves, but it is a rather tedious job. Moreover, an application can be run in either debug or release mode. In debug mode, additional information is added in order to allow debugging; in release mode, all such information is omitted in order to make the execution as fast as possible. The code of this article is developed with Visual Studio 2008. The Windows 32 bits Application Programming Interface (Win32 API) is a huge C function library. It contains a couple of thousand functions for managing the Windows system. With the help of Win32 API it is possible to totally control the Windows operating system. However, as the library is written in C, it could be a rather tedious job to develop a large application, even though it is quite possible. That is the main reason for the existence of the Microsoft Foundation Classes (MFC). It is a large C++ class library containing many classes encapsulating the functionality of Win32 API. It does also hold some generic classes to handle lists, maps, and arrays. MFC combines the power of Win32 API with the advantages of C++. However, on some occasions MFC is not enough. When that happens, we can simply call an appropriable Win32 API function, even though the application is written in C++ and uses MFC. Most of the classes of MFC belong to a class hierarchy with CObject at the top. On some occasions, we have to let our classes inherit CObject in order to achieve some special functionality. The baseclass Figure in the Draw and Tetris applications inherits CObject in order to read or write objects of unknown classes. The methods UpdateAllViews and OnUpdate communicate by sending pointers to CObject objects. The Windows main class is CWnd. In this environment, there is no function main. Actually, there is a main, but it is embedded in the framework. We do not write our own main function, and there is not one generated by the Application Wizard. Instead, there is the object theApp, which is an instance of the application class. The application is launched by its constructor. When the first version of MFC was released, there was no standard logical type in C++. Therefore, the type BOOL with the values TRUE and FALSE was introduced. After that, the type bool was introduced to C++. We must use BOOL when dealing with MFC method calls, and we could use bool otherwise. However, in order to keep things simple, let us use BOOL everywhere. In the same way, there is a MFC class CString that we must use when calling MFC methods. We could use the C++ built-in class string otherwise. However, let us use CString everywhere. The two classes are more or less equivalent. There are two types for storing a character, char and wchar_t. In earlier version of Windows, you were supposed to use char for handling text, and in more modern versions you use wchar_t. In order to make our application independent of which version it is run on, there are two macros TCHAR and TEXT. TCHAR is the character type that replaces char and wchar_t. TEXT is intended to encapsulate character and string constants. TCHAR *pBuffer;stScore.Format(TEXT("Score: %d."), iScore); There is also the MFC type BYTE which holds a value of the size of one byte, and UINT which is shorthand for unsigned integer. Finally, all generated framework classes have a capital C at the beginning of the name. The classes we write ourselves do not. The Document/View model The applications in this article are based on the Document/View model. Its main idea is to have two classes with different responsibilities. Let us say we name the application Demo, the Application Wizard will name the document class CDemoDoc and the view class will be named CDemoView. The view class has two responsibilities: to accept input from the user by the keyboard or the mouse, and to repaint the client area (partly or completely) at the request of the document class or the system. The document's responsibility is mainly to manage and modify the application data. The model comes in two forms: Single Document Interface (SDI) and Multiple Document Interface (MDI). When the application starts, a document object and a view object are created, and connected to each other. In the SDI, it will continue that way. In the MDI form, the users can then add or remove as many views they want to. There is always exactly one document object, but there may be one or more view objects, or no one at all. The objects are connected to each other by pointers. The document object has a list of pointers to the associated view objects. Each view object has a fieldm_pDocument that points at the document object. When a change in the document's data has occurred, the document instructs all of its views to repaint their client area by calling the method UpdateAllViews in order to reflect the change. The message system Windows is built on messages. When the users press one of the mouse buttons or a key, when they resize a window, or when they select a menu item, a message is generated and sent to the current appropriate class. The messages are routed by a message map. The map is generated by the Application Wizard. It can be modified manually or with the Properties Window View (the Messages or Events button). The message map is declared in the file class' header file as follows: DECLARE_MESSAGE_MAP() The message map is implemented in the class' implementation file as follows: BEGIN_MESSAGE_MAP(this_class, base_class)// Message handlers.END_MESSAGE_MAP() Each message has it own handle, and is connected to a method of a specific form that catches the message. There are different handlers for different types of messages. There are around 200 messages in Windows. Here follows a table with the most common ones. Note that we do not have to catch every message. We just catch those we are interested in, the rest will be handled by the framework. Message Handler/Method Sent WM_CREATE ON_WM_CREATE/OnCreate When the window is created, but not yet showed. WM_SIZE ON_WM_SIZE/OnSize When the window has been resized. WM_MOVE ON_WM_MOVE/OnMove When the window has been moved. WM_SETFOCUS ON_WM_SETFOCUS/ OnSetFocus When the window receives input focus. WM_KILLFOCUS ON_WM_KILLFOCUS/ OnKillFocus When the window loses input focus. WM_VSCROLL ON_WM_VSCROLL/ OnVScroll When the user scrolls the vertical bar. WM_HSCROLL ON_WM_HSCROLL/ OnHScroll When the user scrolls the horizontal bar. WM_LBUTTONDOWN   WM_MBUTTONDOWN   WM_RBUTTONDOWN ON_WM_LBUTTONDOWN/ OnLButtonDown ON_WM_MBUTTONDOWN/ OnMButtonDown ON_WM_RBUTTONDOWN/ OnRButtonDown When the user presses the left, middle, or right mouse button. WM_MOUSEMOVE ON_WM_MOUSEMOVE/ OnMouseMove When the user moves the mouse, there are flags available to decide whether the buttons are pressed. WM_LBUTTONUP   WM_MBUTTONUP   WM_RBUTTONUP ON_WM_LBUTTONUP/ OnLButtonUp ON_WM_MUTTONUP/ OnMButtonUp ON_WM_RUTTONUP/ OnRButtonUp When the user releases the left, middle, or right button. WM_CHAR ON_WM_CHAR/OnChar When the user inputs a writable character of the keyboard. WM_KEYDOWN ON_WM_KEYDOWN/ OnKeyDown When the user presses a key of the keyboard. WM_KEYUP ON_WM_KEYUP/ OnKeyUp When the user releases a key of the keyboard. WM_PAINT ON_WM_PAINT/OnPaint When the client area of the window needs to be repainted, partly or completely. WM_CLOSE ON_WM_CLOSE/OnClose When the user clicks at the close button in the upper right corner of the window. WM_DESTROY ON_WM_DESTROY/ OnDestroy When the window is to be closed. WM_COMMAND ON_COMMAND(Identifier, Name)/OnName   When the user selects a menu item, a toolbar button, or a accelerator key connected to the identifier. WM_COMMAND_ UPDATE ON_COMMAND_ UPDATE_UI(Identifier, Name)/OnUpdateName On idle time, when the system is not busy with any other task, this message is sent in order to enable/disable or to check menu items and toolbar buttons. When a user selects a menu item, a command message is sent to the application. Thanks to MFC, the message can be routed to virtually any class in the application. However, in the applications of this article, all menu messages are routed to the document class. It is possible to connect an accelerator key or a toolbar button to the same message, simply by giving it the same identity number. Moreover, when the system is in idle mode (not busy with any other task) thecommand update message is sent to the application. This gives us an opportunity to check or disable some of the menu items. For instance, the Save item in the File menu should be grayed (disabled) when the document has not been modified and does not have to be saved. Say that we have a program where the users can paint in one of three colors. The current color should be marked by a radio box. The message map and its methods can be written manually or be generated with the Resource View (the View menu in Visual Studio) which can help us generate the method prototype, its skeleton definition, and its entry in the message map. The Resource is a system of graphical objects that are linked to the application. When the framework is created by the Application Wizard, the standard menu bar and toolbar are included. We can add our own menus and buttons in Resource Editor, a graphical tool of Visual Studio. The coordinate system In Windows, there are device (physical) and logical coordinates. There are several logical coordinate mapping systems in Windows. The simplest one is the text system; it simply maps one physical unit to the size of a pixel, which means that graphical figures will have different size monitors with different sizes or resolutions. This system is used in the Ring and Tetris applications. The metric system maps one physical unit to a tenth of a millimeter (low metric) or a hundredth of a millimeter (high metric). There is also the British system that maps one physical unit to a hundredth of an inch (low English) or a thousandth of an inch (high English). The British system is not used in this article. The position of a mouse click is always given in device units. When a part of the client area is invalidated (marked for repainting), the coordinates are also given in device units, and when we create or locate the caret, we use device coordinates. Except for these events, we translate the positions into logical units of our choice. We do not have to write translation routines ourselves, there are device context methods LPtoDP (Logical Point to Device Point) and DPtoLP (Device Point to Logical Point) in the next section that do the job for us. The setting of the logical unit system is done in OnInitialUpdate and OnPrepareDC in the view classes. In the Ring and Tetris Applications, we just ignore the coordinates system and use pixels. In the Draw application, the view class is a subclass of the MFC class CScrollView. It has a method SetScrollSizes that takes the logical coordinate system and the total size of the client area (in logical units). Then the mapping between the device and logical system is done automatically and the scroll bars are set to appropriate values when the view is created and each time its size is changed. void SetScrollSizes(int nMapMode, CSize sizeTotal, const CSize& sizePage = sizeDefault, const CSize& sizeLine = sizeDefault); In the Calc and Word Applications, however, we set the mapping between the device and logical system manually by overriding the OnPrepareDC method. It calls the method SetMapMode which sets the logical horizontal and vertical units to be equal. This ensures that circles will be kept round. The MFC device context method GetDeviceCaps returns the size of the screen in pixels and millimeters. Those values are used in the call to SetWindowExt and SetViewportExt, so that the logical unit is one hundredth of a millimeter also in those applications. The SetWindowOrg method sets the origin of the view's client area in relation to the current positions of the scroll bars, which implies that we can draw figures and text without regarding the current positions of the scroll bars. int SetMapMode(int iMapMode);int GetDeviceCaps(int iIndex) const;CSize SetWindowExt(CSize szScreen);CSize SetViewportExt(CSize szScreen);CPoint SetWindowOrg(CPoint ptorigin);
Read more
  • 0
  • 0
  • 1876

article-image-jboss-portals-and-ajax-part-1
Packt
16 Oct 2009
7 min read
Save for later

JBoss Portals and AJAX - Part 1

Packt
16 Oct 2009
7 min read
Rich user interfaces and AJAX Rich user interfaces can be achieved by using a combination of dynamic HTML elements such as HTML and JavaScript. However, the scope of such an interface is limited to client-side behavior and has minimal functional implications due to the lack of server-side interactions. The power of AJAX is in its capability to provide even richer interface by supplementing its dynamic user interface with powerful functionality through seamless server-side invocation power. AJAX allows individual user interface components to communicate with the server and exchange data without the need for refreshing the whole screen. This is achieved using a process called Web Remoting. Web remoting, or the process of communicating between a browser and a server, can be performed in multiple ways. The popular approaches that are supported by today's browsers are IFrames and XMLHttpRequest. Dynamic HTML can be complemented with either of these methods to generate AJAX functionality. Asynchronous JavaScript and XML or AJAX Asynchronous communication between the client and the server forms the backbone of AJAX. Although an asynchronous request-response method can provide significant value in the development of rich functionality by itself, the results are lot more pronounced when used in conjunction with other functional standards such as CSS, DOM, JavaScript, and so on. The predominant popularity of AJAX stems from such usage. Client-server communication can be achieved either by using IFrames, or by using the supported JavaScript function called XMLHttpRequest(). Due to certain limitations of IFrames, XMLHttpRequest has gained a lot more acceptance. While IFrame can also be an effective option for implementing AJAX-based solutions, in this article, we will focus largely on an XMLHttpRequest-based implementation. The primary advantage of using AJAX-based interfaces is that the update of content occurs without page refreshes. A typical AJAX implementation using XMLHttpRequest happens as described in the following steps: An action on the client side, whether this is a mouse click or a timed refresh, triggers a client event An XMLHttpRequest object is created and configured The XMLHttpRequest object makes a call The request is processed by a server-side component The component returns an XML (or an equivalent) document containing the result The XMLHttpRequest object calls the callback() function and processes the result The HTML DOM is updated with any resulting values The following simplified image illustrates the high-level steps involved in an AJAX request flow. The portal client page gets served to the client browser, where the execution of JavaScript functions takes place. The following example illustrates the initialization of the request object and its basic use: if (window.XMLHttpRequest) // Object of the current window { // for non-IE browsers request = new XMLHttpRequest();}else if (window.ActiveXObject){ // For IE request = new ActiveXObject("Microsoft.XMLHTTP");}request.onreadystatechange = function(){ // do something to process response};if (request.readyState == 4){ // everything received, OK. Do something now..} else { // wait for the response to come to ready state} In subsequent sections, we will modify our sample portal application by adding AJAX functionality to one of the portlets. AJAX in JBoss portal AJAX has gained tremendous popularity in the traditional web application development world due to the richness and agility that it brings to user interfaces. Portals, such as JBoss portal, can also gain significantly from AJAX, in terms of implementation of both behavior and functionality. Refreshing the page content tends to be a time-consuming and resource-intensive process. Every request that a user makes to the server, either by clicking on submissions or links, results in the portal calling doView() and a series of methods for each portlet on the page, one at a time, before aggregating the results and sending the response back to the browser. Using AJAX allows for simultaneous submissions of request in their own independent threads of execution, resulting in an asynchronous and parallel execution. The portal page refresh overhead is now only as long as the time consumed by the slowest portlet. The response times observed by the user improve dramatically, while at the same time allowing more functionality on pages. Architecturally, vertical independent stacks of execution facilitate cleaner and more modular designs and implementations. AJAX can be implemented in JBoss portal in the following two ways: Using in-built support for asynchronous portal behavior by using configurations Writing custom behavior in portlets and page content by using AJAX libraries The in-built support for asynchronous behavior comprises of support for both markup and content. The markup support is in layouts and renderers, while the content is supported through configurable drag-drop and partial page refresh behavior. Almost all of the AJAX behavior supported by JBoss portal relates to asynchronous communication between the client and the portal servers. The only exception is the drag-drop behavior, which is largely view functionality. As far as the custom development within a portlet is concerned, the options are innumerable. A portlet can be developed using many advanced frameworks that are available as either commercial or open source products. For example, user interface features such as drag-and-drops, grids, accordion selects, pull-down menus, content refresh, and so on can be implemented by using third-party libraries including Scriptaculous, JQuery, and DOJO, which have gained a strong following among developers, even on traditional applications and non-portal platforms. In the next few sections, we will walk through an example of AJAX-enabled portlets using one of these libraries, developed on the JBoss portal platform. However, before we go into the implementation, let's step back and understand the limitations that the current portlet specification– JSR-286–addresses, facilitating easy development of AJAX portlets. JSR-168 AJAX limitations Before we look at the features and options provided by the new specification, let's look at how traditional JSR-168 portlets functioned. As shown in the following figure, the "Action" request invoked the processAction method on the server, which implemented controller logic to route it to the correct view. The "Render" request then invokes the render method to serve the content page to the browser. However, when the portlet uses AJAX and needs to makes an asynchronous call, it has to use ActionURL. This in turn follows the standard processing when processAction processes the request and the render method creates the user interface. However, now when the user interface is sent back, the portal injects some other markup and recreates the entire portal page. Hence, instead of refreshing a snippet of user interface, we end up refreshing the whole page. The issues with JSR-168 and AJAX can be broadly summarized as follows: ActionURL and RenderURL point to a portal, and not to a portlet. When we point to a portal, the result is a complete portal page, even if the portlet generates only a snippet. As per the specification, the user interface rendered by the portlet is supposed to be aggregated with some other markup and served back to the browser. When more than only the necessary data and markup is sent back, the JavaScript code on the client side that makes the asynchronous call cannot process the request. Asynchronous calls are made through XMLHttpRequest, which is designed to consume and process the complete response from the portlet. With the portal processing the request in between, XMLHttpRequest cannot consume the original response for processing. This defeats the purpose and value of using asynchronous calls to the server, and we end up with traditional full page refreshes. There were obviously a few workarounds to this. The most common practice was to serve the request from outside of the portal container into the web container. The idea is that the AJAX call can still be made to ActionURL, but the render function copies or shares its context with a traditional Java servlet in the web container of the application server. The AJAX call can now make a direct request to the servlet and get an asynchronous response from the servlet with no interference from the portal. There was a need for a better solution, and one that was incorporated as part of the specification. JSR-286, the latest portlet specification, addresses these problems.
Read more
  • 0
  • 0
  • 2399
Packt
16 Oct 2009
17 min read
Save for later

WCF – Windows Communication Foundation

Packt
16 Oct 2009
17 min read
What is WCF? WCF is the acronym for Windows Communication Foundation. It is Microsoft's latest technology that enables applications in a distributed environment to communicate with each other. WCF is Microsoft's unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments. WCF is built on the Microsoft .NET Framework and simplifies the development of connected systems. It unifies a broad array of distributed systems capabilities in a composable, extensible architecture that supports multiple transports, messaging patterns, encodings, network topologies, and hosting models. It is the next version of several existing products—ASP.NET's web methods (ASMX) and Microsoft Web Services Enhancements (WSE) for Microsoft .NET, .NET Remoting, Enterprise Services, and System.Messaging. The purpose of WCF is to provide a single programming model that can be used to create services on the .NET platform for organizations. Why is WCF used for SOA? As we have seen in the previous section, WCF is an umbrella technology that covers ASMX web services, .NET remoting, WSE, Enterprise Service, and System.Messaging. It is designed to offer a manageable approach to distributed computing, broad interoperability, and direct support for service orientation. WCF supports many styles of distributed application development by providing a layered architecture. At its base, the WCF channel architecture provides asynchronous, untyped message-passing primitives. Built on top of this base are protocol facilities for secure, reliable, transacted data exchange and a broad choice of transport and encoding options. Let us take an example to see why WCF is a good approach for SOA. Suppose a company is designing a service to get loan information. This service could be used by the internal call center application, an Internet web application, and a third-party Java J2EE application such as a banking system. For interactions with the call center client application, performance is important. For communication with the J2EE-based application however, interoperability becomes the highest goal. The security requirements are also quite different between the local Windows-based application, and the J2EE-based application running on another operating system. Even transactional requirements might vary, with only the internal application being allowed to make transactional requests. With these complex requirements, it is not easy to build the desired service with any single existing technology. For example, the ASMX technology may serve well for the interoperability, but its performance may not be ideal. The .NET remoting will be a good choice from the performance perspective, but it is not good at interoperability. Enterprise Services could be used for managing object lifetimes and defining distributed transactions, but Enterprise Services supports only a limited set of communication options. Now with WCF, it is much easier to implement this service. As WCF has unified a broad array of distributed systems capabilities, the get loan service can be built with WCF for all of its application-to-application communication. The following shows how WCF addresses each of these requirements: Because WCF can communicate using web service standards, interoperability with other platforms that also support SOAP, such as the leading J2EE-based application servers, is straightforward. You can also configure and extend WCF to communicate with web services using messages not based on SOAP, for example, simple XML formats such as RSS. Performance is of paramount concern for most businesses. WCF was developed with the goal of being one of the fastest distributed application platforms developed by Microsoft. To allow for optimal performance when both parties in a communication are built on WCF, the wire encoding used in this case is an optimized binary version of an XML Information Set. Using this option makes sense for communication with the call center client application, because it is also built on WCF, and performance is an important concern. Managing object lifetimes, defining distributed transactions, and other aspects of Enterprise Services, are now provided by WCF. They are available to any WCF-based application, which means that the get loan service can use them with any of the other applications that it communicates with. Because it supports a large set of the WS-* specifications, WCF helps to provide reliability, security, and transactions when communicating with any platform that supports these specifications. The WCF option for queued messaging, built on Message Queuing, allows applications to use persistent queuing without using another set of application programming interfaces. The result of this unification is greater functionality, and significantly reduced complexity. WCF architecture The following diagram illustrates the major layers of the Windows Communication Foundation (WCF) architecture. This diagram is taken from the Microsoft web site (http://msdn.microsoft.com/en-us/library/ms733128.aspx): The Contracts layer defines various aspects of the message system. For example, the Data Contract describes every parameter that makes up every message that a service can create or consume. The Service runtime layer contains the behaviors that occur only during the actual operation of the service, that is, the runtime behaviors of the service. The Messaging layer is composed of channels. A channel is a component that processes a message in some way, for example, authenticating a message. In its final form, a service is a program. Like other programs, a service must be run in an executable format. This is known as the hosting application. In the next section, we will explain these concepts in detail. Basic WCF concepts—WCF ABCs There are many terms and concepts around WCF, such as address, binding, contract, endpoint, behavior, hosting, and channels. Understanding these terms is very helpful when using WCF. Address The WCF Address is a specific location for a service. It is the specific place to which a message will be sent. All WCF services are deployed at a specific address, listening at that address for incoming requests. A WCF Address is normally specified as a URI, with the first part specifying the transport mechanism, and the hierarchical part specifying the unique location of the service. For example, http://www.myweb.com/myWCFServices/SampleService can be an address for a WCF service. This WCF service uses HTTP as its transport protocol, and it is located on the server www.myweb.com, with a unique service path of myWCFServices/SampleService. The following diagram illustrates the three parts of a WCF service address. Binding Bindings are used to specify the transport, encoding, and protocol details required for clients and services to communicate with each other. Bindings are what WCF uses to generate the underlying wire representation of the endpoint. So, most of the details of the binding must be agreed upon by the parties that are communicating. The easiest way to achieve this is for clients of a service to use the same binding that the service uses. A binding is made up of a collection of binding elements. Each element describes some aspect of how the service communicates with clients. A binding must include at least one transport binding element, at least one message encoding binding element (which can be provided by the transport binding element by default), and any number of other protocol binding elements. The process that builds a runtime out of this description allows each binding element to contribute code to that runtime. WCF provides bindings that contain common selections of binding elements. These can either be used with their default settings, or the default values can be modified according to user requirements. These system-provided bindings have properties that allow direct control over the binding elements and their settings. The following are some examples of the system-provided bindings: BasicHttpBinding, WSHttpBinding, WSDualHttpBinding, WSFederationHttpBinding, NetTcpBinding, NetNamedPipeBinding, NetMsmqBinding, NetPeerTcpBinding, and MsmqIntegrationBinding. Each one of these built-in bindings has predefined required elements for a common task, and is ready to be used in your project. For instance, the BasicHttpBinding uses HTTP as the transport for sending SOAP 1.1 messages, and it has attributes and elements such as receiveTimeout, sendTimeout, maxMessageSize, and maxBufferSize. You can accept the default settings of its attributes and elements, or overwrite them as needed. Contract A WCF contract is a set of specifications that define the interfaces of a WCF service. A WCF service communicates with other applications according to its contracts. There are several types of WCF contracts, such as Service Contract, Operation Contract, Data Contract, Message Contract, and Fault Contract. Service contract A service contract is the interface of the WCF service. Basically, it tells others what the service can do. It may include service-level settings, such as the name of the service, the namespace of the service, and the corresponding callback contracts of the service. Inside the interface, it can define a bunch of methods, or service operations for specific tasks. Normally, a WCF service has at least one service contract. Operation contract An operation contract is defined within a service contract. It defines the parameters and return type of an operation. An operation can take data of a primitive (native) data type, such as an integer as a parameter, or it can take a message, which should be defined as a message contract type. Just as a service contract is an interface, an operation contract is a definition of an operation. It has to be implemented in order that the service functions as a WCF service. An operation contract also defines operation-level settings, such as the transaction flow of the operation, the directions of the operation (one-way, two-way, or both ways), and fault contract of the operation. The following is an example of an operation contract: [WCF::FaultContract(typeof(MyWCF.EasyNorthwind.FaultContracts.ProductFault))]MyWCF.EasyNorthwind.MessageContracts.GetProductResponseGetProduct(MyWCF.EasyNorthwind.MessageContracts.GetProductRequest request); In this example, the operation contract's name is GetProduct, and it takes one input parameter, which is of type GetProductRequest (a message contract) and has one return value, which is of type GetProductResponse (another message contract). It may return a fault message, which is of type ProductFault (a fault contract), to the client applications. We will cover message contract and fault contract in the following sections. Message contract If an operation contract needs to pass a message as a parameter or return a message, the type of these messages will be defined as message contracts. A message contract defines the elements of the message, as well as any message-related settings, such as the level of message security, and also whether an element should go to the header or to the body. The following is a message contract example: namespace MyWCF.EasyNorthwind.MessageContracts{ /// <summary> /// Service Contract Class - GetProductResponse /// </summary> [WCF::MessageContract(IsWrapped = false)] public partial class GetProductResponse { private MyWCF.EasyNorthwind.DataContracts.Product product; [WCF::MessageBodyMember(Name = "Product")] public MyWCF.EasyNorthwind.DataContracts.Product Product { get { return product; } set { product = value; } } }} In this example, the namespace of the message contract is MyWCF.EasyNorthwind.MessageContracts, and the message contract's name is GetProductResponse. This message contract has one member, which is of type Product. Data contract Data contracts are data types of the WCF service. All data types used by the WCF service must be described in metadata to enable other applications to interoperate with the service. A data contract can be used by an operation contract as a parameter or return type, or it can be used by a message contract to define elements. If a WCF service uses only primitive (native) data types, it is not necessary to define any data contract. The following is an of example data contract: namespace MyWCF.EasyNorthwind.DataContracts{ /// <summary> /// Data Contract Class - Product /// </summary> [WcfSerialization::DataContract(Namespace = "http://MyCompany.com/ ProductService/EasyWCF/2008/05", Name = "Product")] public partial class Product { private int productID; private string productName; [WcfSerialization::DataMember(Name = "ProductID", IsRequired = false, Order = 0)] public int ProductID { get { return productID; } set { productID = value; } } [WcfSerialization::DataMember(Name = "ProductName", IsRequired = false, Order = 1)] public string ProductName { get { return productName; } set { productName = value; } } }} In this example, the namespace of the data contract is MyWCF.EasyNorthwind.DataContracts, the name of the data contract is Product, and this data contract has two members (ProductID and ProductName).   Fault contract In any WCF service operation contract, if an error can be returned to the caller, the caller should be warned of that error. These error types are defined as fault contracts. An operation can have zero or more fault contracts associated with it. The following is a fault contract example: namespace MyWCF.EasyNorthwind.FaultContracts{ /// <summary> /// Data Contract Class - ProductFault /// </summary> [WcfSerialization::DataContract(Namespace = "http://MyCompany.com/ ProductService/EasyWCF/2008/05", Name = "ProductFault")] public partial class ProductFault { private string faultMessage; [WcfSerialization::DataMember(Name = "FaultMessage", IsRequired = false, Order = 0)] public string FaultMessage { get { return faultMessage; } set { faultMessage = value; } } }} In this example, the namespace of the fault contract is MyWCF.EasyNorthwind.FaultContracts, the name of the fault contract is ProductFault, and the fault contract has only one member (FaultMessage). Endpoint Messages are sent between endpoints. Endpoints are places where messages are sent or received (or both), and they define all of the information required for the message exchange. A service exposes one or more application endpoints (as well as zero or more infrastructure endpoints). A service can expose this information as the metadata that clients can process to generate appropriate WCF clients and communication stacks. When needed, the client generates an endpoint that is compatible with one of the service's endpoints. A WCF service endpoint has an address, a binding, and a service contract(WCF ABC). The endpoint's address is a network address where the endpoint resides. It describes, in a standard-based way, where messages should be sent. Each endpoint normally has one unique address, but sometimes two or more endpoints can share the same address. The endpoint's binding specifies how the endpoint communicates with the world, including things such as transport protocol (TCP, HTTP), encoding (text, binary), and security requirements (SSL, SOAP message security). The endpoint's contract specifies what the endpoint communicates, and is essentially a collection of messages organized in the operations that have basic Message Exchange Patterns (MEPs) such as one-way, duplex, or request/reply. The following diagram shows the components of a WCF service endpoint. Behavior A WCF behavior is a type, or settings to extend the functionality of the original type. There are many types of behaviors in WCF, such as service behavior, binding behavior, contract behavior, security behavior and channel behavior. For example, a new service behavior can be defined to specify the transaction timeout of the service, the maximum concurrent instances of the service, and whether the service publishes metadata. Behaviors are configured in the WCF service configuration file. Hosting A WCF service is a component that can be called by other applications. It must be hosted in an environment in order to be discovered and used by others. The WCF host is an application that controls the lifetime of the service. With .NET 3.0 and beyond, there are several ways to host the service. Self hosting A WCF service can be self-hosted, which means that the service runs as a standalone application and controls its own lifetime. This is the most flexible and easiest way of hosting a WCF service, but its availability and features are limited. Windows services hosting A WCF service can also be hosted as a Windows service. A Windows service is a process managed by the operating system and it is automatically started when Windows is started (if it is configured to do so). However, it lacks some critical features (such as versioning) for WCF services. IIS hosting A better way of hosting a WCF service is to use IIS. This is the traditional way of hosting a web service. IIS, by nature, has many useful features, such as process recycling, idle shutdown, process health monitoring, message-based activation, high availability, easy manageability, versioning, and deployment scenarios. All of these features are required for enterprise-level WCF services. Windows Activation Services hosting The IIS hosting method, however, comes with several limitations in the service-orientation world; the dependency on HTTP is the main culprit. With IIS hosting, many of WCF's flexible options can't be utilized. This is the reason why Microsoft specifically developed a new method, called Windows Activation Services, to host WCF services. Windows Process Activation Service (WAS) is the new process activation mechanism for Windows Server 2008 that is also available on Windows Vista. It retains the familiar IIS 6.0 process model (application pools and message-based process activation) and hosting features (such as rapid failure protection, health monitoring, and recycling), but it removes the dependency on HTTP from the activation architecture. IIS 7.0 uses WAS to accomplish message-based activation over HTTP. Additional WCF components also plug into WAS to provide message-based activation over the other protocols that WCF supports, such as TCP, MSMQ, and named pipes. This allows applications that use the non-HTTP communication protocols to use the IIS features such as process recycling, rapid fail protection, and the common configuration systems that were only available to HTTP-based applications. This hosting option requires that WAS be properly configured, but it does not require you to write any hosting code as part of the application. [Microsoft MSN, Hosting Services, retrieved on 3/6/2008 from http://msdn2.microsoft.com/en-us/library/ms730158.aspx] Channels As we have seen in the previous sections, a WCF service has to be hosted in an application on the server side. On the client side, the client applications have to specify the bindings to connect to the WCF services. The binding elements are interfaces, and they have to be implemented in concrete classes. The concrete implementation of a binding element is called a channel. The binding represents the configuration, and the channel is the implementation associated with that configuration. Therefore, there is a channel associated with each binding element. Channels stack on top of one another to create the concrete implementation of the binding—the channel stack. The WCF channel stack is a layered communication stack with one or more channels that process messages. At the bottom of the stack is a transport channel that is responsible for adapting the channel stack to the underlying transport (for example, TCP, HTTP, SMTP and other types of transport). Channels provide a low-level programming model for sending and receiving messages. This programming model relies on several interfaces and other types collectively known as the WCF channel model. The following diagram shows a simple channel stack: Metadata The metadata of a service describes the characteristics of the service that an external entity needs to understand in order to communicate with the service. Metadata can be consumed by the ServiceModel Metadata Utility Tool (Svcutil.exe) to generate a WCF client and the accompanying configuration that a client application can use to interact with the service. The metadata exposed by the service includes XML schema documents, which define the data contract of the service, and WSDL documents, which describe the methods of the service. Though WCF services will always have metadata, it is possible to hide the metadata from outsiders. If you do so, you have to pass the metadata to the client side by other means. This practice is not common, but it gives your services an extra layer of security. When enabled via the configuration settings through metadata behavior, metadata for the service can be retrieved by inspecting the service and its endpoints. The following configuration setting in a WCF service configuration file will enable the metadata publishing for HTTP transport protocol: <serviceMetadata httpGetEnabled="true" />
Read more
  • 0
  • 0
  • 2350

article-image-asterisk-gateway-interface-scripting-php
Packt
16 Oct 2009
4 min read
Save for later

Asterisk Gateway Interface Scripting with PHP

Packt
16 Oct 2009
4 min read
PHP-CLI vs PHP-CGI Most Linux distributions include both versions of PHP when installed, especially if you are using a modern distribution such as CentOS or Mandriva. When writing AGI scripts with PHP, it is imperative that you use PHP-CLI, and not PHP-CGI. Why is this so important? The main issue is that PHP-CLI and PHP-CGI handle their STDIN (standard input) slightly differently, which makes the reading of channel variables via PHP-CGI slightly more problematic. The php.ini configuration file The PHP interpreter includes a configuration file that defines a set of defaults for the interpreter. For your scripts to work in an efficient manner, the following must be set—either via the php.ini file, or by your PHP script: ob_implicit_flush(false); set_time_limit(5); error_log = filename;error_reporting(0); The above code snippet performs the following: Directive Description ob_implicit_flush(false); Sets your PHP output buffering to false, in order to make sure that output from your AGI script to Asterisk is not buffered, and takes longer to execute set_time_limit(5); Sets a time limit on your AGI scripts to verify that they don't extend beyond a reasonable time of execution; there is no rule of thumb relating to the actual value; it is highly dependant on your implementation Depending on your system and applications, your maximum time limit may be set to any value; however, we suggest that you verify your scripts, and are able to work with a maximum limit of 30 seconds. error_log=filename; Excellent for debugging purposes; always creates a log file error_reporting(E_NONE); Does not report errors to the error_log; changes the value to enable different logging parameters; check the PHP website for additional information about this AGI script permissions All AGI scripts must be located in the directory /var/lib/asterisk/agi-bin, which is Asterisk's default directory for AGI scripts. All AGI scripts should have the execute permission, and should be owned by the user running Asterisk. If you are unfamiliar with these, consult with your system administrator for additional information. The structure of a PHP based AGI script Every PHP based AGI script takes the following form: #!/usr/bin/php -q <? $stdin = fopen(‘php://stdin’, ‘r’); $stdout = fopen(‘php://stdout’, ‘w’); $stdlog = fopen(‘my_agi.log’, ‘w’); /* Operational Code starts here */ .. .. ..?> Upon execution, Asterisk transmits a set of information to our AGI script via STDIN. Handling of that input is best performed in the following manner: #!/usr/bin/php -q <? $stdin = fopen(‘php://stdin’, ‘r’); $stdout = fopen(‘php://stdout’, ‘w’); $stdlog = fopen(‘my_agi.log’, ‘w’); /* Handling execution input from Asterisk */ while (!feof($stdin)) { $temp = fgets($stdin); $temp = str_replace("n","",$temp); $s = explode(":",$temp); $agivar[$s[0]] = trim($s[1]); if $temp == "") { break; } } /* Operational Code starts here */ .. .. ..?> Once we have handled our inbound information from the Asterisk server, we can start our actual operational flow. Communication between Asterisk and AGI The communication between Asterisk and an AGI script is performed via STDIN and STDOUT (standard output). Let's examine the following diagram: In the above diagram, ASC refers to our AGI script, while AST refers to Asterisk itself. As you can see from the diagram above, the entire flow is fairly simple. It is just a set of simple I/O queries and responses that are carried through the STDIN/STDOUT data streams. Let's now examine a slightly more complicated example: The above figure shows an example that includes two new elements in our AGI logic—access to a database, and to information provided via a web service. For example, the above image illustrates something that may be used as a connection between the telephony world and a dating service. This leads to an immediate conclusion that just as AGI is capable of connecting to almost any type of information source, depending solely on the implementation of the AGI script and not on Asterisk, Asterisk is capable of interfacing with almost any type of information source via out-of-band facilities. Enough of talking! Let's write our first AGI script.
Read more
  • 0
  • 0
  • 6738

article-image-extending-document-management-alfresco-3
Packt
16 Oct 2009
5 min read
Save for later

Extending Document Management in Alfresco 3

Packt
16 Oct 2009
5 min read
Microsoft Office 2003 add-ins For Microsoft Windows users, a natural way of working with the files is by using the Microsoft Office tools. It would be a tedious job for Content Managers to have to search and locate the documents using an Alfresco web client, copy them onto their local desktop, edit them, upload them to Alfresco, and secure them. How about having all of the features mentioned above in your choice of editor itself? Alfresco provides Office add-ins for MS Word 2003, MS Excel 2003, and MS PowerPoint 2003, to allow them to manage the content directly from those tools. This improves the productivity of Content Managers. Support for Microsoft Office 2007 Although the Alfresco add-ins were developed for Microsoft Office 2003, they are also compatible with Microsoft Office 2007. If you are using Microsoft Office 2007 on Windows Vista, then the add-in is not effective, as it provides read-only access to the repository. Unfortunately, this is a known problem with Vista, as Microsoft has rewritten the WebDAV parts of Vista. You may consider the workarounds that are provided at the following URL: http://blogs.msdn.com/sharepoint/archive/2007/10/19/known-issue-office-2007-on-windows-vista-prompts-for-user-credentials-when-opening-documents-in-a-sharepoint-2007-site.aspx Installation Download the Alfresco office add-ins (ZIP file) from the source forge web site, by visiting the following URL: http://sourceforge.net/project/showfiles.php?group_id=143373&package_id=237030 An individual installer (for Microsoft Word, Excel, and Power Point), as well as a combined installer, is available for download. Select an appropriate add-into download. Unzip the ZIP file and run the Setup.exe file contained within it. The set-up program will download the components that are needed, from the Microsoft web site. Once the set-up is complete, you can open the Office tool and use the add-in. For example, for MS Word 2003, you will notice a new button named Alfresco. For MS Word 2007, you will notice the add-in, as shown in the following screenshot: Configuration Click on the Alfresco button to open the add-in window. You need to configure the add-in, by clicking on the link provided at the bottom of the add-in window. Provide the URL details for the web client, WebDAV, and CIFS, as shown in the upcoming screenshot. No matter how you access the repository, you will still have to go through Alfresco's security rules. Provide the Userid and password for the purpose of authentication. The access to the Alfresco repository will be based on the authorization of the user. Click on the Save Settings button to go the main screen. If you have more than one Alfresco server to connect to, then you might have to manually change the settings as needed. Currently, there is no facility for storing the settings for more than one Alfresco server. Features of MS Word add-in The Alfresco add-in allows you to carry out the following activities directly from Microsoft Word. Refer to the following screenshot for more details: My Alfresco: Displays the My Alfresco dashlets Browse Spaces: Browses the entire repository for spaces and files. Search: Searches the repository for keywords. View Details: Views the details of the selected document. Workflow: Starts workflow for the active document. Tags: Allows you to add tags to the document. Transform to PDF: Transforms the selected MS Word document into PDF. Insert into Word: Inserts the selected document into Microsoft Word for editing. Save to Alfresco: Saves the current document to the current space. If the document has not been given a filename yet, then a pop-up panel will prompt you for one. Editing a file in Word To edit a file in Microsoft Word, double-click on the file name. The file is opened directly for editing. The MS Word file is locked for others, while it is being edited by you, as shown in the upcoming screenshot. You can perform all of the Alfresco repository activities, such as adding new tags and initiating a workflow approval process. Saving the file in Microsoft Word will directly save it in the Alfresco repository. If auto version is enabled, then it will be versioned automatically. When you close the file in MS Word, or exit from MS Word, the file will be unlocked in the repository. Recovering deleted content When you delete an item (either content or space) in Alfresco, the item is not deleted from the server, but is moved to a temporary store called Archive Space Store. This gives you a chance to recover items that were deleted. Deleted items will be kept in the temporary store forever, until you decide to either recover or purge them. These features are available to administrators through the Manage Deleted Items action. To test these features, log in as an administrator, create a couple of dummy files in any space, and then delete them. Click on the User Profile Icon  option, located above the menu item, and then click on the Manage Deleted Items button. The Manage Deleted Items pane appears, as shown in the following screenshot: You can list all of the deleted content by clicking on the Show All button, as highlighted in the preceding screenshot. You can also search for deleted items by name, by content, by date, or by the person who deleted it, by using the search options provided. Select the item that you previously deleted, and then click on the Recover Listed Items icon, as shown in the preceding screenshot. You will notice that the item is recovered to the original space. When an item is recovered, it is removed from the archive space store and moved to the original space from which it was deleted. Purged items are deleted forever and cannot be recovered. Because the deleted items will otherwise be in the temporary store forever, it is a good practice to purge them periodically. It is also recommended that you take regular backups of your data.  
Read more
  • 0
  • 0
  • 2259
article-image-managing-content-through-tagging-grails-part-1
Packt
16 Oct 2009
9 min read
Save for later

Managing Content through Tagging in Grails: Part 1

Packt
16 Oct 2009
9 min read
Add basic tagging Tagging is a loose, community-based way of categorizing content. It allows a group of people to categorize by consensus. Anyone is able to tag a piece of content. The more a tag is used, the more meaning it takes on and the more widely used it becomes. This categorization by consensus has been dubbed as folksonomy (http://en.wikipedia.org/wiki/Folksonomy) So let's get started by building our tagging support. Tagging domain model When implementing tagging in our system, we need to consider the following: We must be able to have many tags in our system We must be able to associate a single tag with many different files and messages We need to make sure that new domain objects can be easily tagged without having to change the tagging logic We want to know when a domain object was tagged To satisfy these requirements, we need to create the following new domain classes: Tag—to store the name of the tag. There is one instance of this class per unique tag name in the application. Tagger—to store the relationship from domain objects to a tag. This allows us to store the date a tag was added to a domain object. Let's create these domain classes and then write a test to prove that we can tag a message using this tagging structure. The Tag class We are going to separate the tagging classes out from our application domain classes. Create a folder under grails-app/domain called tagging. This is where we will put the domain model to implement tagging. Our Tag class is extremely simple and holds only a name property: package taggingclass Tag { String name static constrains = { name( blank: false ) } } The Tagger class The next class that we are going to create is the Tagger class. In relational terms, this object represents a link table between a Tag and any other domain class. It is important that the relationship between tagged domain classes and the Tagger relationship class is unidirectional. By this, we mean the domain classes are allowed to know that they can be tagged, but tags do not know which domain classes can be tagged, otherwise every tagged domain class would need a special relationship class. Create the Tagger class as a domain class in the tagging package as follows: package taggingclass Tagger { Tag tag static constraints = { tag( nullable: false ) }} The basics of our tagging model are complete! We now need some logic to allow tags to be created. Create a new service class called TagService under grails-app/services/tagging, as shown below: package taggingclass TagService { boolean transactional = true def createTagRelationships(String spaceDelimitedTags) { return spaceDelimitedTags?.split(' ')?.collect { tagName -> createTagRelationship( tagName ) }}def createTagRelationship(String tagName) {def tag = Tag.findByName(tagName)?: new Tag(name: tagName).save()return new Tagger( tag: tag )} This service provides two utility methods to create new relationships by tag name or by a space delimited string of tag names. The important behavior of these two methods is that they do not allow duplicate tags to be created in the application. If a tag name already exists, the tag will be retrieved from the database and used as the tag in the relationship. Notice that the createTagRelationships method is using the collect method to simplify what would normally take a few more lines of code to achieve. The collect method is dynamically added to any object that can be iterated over. For example, collections, arrays, strings and so on. It takes a closure as its argument and executes this closure for each item in the collection. The return value from each execution of the closure is added to a new collection that the collect method builds up and then returns once it has finished iterating the original collection. In createTagRelationship, we are using another neat language feature of Groovy called the "Elvis operator". It is named so, as it looks like Elvis' hair style. This is a shorter version of the normal Java ternary operator. If the operand being checked is true then the checked operand will be returned as the default, otherwise the alternative operand will be used. So in our example:     def tag = Tag.findByName(tagName) ?: new Tag(name: tagName).save() If a tag can be found from the database then it is used, otherwise a new tag is created. Tagging a message The next step is to allow a message to be tagged. Write some integration tests to make sure the relationships are working before using tagging in the application. In the folder test/integration/app, create the file TaggableIntegrationTests.groovy and add the following code: package appimport tagging.Tagclass TaggableIntegrationTest extends GroovyTestCase { User flancelot protected void setUp() { flancelot = User.findByUsername('flancelot') Tag.list().each { it.delete() } Message.list().each { it.delete() } }} The code above sets up the test data needed to create messages and associate tags to messages. Remember that the flancelot user already exists because it was created by the BootStrap class. The first test will determine that we can add tags to a message and then retrieve messages by tag. Add the following test method to your test class: void testCanRetrieveMessagesByTags() { Message message = new Message(user: flancelot, title: 'tagged', detail: "I've been tagged.").save(flush: true) Message secondMessage = new Message(user: flancelot, title: 'other tagged', detail: "I've been tagged.").save(flush: true) message.addTag('urgent') message.addTag('late') secondMessage.addTag('urgent') def taggedMessages = Message.withTag( 'urgent' ) assertEquals(2, taggedMessages.size()) assertEquals(2, Tag.list().size()) def secondMessages = Message.withTag( 'late' ) assertEquals(1, secondMessages.size()) assertEquals(2, Tag.list().size())} The test above does the following: Creates two new messages Adds the urgent tag to both messages Adds the late tag to one message Checks if we can retrieve both messages by using the urgent tag Checks if only one message is returned for the late tag Notice that the highlighted lines of code have not been implemented yet. To allow this test to pass, we need to add the following methods to the Message domain class: addTag—instance method to allow a message to be tagged withTag—class method to retrieve all messages with a particular tag Add the following method to the Message class (don't forget to import tagging.Tagger): def addTag(String tagName) { tags = (tags)?:[] tags << tagService.createTagRelationship( tagName )} This method simply delegates the creation of the tag relationship off to the TagService class, and then stores the relationship in the tags list. Add the following method to the Message class that retrieves all messages with a given tag name: def static withTag(String tagName) { return Message.withCriteria { tags { tag { eq('name', tagName ) } } }} This method must be static on the Message class, as it is used to load message instances for a given tag. We do not want to have to instantiate a message before we can perform the search. Before running the test, you will notice both of these new methods assume that there is a property on the Message class called tags. This has not yet been created. We need to create a one-to-many relationship from Message to Tagger that will allow messages to be tagged. We also need to inject the TagService into new instances of the Message class so the work for creating a new tag relationship can be delegated. Add the relationship to the Message class and inject TagService as shown below: class Message { def tagService static hasMany = [tags:Tagger] ...} Now we can run our tests by entering the following on the command line: grails test-app We should see some output in the command line similar to: Running test app.TaggableTest... testCanRetrieveMessagesByTags...SUCCESS Tagging a file Now that we have implemented tagging for messages, we need to make tagging available for files. Currently the logic for creating and fetching tags is in the Message domain class. We need to extract this logic so the File domain class can reuse it. It's time to look at how GORM supports inheritance. GORM inheritance The GORM supports inheritance of domain classes by default through the underlying Hibernate framework. Hibernate has a number of strategies for handling inheritance and Grails supports the following two: Table-per-hierarchy—this strategy creates one database table per inheritance hierarchy. This is the default strategy in Grails. Table-per-subclass—this strategy creates a database table for each subclass in an inheritance hierarchy and treats the inheritance (is a) relationship as a foreign key (has a) relationship. Taking our domain as an example, we have two classes. They are Message and File. We are going to make them both extend a super class Taggable, which will handle all of our tagging logic and state. Table-per-hierarchy If we were to choose the table-per-hierarchy strategy, we would end up with one table called Taggable that contained the data for both Message and File. The database structure would look something like: The interesting side-effect of this approach is that all of the fields to be persisted must be nullable. If a File is created and persisted, it is obviously not possible for the fields from Message to be populated. Table-per-subclass By using the table-per-subclass strategy, we would keep two separate tables called Message and File, and both would have the tags relationship inherited from Taggable. So the Message table will look like: We can see in the diagram above that the Message and File tables have remained separate and a table representing the superclass Taggable has been created, which the subclass tables have foreign key relationships to. In the table-per-subclass strategy, a table must exist to represent the inheritance (is a) relationship. We are going to follow the table-per-subclass strategy so that we can retain database level data integrity. The default behavior for GORM is to use the table-per-hierarchy strategy. To override this we must use the mapping property: static mapping = { tablePerHierarchy false}
Read more
  • 0
  • 0
  • 2050

article-image-find-closest-mashup-plugin-ruby-rails
Packt
16 Oct 2009
10 min read
Save for later

Find closest mashup plugin with Ruby on Rails

Packt
16 Oct 2009
10 min read
Building a kiosk locator feature for your site Your company has just deployed 500 multi-purpose payment kiosks around the country, cash cows for the milking. Another 500 more are on the way, promising to bring in the big bucks for all the hardworking employees in the company. Naturally your boss wants as many people as possible to know about them and use them. The problem is that while the marketing machine churns away on the marvels and benefits of the kiosks, the customers need to know where they are located to use them. He commands you: "Find a way to show our users where the nearest kiosks to him are, and directions to reach them!" What you have is a database of all the 500 locations where the kiosks are located, by their full address. What can you do? Requirements overview Quickly gathering your wits, you penned down the following quick requirements: Each customer who comes to your site needs to be able to find the closest kiosk to his or her current location. He or she might also want to know the closest kiosk to any location. You want to let the users determine the radius of the search. Finding the locations of the closest kiosks, you need to show him how to reach them. You have 500 kiosks now, (and you need to show where they are) but another 500 will be coming, in 10s and 20s, so the location of the kiosks need to be specified during the entry of the kiosks. You want to put all of these on some kind of map. Sounds difficult? Only if you didn't know about web mashups! Design The design for this first project is rather simple. We will build a simple database application using Rails and create a main Kiosk class in which to store the kiosk information including its address, longitude, and latitude information. After populating the database with the kiosk information and address, we will use a geolocation service to discover its longitude and latitude. We store the information in the same table. Next, we will take the kiosk information and mash it up with Google Maps and display the kiosks as pushpins on the online map and place its information inside an info box attached to each pushpin. Mashup APIs on the menu In this article we will be using the following services to create a 'find closest' mashup plugin: Google Maps APIs including geocoding services Yahoo geocoding services (part of Yahoo Maps APIs) Geocoder.us geocoding services Geocoder.ca geocoding services Hostip.info Google Maps Google Maps is a free web-based mapping service provided by Google. It provides a map that can be navigated by dragging the mouse across it and zoomed in and out using the mouse wheel or a zoom bar. It has three forms of views—map, satellite and a hybrid of map and satellite. Google Maps is coded almost entirely in JavaScript and XML and Google provides a free JavaScript API library that allows developers to integrate Google Maps into their own applications. Google Maps APIs also provide geocoding capabilities, that is, they able to convert addresses to longitude and latitude coordinates. We will be using two parts of Google Maps: Firstly to geocode addresses as part of GeoKit's APIs Secondly to display the found kiosk on a customized Google Maps map Yahoo Maps Yahoo Maps is a free mapping service provided by Yahoo. Much like Google Maps it also provides a map that is navigable in a similar way and also provides an extensive set of APIs. Yahoo's mapping APIs range from simply including the map directly from the Yahoo Maps website, to Flash APIs and JavaScript APIs. Yahoo Maps also provides geocoding services. We will be using Yahoo Maps geocoding services as part of GeoKit's API to geocode addresses. Geocoder.us Geocoder.us is a website that provides free geocoding of addresses and intersections in the United States. It relies on Geo::Coder::US, a Perl module available for download from the CPAN and derives its data from the TIGER/Line data set, public-domain data from the US Census Bureau. Its reliability is higher in urban areas but lower in the other parts of the country. We will be using Geocoder.us as part of GeoKit's API to geocode addresses. Geocoder.ca Geocoder.ca is a website that provides free geocoding of addresses in the United States and Canada. Like Geocoder.us. it uses data from TIGER/Line but in addition, draws data from GeoBase, the Canadian government-related initiative that provides geospatial information on Canadian territories. We will be using Geocoder.ca as part of GeoKit's API to geocode addresses. Hostip.info Hostip.info is a website that provides free geocoding of IP addresses. Hostip.info offers an HTTP-based API as well as its entire database for integration at no cost. We will be using Hostip.info as part of GeoKit's API to geocode IP addresses. GeoKit GeoKit is a Rails plugin that enables you to build location-based applications. For this article we will be using GeoKit for its geocoding capabilities in two ways: To determine the longitude and latitude coordinates of the kiosk from its given address To determine the longitude and latitude coordinates of the user from his or her IP address GeoKit is a plugin to your Rails application so installing it means more or less copying the source files from the GeoKit Subversion repository and running through an installation script that adds certain default parameters in your environment.rb file. To install the GeoKit, go to your Rails application folder and execute this at the command line: $./script/plugin install svn://rubyforge.org/var/svn/geokit/trunk This will copy the necessary files to your RAILS_ROOT/vendor/plugins folder and run the install.rb script. Configuring GeoKit After installing GeoKit you will need to configure it properly to allow it to work. GeoKit allows you to use a few sets of geocoding APIs, including Yahoo, Google, Geocoder.us, and Geocoder.ca. These geocoding providers can be used directly or through a cascading failover sequence. Using Yahoo or Google requires you to register for an API key but they are free. Geocoder.us is also free under certain terms and conditions but both Geocoder.us and Geocoder.ca have commercial accounts. In this article I will briefly go through how to get an application ID from Yahoo and a Google Maps API key from Google. Getting an application ID from Yahoo Yahoo's application ID is needed for any Yahoo web service API calls. You can use the same application ID for all services in the same application or multiple applications or one application ID per service. To get the Yahoo application ID, go to https://developer.yahoo.com/wsregapp/index.php and provide the necessary information. Note that for this application you don't need user authentication. Once you click on submit, you will be provided an application ID. Getting a Google Maps API key from Google To use Google Maps you will need to have a Google Maps API key. Go to http://www.google.com/apis/maps/signup.html. After reading the terms and conditions you will be asked to give a website URL that will use the Google Maps API. For geocoding purposes, this is not important (anything will do) but to display Google Maps on a website, this is important because Google Maps will not display if the URL doesn't match. However all is not lost if you have provided the wrong URL at first; you can create any number of API keys from Google. Configuring evironment.rb Now that you have a Yahoo application ID and a Google Maps API key, go to environment.rb under the RAILS_ROOT/config folder. Installing GeoKit should have added the following to your environment.rb file: # Include your application configuration below # These defaults are used in GeoKit::Mappable.distance_to and in acts_as_mappable GeoKit::default_units = :miles GeoKit::default_formula = :sphere # This is the timeout value in seconds to be used for calls to the geocoder web # services. For no timeout at all, comment out the setting. The timeout unit is in seconds. # GeoKit::Geocoders::timeout = 3 # These settings are used if web service calls must be routed through a proxy. # These setting can be nil if not needed, otherwise, addr and port must be filled in at a minimum. If the proxy requires authentication, the username and password can be provided as well. GeoKit::Geocoders::proxy_addr = nil GeoKit::Geocoders::proxy_port = nil GeoKit::Geocoders::proxy_user = nil GeoKit::Geocoders::proxy_pass = nil # This is your yahoo application key for the Yahoo Geocoder # See http://developer.yahoo.com/faq/index.html#appid and http://developer.yahoo.com/maps/rest/V1/geocode.html GeoKit::Geocoders::yahoo = <YOUR YAHOO APP ID> # This is your Google Maps geocoder key. # See http://www.google.com/apis/maps/signup.html and http://www.google.com/apis/maps/documentation/#Geocoding_Examples GeoKit::Geocoders::google = <YOUR GOOGLE MAPS KEY> # This is your username and password for geocoder.us # To use the free service, the value can be set to nil or false. For usage tied to an account, the value should be set to username:password. # See http://geocoder.us and http://geocoder.us/user/signup GeoKit::Geocoders::geocoder_us = false # This is your authorization key for geocoder.ca. # To use the free service, the value can be set to nil or false. For usage tied to an account, set the value to the key obtained from Geocoder.ca # See http://geocoder.ca and http://geocoder.ca/?register=1 GeoKit::Geocoders::geocoder_ca = false # This is the order in which the geocoders are called in a failover scenario # If you only want to use a single geocoder, put a single symbol in the array. # Valid symbols are :google, :yahoo, :us, and :ca # Be aware that there are Terms of Use restrictions on how you can use the various geocoders. Make sure you read up on relevant Terms of Use for each geocoder you are going to use. GeoKit::Geocoders::provider_order = [:google,:yahoo] Go to the lines where you are asked to put in the Yahoo and Google keys and change the values accordingly. Make sure the keys are within apostrophes. Then go to the provider order and put in the order you want (the first will be tried; if that fails it will go to the next until all are exhausted): GeoKit::Geocoders::provider_order = [:google,:yahoo] This completes the configuration of GeoKit. YM4R/GM YM4R/GM is another Rails plugin, one that facilitates the use of Google Maps APIs. We will be using YM4R/GM to display the kiosk locations on a customized Google Map. This API essentially wraps around the Google Maps APIs but also provides additional features to make it easier to use from Ruby. To install it, go to your Rails application folder and execute this at the command line: $./script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm During the installation, the JavaScript files found in the RAILS_ROOT/vendors/plugin/javascript folder will be copied to the RAILS_ROOT/public/javascripts folder. A gmaps_api_key.yml file is also created in the RAILS_ROOT/config folder. This file is a YAML representation of a hash, like the database.yml file in which you can set up a test, development, and production environment. This is where you will put in your Google Maps API key (in addition to the environment.rb you have changed earlier). For your local testing you will not need to change the values but once you deploy this in production on an Internet site you will need to put in a real value according to your domain.
Read more
  • 0
  • 0
  • 2386
Modal Close icon
Modal Close icon