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

How-To Tutorials

7019 Articles
article-image-email-languages-and-jfile-joomla
Packt
21 Oct 2009
13 min read
Save for later

Email, Languages, and JFile with Joomla!

Packt
21 Oct 2009
13 min read
Sending emails Joomla!'s core content management has a built-in feature where visitors are able to send articles to their friends through email. A similar feature can be added to the "Restaurant Reviews" component. The component can be modified to display a link to a form where the email address of a friend can be entered along with a short message. We will create a new view to handle this form. Go to the /components/com_restaurants/views folder of your Joomla! component and create a new folder named email. In this folder, create a file called view.html.php, and load it with the following code: <?phpdefined( '_JEXEC' ) or die( 'Restricted access' );jimport( 'joomla.application.component.view');JTable::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR . DS . 'tables');class RestaurantsViewEmail extends JView{ function display($tpl = null) { $id = JRequest::getInt('id', 0); $review =& JTable::getInstance('review', 'Table'); $review->load($id); $this->assignRef('review', $review); parent::display($tpl); }} This code first checks to make sure that the file is not being called directly, loads in the framework code for views, and adds /administrator/components/com_restaurants/tables to the include path list of JTable. After declaring RestaurantsViewEmail as an extension of JView, the display() function pulls in the restaurant review ID from the request. The getInstance() member function of JTable is used to get a reference to a table object for reviews. The review matching the ID is then loaded and assigned to the template using the assignRef() member function. Finally, JView's original display() member function is called. Although the code in view.html.php now loads the review that our visitors are trying to email, the form still needs to be added. Create a folder named tmpl in the existing /components/com_restaurants/views/email folder, and create a new file default.php inside it with the following code: <?php defined( '_JEXEC' ) or die( 'Restricted access' ); ?><form action="index.php" method="post"> <div class="contentheading">Email review</div> <p>&nbsp;</p> <p>Fill this form to send this review of <em> <?php echo htmlspecialchars($this->review->name) ?> </em> to someone you know who will find it useful:</p> <div> <strong>Your name:</strong> </div> <p> <input type="text" name="sender_name" value="" /> </p> <div> <strong>Your email address:</strong> </div> <p> <input type="text" name="sender_email" value="" /> </p> <div><strong>Recipient's email address:</strong></div> <p> <input type="text" name="recipient" value="" /> </p> <div><strong>Message:</strong></div> <p> <textarea name="message" rows="4" cols="40"></textarea> </p> <p> <input type="submit" value="Send Review" class="button" /> </p> <?php echo JHTML::_( 'form.token' ); ?> <input type="hidden" name="id" value= "<?php echo $this->review->id; ?>" /> <input type="hidden" name="task" value="sendemail" /> <input type="hidden" name="option" value= "<?php echo $option; ?>" /></form> Before any output occurs, the code checks to make sure that the request is coming from within Joomla! and is not being called directly. The file then outputs a brief message identifying the review by name, so that the visitors are sure of what they are sending. The form then continues with fields for the visitor's name and email address, the email address of their friend, and an optional message. Just after the submit button, there is a series of hidden fields. First, JHTML::_('form.token') is called to generate a token for the request. This is the same style of token as is used in the backend to thwart CSRF attacks, only here it is used to cut down on abuse. Next, the ID of the review being emailed is placed into the form. The task variable is set to sendemail, which is a function that we will add to the controller in a moment. Finally, option is set, so that Joomla! loads the com_restaurants component. Linking the form If you now load index.php?option=com_restaurants&view=email in your browser, you will see this screen: The message at the top of the screen is incomplete as we simply loaded the view without a review id. Although we could add id as a parameter onto the end of the URL, our visitors will not be doing this. They will need a link to follow from the review itself. To add this link, we need to make some small adjustments to the single view. This view first needs to generate URLs to the email view with the ID already included. Do this by making the following highlighted adjustment to the display() function in /components/com_restaurants/views/single/view.html.php: $date = JHTML::Date($review->review_date);$backlink = JRoute::_('index.php?option=com_restaurants');$emaillink = JRoute::_('index.php?option=com_restaurants&view=email&id=' . $id);$user =& JFactory::getUser();$comments =& $this->get('Comments');$this->assign('display_comments', $params->get('display_comments', '1'));$this->assignRef('review', $review);$this->assignRef('smoking', $smoking);$this->assignRef('date', $date);$this->assignRef('backlink', $backlink);$this->assignRef('emaillink', $emaillink);$this->assignRef('name', $user->name);$this->assignRef('comments', $comments);parent::display($tpl); With a URL to the email view now being generated, we now need to display it. Open /components/com_restaurants/views/single/tmpl/default.php and add the following highlighted code: <p><?php echo htmlspecialchars($this->review->review); ?></p><p><em>Notes:</em> <?php echo htmlspecialchars($this->review->notes); ?></p><p><a href="<?php echo htmlspecialchars($this->emaillink); ?>">Email this to a friend</a></p><a href="<?php echo htmlspecialchars($this->backlink); ?>">&lt; return to the reviews</a> After saving the files, navigate to one of the restaurant reviews in the frontend. Your screen should now have an Email this to a friend link, like the following screenshot: When you click on the Email this to a friend link, you will get a screen that looks like the following: Sending email With the form and the navigation in place, we can now focus on creating the function that creates the email and sends it to the correct place. Throughout the creation of this component, we have used member functions of JRequest to filter our input. We will do the same here, but go one step further by verifying that the mail addresses entered are valid. This extra step is necessary as malicious users can otherwise add invalid newline characters to your email fi elds, taking control of the message sending process. Once a remote user has control, the message can be sent anywhere with any text. This is known as an "Email Header Injection attack". If you fail to protect your website against this type of attack, your component could be hijacked and used to send thousands of spam messages without your knowledge. With this caution in mind, we will write the sendemail() function to process the form and send the review. Open /components/com_restaurants/restaurants.php and add this function to the controller class: function sendemail(){ JRequest::checkToken() or jexit( 'Invalid Token' ); JTable::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR . DS . 'tables'); $sender_email = JRequest::getString('sender_email', ''); $recipient = JRequest::getString('recipient', ''); $sender_name = JRequest::getString('sender_name', ''); $message = JRequest::getString('message', ''); $id = JRequest::getInt('id', 0); jimport( 'joomla.mail.helper' ); if (!JMailHelper::isEmailAddress($sender_email) || !JMailHelper::isEmailAddress($recipient)) { JError::raiseError(500, 'One of the emails you entered is invalid. Please try again.'); } $review =& JTable::getInstance('review', 'Table'); $review->load($id); $link = JURI::base() . 'index.php?option=com_restaurants&view= single&id=' . $id; $subject = $sender_name . ' wants you to know about ' . $review->name; $body = "Here's a review of {$review->name}:nn"; $body .= "{$review->review}nn"; if ($message != '') { $body .= $sender_name . " also added this message:n"; $body .= '"' . $message . '"' . "nn"; } $body .= "For all of the details, follow this link: {$link}"; $sender_name = JMailHelper::cleanAddress($sender_name); $subject = JMailHelper::cleanSubject($subject); $body = JMailHelper::cleanBody($body); if (JUtility::sendMail($sender_email, $sender_name, $recipient, $subject, $body) !== true) { JError::raiseNotice( 500, 'Email failed.' ); } JRequest::setVar('view', 'email'); JRequest::setVar('layout', 'success'); $this->display();} Before even checking the variables, the checkToken() member function of JRequest is called to make sure that the user actually loaded the form. Although this will not prevent spammers from abusing your component, it will slow them down; they will need to load your form and extract the token for each message. Next, the path /administrator/components/com_restaurants/tables is added to the list of paths JTable will use to find table classes. This is necessary because we will be loading the review in a moment, in order to extract the summary and title. The email address of the sender, the address of the recipient, the name of the sender,any added message, and the review's ID are all extracted from the HTTP request.With the exception of the id field, all fields are filtered as strings. The id field is more stringently filtered to ensure that the value is also an integer. Joomla! has a library for handling email data, which we pull in by calling jimport( 'joomla.mail.helper' );. This is used immediately to ensure that the entered email addresses are in a valid format. Both the sender's address and the recipient's address are tested. If either one is in an invalid format or contains newlines, the raiseError() member function of JError is used to stop the script and display a message. The function continues by generating some review-specific data. The review is loaded from the database, and then a link back to the review is built using the review's ID. A subject line is built with the sender's name and the name of the restaurant. The body of the email starts with the name of the review, followed by the review itself. If the visitor added a personal message then this is added, along with their name. The link to the full review is added at the end. With all of the content generated, there is one step left before sending the message. The formats of the email addresses have already been validated, but the sender's name, subject, and body all contain user-supplied data. These must be filtered before they are sent off. The cleanAddress(), cleanSubject(), and cleanBody() member functions of JMailHelper strip out any attempts at email header injections. Finally, the sendMail() member function of JUtility is called to send the email with the sender's address, sender's name, recipient's email address, subject line, and body as the respective parameters. If this function fails for any reason, the raiseError() member function of JError is called and processing stops. Adding a success message When you perform an action that sends an email, most web applications will display an "email success" screen letting you know that the message went through. Our component will be no different. At the end of the sendemail() function, we set the view request variable to email, set the layout request variable to success, and then call the display() member function that defaults to JView::display(). Why aren't we calling $this->setRedirect()?Typically, $this->setRedirect() would be called to tell the controller to redirect the user to a specific page. This time, we have chosen to instead set the request variables and call the display() function directly. This prevents Joomla! from sending a redirect HTTP header to the browser, which ultimately saves another trip to the server. Because we want to display a message instead of going back to the review straight away, this makes sense. It may also be useful in cases where you have a client-side application that would otherwise be confused by a redirect. Instead of creating an entirely separate view to handle the success screen, we have opted instead to set the layout request variable and point back to the email view. This helps us to cut down on the number of views required, and allows us to reuse some of the view code. To add the markup for the success screen, we need to create a new file called success.php to the tmpl folder of the email view. Enter the code below in success.php: <?php defined( '_JEXEC' ) or die( 'Restricted access' ); ?><div class="componentheading">Success!</div><p>The review for <?php echo htmlspecialchars($this->review->name) ?> has been successfully emailed.</p><p><a href="<?php echo htmlspecialchars($this->reviewlink) ?>">Return to the review for <?php echo htmlspecialchars($this->review->name) ?>.</a></p> After checking to make sure that the request to success.php is coming from within Joomla!, a confirmation message, including the name, of the review is displayed. A link back to the review is also output. However, the URL for this link has not yet been generated. To do this, go to /components/com_restaurants/views/email/view.html.php and add the highlighted code to the display() function: $review->load($id);$reviewlink = JRoute::_('index.php?option=com_restaurants&view= single&id=' . $id);$this->assignRef('review', $review);$this->assign('reviewlink', $reviewlink);parent::display($tpl); Save all of your code, then load one of the reviews and click on the Email this to a friend link. Fill the form and click the Send Review button. If the email goes through correctly, you should see a screen like the following: If you sent the review to yourself, the email should look similar to the following: Here's a review of The Daily Dish: Chicken fried steak, meatloaf, potatoes, string beans and hot turkey sandwiches are all favorites from this venerable institution the locals swear by. Apple, pumpkin, and pecan pies round out the dessert selection.Dinner there won't break the bank, either. Ralph Elderman also added this message:"You should really try this place sometime. I take the family there every week!" For all of the details, follow this link: http://localhost/index.php?option=com_restaurants&view=single&id=2
Read more
  • 0
  • 0
  • 4833

article-image-installing-and-using-openfire
Packt
21 Oct 2009
6 min read
Save for later

Installing and Using Openfire

Packt
21 Oct 2009
6 min read
The Openfire instant messaging server is very easy to install. In fact, it's totally newbie-proof. So much so, that unlike other complex server software, even if you've never setup up Openfire before, you'll be able to get it up and running on your first try. If you're sceptical, by the time we are done with this short article, we'll have ourselves a fully-functional Openfire server that will register users and connect with clients. Preparing Your System Openfire is a cross-platform server and can be installed under Linux, Solaris, Mac, or Windows operating system environments. Openfire reserves its enormity for its users. When it comes to system requirements, Openfire is very suave and a perfect gentleman who has very moderate demands. You don't need to spend much time preparing your system for installing Openfire. Just pick out the environment you're comfortable with—Windows or one of the popular Linux distributions such as Fedora, Debian, or Ubuntu, and you're good to go. You don't have to run around getting obscure libraries or worry about mismatched versions. But like any hard-working gentleman, Openfire has a thing for caffeine, so make sure you have Java on your system. No need to run to the kitchen—this isn't the Java in the cupboard. Openfire is written in the Java programming language, so it'll need a Java Runtime Environment (JRE) installed on your system. A JRE creates a simple (breathable, so to say) environment for Java applications to live and function in. It's available as a free download and is very easy to install. If you're installing under Windows, just skip to the "Installing Under Windows" section later in the article. Linux Users Get Your Cuppa! Sun's Java Runtime Environment is available as a free download from Sun's website (http://www.java.com/en/download/linux_manual.jsp) or it can also be installed from your distribution's software management repositories. Users of RPM-based systems can safely skip this section because the Openfire installer for their distribution already includes a JRE. On the other hand, users of Debian-based systems such as Ubuntu will have to install the JRE before installing Openfire. Thanks to the popular apt-get package management system, there isn't much to installing the JRE. Because Sun's JRE isn't free and is also not an open source software, most Linux distributions make the JRE package available in their non-free tree. If the following command doesn't work, check out the detailed installation instructions for your specific distribution, at  https://jdk-distros.dev.java.net. Open a console and issue the following command: $ sudo apt-get install sun-java6-jre Now the apt-get system will automatically fetch, install, and activate the JRE for you! Meet The Protagonists This article is about making sure that you have no trouble installing one file. This one file is the Openfire installer and it is available in multiple flavors. The four flavors we're concerned with aren't as exotic as Baskin Robbins' 31 flavors but that doesn't make the decision any easier. The Openfire project releases several installers. The four flavors we're concerned with are: Openfire-3.5.2-1.i386.rpm: RPM package for Fedora Linux and other RPM-based variants Openfire_3.5.2_all.deb: DEB package for Debian, Ubuntu Linux and their derivates Openfire_3_5_2.tar.gz: Compressed "tarball" archive that'll work on any Linux distribution Openfire_3_5_2.exe: Openfire installer for Windows We'll cover installing Openfire from all of these files, so that you may use Openfire from your favorite Linux distribution or from within Windows. Just to reiterate here, the Windows installer and the RPM Linux installer both bundle the JRE, while the other other versions do not. The Actual Install-Bit Alright, so you have the Java JRE setup and you've downloaded the Openfire installer. In this section, we'll install Openfire server from the various versions we discussed in the last section. Let's first install from the source tarball. The first step when dealing with .tar.gz source archive is to extract the files. Let's extract ours under /tmp and then move the extracted directory under /opt. # tar zxvf openfire_3_5_2.tar.gz# mv openfire /opt Now we'll create a non-priviledged user and group for running Openfire. # groupadd openfire# useradd -d /opt/openfire -g openfire openfire Next, we'll change ownership of the openfire/directory to the newly-created user and group. # chown -R openfire:openfire /opt/openfire Believe it or not, that's it! You've just installed Openfire server. Surprised? Get ready for more. It gets even simpler if you install using the precompiled RPM or DEB binaries. In the case of RPM, Openfire is installed under /opt/openfire and in case of the DEB file, Openfire resides under /etc/openfire. On RPM-based systems such as Fedora and its derivates (as root), use: # rpm -ivh openfire-3.5.2-1.i386.rpm On DEB-based systems such as Debian, Ubuntu, and so on, use: $ sudo dpkg -i openfire_3.5.2_all.deb Voila! You're done. Now, who thought my "installing Openfire is totally newbie-proof" comment was an exaggeration? Running Openfire on Linux/Unix So, we now have Openfire on our favourite Linux distribution, whichever distribution this may be. Now it's time to fire it up and get going. Depending on how you installed Openfire, the procedure to start it varies a little. If you've installed Openfire from the RPM or DEB, you'll be pleased to know that the Openfire developers have already done most of the hard work for you. These binaries contain some custom handling for the RedHat/Debian-like environments. You can start and stop Openfire just like any other service on your system: # /etc/init.d/openfire startStarting Openfire: You can also view the other options available: # /etc/init.d/openfireUsage /etc/init.d/Openfire {start|stop|restart|status|condrestart|reload} On the other hand, if you've installed Openfire using the .tar.gz archive, you can start and stop Openfire using the bin/openfire script in your Openfire installation directory. First, change to the user that owns the /opt/openfire directory: # su - openfire# cd /opt/openfire/bin/# ./openfire startStarting Openfire And now you have Openfire up and running! If you are using a firewall, which you most probably are, make sure to forward traffic on ports 5222 and 5223 (for SSL) which clients use for connecting with the Openfire server. Also forward traffic on port 7777 for file transfer. Linux users can skip the next section on installing Openfire under Windows and move directly to the section that discusses the preliminary Openfire setup.
Read more
  • 0
  • 0
  • 5933

article-image-creating-pseudo-3d-imagery-gimp-part-2
Packt
21 Oct 2009
6 min read
Save for later

Creating Pseudo-3D Imagery with GIMP: Part 2

Packt
21 Oct 2009
6 min read
The next step would be to play around with Layer Modes which, I believe, is one of the most exciting aspects of graphic design. Let's leave layer “lower shine” for awhile and let's get back to layer “upper shine”, and change its layer mode to make it look more appealing and following a scheme in accordance to the color of the sphere. To do this, let's select “upper shine” layer on the Layers Window and right above the Opacity Slider is a dropdown menu containing lots of interesting layer modes, each having its own distinct advantages. You can play around and choose whichever suits your vision the best. I chose Overlay for that matter. Ever since I've started GIMPing, this layer mode has been my best friend for a couple of years already, it works like a charm most of the time.  I wonder though why on some applications, applying the overlay layer mode does different results.  As in the case of Photoshop, the closest I could get with GIMP's overlay is the Screen mode.  You've got to play around a bit and see which works best for you. Do the same thing for the “lower shine” layer, choosing Overlay as the layer mode.  Then, whenever you see fit, you can duplicate the layers to achieve a multiplied effect of the mode. I did that because it felt that something was still missing in the luminous aspect of the shine. So I selected each layer, duplicated them both and voila. To duplicate a layer, you can either right click on the layer name and choose Duplicate Layer from the choices or just press the Duplicate Button on the bottom part of the Layers Window. Duplicated Layers Next, we'll add additional highlights to better emulate specular reflections. And again, we're exploiting the Ellipse Select Tool and another new technique called Feathering. I don't know exactly the definition of feathering in CG, but as far as my experience goes, feathering is a technique from sets of tools where you soften the edges of a selection creating a subtle transition and blurred edges. Create a new layer at the top of the layer stack and call it “blurred shine”, then give it a Layer Fill Type of Transparency, just like what we did with the previous layers.  And with layer 'blurred shine” active, let's create an elliptical selection on the upper left hand part of the sphere, just where the sharp shine has been cast. Creating the Specular Selection With the selection active, right click on the Image Window and choose Select > Feather, then input a value for the feather and the unit to be used. I used 50 pixels. You might have noticed now that the selection seemed to have become smaller, and that's alright, that means you've done it right.  And with the marching ants still active, grab the Bucket Fill Tool over at the Toolbox Window or press SHIFT + B to activate it. Change your foreground color to something close to white or simply pure white, then with the Bucket Fill Tool active, click on the active selection. Tadaaaa! You just created a replica of a specular highlight, though not so close enough. What's great about feathering selections as opposed to applying a blur filter is that you only blur the selection border and not the entire selection. So, say, you have a picture of yourself and you wanted your face fade out smoothly on a vast landscape that you have photographed. Simply create a selection around your face, then apply a Feather to that selection, invert the selection and delete the outer parts, thus leaving only your face and the landscape behind (supposing you have your picture on a separate layer above the landscape layer.) Feathering the Selection Applying the Color with the Bucket Fill Whew, that was pretty quick, isn't it? I hope you agree with me on that.  If so, let's create another one, though smaller and placed just on the left of the blurred shine.  Create a new layer for this new blurred shine and name it “small blurred shine”.  Follow the same procedure for the feathering and color-filling. I used the same feather value for the smaller selection (even though it obviously is smaller), just so it almost affects the center of the selection, blurring the whole selection already, which is what I like for this part. And then, just like what we did with the upper and lower shine respectively, we'll change the Layer Modes to Overlay and duplicate the layers as we see fit.  Doing so results in this image: Blurred Shines Overlay Our sphere now looks a lot better than it had been when we first added its color. However, the shading still looks a bit flat and volumeless. To deal with that, we'll simulate the strength with which the light diffused our sphere object, creating deeper shadows on the opposite side of the light source. Duplication of layers is not only a matter of multiplying the effects of layer effects or such, but it can also be a good way to trace your changes, or better yet, as safe backups where working on the duplicate doesn't affect the original one and you can go back each time to the untouched layer anytime you want to see the differences that have been made.  But be careful though, the more layers and contents of each layer you have, the more computing memory will be consumed and will eventually cause a system slow down. Let's select the “sphere” layer and duplicate in once.  Automatically, the duplicate layer which is now named “sphere copy” becomes the active layer.  Right Click on “sphere copy” layer and choose Alpha to Selection to create a selection out of the fully opaque sphere. Next step is to shrink the selection such that we create a smaller elliptical selection inside the sphere.  To do this, right click on the Image Window and choose Select > Shrink.  Then on the pop up window that appears, type in an appropriate value for the shrinking. I chose 50 pixels. Shrinking the Selection Shrinked Selection Remember how we moved the selection last time? I believe you do. To translate/move our selection, grab the Ellipse Select Tool and activate the selection by clicking on it (clicking the middle portion of the selection makes this easier) until you see your cursor change into crossed arrows, this means you have just activated the move tool for the selection. And since the light is coming from the upper left direction, we would want to move the selection over to the location where the specular reflections are and where the lightest shading is.  Thats because later on, we'll be using this same selection to create shadows on the opposite side of the shade.  Now go ahead and drag the selection over to the upper left portion of the sphere.
Read more
  • 0
  • 0
  • 3995

article-image-creating-pseudo-3d-imagery-gimp-part-1
Packt
21 Oct 2009
9 min read
Save for later

Creating Pseudo-3D Imagery with GIMP: Part 1

Packt
21 Oct 2009
9 min read
In the previous article I've written ( Creating Convincing Images with Blender Internal Renderer-part1), I discussed about creating convincing 3D still images through color manipulation, proper shadowing, minimal lighting, and a bit of post-processing, all using but one application – Blender. This time, the article you're about to read will give us some thoughts on how to mimic a 3D scene with the use of some basic 2D tools. Here again, I would stress that nothing beats a properly planned image, that applies to all genres you can think of. Some might think it's a waste of precious time to start sitting and planning without having a concrete output at the end of the thought process. But believe me, the ideas you planned will be far more powerful and beautiful than those ideas you just had, when you were just messing around and playing with the tool directly. In this article, I wouldn't be teaching you how to paint since I'm not good at it, rather I'll be leading you through a series of steps on how to digitally sketch/draw your scenes, give them subtle color shifts, add fake lighting, and apply filter effects to further emulate how 3D does its job. Primarily, this all leads you into a guide on how I create my digital drawings (though I admit they're not the best of its kind), but somehow I'm very proud, I eventually gave life to them from concept stage to digital art stage. It might be a bit daunting at first, but as you go along the series, you'll notice it gets simpler.  However, some might get confused as to how this applies to other applications since we're focusing on The GIMP in this article. That's not a problem at all once you are familiar with your own tool; it will just be a matter of working around the tools and options. I have been using The GIMP for a long time already, and as far as I can remember, I haven't complained on its shortcomings since those shortcomings are only but bits of features which I wouldn't be need at all.  So to those of you who have been and are using other image editing programs like Adobe Photoshop, Corel, etc., you're welcome to wander around and feel free to interpret some GIMP tools to that of yours.  It's all the same after all, just a tad bit difference on the interface. Just like what Jeremy Birn has said on one of his books: “Being an expert user of a 3D Program, bit itself, does not make the user into an artist more than learning to run a Word Processor makes someone into a good writer.” Additionally, one vital skill you have to develop is the skill of observation, which I myself ham yet to master. Methods Used Basic Drawing Selection Addition, Subtraction, Intersection Gradient Coloring Color Mixing Layering Layer Modes Layer Management Using Filters Requirements Latest version of The GIMP (download at http://www.gimp.org/downloads) Basic knowledge of image editing programs with layering capabilities Patience Let's Get Started! I would already assume you have the latest version of GIMP installed on your system and is running properly, otherwise, fix the problem or ask help from the forum (http://www.gimptalk.com). I'm also assuming you have all your previous tasks done before sitting down and going over this article (which I'm pretty much positive you are). And then lastly, be patient. Sketch it out The very first thing we're going to do is to sketch our ideas for the image, much like a single panel of a storyboard. It doesn't matter how good you draw it as long as you understand it yourself and you know what's going on in the drawing. This time, you can already visualize and create a picture of your final output and it's great if you did, if not, it's fine still. The important thing is we have laid down our scene one way or another. You can take your time sketching out your scenes and adding details to them like how many objects are seen, how many are in focus, what colors do they represent, how are your characters' facial expressions, what is the size of your image, etc. So just in case we forgot how it's going to look like in the end, we have a reference to call upon and that is your initial sketch. This way, you'll also be affected by the persistence of vision where after hours and hours (yay!) of looking on your sketch, you somehow see an afterimage of what you are about to create, and that's a good thing! I'm not good at sketching so please bear with my drawing: After this, it's now time to open up The GIMP and begin the actual fun part! First Run After executing GIMP, this should (and most likely) be the initial screen that's going to be displayed on your screen: The GIMP Initial Screen We don't want Wilbur (GIMP's Mascot) to be glaring at us from a blank empty window all the time, do we? And right now we could go ahead and add a canvas with which we'll be adding our aesthetic elements into, but before that you might want to inspect your application and tool preferences just to make sure you have set everything right. Activate the window with the menu bar at the top (since we currently have three windows to choose from), and then locate Edit > Preferences, as seen below: Locating GIMP's Preferences GIMP Preferences Everything you see here should be self-explanatory, if it isn't, just leave it for the moment and check the manual later, since I'm pretty much sure that thing you didn't understand on the Preferences must be something we will not use here.  So go ahead and save whatever changes you did and sometimes, GIMP might ask you to restart the application for the changes to take effect, then do what she says and we should be back on the black canvas shortly after application restart. By now, we should be having three windows, the main Toolbox Window (located on the left), the main Image Window (located on the middle), and the Layers Window (located on the right).  If, by any chance, the Layer Window is not there, go ahead and activate the Image Window and go to Windows > Layers or press CTRL + L to bring up the Layer Window. Showing the Layers Window Creating the Canvas Now that everything's set up, we'll go ahead and add a properly-sized canvas that we'll paint on, which will be the entire universe for our creation at a later stage. Let's go and create than now by going to File > New or by pressing CTRL+ N. A window will pop up asking you to edit and confirm the image settings for the canvas you're creating. You can choose from a variety of templates to use or you can manually input sizes (which we are going to do).  Before that, change the unit for coordinate display to inches just so we could have a better visual reference of how big our drawing canvass will be. Then on the Width input box, type 9 (for nine inches), and for the Height input box, type 6 (for six inches) respectively. This, however, is a very subjective portion, since you can just have any size you prefer, I just chose nine inches by six inches for the purposes of this article. Clicking the Advanced Options drop-down menu will reveal more options for you.  But right now, we'll never deal with that, just the width and height are sufficient for what we'll be need. When you're done setting up the dimensions and settings, click OK to confirm (is there a chance we could chance the OK buttons to “Alright” buttons, which sounds, uhmmm, better). Creating a New Image At this moment, we should be seeing a blank canvas with the dimensions that we've set awhile back. Then just at the right window (Layers Window), you'll notice there's already one layer present as compared to the default which is none. So everytime we add a new layer (which is very vital), we'll be referencing them over to the Layers Window. Since the creation of the layering system in image editors, it has been a blast to organize elements of an image and apply special effects on them as necessary. We can imagine layers as transparent sheets overlaying each other to form one final image; one transparent sheet can have a landscape drawn, another sheet contains trees and vegetation, and another sheet (which is above the tree sheets) is our main character. So together, we see a character with trees on a landscape in one. But as far as traditional layering is concerned, digital layering has been far more superior in terms of flexibility and the amount of modes we can experiment with. New Image with Layer This time might be a good idea to save our file natively, by that I mean save it in a format that is recognizable only by GIMP and that is lossless in format, so whether we save it a couple of times as such, no image compression happens and the image quality is not compromised. However, the native format is only related to GIMP and is not known elsewhere, so uploading such file to your website will show no image at all because it isn't recognized by the browser. In order to make it generally compatible, we export our image to known formats like JPEG, PNG, GIF, etc. depending on your need. Saving an image file on its native format preserves all the options we have like selections, paths, layers, layer modes, palettes, and many more. This native format that GIMP uses is known as .XCF which stands for “eXperimental Computing Facility”. Throughout this article, we'll save our files mainly in .xcf format and later on, when our tasks are done and we call our image finished, that's the time we export it to a readable and viewable format. Let's go ahead and save our file by going to File > Save, or by pressing CTRL + S. This brings up a window that we can type our filename into and browse and create the location for our files. Type whatever filename you wish and append the “.xcf” file extension at the end of the filename, or you can choose “GIMP xcf image” from a list on the lower half of the window. Saving an Image as XCF
Read more
  • 0
  • 1
  • 7704

article-image-facebook-application-development-ruby-rails
Packt
21 Oct 2009
4 min read
Save for later

Facebook Application Development with Ruby on Rails

Packt
21 Oct 2009
4 min read
Technologies needed for this article RFacebook RFacebook (http://rfacebook.rubyforge.org/index.html) is a Ruby interface to the Facebook APIs. There are two parts to RFacebook—the gem and the plug-in. The plug-in is a stub that calls RFacebook on the Rails library packaged in the gem. RFacebook on Rails library extends the default Rails controller, model, and view. RFacebook also provides a simple interface through an RFacebook session to call any Facebook API. RFacebook uses some meta-programming idioms in Ruby to call Facebook APIs. Indeed Indeed is a job search engine that allows users to search for jobs based on keywords and location. It includes job listings from major job boards and newspapers and even company career pages. Acquiring candidates through Facebook We will be creating a Facebook application and displaying it through Facebook. This application, when added into the list of a user's applications, allows the user to search for jobs using information in his or her Facebook profile. Facebook applications, though displayed within the Facebook interface, are actually hosted and processed somewhere else. To display it within Facebook, you need to host the application in a publicly available website and then register the application. We will go through these steps in creating the Job Board Facebook application. Creating a Rails application Next, create a Facebook application. To do this, you will need to first add a special application in your Facebook account—the Developer application. Go to http://www.facebook.com/developers and you will be asked to allow Developer to be installed in your Facebook account. Add the Developer application and agree to everything in the permissions list. You will not have any applications yet, so click on the create one link to create a new application. Next you will be asked for the name of the application you want to create. Enter a suitable name; in our case, enter 'Job Board' and you will be redirected to the Developer application main page, where you are shown your newly created application with its API key and secret. You will need the API key and secret in a while. Installing and configuring RFacebook RFacebook consists of two components—the gem and the plug-in. The gem contains the libraries needed to communicate with Facebook while the plug-in enables your Rails application to integrate with Facebook. As mentioned earlier, the plug-in is basically a stub to the gem. The gem is installed like any other gem in Ruby: $gem install rfacebook To install the plug-in go to your RAILS_ROOT folder and type in: $./script/plugin install svn://rubyforge.org/var/svn/rfacebook/trunk/rfacebook/plugins/rfacebook Next, after the gem and plug-in is installed, run a setup rake script to create the configuration file in the RAILS_ROOT folder: $rake facebook:setup This creates a facebook.yml configuration file in RAILS_ROOT/config folder. The facebook.yml file contains three environments that mirror the Rails startup environments. Open it up to configure the necessary environment with the API key and secret that you were given when you created the application in the section above. development: key: YOUR_API_KEY_HERE secret: YOUR_API_SECRET_HERE canvas_path: /yourAppName/ callback_path: /path/to/your/callback/ tunnel: username: yourLoginName host: www.yourexternaldomain.com port: 1234 local_port: 5678 For now, just fill in the API key and secret. In a later section when we configure the rest of the Facebook application, we will need to revisit this configuration. Extracting the Facebook user profile Next we want to extract the user's Facebook user profile and display it on the Facebook application. We do this to let the user confirm that this is the information he or she wants to send as search parameters. To do this, create a controller named search_controller.rb in the RAILS_ROOT/app/controllers folder. class SearchController < ApplicationController before_filter :require_facebook_install layout 'main' def index view render :action => :view end def view if fbsession.is_valid? response = fbsession.users_getInfo(:uids => [fbsession.session_user_id], :fields => ["current_location", "education_history", "work_history"]) @work_history = response.work_history @education_history = response.education_history @current_location = response.current_location endend
Read more
  • 0
  • 0
  • 3936

article-image-comparing-asterisk-and-openser
Packt
21 Oct 2009
4 min read
Save for later

Comparing Asterisk and OpenSER

Packt
21 Oct 2009
4 min read
Introduction If you work with IP telephony, it's quite possible that you have not heard about OpenSER, but certainly you must have heard about Asterisk. Well, I love a polemic headline and I have seen this question asked in the forums many times.  So, I will dare to compare these two very popular softwares dedicated to the VoIP market.  The idea here is not to show you which one is the best, but mainly how they are different from each other. Below is a comparison topic by topic. Architecture Asterisk is a Back to Back User Agent (B2BUA), while OpenSER is a Session Initiation Protocol (SIP) Proxy.  This makes all the difference between them. The SIP proxy architecture is faster than a B2BUA because it deals only with signaling. On the other hand, the B2BUA architecture, even being slower, handles the media and it is capable of several services not available in a SIP proxy such as Codec Translation (that is G729<->G.711), Protocol Translation (SIP<->H323), and services related to media such as IVR, Queuing, Text to Speech, and Voice Recognition. Nat Traversal OpenSER deals a lot better with NAT traversal then Asterisk. You can send the media from your customer directly to the provider using OpenSER in most cases (non-symmetric NAT). Manipulating directly the SIP protocol allows you to handle special cases, such as, when you have two customers behind the same NAT device and want to send the media directly between them. Load Balancing OpenSER has specific load balancing algorithms with hash. So it can load balance by the "ruri", "username", "call-id", and some other properties. It can use redirected messages consuming very few resources from the load balancer machine. Failover is part of the solution, things you won't find on Asterisk, but are complementary. Low Level Access to SIP Header and Transactions OpenSER gives you low level access to the protocol. You can handle all the requests and responses. So it is possible, most times, to translate between two incompatible versions of SIP, handling directly the SIP headers, requests, and responses. This is an important feature when you have SIP implementations from different manufacturers, which can be incompatible between each other. Integration with Radius, Diameter, and LDAP OpenSER has built-in integration with LDAP, Radius, and Diameter. While this is also possible with Asterisk, the implementation on OpenSER is developed in C, integrated as a module, and is part of the OpenSER distribution (no perl, no python, no third-party modules). Carrier Class Routing The module CARRIERROUTE implements sophisticated algorithms to route calls to the PSTN. Some times VoIP providers have tables with more then 40.000 routes. In this case, you will absolutely need a specific routing module capable of failback, blacklists, and some other features specific to VoIP providers. Media Services OpenSER is a SIP Proxy and is not capable of any media related services. So it is not possible to create, using OpenSER, systems such as VoiceMail, IVR, TTS, and Voice Recognition. However, it is possible to integrate any of these services to the platform using a separate Media Server such as Asterisk, Yate, and FreeSwitch.  This is by design, and it is the way the SIP protocol is defined in the standards (RFC3261). Connectivity to the PSTN OpenSER always need a SIP gateway to connect to the PSTN. There is no possibility to install telephony cards in the server.  In several cases, Asterisk is used as the PSTN gateway for OpenSER. Conclusion I love this discussion, because Asterisk and OpenSER completes one another. OpenSER provides rock solid SIP services to VoIP providers, it is capable to handle large volumes of calls, to load balance SIP, to solve advanced NAT scenarios, and to deal with SIP signaling as no other. Asterisk is a B2BUA, very strong in the PBX market. It is simpler to configure and can handle low to medium volumes. Asterisk can be used as a "single box does it all", while OpenSER requires all the architectural components of SIP to work. OpenSER is a "hit" in the VoIP provider market and in Universities. Asterisk PBX is a success in the IP PBX market, and it is getting a piece of the small to medium VoIP providers. Usually you start using OpenSER when you have some special need, such as load balancing or when you have large volumes such as more than a thousand registered users. Choose wisely!   If you have read this article you may be interested to view : Using Asterisk as a PSTN Gateway for OpenSER Building the User Portal with SerMyAdmin for OpenSER
Read more
  • 0
  • 0
  • 4773
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-apache-ofbiz-service-engine-part-2
Packt
20 Oct 2009
16 min read
Save for later

Apache OFBiz Service Engine: Part 2

Packt
20 Oct 2009
16 min read
Calling Services from Java Code So far, we have explored services invoked as events from the controller (example <event type="service" invoke="learningFirstService"/>). We now look at calling services explicitly from code. To invoke services from code, we use the dispatcher object, which is an object of type org.ofbiz.service.ServiceDispatcher. Since this is obtainable from the DispatchContext we can invoke services from other services. To demonstrate this we are going to create one simple service that calls another. In our services.xml file in ${component:learning}servicedef add two new service definitions: <service name="learningCallingServiceOne" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="callingServiceOne"> <description>First Service Called From The Controller</description> <attribute name="firstName" type="String" mode="IN" optional="false"/> <attribute name="lastName" type="String" mode="IN" optional="false"/> <attribute name="planetId" type="String" mode="IN" optional="false"/> <attribute name="fullName" type="String" mode="OUT" optional="true"/> </service> <service name="learningCallingServiceTwo" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="callingServiceTwo"> <description>Second Service Called From Service One</description> <attribute name="planetId" type="String" mode="IN" optional="false"/> </service> In this simple example it is going to be the job of learningCallingServiceOne to prepare the parameter map and pass in the planetId parameter to learningCallingServiceTwo. The second service will determine if the input is EARTH, and return an error if not. In the class org.ofbiz.learning.learning.LearningEvents, add the static method that is invoked by learningCallingServiceOne: public static Map callingServiceOne(DispatchContext dctx, Map context){ LocalDispatcher dispatcher = dctx.getDispatcher(); Map resultMap = null; String firstName = (String)context.get("firstName"); String lastName = (String)context.get("lastName"); String planetId = (String)context.get("planetId"); GenericValue userLogin = (GenericValue)context.get("userLogin"); Locale locale = (Locale)context.get("locale"); Map serviceTwoCtx = UtilMisc.toMap("planetId", planetId, "userLogin", userLogin, "locale", locale); try{ resultMap = dispatcher.runSync("learningCallingServiceTwo", serviceTwoCtx); }catch(GenericServiceException e){ Debug.logError(e, module); } resultMap.put("fullName", firstName + " " + lastName); return resultMap; } and also the method invoked by learningServiceTwo: public static Map callingServiceTwo(DispatchContext dctx, Map context){ String planetId = (String)context.get("planetId"); Map resultMap = null; if(planetId.equals("EARTH")){ resultMap = ServiceUtil.returnSuccess("This planet is Earth"); }else{ resultMap = ServiceUtil.returnError("This planet is NOT Earth"); } return resultMap; } To LearningScreens.xml add: <screen name="TestCallingServices"> <section> <actions><set field="formTarget" value="TestCallingServices"/></actions> <widgets> <include-screen name="TestFirstService"/> </widgets> </section></screen> Finally add the request-map to the controller.xml file: <request-map uri="TestCallingServices"> <security auth="false" https="false"/> <event type="service" invoke="learningCallingServiceOne"/> <response name="success" type="view" value="TestCallingServices"/> <response name="error" type="view" value="TestCallingServices"/> </request-map> and also the view-map: <view-map name="TestCallingServices" type="screen" page="component://learning/widget/learning/LearningScreens.xml#TestCallingServices"/> Stop, rebuild, and restart, then fire an OFBiz http request TestCallingServices to webapp learning. Do not be alarmed if straight away you see error messages informing us that the required parameters are missing. By sending this request we have effectively called our service with none of our compulsory parameters present. Enter your name and in the Planet Id, enter EARTH. You should see: Try entering MARS as the Planet Id. Notice how in the Java code for the static method callingServiceOne the line resultMap = dispatcher.runSync("learningCallingServiceTwo", serviceTwoCtx); is wrapped in a try/catch block. Similar to how the methods on the GenericDelegator object that accessed the database threw a GenericEntityException, methods on our dispatcher object throw a GenericServiceException which must be handled. There are three main ways of invoking a service: runSync—which runs a service synchronously and returns the result as a map. runSyncIgnore—which runs a service synchronously and ignores the result. Nothing is passed back. runAsync—which runs a service asynchronously. Again, nothing is passed back. The difference between synchronously and asynchronously run services is discussed in more detail in the section called Synchronous and Asynchronous Services. Implementing Interfaces Open up the services.xml file in ${component:learning}servicedef and take a look at the service definitions for both learningFirstService and learningCallingServiceOne. Do you notice that the <attribute> elements (parameters) are the same? To cut down on the duplication of XML code, services with similar parameters can implement an interface. As the first service element in this file enter the following: <service name="learningInterface" engine="interface"> <description>Interface to describe base parameters for Learning Services</description> <attribute name="firstName" type="String" mode="IN" optional="false"/> <attribute name="lastName" type="String" mode="IN" optional="false" /> <attribute name="planetId" type="String" mode="IN" optional="false"/> <attribute name="fullName" type="String" mode="OUT" optional="true"/></service> Notice that the engine attribute is set to interface. Replace all of the <attribute> elements in the learningFirstService and learningCallingServiceOne service definitions with: <implements service="learningInterface"/> So the service definition for learningServiceOne becomes: <service name="learningCallingServiceOne" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="callingServiceOne"> <description>First Service Called From The Controller</description> <implements service="learningInterface"/></service> Restart OFBiz and then fire an OFBiz http request TestCallingServices to webapp learning. Nothing should have changed—the services should run exactly as before, however our code is now somewhat tidier. Overriding Implemented Attributes It may be the case that the interface specifies an attribute as optional="false", however, our service does not need this parameter. We can simply override the interface and add the <attribute> element with whatever settings we wish. For example, if we wish to make the planetId optional in the above example, the <implements> element could remain, but a new <attribute> element would be added like this: <service name="learningCallingServiceOne" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="callingServiceOne"> <description>First Service Called From The Controller</description> <implements service="learningInterface"/> <attribute name="planetId" type="String" mode="IN" optional="false"/></service> Synchronous and Asynchronous Services The service engine allows us to invoke services synchronously or asynchronously. A synchronous service will be invoked in the same thread, and the thread will "wait" for the invoked service to complete before continuing. The calling service can obtain information from the synchronously run service, meaning its OUT parameters are accessible. Asynchronous services run in a separate thread and the current thread will continue without waiting. The invoked service will effectively start to run in parallel to the service or event from which it was called. The current thread can therefore gain no information from a service that is run asynchronously. An error that occurs in an asynchronous service will not cause a failure or error in the service or event from which it is called. A good example of an asynchronously called service is the sendOrderConfirmation service that creates and sends an order confirmation email. Once a customer has placed an order, there is no need to wait while the mail service is called and the mail sent. The mail server may be down, or busy, which may result in an error that would otherwise stop our customer form placing the order. It is much more preferable to allow the customer to continue to the Order Confirmation page and have our business receive the valuable order. By calling this service asynchronously, there is no delay to the customer in the checkout process, and while we log and fix any errors with the mail server, we still take the order. Behind the scenes, an asynchronous service is actually added to the Job Scheduler. It is the Job Scheduler's task to invoke services that are waiting in the queue. Using the Job Scheduler Asynchronous services are added to the Job Scheduler automatically. However, we can see which services are waiting to run and which have already been invoked through the Webtools console. We can even schedule services to run once only or recur as often as we like. Open up the Webtools console at https://localhost:8443/webtools/control/main and take a look under the Service Engine Tools heading. Select Job List to view a full list of jobs. Jobs without a Start Date/Time have not started yet. Those with an End Date/Time have completed. The Run Time is the time they are scheduled to run. All of the outstanding jobs in this list were added to the JobSandbox Entity when the initial seed data load was performed, along with the RecurrenceRule (also an Entity) information specifying how often they should be run. They are all maintenance jobs that are performed "offline". The Pool these jobs are run from by default is set to pool. In an architecture where there may be multiple OFBiz instances connecting to the same database, this can be important. One OFBiz instance can be dedicated to performing certain jobs, and even though job schedulers may be running on each instance, this setting can be changed so we know only one of our instances will run this job. The Service Engine settings can be configured in frameworkserviceconfigserviceengine.xml. By changing both the send-to-pool attribute and the name attribute on the <run-from-pool element>, we can ensure that only jobs created on an OFBiz instance are run by this OFBiz instance. Click on the Schedule Job button and in the Service field enter learningCallingServiceOne, leave the Pool as pool and enter today's date/time by selecting the calendar icon and clicking on today's date. We will need to add 5 minutes onto this once it appears in the box. In the below example the Date appeared as 2008-06-18 14:11:24.265. This job is only going to be scheduled to run once, although we could specify any recurrence information we wish. Select Submit and notice that scheduler is already aware of the parameters that can (or must, in this case) be entered. This information has been taken from the service definition in our services.xml file. Press Submit to schedule the job and find the entry in the list. This list is ordered by Run Time so it may not be the first. Recurring maintenance jobs are imported in the seed data and are scheduled to run overnight. These will more than likely be above the job we have just scheduled since their run-time is further in the future. The entered parameters are converted to a map and then serialized to the database. They are then fed to the service at run time. Quickly Running a Service Using the Webtools console it is also possible to run a service synchronously. This is quicker than going through the scheduler should you need to test a service or debug through a service. Select the Run Service button from the menu and enter the same service name, submit then enter the same parameters again. This time the service is run straight away and the OUT parameters and messages are passed back to the screen: Naming a Service and the Service Reference Service names must be unique throughout the entire application. Because we do not need to specify a location when we invoke a service, if service names were duplicated we can not guarantee that the service we want to invoke is the one that is actually invoked. OFBiz comes complete with a full service reference, which is in fact a dictionary of services that we can use to check if a service exists with the name we are about to choose, or even if there is a service already written that we are about to duplicate. From https://localhost:8443/webtools/control/main select the Service Reference and select "l" for learning. Here we can see all of our learning services, what engine they use and what method they invoke. By selecting the service learningCallingServiceOne, we can obtain complete information about this service as was defined in the service definition file services.xml. It even includes information about the parameters that are passed in and out automatically. Careful selection of intuitive service names and use of the description tags in the service definition files are good practice since this allows other developers to reuse services that already exists, rather than duplicate work unnecessarily. Event Condition Actions (ECA) ECA refers to the structure of rules of a process. The Event is the trigger or the reason why the rule is being invoked. The condition is a check to see if we should continue and invoke the action, and the action is the final resulting change or modification. A real life example of an ECA could be "If you are leaving the house, check to see if it is raining. If so, fetch an umbrella". In this case the event is "leaving the house". The condition is "if it is raining" and the action is "fetch an umbrella". There are two types of ECA rules in OFBiz: Service Event Condition Actions (SECAs) and Entity Event Condition Actions (EECAs). Service Event Condition Actions (SECAs) For SECAs the trigger (Event) is a service being invoked. A condition could be if a parameter equalled something (conditions are optional), and the action is to invoke another service. SECAs are defined in the same directory as service definitions (servicedef). Inside files named secas.xml Take a look at the existing SECAs in applicationsorderservicedefsecas.xml and we can see a simple ECA: <eca service="changeOrderStatus" event="commit" run-on-error="false"> <condition field-name="statusId" operator="equals" value="ORDER_CANCELLED"/> <action service="releaseOrderPayments" mode="sync"/></eca> When the changeOrderStatus transaction is just about to be committed, a lookup is performed by the framework to see if there are any ECAs for this event. If there are, and the parameter statusId is ORDER_CANCELLED then the releaseOrderPayments service is run synchronously. Most commonly, SECAs are triggered on commit or return; however, it is possible for the event to be in any of the following stages in the service's lifecycle: auth—Before Authentication in-validate—Before IN parameter validation out-validate—Before OUT parameter validation invoke—Before service invocation commit—Just before the transaction is committed return—Before the service returns global-commit global-rollback The variables global-commit and i are a little bit different. If the service is part of a transaction, they will only run after a rollback or between the two phases (JTA implementation) of a commit. There are also two specific attributes whose values are false by default: run-on-failure run-on-error You can set them to true if you want the SECA to run in spite of a failure or error. A failure is the same thing as an error, except it doesn't represent a case where a rollback is required. It should be noted that parameters passed into the trigger service are available, if need be, to the action service. The trigger services OUT parameters are also available to the action service. Before using SECAs in a component, the component must be informed of the location of the ECA service-resources: <service-resource type="eca" loader="main" location="servicedef/secas.xml"/> This line must be added under the existing <service-resource> elements in the component's ofbiz-component.xml file. Entity Event Condition Actions (EECAs) For EECAs, the event is an operation on an entity and the action is a service being invoked. EECAs are defined in the same directory as entity definitions (entitydef): inside files named eecas.xml. They are used when it may not necessarily be a service that has initiated an operation on the entity, or you may wish that no matter what service operates on this entity, a certain course of action to be taken. Open the eecas.xml file in the applicationsproductentitydef directory and take a look at the first <eca> element: <eca entity="Product" operation="create-store" event="return"> <condition field-name="autoCreateKeywords" operator="not-equals" value="N"/> <action service="indexProductKeywords" mode="sync" value-attr="productInstance"/></eca> This ECA ensures that once any creation or update operation on a Product record has been committed, so long as the autoCreateKeywords field of this record is not N, then the indexProductKeywords service will be automatically invoked synchronously. The operation can be any of the following self-explanatory operations: create store remove find create-store (create or store/update) create-remove store-remove create-store-remove any The return event is by far the most commonly used event in an EECA. But there are also validate, run, cache-check, cache-put, and cache-clear events. There is also the run-on-error attribute. Before using EECAs in a component, the component must be informed of the location of the eca entity-resource: <entity-resource type="eca" loader="main" location="entitydef/eecas.xml"/> must be added under the existing <entity-resource> elements in the component's ofbiz-component.xml file. ECAs can often catch people out! Since there is no apparent flow from the trigger to the service in the code they can be difficult to debug. When debugging always keep an eye on the logs. When an ECA is triggered, an entry is placed into the logs to inform us of the trigger and the action. Summary This brings us to the end of our investigation into the OFBiz Service Engine. We have discovered how useful the Service Oriented Architecture in OFBiz can be and we have learnt how the use of some of the built in Service Engine tools, like the Service Reference, can help us when we are creating new services. In this article we have looked at: Calling services from code (using dispatcher). IN/OUT parameter mismatch when calling services Sending feedback; standard return codes success, error and fail. Implementing Service Interfaces Synchronous and asynchronous services Using the Service Engine tools ECAs: Event Condition Actions
Read more
  • 0
  • 0
  • 3087

article-image-building-personal-community-liferay-portal-52
Packt
20 Oct 2009
7 min read
Save for later

Building Personal Community in Liferay Portal 5.2

Packt
20 Oct 2009
7 min read
Besides public web sites, it would be nice if we could provide a personal community, that is, My Community, for each registered user. In My Community, users can have a set of public and private pages. Here you can save your favorite games, videos and playlists, and the My Street theme — your background color. As shown in the following screenshot, there is a page my_street with a portlet myStreet, where an end user can sign up, log in, or handle an issue such as Forgot Your Password? o When you click on the SIGN UP button, this My Street portlet will allow the end users to set up his/her account such as creating a nickname, password hint question, password hint answer, your password, and verify password. Further, as the end user, you can set up favorite games, videos and playlists, and background color. You can have your own favorites: number of favorites displayed in My Street (for example, 4, 20, and 35) and My Street theme, (for example, default, Abby Cadabby, Bert, Big Bird, Cookie Monster, and so on). A set of default My Street themes is predefined in /cms_services/images/my_street/ under the folder $CATALINA_HOME/webapps/ and you can choose any one of them at any time. At the same time, you can upload a photo to your own Book Street web page. When logged in, the My Street theme will be applied on Home page, Games landing page, Videos landing page, and Playlist landing page. For example, current user's My Street theme could be applied on Playlist landing page. You may play videos, games, and playlists when you visit the web site www.bookpubstreet.com. When you find your favorite videos, games, and playlists, you can add them into My Street. As shown in the following screenshot, you could be playing a playlist Tickle Time. If you are interested in this playlist, just click on the Add to My Street button. The playlist Tickle Time will be added into My Street as your favorite playlist. In this section, we will show how to implement these features. Customizing user model First, let's customize user model in service.xml in order to support extended user and user preferences. To do so, use the following steps: Create a package com.ext.portlet.user in the /ext/ext-impl/src folder. Create an XML file service.xml in the package com.ext.portlet.comment and open it. Add the following lines in this file and save it: <?xml version="1.0"?><!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 5.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_5_2_0.dtd"><service-builder package-path="com.ext.portlet.user"> <namespace>ExtUser</namespace> <entity name="ExtUser" uuid="false" local-service="true" remote-service="true" persistence-class="com.ext.portlet.user.service. persistence. ExtUserPersistenceImpl"> <column name="userId" type="long" primary="true" /> <column name="favorites" type="int" /> <column name="theme" type="String" /> <column name="printable" type="boolean" /> <column name="plainPassword" type="String" /> <column name="creator" type="String" /> <column name="modifier" type="String" /> <column name="created" type="Date" /> <column name="modified" type="Date" /> </entity> <entity name="ExtUserPreference" uuid="false" local-service="true" remote-service="true" persistence-class="com.ext.portlet.user.service. persistence.ExtUserPreferencePersistenceImpl"> <column name="userPreferenceId" type="long" primary="true" /> <column name="userId" type="long"/> <column name="favorite" type="String" /> <column name="favoriteType" type="String" /> <column name="date_" type="Date" /> </entity> <exceptions> <exception>ExtUser</exception> <exception>ExtUserPreference</exception> </exceptions></service-builder> The code above shows the customized user model, including userId associated with USER_ table, favourites, theme, printable, plainPassword, and so on. This code also shows user preferences model, including userPreferenceId, userId, favorite (for example, game/video/playlist UID), favoriteType (for example, game/video/playlist), and the updated date date_. Of course, these models are extensible. You can extend these models for your unique current needs or future requirements. Enter the following tables into database through command prompt: create table ExtUser ( userId bigint not null primary key, creator varchar(125), modifier varchar(125), created datetime null,modified datetime null, favorites smallint, theme varchar(125), plainPassword varchar(125), printable boolean ); create table ExtUserPreference ( usePreferenceId bigint not null primary key, userId bigint not null,favorite varchar(125), favoriteType varchar(125),date_ datetime null ); The preceding code shows the database SQL script for customized user model and user preference model. Similar to XML model ExtUser, this code shows the userId, favorites, theme, plainPassword, and printable table fields. Again, for the XML model ExtUserPreference, this code shows the userId, favorite, favoriteType, date_, and userPreferenceId table fields. Afterwards, we need to build a service with ServiceBuilder. After preparing service.xml, you can build services. To do so, locate the XML file /ext/ext-impl/buildparent.xml, open it, add the following lines between </target> and <target name="build-service-portlet-reports">, and save it: <target name="build-service-portlet-extUser"> <antcall target="build-service"> <param name="service.file" value="src/com/ext/portlet/user/service.xml" /> </antcall></target> When you are ready, just double-click on the Ant target build-service-portletextUser. ServiceBuilder will build related models and services for extUser and extUserPreference.   Building the portlet My Street Similar to how we had built portlet Ext Comment, we can build the portlet My Street as follows: Configure the portlet My Street in both portlet-ext.xml and liferay-portlet-ext.xml files. Set title mapping in the Language-ext.properties file. Add the My Street portlet to the Book category in the liferay-display.xml file. Finally, specify Struts actions and forward paths in the struts-config.xml and tiles-defs.xml files, respectively. Then, we need to create Struts actions as follows: Create a package com.ext.portlet.my_street.action in the folder /ext/ext-impl/src. Add the Java files ViewAction.java, EditUserAction.java, and CreateAccountAction.java in this package. Create a Java file AddUserLocalServiceUtil.java in this package and open it. Add the following methods in AddUserLocalServiceUtil.java and save it: public static ExtUser getUser(long userId){ ExtUser user = null; try{ user = ExtUserLocalServiceUtil.getExtUser(userId); } catch (Exception e){} if(user == null){ user = ExtUserLocalServiceUtil.createExtUser(userId); try{ ExtUserLocalServiceUtil.updateExtUser(user); } catch (Exception e) {} } return user;}public static void deleteUser(long userId) { try{ ExtUserLocalServiceUtil.deleteExtUser(userId); } catch (Exception e){} }public static void updateUser(ActionRequest actionRequest, long userId) { /* ignore details */}public static List<ExtUserPreference> getUserPreferences( long userId, int limit){ /* ignore details */}public static ExtUserPreference addUserPreference( long userId, String favorite, String favoriteType){ /* ignore details */ } As shown in the code above, it shows methods to get ExtUser and ExtUserPreference, to delete ExtUser, and to add and update ExtUser and ExtUserPreference. In addition, we need to provide default values for private page and friendly URL in portal-ext.properties as follows: ext.default_page.my_street.private_page=falseext.default_page.my_street.friend_url=/my_street The code above shows the default private page of my_street as false, default friendly URL of my_street as /my_street. Therefore, you can use VM service to generate a URL in order to add videos, games, and playlists into My Street. Adding Struts view page Now we need to build Struts views pages view.jsp, forget_password.jsp, create_account.jsp, congratulation.jsp, and congrates_uid.jsp. The following are main steps to do so: Create a folder my_street in /ext/ext-web/docroot/html/portlet/ext/. Create JSP file pages view.jsp, view_password.jsp, userQuestions.jsp, edit_account.jsp, create_account.jsp, congratulation.jsp, and congrates_uid.jsp in /ext/ext-web/docroot/html/portlet/ext/my_street/. Note that congrates_uid.jsp is used for the pop-up congratulation of Add to My Street. When you click on the Add to My Street button, a window with congrates_uid.jsp will pop up. userQuestions.jsp is used when the user has forgotten the password of My Street, view_password.jsp is for general view of My Street, congratulation.jsp is used to represent successful information after creating user account, and edit_account.jsp is used to create/update user account.
Read more
  • 0
  • 0
  • 1846

article-image-delicious-tagometer-widget
Packt
20 Oct 2009
10 min read
Save for later

Delicious Tagometer Widget

Packt
20 Oct 2009
10 min read
Background Concept Delicious was founded by Joshua Schachter in 2003 and acquired by Yahoo in 2005. This website was formerly used to run in the domain http://del.icio.us hence known as del.icio.us. Now, this domain redirects to the domain http://delicious.com. This website got redesigned in July 2008 and the Delicious 2.0 went live with new domain, design and name. Delicious is probably one of the largest social bookmarking website in the WWW world for discovering, sharing and storing the interesting and useful URL on the Internet. When saving the URL, user can enter tags for the URL which is quite useful when you’ve to search the particular URL from many bookmarks. The number of saves of a particular URL in Delicious is one of the measurements for checking popularity of that URL. Delicious Tagometer As the name specifies, Delicious Tagometer is a badge which displays the tags as well count of the users who have saved the particular URL. Tagometer gets displayed in the web page which contains the code given below: <script src="http://static.delicious.com/js/blogbadge.js"></script> This is the new URL of the Tagometer badge from the Delicious. The URL for the Tagometer used to be different in the del.icio.us domain in past. For more information on future updates, you can check http://delicious.com/help. The delicious Tagometer looks as shown: As you can easily guess, the above Tagometer is placed on a web page whose URL has not yet been saved in Delicious. Now let’s take a look at the Tagometer which is placed on a web page whose URL is saved by many users of Delicious. In the above widget, the text “bookmark this on Delicious" is the hyperlink for saving the URL in delicious. To save an URL in Delicious, you have to provide the URL and give a Title on the http://delicious.com/save page. After clicking on the “bookmark this on Delicious” hyperlink on the Delicious Tagometer widget you can see the image of the web page on delicious. The Delicious Tagometer widget also shows the list of tags which are used by the users of Delicious to save the URL. Each of these tags link to a tag specific page of Delicious. For example, an URL saved with tag JavaScript can be found on the page http://delicious.com/tag/javascript. And, the number is linked to the URL specific page on Delicious. For example, if you wish to view the users and their notes on the saves of the URL- http://digg.com, then the URL of delicious will be http://delicious.com/url/926a9b7a561a3f650ff41eef0c8ed45d The last part “926a9b7a561a3f650ff41eef0c8ed45d” is the md5 hash of the URL http://digg.com. The md5 is a one way hashing algorithm which converts a given string to a 32 character long string known as md5 digest. This hashed string can’t be reversed back into original string.  The md5 function protects and ensures data integrity of Delicious Data Feeds. Delicious data feeds are read-only web feeds containing bookmark information and other information which can be used third party websites. These feeds are available into two different format: RSS and JSON. Among the various data feeds on the Delicious, let’s look at the details of the data feed which contains summary information of a URL. According to Delicious feed information page, these data feed for URL information can be retrieved via following call, http://feeds.delicious.com/v2/json/urlinfo/{url md5} It clearly specifies summary of URL can be retrieved in the json format only from Delicious. To get the summary about a URL, You can provide the actual URL in the url parameter of the above URL. Alternatively, you can provide md5() hash of the url in the hash parameter in the above URL. Now, let’s look at feed URLs which can be used to access the summary of the http://digg.com from Delicious: http://feeds.delicious.com/v2/json/urlinfo?callback=displayTotalSaves&url=http://digg.com OR http://feeds.delicious.com/v2/json/urlinfo?callback=displayTotalSaves&hash=926a9b7a561a3f650ff41eef0c8ed45d From the above URLs, it is clear that md5 hash of the string "http://digg.com" is 926a9b7a561a3f650ff41eef0c8ed45d When JSON is used as the format of data returned form Delicious feed then you must specify the JavaScript callback function to handle the JSON data. Now, let look at the JSON data which is returned from any of the above URL of Delicious feed. displayTotalSaves([{"hash":"926a9b7a561a3f650ff41eef0c8ed45d","title":"digg", "url":"http://digg.com/","total_posts":51436,"top_tags":{"news":23581, "digg":10771,"technology":10713,"blog":8628,"web2.0":7800, "tech":6459,"social":5436,"daily":5173,"community":4477,"links":2512}}]) As you can see clearly, the above JSON data contains hash of URL, the URL itself, total no of saves in Delicious in total_posts variable. Along with them, different tags including number of times that tag is used by different users of Delicious for saving the URL  http://digg.com. If the URL is not saved in Delicious then data returned from Delicious feed will be like this : displayTotalSaves([]) Now, having understod the information returned above, let’s see how to create Delicious widget step by step. Creating Delicious Tagometer Widget Our Delicious Tagometer widget looks very similar to actual Delicious Tagometer widget but has different format and texts. In the Tagometer badge provided by delicious, there is no option for specifying a particular URL whose summary is to be displayed. It automatically displays the details of the URL of the web page containing the code. While in our custom widget, you can also specify the URL explicitly in the badge which is an optional parameter. For creating this widget, we will use JavaScript, CSS, XHTML and Delicious’s data feed in JSON format. The above image is of the Delicious widget which we’re going to make and you can see clearly that the provided URL is not yet saved on Delicious. Now, let’s look at the Custom Delicious Tagometer which we can see for a URL saved on the delicious. The above badge of delicious is displayed for the URL: http://yahoo.com. Writing Code for Delicious First of all, let’s start looking at the JavaScript code for handling the parameters-url and title of the web page, when it is not provided. If these parameters are not defined explicitly then url and title of the web page using the widget is provided for saving the bookmark. if(typeof delicious_widget_url!='undefined') delicious_widget_url=encodeURIComponent(delicious_widget_url);else delicious_widget_url=encodeURIComponent(document.location);if(typeof delicious_widget_title!='undefined') delicious_widget_title=encodeURIComponent(delicious_widget_title);else delicious_widget_title=encodeURIComponent(document.title); As can be seen from the above code, if the variable delicious_widget_url is not defined already then the URL of the current document encoded with encodeURIComponent() function is assigned to this variable. If delicious_widget_url variable is already defined then it is encoded with encodeURIComponent() function and assigned to the same variable. The typeof JavaScript operator can be used for checking the type of variable and also serves a very useful purpose of checking whether the variable or function is already defined or not. For example, the statement: typeof xyz==’function’ returns true if the function xyz is already defined. Similarly, if the variable delicious_widget_title is not defined then document.title, which contains title of current web page, is encoded with encodeURIComponent() function and assigned to the delicious_widget_title variable . Next, a variable del_rand_number is defined for handling multiple instances of the widget. var del_rand_number=Math.floor(Math.random()*1000); The Math.random() function returns random values between 0 to 1 and when multiplied by 1000 results in a random number between 1 to 1000. Since this random number is a  floating point number hence floor() function of JavaScript Math Object is used for converting it to the greatest whole number which is less than or equal to generated random number. The Math object of JavaScript has three different functions which can be used to convert a floating point number to whole number:Math.floor(float_val) – converts to greatest integer less than or equal to float_val.Math.ceil(float_val) – converts to smallest integer grater than or equal to float_val.Math.round(float_val) – converts to nearest integer. If the decimal portion of float_val is greater than or equal to .5 then the resulting integer is the next whole number otherwise resulting number is rounded to the nearest integer less than float_val. After that, now using above random number let’s define a variable which holds the “id” of the element in widget for displaying total no. of saves and tags. var del_saved_id="delicious-saved-"+del_rand_number; Now, let’s look at the initWidget() function for initializing the widget. function initWidget(){ //write the elements needed for widget writeWidgetTexts(); //now attach the stylesheet to the document var delCss=document.createElement("link"); delCss.setAttribute("rel", "stylesheet"); delCss.setAttribute("type", "text/css"); delCss.setAttribute("href", "http://yourserver.com/delicious/delicious.css"); document.getElementsByTagName("head")[0].appendChild(delCss); //now call the script of delicious var delScript = document.createElement("script"); delScript.setAttribute("type", "text/javascript"); delScript.setAttribute("src", "http://feeds.delicious.com/v2/json/urlinfo?callback=displayTotalSaves&url="+delicious_widget_url); //alert(delicious_widget_url); document.getElementsByTagName("head").item(0).appendChild(delScript); } At the start of the above code, the function writeWidgetTexts(); is called for writing the content of widget. The functions createElement() and setAttribute() are DOM manipulation function for creating a element and adding attribute to the element respectively. So, the next four statements of the above function create link element and sets various attributes for attaching CSS document to the page using widget. Once link element is created and various attribute is assigned to it the next step is to append it to the document using widget, which is done with appendChild() function in the next line of above function. getElementsByTagName() is a DOM function for accessing the document by the name of tag. Unlike getElementById() which access single element in the document, getElementsByTagName() can access multiple elements of DOM with the help of index. For example, document.getElementsByTagName("div")[0] or document.getElementsByTagName("div").item(0) refers to the first division element of the document Similarly, script element is created for getting JSON feed from Delicious. The call back JavaScript function displayTotalSaves() is used for handling JSON data returned from Delicious.
Read more
  • 0
  • 0
  • 1757

article-image-rotating-post-titles-post-preview-gadget
Packt
20 Oct 2009
6 min read
Save for later

The Rotating Post Titles with Post Preview Gadget

Packt
20 Oct 2009
6 min read
The Rotating Post Titles with Post Preview gadget lists all your blog posts classified according to labels or categories. Blogger uses Labels to classify posts while Wordpress uses Categories for the same. Clicking on a Label or a category in the sidebar of a blog brings up all posts associated with that particular label or category. However, you will see only posts associated with that one label. In this gadget post titles are grouped under their respective labels. In this gadget in one look you can see all the post titles in that blog and all the labels in it. Thus you get a full summary of the blog. Hovering on a post title shows the Post Preview in the top pane. You can then click on it to go to that post to read it in full detail. What is Google AJAX feed API? AJAX (shorthand for asynchronous JavaScript and XML) is a web development technique which retrieves data from the server asynchronously in the background without interfering with the display, and behaviour of the existing page. The whole page is not refreshed when data is retrieved. Only that section of the page which is a part of the gadget shows the data brought. With the Google AJAX Feed API, you can retrieve feeds and mash them up using Javascript. In this gadget, we will retrieve the post titles from the label feeds and display them using Javascript code. See picture below: This gadget shows list of posts grouped by label from my blog http://www.blogdoctor.me. Four post titles from three labels are shown but the code can be modified to show all posts from all labels (categories). This label is also shown as Gadget No 4 in My Gadget Showcase blog. The cursor autoscrolls down the post titles, and each post preview is shown at the top as an excerpt for five seconds before moving on to the next post. Obtaining the Google AJAX API Key The first step in installing the above gadget is to get the Google AJAX API Key. It is free and you can easily obtain it for any site blog or page by signing up for the key at the API key signup page. Type in your blog address in the My web site URL text box and click the "Generate API Key" button. On the resulting page copy the key and paste it in code below as shown. Customizing the code In the code below replace PASTE AJAX API KEY HERE with your actual key obtained above. <!-- ++Begin Dynamic Feed Wizard Generated Code++ --><!-- // Created with a Google AJAX Search and Feed Wizard // http://code.google.com/apis/ajaxsearch/wizards.html --> <!-- // The Following div element will end up holding the actual feed control. // You can place this anywhere on your page. --><div id="content"> <span style="color:#676767;font-size:11px;margin:10px;padding:4px;">Loading...</span> </div><!-- Google Ajax Api --> <script src="http://www.google.com/jsapi?key=PASTE AJAX API KEY HERE" type="text/javascript"></script> <!-- Dynamic Feed Control and Stylesheet --> <script src="http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js" type="text/javascript"></script> <style type="text/css"> @import url("http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css"); </style><script type="text/javascript"> google.load('feeds', '1'); function OnLoad() { var feeds = [ { title: 'LABEL_1', url: 'http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL1?max-results=100' }, { title: 'LABEL_2', url: 'http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL2?max-results=100' }, { title: 'LABEL_3', url: 'http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL3?max-results=100' } ]; var options = { stacked : true, horizontal : false, title : "Posts from BLOG_TITLE" }; new GFdynamicFeedControl(feeds, 'content', options); document.getElementById('content').style.width = "200px"; } google.setOnLoadCallback(OnLoad); </script> In the above code replace LABEL_1, LABEL_2 and LABEL_3 and LABEL1, LABEL2 and LABEL3 by respective Label Names and BLOG_TITLE by the actual title of your blog. Also replace MYBLOG by actual blog subdomain. This is for blogspot blogs only. For Wordpress blog you will have to replace the label feeds:: http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL1?max-results=100 http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL2?max-results=100 http://MYBLOG.blogspot.com/feeds/posts/default/-/LABEL3?max-results=100 by the Category feed URLs from Wordpress blog. After customizing the above code in Blogger paste it in a HTML gadget while in Wordpress paste it in a Text widget. Further Customization To show more than four posts per label or category, you will have to modify the following Javascript code file: http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js In the above mentioned Javascript code file, alter the following code line in it : GFdynamicFeedControl.DEFAULT_NUM_RESULTS = 4; Change '4' to '1000' and save the file as a MODgfdynamicfeedcontrol.js file in a text editor like Notepad. Upload the file to a free host and replace the link of the file in the above code. To change the styling of the gadget, you will have to modify the following file: http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css Then save the modified file and upload it to a free host and replace its link in the above code. Working Example Posts from The Blog Doctor Change Post Formatting According to Author. by Vin - 30 Apr 2008 If you have a Team Blog made up of two authors you can change the formatting of the posts written by one author to ... Template Calling all Newbie Bloggers! Upgrade Classic Template without the "UPGRADE YOUR TEMPLATE" button. The Minimalist Minima Photoblog Template. Making the COMMENTS Link more User Friendly. CSS Change Post Formatting According to Author. Free CSS Navigation Menus in Blogger. Fix the Page Elements Layout Editor No Scrollbar Problem. Frame the Blog Header Image. Blogger Hacks Rounded Corner Headers for Blogger. Timestamp under the Date and Other Hacks. Add Icon to Post Titles. Many Headers In One Blog.   Summary The Rotating Post Titles with Post Preview gadget provides an at-a glance summary of your blog. All the posts are grouped by label or category and are linked to their post pages. The constantly rotating post excerpts at the top draws the attention of the reader and gets him/her more involved and eager to explore your blog. This increases the traffic and decreases the bounce rate of visitors from your blog.nara
Read more
  • 0
  • 0
  • 3925
article-image-debugging-rest-web-services
Packt
20 Oct 2009
13 min read
Save for later

Debugging REST Web Services

Packt
20 Oct 2009
13 min read
(For more resources on this subject, see here.) Message tracing The first symptom that you will notice when you are running into problems is that the client would not behave the way you want it to behave. As an example, there would be no output, or the wrong output. Since the outcome of running a REST client depends on the request that you send over the wire and the response that you receive over the wire, one of the first things is to capture the messages and verify that those are in the correct expected format. REST Services and clients interact using messages, usually in pairs of request and response. So if there are problems, they are caused by errors in the messages being exchanged. Sometimes the user only has control over a REST client and does not have access to the implementation details of the service. Sometimes the user will implement the REST service for others to consume the service. Sometimes the Web browser can act as a client. Sometimes a PHP application on a server can act as a REST client. Irrespective of where the client is and where the service is, you can use message capturing tools to capture messages and try to figure out the problem. Thanks to the fact that the service and client use messages to interact with each other, we can always use a message capturing tool in the middle to capture messages. It is not that we must run the message capturing tool on the same machine where the client is running or the service is running; the message capturing tool can be run on either machine, or it can be run on a third machine. The following figure illustrates how the message interaction would look with a message capturing tool in place. If the REST client is a Web browser and we want to capture the request and response involved in a message interaction, we would have to point the Web browser to message capturing tool and let the tool send the request to the service on behalf of the Web browser. Then, since it is the tool that sent the request to the service, the service would respond to the tool. The message capturing tool in turn would send the response it received from the service to the Web browser. In this scenario, the tool in the middle would gain access to both the request and response. Hence it can reveal those messages for us to have a look. When you are not seeing the client to work, here is the list of things that you might need to look for: If the client sends a message If you are able to receive a response from a service If the request message sent by the client is in the correct format, including HTTP headers If the response sent by the server is in the correct format, including the HTTP headers In order to check for the above, you would require a message-capturing tool to trace the messages. There are multiple tools that you can use to capture the messages that are sent from the client to the service and vice versa. Wireshark (http://www.wireshark.org/) is one such tool that can be used to capture any network traffic. It is an open-source tool and is available under the GNU General Public License version 2. However this tool can be a bit complicated if you are looking for a simple tool. Apache TCPMon (http://ws.apache.org/commons/tcpmon/) is another tool that is designed to trace web services messages. This is a Java based tool that can be used with web services to capture the messages. Because TCPMon is a message capturing tool, it can be used to intercept messages sent between client and service, and as explained earlier, can be run on the client machine, the server machine or on a third independent machine. The only catch is that you need Java installed in your system to run this tool. You can also find a C-based implementation of a similar tool with Apache Axis2/C (http://ws.apache.org/axis2/c). However, that tool does not have a graphical user interface. There is a set of steps that you need to follow, which are more or less the same across all of these tools, in order to prepare the tool for capturing messages. Define the target host name Define the target port number Define the listen port number Target host name is the name of the host machine on which the service is running. As an example, if we want to debug the request sent to the Yahoo spelling suggestion service, hosted at http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion, the host name would be search.yahooapis.com. We can either use the name of the host or we can use the IP address of the host because the tools are capable of dealing with both formats in place of the host name. As an example, if the service is hosted on the local machine, we could either use localhost or 127.0.0.1 in place of the host name. Target port number is the port number on which the service hosting web server is listening; usually this is 80. As an example, for the Yahoo spelling suggestion service, hosted at http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion, the target port number is 80. Note that, when the service URL does not mention any number, we can always use the default number. If it was running on a port other than port 80, we can find the port number followed by the host name and preceded with character ':'. As an example, if we have our web server running on port 8080 on the local machine, we would have service URL similar to http://localhost:8080/rest/04/library/book.php. Here, the host name is localhost and the target port is 8080. Listen port is the port on which the tool will be listening to capture the messages from the client before sending it to the service. For an example, say that we want to use port 9090 as our listen port to capture the messages while using the Yahoo spelling suggestion service. Under normal circumstances, we will be using a URL similar to the following with the web browser to send the request to the service. http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto When we want to send this request through the message capturing tool and since we decided to make the tools listen port to be 9090 with the tool in the middle and assuming that the tool is running on the local machine, we would now use the following URL with the web browser in place of the original URL. http://localhost:9090/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto Note that we are not sending this request directly to search.yahooapis.com, but rather to the tool listening on port 9090 on local host. Once the tool receives the request, it will capture the request, forward that to the target host, receive the response and forward that response to the web browser. The following figure shows the Apache TCPMon tool. You can see localhost being used as the target host, 80 being the target port number and 9090 being the listening port number. Once you fill in these fields you can see a new tab being added in the tool showing the messages being captured. Once you click on the Add button, you will see a new pane as shown in the next figure where it will show the messages and pass the messages to and from the client and service. Before you can capture the messages, there is one more step. That is to change the client code to point to the port number 9090, since our monitoring tool is now listening on that port. Originally, we were using port 80 $url = 'http://localhost:80/rest/04/library/book.php'; or just $url = 'http://localhost/rest/04/library/book.php'; because the default port number used by a web server is port 80, and the client was directly talking to the service. However, with the tool in place, we are going to make the client talk to the tool listening on port 9090. The tool in turn will talk to the service. Note that in this sample we have all three parties, the client, the service, and the tool running on the same machine. So we will keep using localhost as our host name. Now we are going to change the service endpoint address used by the client to contain port 9090. This will make sure that the client will be talking to the tool. $url = 'http://localhost:9090/rest/04/library/book.php'; As you can see, the tool has captured the request and the response. The request appears at the top and the response at the bottom. The request is a GET request to the resource located at /rest/04/library/book.php. The response is a success response, with HTTP 200 OK code. And after the HTTP headers, the response body, which is in XML follows. As mentioned earlier, the first step in debugging is to verify if the client has sent a request and if the service responded. In the above example, we have both the request and response in place. If both were missing then we need to check what is wrong on either side. If the client request was missing, you can check for the following in the code. Are you using the correct URL in client Have you written the request to the wire in the client? Usually this is done by the function curl_exec when using Curl If the response was missing, you can check for the following. Are you connected to the network? Because your service can be hosted on a remote machine Have you written a response from the service? That is, basically, have you returned the correct string value from the service? In PHP wire, using the echo function to write the required response to the wire usually does this. If you are using a PHP framework, you may have to use the framework specific mechanisms to do this. As an example, if you are using the Zend_Rest_Server class, you have to use handle() method to make sure that the response is sent to the client. Here is a sample error scenario. As you can see, the response is 404 not found. And if you look at the request, you see that there is a typo in the request. We have missed 'k' from our resource URL, hence we have sent the request to /rest/04/library/boo.php, which does not exist, whereas the correct resource URL is /rest/04/library/book.php. Next let us look at the Yahoo search example that was discussed earlier to identify some advanced concepts. We want to capture the request sent by the web browser and the response sent by the server for the request. http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&ampquery=apocalipto. As discussed earlier, the target host name is search.yahooapis.com. The target port number is 80. Let's use 9091 as the listen. Let us use the web browser to send the request through the tool so that we can capture the request and response. Since the tool is listening on port 9091, we would use the following URL with the web browser. http://localhost:9091/WebSearchService/V1/spellingSuggestion?appid=YahooDemo&ampquery=apocalipto When you use the above URL with the web browser, the web browser would send the request to the tool and the tool will get the response from the service and forward that to the web browser. We can see that the web browser gets the response. However, if we have a look at the TCPMon tool's captured messages, we see that the service has sent some binary data instead of XML data even though the Web browser is displaying the response in XML format. So what went wrong? In fact, nothing is wrong. The service sent the data in binary format because the web browser requested that format. If you look closely at the request sent you will see the following. GET /WebSearchService/V1/spellingSuggestion?appid=YahooDemo&query=apocalipto HTTP/1.1Host: search.yahooapis.com:9091User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5Accept-Language: en-us,en;q=0.7,zh-cn;q=0.3Accept-Encoding: gzip,deflateAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7Keep-Alive: 300Connection: keep-alive In the request, the web browser has used the HTTP header. Accept-Encoding: gzip,deflate This tells the service that the web browser can handle data that comes in gzip compressed format. Hence the service sends the data compressed to the web browser. Obviously, it is not possible to look into the XML messages and debug them if the response is compressed. Hence we should ideally capture the messages in XML format. To do this, we can modify the request message on the TCPMon pane itself and resend the message. First remove the line Accept-Encoding: gzip,deflate Then click on the Resend button. Once we click on the Resend button, we will get the response in XML format. Errors in building XML While forming XML as request payload or response payload, we can run into errors through simple mistakes. Some would be easy to spot but some are not. Most of the XML errors could be avoided by following a simple rule of thumb-each opening XML tag should have an equivalent closing tag. That is the common mistake that can happen while building XML payloads. In the above diagram, if you look carefully in the circle, the ending tag for the book element is missing. A new starting tag for a new book is started before the first book is closed. This would cause the XML parsing on the client side to fail. In this case I am using the Library system sample and here is the PHP source code causing the problem. echo "<books>";while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) { echo "<book>"; foreach ($line as $key => $col_value) { echo "<$key>$col_value</$key>"; } //echo "</book>";}echo "</books>"; Here I have intentionally commented out printing the closing tag to demonstrate the error scenario. However, while writing this code, I could have missed that as well, causing the system to be buggy. While looking for XML related errors, you can use the manual technique that we just used. Look for missing tags. If the process looks complicated and you cannot seem to find any XML errors in the response or request that you are trying to debug, you can copy the XML captured with the tool and run it through an XML validator tool. For example, you can use an online tool such as http://www.w3schools.com/XML/xml_validator.asp. You can also check if the XML file is well formed using an XML parser
Read more
  • 0
  • 0
  • 5013

article-image-customizing-page-management-liferay-portal-52-systems-development
Packt
20 Oct 2009
5 min read
Save for later

Customizing Page Management in Liferay Portal 5.2 Systems Development

Packt
20 Oct 2009
5 min read
Customizing page management with more features The Ext Manage Pages portlet not only clones the out of the box Manage Pages portlet, but it also extends the model and service — supporting customized data, for example, Keywords. We can make these Keywords localized too.   Adding localized feature Liferay portal is designed to handle as many languages as you want to support. By default, it supports up to 22 languages. When a page is loading, the portal will detect the language, pull up the corresponding language file, and display the text in the correct language. We want the Keywords to be localized too. For example, the default language is English (United States) and the localized language is Deutsch (Deutschland). Thus, you have the ability to enter not only the Name and HTML Title in German, but also the Keywords in German. As shown in the following screenshot, when you change the language of the page in German using the language portlet, you will see the entire web site changed to German, including the portlet title and input fields. For example, the title of the portlet now has the Ext Seiteneinstellungen value and the Keywords now become Schlüsselwörter. How do we implement this feature? In other words, how do we customize the language display in the page management? Let's add the localized feature for the Ext Manage Pages portlet. Extending model for locale First of all, we need to extend the model and to implement that model in order to support the localized feature. For the ExtLayout model, let's add the locale method first. Locate the ExtLayout.java file from the com.ext.portlet.layout.model package in the /ext/ext-service/src folder, and open it. Add the following lines before the line } in ExtLayout.java and save it: public String getKeywords(Locale locale);public String getKeywords(String localeLanguageId);public String getKeywords(Locale locale, boolean useDefault);public String getKeywords(String localeLanguageId, boolean useDefault);public void setKeywords(String keywords, Locale locale); As shown in the code above, it adds getting and setting methods for the Keywords field with locale features. Now let's add the implementation for the ExtLayout model: Locate the ExtLayoutImpl.java file from the com.ext.portlet.layout.model.impl package in the /ext/ext-impl/src folder and open it. Add the following lines before the last } in ExtLayoutImpl.java file and save it: public String getKeywords(Locale locale) { String localeLanguageId = LocaleUtil.toLanguageId(locale); return getKeywords(localeLanguageId);}public String getKeywords(String localeLanguageId) { return LocalizationUtil.getLocalization(getKeywords(), localeLanguageId);}public String getKeywords(Locale locale, boolean useDefault) { String localeLanguageId = LocaleUtil.toLanguageId(locale); return getKeywords(localeLanguageId, useDefault);}public String getKeywords(String localeLanguageId, boolean useDefault) { return LocalizationUtil.getLocalization( getKeywords(), localeLanguageId, useDefault);}public void setKeywords(String keywords, Locale locale) { String localeLanguageId = LocaleUtil.toLanguageId(locale); if (Validator.isNotNull(keywords)) { setKeywords(LocalizationUtil.updateLocalization( getKeywords(), "keywords", keywords, localeLanguageId)); } else { setKeywords(LocalizationUtil.removeLocalization( getKeywords(), "keywords", localeLanguageId)); }} As shown in the code above, it adds implementation for get and set methods of the ExtLayout model. Customizing language properties Language files have locale-specific definitions. By default, Language.properties (at /portal/portal-impl/src/content) contains English phrase variations further defined for United States, while Language_de.properties (at /portal/portal-impl/src/content) contains German phrase variations further defined for Germany. In Ext, Language-ext.properties (available at /ext/ext-impl/src/content) contains English phrase variations further defined for United States, while Language-ext_de.properties (should be available at /ext/ext-impl/src/content) contains German phrase variations further defined for Germany. First, let's add a message in Language-ext.properties, by using the following steps: Locate the Language-ext.properties file in the /ext/ext-impl/src/content folder and open it. Add the following line after the line view-reports=View Reports for Books and save it. keywords=Keywords This code specifies the keywords message key with a Keywords value in English: Then we need to add German language feature in Language-ext_de.properties as follows: Create a language file Language-ext_de.properties in the /ext/ext-impl/src/content folder and open it. Add the following lines at the beginning and save it: ## Portlet namesjavax.portlet.title.EXT_1=Berichtejavax.portlet.title.jsp_portlet=JSP Portletjavax.portlet.title.book_reports=Berichte für das Buchjavax.portlet.title.extLayoutManagement=Ext Seiteneinstellungenjavax.portlet.title.extCommunities=Ext Communities## Messagesview-reports=Ansicht-Berichte für Bücherkeywords=Schlüsselwörter## Category titlescategory.book=Buch## Model resourcesmodel.resource.com.ext.portlet.reports.model.ReportsEntry= Buch ## Action namesaction.ADD_BOOK=Fügen Sie Buch hinzu As shown in the code above, it specifies the same keys as that of Language-ext.properties. But all the keys' values were specified in German instead of English. For example, the message keywords has a Schlüsselwörter value in German. In addition, you can set German as the default language and Germany as the default country if it is required. Here are the simple steps to do so: Locate the system-ext.properties file in the /ext/ext-impl/src folder and open it. Add the following lines at the end of system-ext.properties and save it: user.country=DEuser.language=de The code above sets the default locale — the language German (Deutsch) and the country Germany (Deutschland). In general, there are many language files, for example Language-ext.properties and Language-ext_de.properties, and some language files would overwrite others in runtime loading. For example, Languageext_de.properties will overwrite Language-ext.properties when the language is set as German. These are the three simple rules which indicate the priorities of these language files: The ext versions take precedence over the non-ext versions. The language-specific versions, for example _de, take precedence over the non language-specific versions. The location-specific versions, such as -ext_de, take precedence over the non location-specific versions. For instance, the following is a ranking from bottom to top for the German language: Language-ext_de.properties Language_de.properties Language-ext.properties Language.properties
Read more
  • 0
  • 0
  • 2315

article-image-mastering-phpmyadmin-4-editions-5-years
Packt
20 Oct 2009
4 min read
Save for later

Mastering phpMyAdmin: 4 Editions in 5 years

Packt
20 Oct 2009
4 min read
Among the daily deluge of spam, sometimes there is a real email – and sometimes even an important one. I received such an email at the end of October 2003 from Louay Fatoohi, presenting himself as the Editorial Director of a new publishing company, Packt Publishing. He was asking if I would be interested in writing a book about phpMyAdmin (which is a web interface for the MySQL database). At this time, our software product was already popular with about 150,000 downloads per month, but the lack of serious and complete user documentation held it back. This translated into many requests from users about how to accomplish some tasks with the software. Moreover, the small team of five active developers (all volunteers) was using all its free time for planning and coding new features so we did not see how to improve the documentation with volunteer work only. I did not know Mr Fatoohi but his email (and the following ones) looked serious so I committed myself to this project. I noticed that producing a clear book outline was very important. I already had in mind that each chapter should focus on a specific task or group of similar tasks. In the next days, a few iterations of the outline were done to balance the chapter lengths. Receiving a paper contract from England was new for me – in fact the whole process felt new to me as this was my first book. Writing for others is challenging and dealing with the comments of reviewers and editors can be a humbling experience; I had to defend some ideas I had put in the book but gladly accepted suggestions for improvement or clarification. It took about three months, working over the weekends (I have a day job) to write the first edition, Mastering phpMyAdmin for Effective MySQL Management, which was published in April 2004. Since this manual covers the complete interface, I was in fact testing the whole software, finding bugs along the way, which forced me to fix them in order to produce correct screenshots! Needless to say, I was very proud of being the first published author for this company. Meanwhile, an interface redesign was taking place in phpMyAdmin for version 2.6.0; this meant that many screenshots in the book would no longer reflect the upcoming version of the software. The decision was made by Packt to publish a book update. During the summer of 2004, I already knew what the new version would look like so I started preparing this update. The new version of the software was released at the end of September and the book update (bearing the same ISBN as the first edition) somewhere in October! In June 2005 we organized the first phpMyAdmin team meeting in Germany during the LinuxTag event where we demoed our software. I was happy to meet Mr Fatoohi, Damian Carvill and other representatives from Packt who had a booth there too. I found the whole team very dynamic and very much readers-oriented. I know that publishing is a business but they understand that quality is important; they also respect me as an author (especially about schedules). Over the years, translations of the book were published, directly by Packt or via other publishers. I wrote the French version, while two phpMyAdmin developers did the German one. Versions in Czech, Italian and Spanish were also born and they are all proudly displayed in my house near the workstation. Meanwhile, phpMyAdmin’s march was continuing, with an average of 250,000 downloads per month. It should be noted that many users do not need to download it directly because host providers install the software for them, or Linux distributors include it on their DVD, this is why we cannot know exactly the number of users. The development team changed a bit but new features were appearing so I guess Packt Publishing resigned itself about the need to update this title from time to time. This is why I took to my pencil again – rather my keyboard – to produce the October 2006 edition, Mastering phpMyAdmin 2.8 which covered a new setup mechanism. In March 2008, Mastering phpMyAdmin 2.11 was published, followed by Mastering phpMyAdmin 3.1 in March 2009. My family is now accustomed to my new habit of taking a few weeks per year to produce the new update. I would like to express my wholeheartedly gratitude to Packt Publishing for their support into this ongoing project. --Marc Delisle
Read more
  • 0
  • 0
  • 4612
article-image-data-migration-scenarios-sap-business-one-application-part-1
Packt
20 Oct 2009
25 min read
Save for later

Data Migration Scenarios in SAP Business ONE Application- part 1

Packt
20 Oct 2009
25 min read
Just recently, I found myself in a data migration project that served as an eye-opener. Our team had to migrate a customer system that utilized Act! and Peachtree. Both systems are not very famous for having good accessibility to their data. In fact, Peachtree is a non-SQL database that does not enforce data consistency. Act! also uses a proprietary table system that is based on a non-SQL database. The general migration logic was rather straightforward. However, our team found that the migration and consolidation of data into the new system posed multiple challenges, not only on the technical front, but also for the customer when it came to verifying the data. We used the on-the-edge tool xFusion Studio for data migration. This tool allows migrating and synchronizing data by using simple and advanced SQL data messaging techniques. The xFusion Studio tool has a graphical representation of how the data flows from the source to the target. When I looked at one section of this graphical representation, I started humming the song Welcome to the Jungle. Take a look at the following screenshot and find out why Guns and Roses may have provided the soundtrack for this data migration project: What we learned from the above screenshot is quite obvious and I have dedicated this article to helping you overcome these potential issues. Keep it simple and focus on information rather than data. You know that just by having more data does not always mean you’ve added more information. Sometimes, it just means a data jungle has been created. Making the right decisions at key milestones during the migration can keep the project simple and guarantee the success. Your goal should be to consolidate the islands of data into a more efficient and consistent database that provides real-time information. What you will learn about data migration In order to accomplish the task of migrating data from different sources into SAP Business ONE application, a strategy must be designed that addresses the individual needs of the project at hand. The data migration strategy uses proven processes and templates. The data migration itself can be managed as a mini project depending on the complexity. During the course of this article, the following key topics will be covered. The goal is to help you make crucial decisions, which will keep a project simple and manageable: Position the data migration tasks in the project plan – We will start by positioning the data migration tasks in the project plan. I will further define the required tasks that you need to complete as a part of the data migration. Data types and scenarios – With the general project plan structure in place, it is time to cover the common terms related to data migration. I will introduce you to the main aspects, such as master data and transactional data, as well as the impact they have on the complexity of data migration. SAP tools available for migration – During the course of our case study, I will introduce you to the data migration tools that come with SAP. However, there are also more advanced tools for complex migrations. You will learn about the main player in this area and how to use it. Process of migration – To avoid problems and guarantee success, the data migration project must follow a proven procedure. We will update the project plan to include the procedure and will also use the process during our case study. Making decisions about what data to bring – I mentioned that it is important to focus on information versus data. With the knowledge of the right tools and procedures, it is a good time to summarize the primary known issues and explain how to tackle them. The project plan We are still progressing in Phase 2 – Analysis and Design. The data migration is positioned in the Solution Architecture section and is called Review Data Conversion Needs (Amount and Type of Data). A thorough evaluation of the data conversion needs will also cover the next task in the project plan called Review Integration Points with any 3rd Party Solution. As you can see, the data migration task stands as a small task in the project plan. But as mentioned earlier, it can wind up being a large project depending on the number and size of data sources that need to be migrated. To honor this, we will add some more details to this task. As the task name suggests, we must review data conversion needs and identify the amount and type of data. This simple task must be structured in phases, just like the entire project that is structured in phases. Therefore, data migration needs to go through the following phases to be successful: 1. Design - Identify all of the Data Sources 2. Extraction of data into Excel or SQL for review and consistency 3. Review of Data and Verification(Via Customer Feedback) 4. Load into SAP System and Verification Note that the validation process and the consequential load could be iterative processes. For example, if the validated data has many issues, it only makes sense to perform a load into SAP if an additional verification takes place before the load. You only want to load data into an SAP system for testing if you know the quality of the records going to be loaded is good. Therefore, new phases were added in the project plan (seen below). Please do this in your project too based on the actual complexity and the number of data sources you have. A thorough look at the tasks above will be provided when we talk about the process of migration. Before we do that, the basic terms related to data migration will be covered. Data sources—where is my data There is a great variety in the potential types data sources. We will now identify the most common sources and explain their key characteristics. However, if there is a source that is not mentioned here, you can still migrate the data easily by transitioning it into one of the following formats. Microsoft Excel and text data migration The most common format for data migration is Excel, or text-based files. Text-based files are formatted using commas or tabs as field separators. When a comma is used as a field separator, the file format is referred to as Comma Separated Values (CSV). Most of the migration templates and strategies are based on Excel files that have specific columns where you can manually enter data, or copy and paste larger chunks. Therefore, if there is any way for you to extract data from your current system and present it in Excel, you have already done a great deal of data migration work. Microsoft Access An Access database is essentially an Excel sheet on a larger scale with added data consistency capability. It is a good idea to consider extracting Access tables to Excel in order to prepare for data migration. SQL If you have very large sets of data, then instead of using Excel, we usually employ an SQL database. The database then has a set of tables instead of Excel sheets. Using SQL tables, we can create SQL statements that can verify data and analyze results sets. Please note that you can use any SQL database, such as Microsoft SQL Server, Oracle, IBM DB, and so on. SaaS (Netsuite, Salesforce) SaaS stands for Software as a Service. Essentially, it means you can use software functionality based on a subscription. However, you don't own the solution. All of the hardware and software is installed at the service center, so you don't need to worry about hardware and software maintenance. However, keep in mind that these services don't allow you to manage the service packs according to your requirements. You need to adjust your business to the schedule of the SaaS company. If you are migrating from a modern SaaS solution, such as Salesforce or Netsuite, you will probably know that the data is not at your site, but rather stored at your solution hosting provider. Getting the data out to migrate to another solution may be done by obtaining reports, which could then be saved in an Excel format. Other legacy data The term legacy data is often mentioned when evaluating larger old systems. Legacy data basically comprises a large set of data that a company is using on mostly obsolete systems. AS/400 or Mainframe The IBM AS/400 is a good example of a legacy data source. Experts who are capable of extracting data from these systems are highly sought after, and so the budget must be on a higher scale. AS/400 data can often be extracted into a text or an Excel format. However, the data may come without headings. The headings are usually documented in a file that describes the data. You need to make sure that you get the file definitions, without which the pure text files may be meaningless. In addition, the media format is worth considering. An older AS/400 system may utilize a backup tape format which is not available on your Intel server. Peachtree, QuickBooks, and Act! Another potential source for data migration may be a smaller PC-based system, such as Peachtree, QuickBooks, or Act!. These systems have a different data format, and are based on non-SQL databases. This means the data cannot be accessed via SQL. In order to extract data from those systems, the proprietary API must be used. For example, if Peachtree displays data in the applications forms, it uses the program logic to put the pieces together from different text files. Getting data out from these types of systems is difficult and sometimes impossible. It is recommended to employ the relevant API to access the data in a structured way. You may want to run reports and export the results to text or Excel. Data classification in SAP Business ONE There are two main groups of data that we will migrate to the SAP Business ONE application: master data and transaction data. Master data Master data is the basic information that SAP Business ONE uses to record transactions (for example, business partner information). In addition, information about your products, such as items, finished goods, and raw materials are considered master data. Master data should always be migrated if possible. It can easily be verified and structured in an Excel or SQL format. For example, the data could be displayed using Excel sheets. You can then quickly verify that the data is showing up in the correct columns. In addition, you can see if the data is broken down into its required components. For example, each Excel column should represent a target field in SAP Business ONE. You should avoid having a single column in Excel that provides data for more than one target in SAP Business ONE. Transaction data Transaction data are proposals, orders, invoices, deliveries, and other similar information that comprise a combination of master data to create a unique business document. Customers often will want to migrate historical transactions from older systems. However, the consequences of doing this may have a landslide effect. For example, inventory is valuated based on specific settings in the finance section of a system. If these settings are not identical in the new system, transactions may look different in the old and the new system. This makes the migration very risky as the data verification becomes difficult on the customer side. I recommend making historical transactions available via a reporting database. For example, often, sales history must be available when migrating data. You can create a reporting database that provides sales history information. The user can use this data via reports within the SAP Business ONE application. Therefore, closed transactions should be migrated via a reporting database . Closed transactions are all of the business-related activities that were fully completed in the old system. Open transactions, on the other hand, are all of the business-related activities that are currently not completed. It makes sense that the open transactions be migrated directly to SAP, and not to a history database because they will be completed within the new SAP system. As a result of the data migration, you would be able to access sales history information from within SAP by accessing a reporting database. Open transactions will be completed within SAP, and then consequently lead to new transactions in SAP. Create a history database for sales history and manually enter open transactions. SAP DI-API Now that we know the main data types for an SAP migration, and the most common sources, we can take a brief look at the way the data is inserted into the SAP system. Based on the SAP guidelines, you are not allowed to insert data directly in the underlying SQL tables. The reason for that is that it can cause inconsistencies. When SAP works with the database, multiple tables are often updated. If you manually update a table to insert data, there is a good chance that another table has a link that also requires updating. Therefore, unless you know the exact table structure for the data you are trying to update, don't mess with the SAP SQL tables. If you carefully read this and understand the table structure, you will now know that there may be situations where you decide to access the tables directly. If you decide to insert data directly into the SAP database tables, you run the risk of losing your warranty. Migration scenarios and key decisions Data migration not only takes place as a part of a new SAP implementation, but also if you have a running system and you want to import leads or a list of new items. Therefore, it is a good idea to learn about the scenarios that you may come across and be able to select the right migration and integration tools. As outlined before, data can be divided into two groups: master data and transaction data. It is important that you separate the two, and structure each data migration accordingly. Master data is an essential component for manifesting transactions. Therefore, even if you need to bring over transactional data, the master data must already be in place. Always start with the master data alongside a verification procedure, and then continue with the relevant transaction data. Let’s now briefly look at the most common situations where you may require the evaluation of potential data migration options. New company (start-up) In this setup, you may not have extensive amounts of existing data to migrate. However, you may want to bring over lead lists or lists of items. During the course of this article, we will import a list of leads into SAP using the Excel Import functionality. Many new companies require the capability to easily import data into SAP. As you already know by now, the import of leads and item information will be considered as importing master data. Working with this master data by entering sales orders and so forth, would constitute transaction data. Transaction data is considered closed if all of the relevant actions are performed. For example, a sales order is considered closed if the items are delivered, invoiced, and paid for. If the chain of events is not complete, the transaction is open. Islands of data scenario This is the classic situation for an SAP implementation. You will first need to identify the available data sources and their formats. Then, you select the master data you want to bring over. With multiple islands of data, an SAP master record may result from more than one source. A business partner record may come, in part, from an existing accounting system, such as QuickBooks or Peachtree. Whereas other parts may come from a CRM system, such as Act!. For example, the billing information may be retrieved from the finance system and the relevant lead and sales information, such as specific contacts and notes, may come from the CRM system. In such a case, you need to merge this information into a new consistent master record in SAP. For this situation, first manually put the pieces together. Once the manual process works, you can attempt to automate the process. Don't try to directly import all of the data. You should always establish an intermediary level that allows for data verification. Only then import the data into SAP. For example, if you have QuickBooks and Act!, first merge the information into Excel for verification, and then import it into SAP. If the amount of data is large, you can also establish an SQL database. In that case, the Excel sheets would be replaced by SQL tables. IBM legacy data migration The migration of IBM legacy data is potentially the most challenging because the IBM systems are not directly compatible with Windows-based systems. Therefore, almost naturally, you will establish a text-based, or an Excel-formatted, representation of the IBM data. You can then proceed with verifying the information. SQL migration The easiest migration type is obviously the one where all of the data is already structured and consistent. However, you will not always have documentation of the table structure where the data resides. In this case, you need to create queries against the SQL tables to verify the data. The queries can then be saved as views. The views you create should always represent a consistent set of information that you can migrate. For example, if you have one table with address information, and another table with customer ID fields, you can create a view that consolidates this information into a single consistent set. Process of migration for your project I briefly touched upon the most common data migration scenarios so you can get a feel for the process. As you can see, whatever the source of data is, we always attempt to create an intermediary platform that allows the data to be verified. This intermediary platform is most commonly Excel or an SQL database. The process of data migration has the following subtasks: Identify available data sources Structure data into master data and transaction data Establish an intermediary platform with Excel or SQL Verify data Match data columns with Excel templates Run migration based on templates and verify data Based on this procedure, I have added more detail to the project plan. As you can see in this example, based on the required level of detail, we can make adjustments to the project plan to address the requirements: SAP standard import features Let's take a look at the available data exchange features in SAP. SAP provides two main tools for data migration. The fi rst option is to use the available menu in the SAP Business ONE client interface to exchange data. The other option is to use the Data Transfer Workbench (DTW). Standard import/export features— walk-through You can reach the Import from Excel form via Administration | Data Import/Export. As you can see in the following screenshot on the right top section of the form, the type of import is a drop-down selection. The options are BP and Items. In the screenshot, we have selected BP, which allows business partner information to be imported. There are drop-down fields that you can select based on the data you want to import. However, keep in mind that certain fields are mandatory, such as the BP Code field, whereas others are optional. The fields you select are associated with a column as you can see here: If you want to find out if a field is mandatory or not, simply open SAP and attempt to enter the data directly in the relevant SAP form. For example, if you are trying to import business partner information, enter the fields you want to import and see if the record can be saved. If you are missing any mandatory fields, SAP will provide an error message. You can modify the data that you are planning to import based on that. When you click on the OK button in the Import from Excel form (seen above), the Excel sheet with all of the data needs to be selected. In the following screenshot, you can see how the Excel sheet in our example looks. For example, column A has all of the BP Codes. This is in line with the mapping of columns to fields that we can see on the Import from Excel form. Please note that the file we select must be in a .txt format. For this example, I used the Save As feature in Excel (seen in the following screenshot) to save the file in the Text MS-DOS (*.txt) format. I was then able to select the BP Migration.txt file. This is actually a good thing because it points to the fact that you can use any application that can save data in the .txt format as the data source. The following screenshot shows the Save As screen: I imported the file and a success message confirms that the records were imported into SAP: A subsequent check in SAP confirms that the BP records that I had in the text file are now available in SAP: In the example, we only used two records. It is recommended to start out with a limited number of records to verify that the import is working. Therefore, you may start by reducing your import file to five records. This has the advantage of the import not taking a long time and you can immediately verify the result. See the following screenshot: Sometimes, it is not clear what kind of information SAP expects when importing. For example, at first Lead, Customer, Vendor were used in Column C to indicate the type of BP that was to be imported. However, this resulted in an error message upon completion of the import. Therefore, system information was activated to check what information SAP requires for the BP Type representation. As you can see in the screenshot of the Excel sheet you get when you click on the OK button in the Import from Excel form, the BP Type information is indicated by only one letter using L, C, or V. In the example screenshot above, you can clearly see L in the lower left section. The same thing is done for Country in the Addresses section. You can try that by navigating to Administration | Sales | Countries, and then hovering over the country you will be importing. In my example, USA was internally represented by SAP as US. It is a minor issue. However, when importing data, all of these issues need to be addressed. Please note that the file you are trying to import should not be open in Excel at the same time, as this may trigger an error. The Excel or text file does not have a header with a description of the data. Standard import/export features for your own project SAP’s standard import functionality for business partners and items is very straightforward. For your own project, you can prepare an Excel sheet for business partners and items. If you need to import BP or item information from another system, you can get this done quickly. If you get an error during the import process, try to manually enter the data in SAP. In addition, you can use the System Information feature to identify how SAP stores information in the database. I recommend you first create an Excel sheet with a maximum of two records to see if the basic information and data format is correct. Once you have this running, you can add all of the data you want to import. Overall, this functionality is a quick way to get your own data into the system. This feature can also be used in case you regularly receive address information. For example, if you have salespeople visiting trade fairs, you can provide them with the Excel sheet that you may have prepared for BP import. The salespeople can directly add their information there. Once they return from the trade fair with the Excel fi les, you can easily import the information into SAP and schedule follow-up activities using the Opportunity Management System. The item import is useful if you work with a vendor who updates his or her price lists and item information on a monthly basis. You can prepare an Excel template where the item information will regularly be entered and you can easily import the updates into SAP. Data Migration Workbench (DTW) The SAP standard import/export features are straightforward, but may not address the full complexity of the data that you need to import. For this situation, you may want to evaluate the SAP Data Migration Workbench (DTW). The functionality of this tool provides a greater level of detail to address the potential data structures that you want to import. To understand the basic concept of the DTW, it is a good idea to look at the different master data sections in SAP as business objects. A business object groups related information together. For example, BP information can have much more detail than what was previously shown in the standard import. The DTW templates and business objects To better understand the business object metaphor, you need to navigate to the DTW directory and evaluate the Templates folder. The templates are organized by business objects. The oBusinessPartners business object is represented by the folder with the same name (seen below). In this folder, you can find Excel template files that can be used to provide information for this type of business object. The following objects are available as Excel templates: BPAccountReceivables BPAddresses BPBankAccounts BPPaymentDates BPPaymentMethods BPWithholdingTax BusinessPartners ContactEmployees Please notice that these templates are Excel .xlt files, which is the Excel template extension. It is a good idea to browse through the list of templates and see the relevant templates. In a nutshell, you essentially add your own data to the templates and use DTW to import the data. Connecting to DTW In order to work with DTW, you need to connect to your SAP system using the DTW interface. The following screenshot shows the parameters I used to connect to the Lemonade Stand database: Once you are connected, a wizard-type interface walks you through the required steps to get started. Look at the next screenshot: The DTW examples and templates There is also an example folder in the DTW installation location on your system. This example folder has information about how to add information to your Excel templates. The following screenshot shows an example for business partner migration. You can see that the Excel template does have a header line on top that explains the content in the particular column. The actual template files also have comments in the header fi le, which provide information about the data format expected, such as String, Date, and so on. See the example in this screenshot: The actual template is empty and you need to add your information as shown here:   DTW for your own project If you realize that the basic import features in SAP are not sufficient, and your requirements are more challenging, evaluate DTW. Think of the data you want to import as business objects where information is logically grouped. If you are able to group your data together, you can modify the Excel templates with your own information. The DTW example folder provides working examples that you can use to get started. Please note that you should establish a test database before you start importing data this way. This is because once new data arrives in SAP, you need to verify the results based on the procedure discussed earlier. In addition, be prepared to fine-tune the import. Often, an import and data verification process takes four attempts of data importing and verification. Summary In this article, we covered the tasks related to data migration. This also included some practical examples for simple data imports related to business partner information and items. In addition, more advanced topics were covered by introducing the SAP DTW (Data Transfer Workbench) and the related aspects to get you started. During the course of this article, we positioned the data migration task in the project plan. The project plan was then fine-tuned with more detail to give some justice to the potential complexity of a data migration project. The data migration tasks established a process, from design to data mapping and verification of the data. Notably, the establishment of an intermediary data platform was recommended for your projects. This will help you verify data at each step of the migration. The key message of keeping it simple will be the basis for every migration project. The data verification task ensures simplicity and the quality of your data. If you have read this article you may be interested to view : Competitive Service and Contract Management in SAP Business ONE Implementation: Part 1 Competitive Service and Contract Management in SAP Business ONE Implementation: Part 2 Data Migration Scenarios in SAP Business ONE Application- part 2
Read more
  • 0
  • 0
  • 11269

article-image-creating-convincing-images-blender-internal-renderer-part2
Packt
20 Oct 2009
9 min read
Save for later

Creating Convincing Images with Blender Internal Renderer-part2

Packt
20 Oct 2009
9 min read
Textures In your journey as a 3d artist, you might have encountered several (if not all) astounding works of art.  And through close inspection, you’ll notice that we barely see them without textures.  That is because textures are one of the most important aspect of 3d, but still, this doesn’t apply to all.  But adding textures to your characters, props, environment, etc. will greatly add to the aesthetic factor of your image that you wouldn’t believe it would. There are a number of ways to add texture to your objects in 3D such as UV mapping techniques, projections, 2D painting, etc.  All of these depend entirely on what kind of render are you trying to achieve.  But for the sake of this article, we’ll try to achieve some nice looking textures without having to worry about the complex tasks involved with it.  And with this, we’ll be using the ever famous and useful procedural textures to create seamless and continuously looking texture mapped over the surface of our models. More information about Procedural Textures can be found on http://www.blender.org/development/release-logs/blender-233/procedural-textures/. Now let’s add some textures, shall we? Let’s select the character model in our scene then go to the Texture tab on the rightmost part of the Material Buttons window and click Add New to add a new texture. Adding a New Texture After having added a new texture, additional windows appear allowing us to further modify how the currently added texture will affect our material.  Name this first texture as “bump” and the mapping options can be seen below. Bump Texture Mapping Settings   Bump Texture Settings Add another texture below the “bump” texture and call it “stain”.  The settings can be seen below. Stain Texture Mapping Settings   Stain Texture Settings We could have added more overlaying textures, but this will do for now just so we could see how the textures have affected our material so far.  Rendering now will only lead us to the image below. Dirtier And Better :) This time might be a good idea to change our framing and staging so we could look at it at a better perspective.  Changing the camera angle and increasing the ground plane’s scale and some adjustments on the spheres, I achieved something like this: New Camera Angle For an even better interaction from within the scene, we will adjust some material settings to simulate hard and reflective surfaces.  It’s a little unfair to give our main character some good materials while neglecting the other stuff we have.  So let’s just get on, and add some decent materials as replacement to the initial materials that both the spheres have had before. Go on and select the larger sphere and edit the current material we have so it would match that of the settings as seen in the image below. You’ll notice I added a Color Ramp to each of the materials, this is to slightly give the color a color transition as would be seen in the natural world, in addition to the current diffuse it already has. The vital part of the shading process of the Spheres is the reflectivity and mirror options as you can see in the following table:     Ray Mirror Freshnel Green Sphere 0.12 0.76 Blue Sphere 0.21 0.99     Green Sphere Material Settings   Blue Sphere Material Settings Our render would now look like this: Reflections to Simulate Mirror Effect and Smoothness To nearly finalize this part, we now deal with adding a texture to the world and varying the colors that would affect the Occlusion effect. To do so, let’s first change the Horizon and Zenith color of our World and change the Ambient Occlusion diffuse energy to the color we’ve just set by changing from “Plain” to “Sky Color”, as seen below. World Settings Rendering now will lead us to: New World Settings Render Notice the subtle difference between the previous render and the latest one where the slight bluish hue is more distinguishable. And then lastly, since we've already added some decent reflective material over to our spheres, it would be best if we can also see some environment being reflected over, to add to the already existent character as one of the objects being reflected. To do this, we're going to add a texture to our World.  This is one nifty tool in simulating an environment since we don't have to do the hard work in manually creating the objects that are going to be reflected.  Not only does it save us a lot of time but also the ease by which we can alter these environment is already a big advantage that we have at our hands. So to do this, let's go ahead and go to our Shading (F5) and select World Buttons.  Scroll to the far left side and you'll see tabs labeled “Texture and Input” and “Map To”, both of these tabs are essential in setting up our World texture so pay close attention to them. Below is an image that further shows you what we need to set up (sorry for the sudden theme change). World Texture You might have already guessed what we should do next, if not, I'll continue on.  After heading over to the “Texture and Input” and “Map To” tabs, let's first focus on what's active by default, that is, “Texture and Input”.  In this part, we'll only need a few things to get started.  First is to click “Add New” to add a new texture datablock to our blender scene, after which, let's edit the name of our texture and name it “environment”, then change the coordinates from “View” to “AngMap” to use a 360 degree angular coordinate, you'll see why in awhile. Adding a World Texture After applying these initial settings, we'll go ahead and proceed to the actual texturing process, which, as far as the World is concerned is just a very quick process.  I suppose you're still on the same Buttons window that we're on last time.  Click on the Texture button or press F6 on your function keys. Bam! Another set of Windows.  You'll see here that the texture we named “environment” awhile back is now reflected over to one of the texture slots, just like what we previously did with texturing the character we have.  But this time, instead of choosing procedural textures like Clouds, Voronoi, Noise, etc., we'll now be dealing with an image texture, as in our case, an HDRi (High Dynamic Range Image).  Our purpose in using an HDR image is to simulate the wide range of intensity levels (brightness and darkness) that is seen in reality and apply these settings over to our world, thus reflected upon by our objects.  As in our case, we'll be using high dynamic range images as light probes which are oriented 360 degrees and that's the very reason why we chose “AngMap” as our World texture coordinate. More info about HDRi can be seen at http://en.wikipedia.org/wiki/High_dynamic_range_imaging and you can download Light Probe Images over at Paul Debevec's collection at http://www.debevec.org/Probes.  Save your downloaded light probe images somewhere you can easily identify them with.  I couldn't stress enough how file organization can greatly help you in your career.  You could just imagine how frustrating it is to find assets among a thousand you already have, without properly placing them in their right places, this counts for every project you have as well . So to open up our Light Probe Image as texture to our World, click the drop down menu and choose “Image” as your texture type.  This tells Blender to use an image instead of the default procedural textures.  Then head to the far right side to locate the Image tab with a Load button on it.  Let's skip the Map Image tab for now. Image as Texture Type Loading an Image Texture Browse over at your downloaded HDR image (which should have an extension of .hdr) and confirm.  Now that the image is loaded, let's leave the default settings as they are since we wouldn't be using them that much.  You'll see on the far left Preview just how wonderful looking our image is.  But rendering your scene right now would yield to nothing but the same previous render we've had.  So if you're itching to get this image right at our scene (which I am too), go back to your World Settings and head over to the “Map To” tab just beside “Texture and Input” then deselect “Blend” and select “Hori” instead.  Kabam! Now we're all set! World Texture Mapping options And now, the moment we've all been eagerly waiting for, the Render! Yup, go ahead and render and it would (luckily) look like the image below. Render with HDRi Environment Then finally, on the next and last part of this article, we'll look on how we can even further add realism to our scene by simulating camera lenses and further enhancing the tone of the image with Composite Nodes.  
Read more
  • 0
  • 0
  • 4082
Modal Close icon
Modal Close icon