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

How-To Tutorials

7018 Articles
article-image-joomla-template-system
Packt
12 Dec 2013
9 min read
Save for later

Joomla! Template System

Packt
12 Dec 2013
9 min read
(For more resources related to this topic, see here.) Every website has some content, and all kinds of information is provided on websites; not just text, but pictures, animations, and video clips—anything that communicates a site's body of knowledge. However, visual design is the appearance of the site. A good visual design is one that is high quality, appropriate, and relevant to the audience and the message it supports. As a large amount of companies feel the need to redesign their site very few years, they need someone who can stand back and figure out what all that content should communicate. This could be you. The basic principle of Joomla! (and other content management systems) is to separate the content from its visual form. Although this separation is not absolute, it is distinct enough to facilitate quick and efficient customization and deployment of websites. Changing the appearance of web pages built on CMS comes down to installing and configuring a new template. A template is a set of files that determine the look and feel of your Joomla-powered website. Templates include information about the general layout of the site and other content, such as graphics, colors, background images, headers, logos, and typography and footers. Each template is different, offering many choices for site owners to almost instantly change the look of their website. You can see the result of this separation of content from presentation by changing the default template (preinstalled in Joomla!). For web designers, learning how to develop templates for content management systems such as Joomla! opens up lots of opportunities. Joomla! gives you big opportunities to build websites. Taking into account the evolution of web browsers, you are only limited by your imagination and skill set, thanks to a powerful and flexible CMS infrastructure. The ability to change or modify the content and appearance of web pages is important in today's online landscape. What is a Joomla! template? As in the case of traditional HTML templates, Joomla! template is a collection of files (PHP, CSS, and JavaScript) that define the visual appearance of the site. Each template has variations on these files, and each template's files are different, but they have a common purpose; they control the placement of the elements on the screen and impact both the presentation of the contents and the usability of the functionality. In general, a template does not have any content, but it can include logo and background images. The Joomla! template controls the way all information is shown on each page of the website. A template contains the stylesheets, locations, and layout information for the web content being displayed. Also each installed component can have its own template to present content that can overwrite the default template's CSS styles. A template alone cannot be called a website. Generally, people think of the template as the appearance of their site. But a template is only a structure (usually painted and colored) with active fields. It determines the appearance of individual elements (for example, font size, color, backgrounds, style, and spacing) and arrangement of individual elements (including modules). In Joomla!, a single page view is generated by the HTML output of one component, selected modules, and the template. Unlike typical websites, where different components of the template are duplicated throughout the website pages, in case of Joomla!, there is just one assigned template that is responsible for displaying content for the entire site. Most CMS's, Joomla! included, have a modular structure that allows easy improvement of the site's appearance and functionality by installing and publishing modules in appropriate areas. Search engines don't care about design, but people do. How well a template is designed and implemented is, therefore, largely responsible for the first impression made by a website, which later translates into the perception that people have of the entire website. Joomla! released Joomla! Version 3.0.0 on September 27, 2012 with significant updates and major developments. With the adoption of the Twitter Bootstrap framework, Joomla! has become the first major CMS to be mobile ready in both visitor and administrator areas. Bootstrap (http://twitter.github.com/bootstrap) is an open source JavaScript framework developed by the team at Twitter. It is a combination of HTML, CSS, and JavaScript code designed to help build user interface components. Bootstrap was also programmed to support both HTML5 and CSS3. As a result, page layout uses a 1152 px * 1132 px * 1116 px * 1104 px grid, whereas previous versions of Joomla! templates used a 940 px wide layout. Default template stylesheets in Joomla! 3.x are written with LESS, and are then compiled to generate the CSS files. Because of the use of Bootstrap, Joomla! 3.x will slowly begin to migrate toward jQuery in the core (instead of MooTools). Mootools is no longer the primary JavaScript library interface. Joomla! 3.x templates are not compatible with previous versions of Joomla! and have been developed as a separate product. Templates – download for free, buy, or build your own I also want to show you the sites where you can download templates for free or buy them; after all, this book is supposed to teach you how to create your own sites. There are a number of reasons for this. First, you might not have the time or the ability to design a template or create it from scratch for the customer. You can set up your website within minutes because all you have to do is install or upload your template and begin adding content. By swapping the header image and changing the background color or image, you can transform a template with very little additional work. Second, as you read the book you will get acquainted with the basic principles of modifying templates, and thus you will learn how to adapt the ready-made solutions to the specific needs of your project. In general, you don't need to know much about PHP to use or tweak prebuilt templates. Templates can be customized by anyone with basic HTML/CSS knowledge. You can customize template elements to make it suit your needs or those of your client using a simple CSS editor; your template can be configured by template parameters. Third, learn from other template developers. Follow every move of your competitors. When they release an interesting, functional, and popular template, follow (but do not copy) them. We can all learn from others; projects by other people are probably one of the most obvious sources of inspiration. The following screenshot presents a few commercial templates for Joomla! 3.x. built in 2013 by popular developers, bearing in mind, however, that the line between inspiration and plagiarism is often very thin: Free templates Premade free templates are a great solution for those who have a limited budget. It is good experience to use the work of different developers and is also a great way to test a new web concept without investing much apart from your time. There are some decent free templates out there that may even be suitable for a small or medium production website. If you don't like a certain template after using it for a bit, ditching it doesn't mean any loss in investment. Unfortunately, there are also some disadvantages of using free templates. These templates are not unique. Several thousands of web designers from around the world may have already downloaded and used the template you have chosen. So if you don't change the colors or layout a bit, your site will look like a clone, which would be quite unprofessional. Generally, free Joomla! templates don't have any important or useful features such as color variants, Google fonts, advanced typography, CSS compression options, or even responsive layout. On the downside of free templates, you have the obvious quality issues. The majority of free templates are very basic and sometimes even buggy. The support for free templates is almost always lacking. While there are a few free templates that are supported by their creators, they are under no obligation to provide full support to your template if you need help adjusting the layout or fixing a problem due to an error. Realize that developers often use free templates to advertise their cost structures, expansion versions, or club subscriptions. That's why some developers require you to leave a link to their website on the bottom of your page if you use their free templates. What was surprising to me was that not all the free templates for Joomla! 3.x are mobile friendly, despite the fact that even the built-in CMS are built as Responsive Web Design (RWD). In most cases, it was presumably intended by the creators to look like JoomlaShine or Globbersthemes. The following is a list of resources from where you can download different kinds of free templates: www.joomla24.com www.joomlaos.de www.siteground.com/joomla-templates.htm www.bestofjoomla.com Quite often, popular developers publish free templates on their websites; in this way they promote their brand and other products such as modules or commercial versions of templates. Those templates always have better quality and features than others. I suggest that you download free templates only from reliable sources. It is with a great deal of care that you should approach templates shared on discussion forums or blogs because there's a high probability that the code template has been deliberately modified. A huge proportion of templates available for free are in fact packaged with malicious code. Summary Hopefully, after reading this article you will have a better understanding of the features of the Joomla! Template Manager and the types of problems it is able to solve. Resources for Article: Further resources on this subject: Installing and Configuring Joomla! on Local and Remote Servers [Article] Joomla! 1.5: Installing, Creating, and Managing Modules [Article] Tips and Tricks for Joomla! Multimedia [Article]
Read more
  • 0
  • 0
  • 11705

article-image-managing-ibm-cognos-bi-server-components
Packt
12 Dec 2013
6 min read
Save for later

Managing IBM Cognos BI Server Components

Packt
12 Dec 2013
6 min read
(for more resources related to this topic, see here.) Cognos BI architecture The IBM Cognos 10.2 BI architecture is separated into the following three tiers: Web server (gateways) Applications (dispatcher and Content Manager) Data (reporting/querying the database, content store, metric store) Web server (gateways) The user starts a web session with Cognos to connect to the IBM Cognos Connection's web-based interface/application using the web browser (Internet Explorer and Mozilla Firefox are the currently supported browsers). This web request is sent to the web server where the Cognos gateway resides. The gateway is a server-software program that works as an intermediate party between the web server and other servers, such as an application server. The following diagram shows the basic view of the three tiers of the Cognos BI architecture: The Cognos gateway is the starting point from where a request is received and transferred to the BI Server. On receiving a request from the web server, the Cognos gateway applies encryption to the information received, adds necessary environment variables and authentication namespace, and transfers the information to the application server (or dispatcher). Similarly, when the data has been processed and the presentation is ready, it is rendered towards the user's browser via the gateway and web server. The following diagram shows the Tier 1 layer in detail: The gateways must be configured to communicate with the application component (dispatcher) in a distributed environment. To make a failover cluster, more than one BI Server may be configured. The following types of web gateways are supported: CGI: This is also the default gateway. This is a basic gateway. ISAPI: This is for the Windows environment. It is the best for Windows IIS (Internet Information Services). Servlet: This gateway is the best for application servers that are supporting servlets. Apache_mod: This gateway type may be used for the Apache server. The following diagram shows an environment in which the web server is load balanced by two server machines: To improve performance, gateways (if more than one) must be installed and configured on separate machines. The application tier (Cognos BI Server) The application tier comprises one or multiple BI Servers. A server's job is to run user requests, for example, queries, reports, and analysis that are received from a gateway. The GUI environment (IBM Cognos Connection) that appears after logging in is also rendered and presented by Cognos BI Server. Another such example is the Metric Studio interface. The BI Server must include the dispatcher and Content Manager (the Content Manager component may be separated from the dispatcher). The following diagram shows BI Server's Tier 2 in detail: Dispatcher The dispatcher has static handlers to many services. Each request that is received is routed to the corresponding service for further processing. The dispatcher is also responsible for starting all the Cognos services at startup. These services include the system service, report service, report data service, presentation service, Metric Studio service, log service, job service, event management service, Content Manager service, batch report service, delivery service, and many others. When there are multiple dispatchers in a multitier architecture, a dispatcher may also send and route requests to another dispatcher. The URIs for all dispatchers must be known to the Cognos gateway(s). All dispatchers are registered in Content Manager (CM), making it possible for all dispatchers to know each other. A dispatcher grid is formed in this way. To improve the system performance, multiple dispatchers must be installed but on separate computers, and the Content Manager component must also be on a separate server. The following diagram shows how multiple dispatcher servers can be added. Services for the BI Server (dispatcher) Each dispatcher has a set of services, which are listed alphabetically in the following table. When the Cognos service is started from Cognos Configuration, all services are started one by one. The following table shows the dispatcher services and their short descriptions: Service Description Agent service Runs the agent. Annotation service Adds comments to reports. Batch report service Handles background report requests. Content manager cache service Handles cache for frequent queries to enhance performance of Content Manager. Content manager service Performs DML in content store db. Cognos deployment is another task for this service. Delivery service For sending e-mails. Event management service Manages the Event Objects (creation, scheduling, and so on) Graphics service Renders graphics for other services such as report service. Human task service Manages human tasks. Index data service For basic full-text functions for storage and retrieval of terms and indexed summary documents. Index search service For search and drill-through functions, including lists of aliases and examples. Index update service For write, update, delete, and administration-related functions. Job service Runs jobs in coordination with the monitor service. Log service For extensive logging of the Cognos environment (file, database, remote-log server, event viewer, and system log). Metadata service For displaying data lineage information (data source, calculation expressions) for the Cognos studios and viewer. Metric studio service This service is used for providing a user interface to metric studio for monitoring and manipulating system KPIs. Migration service Used for migration from old versions to new versions, especially series 7. Monitor service Works as a timer service-it manages the monitoring and running of tasks that were scheduled or marked as background tasks. Helps in failover and recovery for running tasks. Presentation service This service prepares and displays the presentation layer by converting the XML data to HTML or any other format view. IBM Cognos Connection is also prepared by this service. Query service For managing dynamic query requests. Report data service This service prepares data for other applications; for example mobile, Microsoft Office, and so on. Report service Manages report requests. The output is displayed in IBM Cognos Connection. System service This service defines the BI-Bus API compliant service. It gives more data about the BI configuration parameters. Summary This article covered the IBM Cognos BI architecture. Now you must be familiar with the single tier and multitier architectures and a variety of features and options that Cognos provides. resources for article: further resources on this subject: IBM Cognos Insight [article] Integrating IBM Cognos TM1 with IBM Cognos 8 BI [article] IBM Cognos 10 BI dashboarding components [article]
Read more
  • 0
  • 0
  • 4850

article-image-logging-capabilities
Packt
10 Dec 2013
6 min read
Save for later

Logging Capabilities

Packt
10 Dec 2013
6 min read
(For more resources related to this topic, see here.) Posting messages to the log TestComplete allows committing various types of messages to the log: ordinary messages, warnings, logs, and so on. In this section, we will consider examples of how to use these messages. Getting ready Create a file with the name myfile.txt in the root directory of C:. How to do it... In order to see examples of all the message types in the log, the following steps should be performed: Create and launch the following function: function testMessages() { Log.Event("An event", "Event additional Info"); Log.Message("A message", "Message additional Info"); Log.Warning("A warning", "Warning additional Info"); Log.Error("An error", "Error additional Info"); Log.File("C:\somefile.txt", "A file posted to the log"); Log.Link("C:\somefile.txt", "A link to a file"); Log.Link("http://smartbear.com/", "HTTP link"); Log.Link("ftp://smartbear.com/", "FTP link"); } In the result, we will get the following screenshot of the log How it works... In the given example, we have used four different types of messages. They are as follows: Log.Event: This message is an event which occurs when TestComplete interacts with a tested application. Usually, messages of this type are placed into the log at the point of text input or mouse-clicks; however, we can also place custom-made events into the log. Log.Message: This message is an ordinary message that is usually used for prompting a user concerning current actions that are being executed by the script (usually, of a higher level than that of the events; for example, creation of a user, searching for a record, and so on). Log.Warning: This message is a non-critical error. It is used in case the results of the check are different from those expected; nonetheless, execution of the script can carry on. Log.Error: This message is a critical error usually used when an error is a critical one, making any further execution of the test would be futile These four types of message are based on several parameters. The first of them is a string that we observe in the log itself; the second one contains additional information which can be seen in the Additional Info tab, if the message has been clicked on. The second parameter is optional and can be omitted as well as all other parameters. There are two more types of messages: Log.File: This message copies the assigned file into the file with the log, and places a reference-pointer to it. Meanwhile, TestComplete renames the file to avoid naming conflicts, leaving only the original extension intact. Log.Link: This message places a link to the web page or a file, without making a copy of the file itself in the folder with the log. On clicking on the link, the file will open with the help of the associated program or a link in the browser. These two types of message accept the link as the first parameter, and then the message parameters, and those pertaining to the additional information (as the previous four). Only the first parameter is mandatory. Posting screenshots to the log Sometimes, it is necessary to place an image into the log; often, it may be a window screenshot, an image of a controls element, or even that of the whole of the screen. To this end, we use the Log.Picture method. In this section we will consider different ways to place an image into the log. How to do it... The following steps should be performed to place an image to the log: First of all, we will create two image objects for the enabled window and the whole of the screen: var picWindow = Sys.Desktop.ActiveWindow().Picture(); var picDesktop = Sys.Desktop.Picture(); The image of the active window, now being stored in the picWindow variable , will be placed into the log, unchanged: Log.Picture(picWindow, "Active window"); The image of the desktop is reduced by four times via the Stretch method , and then saved on to the file with the help of the SaveToFile method: picDesktop.Stretch(picDesktop.Size.Width/2, picDesktop.Size.Height/2); picDesktop.SaveToFile("c:\desktop.png"); Now we go about creating a new variable of the Picture type, loading up an image into it from the earlier saved file, and then placing the same into the log: var pic = Utils.Picture; pic.LoadFromFile("c:\desktop.png"); Log.Picture(pic, "Resized Desktop"); As a result of function's execution, the log will contain the two images placed therein: that of the enabled window at the moment of test execution, and that of the reduced desktop copy. How it works... The Log.Picture method has one mandatory parameter that is, the image itself; the other parameters being optional. Images of any of the onscreen objects (of a window, of a singular controls element, of the desktop) can be obtained via the Picture method. In our example, with the help of the method, we get the image of the desktop and that of the active window. Instead of the active window, we could use any variable that corresponds to a window or a controls element. Any image can be saved onto the disk with the help of the SaveToFile method. The format of the saved image is determined by its extension (in our case, it is the PNG). If it's necessary to obtain a variable containing the image from the file, we are supposed to create an empty variable placeholder with the help of the Utils.Picture property , and then with the help of the LoadFromFile method , we upload the image into it. In the future, one could handle the image as any other, received with the help of the Picture method. Great-size images can be minified with the help of the Stretch method. The Stretch method uses two parameters: the new width and height of the image. With the help of the Size.Width and Size.Height properties , we could zoom in or out on the image in relation to its original size, without setting the dimensions explicitly. There's more... With the help of the Picture method , we could obtain not only the image of the whole window or a controls element, but just a part of it. For example, the following code gets an image of the upper left square of the desktop within the sizing of 50 x 50 pixels: var picDesktop = Sys.Desktop.Picture(0,0, 50, 50); The values of the parameters are as follows: coordinates of the left and right top corner, and its width and height. There is one important project setting which allows automatic posting images in case of error. To enable this option, right-click on the project name, navigate to Edit | Properties, click on Playback item from the list of options, and enable checkbox Post image on error. Apart from changing the dimensions of the image, TestComplete allows for the execution of several, quite complicated imaging manipulations. For example, the comparison of the two images (the Compare method ), searching for one image inside the other (the Find method ), and so on. Click on the following link to get to know more about these possibilities: http://support.smartbear.com/viewarticle/32131/
Read more
  • 0
  • 0
  • 2394

article-image-installation-oracle-vm-virtualbox-linux
Packt
09 Dec 2013
4 min read
Save for later

Installation of Oracle VM VirtualBox on Linux

Packt
09 Dec 2013
4 min read
(For more resources related to this topic, see here.) Basic requirements The following are the basic requirements for VirtualBox: Processor: Any recent AMD/Intel processor is fine to run VirtualBox. Memory: This is dependent on the size of the RAM that is required for the host OS, plus the amount of RAM needed by the guest OS. In my test environment, I am using 4 GB RAM and going to run Oracle Enterprise Linux 6.2 as the guest OS. Hard disk space: VirtualBox doesn’t need much space, but you need to plan out how much the host OS needs and how much you need for the guest OS. Host OS: You need to make sure that the host OS is certified to run VirtualBox. Host OS At the time of writing this article, VirtualBox runs on the following host operating systems: Windows The following Microsoft Windows operating systems are compatible to run as host OS for VirtualBox: Windows XP, all service packs (32-bit) Windows Server 2003 (32-bit) Windows Vista (32-bit and 64-bit) Windows Server 2008 (32-bit and 64-bit) Windows 7 (32-bit and 64-bit) Windows 8 (32-bit and 64-bit) Windows Server 2012 (64-bit) Mac OS X The following Mac OS X operating systems are compatible to run as host OS for VirtualBox: 10.6 (Snow Leopard, 32-bit and 64-bit) 10.7 (Lion, 32-bit and 64-bit) 10.8 (Mountain Lion, 64-bit) Linux The following Linux operating systems are compatible to run as host OS for VirtualBox: Debian GNU/Linux 5.0 (lenny) and 6.0 (squeeze) Oracle Enterprise Linux 4 and 5, Oracle Linux 6 Red Hat Enterprise Linux 4, 5, and 6 Fedora Core 4 to 17 Gentoo Linux openSUSE 11.0, 11.1, 11.2, 11.3, 11.4, 12.1, and 12.2 Mandriva 2010 and 2011 Solaris Both 32-bit and 64-bit versions of Solaris are supported with some limitations. Please refer to www.virtualbox.org for more information. The following host OS are supported: Solaris 11 including Solaris 11 Express Solaris 10 (update 8 and higher) Guest OS You need to make sure that the guest OSis certified to run on VirtualBox. VirtualBox supports the following guest operating systems: Windows 3.x Windows NT 4.0 Windows 2000 Windows XP Windows Server 2003 Windows Vista Windows 7 DOS Linux (2.4, 2.6, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, and 3.7) Solaris OpenSolaris OpenBSD Installation I have downloaded and used the VirtualBox repository to install VirtualBox. Please ensure the desktop or laptop you are installing VirtualBox on is connected to the Internet. However, this is not mandatory. You can install VirtualBox using the RPM command, which generally adds the complexity of finding and installing the dependency packages, or you can have a central yum server where you can add VirtualBox repository. In my test lab, my laptop is connected to the Internet and I have used the wget command to download and add virtualbox.repository. Installing dependency packages Please ensure installing the packages seen in the following screenshot to make VirtualBox work: Installing VirtualBox 4.2.16 Once the preceding dependency is installed, we are ready to install VirtualBox 4.2.16. Use the command seen in the following screenshot to install VirtualBox: Rebuilding kernel modules The vboxdrv module is a special kernel module that helps to allocate the physical memory and to gain control of the processor for the guest system execution. Without this kernel module, you can still use the VirtualBox manager to configure the virtual machines, but they will not start. When you install VirtualBox by default, this module gets installed on the system. But to maintain future kernel updates, I suggest that you install Dynamic Kernel Module Support (DKMS). In most of the cases, this module installation is straightforward. You can use yum, apt-get, and so on depending on the Linux variant you are using, but ensure that the GNU compiler (GCC), GNU make (make), and packages containing header files for your kernel are installed prior to installing DKMS. Also, ensure that all system updates are installed. Once the kernel of your Linux host is updated and DKMS is not installed, the kernel module needs to be reinstalled by executing the following command as root: The preceding command not only rebuilds the kernel modules but also automatically creates the vboxusers group and the VirtualBox user. If you use Microsoft Windows on your desktop, then download the .exe file, install it, and start it from the desktop shortcut or from the program. Start VirtualBox Use the command seen in the following screenshot in Linux to run VirtualBox: If everything is fine, then the Oracle VM VirtualBox Manager screen appears as seen in the following screenshot: Update VirtualBox You can update VirtualBox with the help of the command seen in the following screenshot: Remove VirtualBox To remove VirtualBox, use the command seen in the following screenshot: Summary In this article we have covered the installation, update, and removal of Oracle VM VirtualBox in the Linux environment. Resources for Article: Further resources on this subject: Oracle VM Management [Article] Extending Oracle VM Management [Article] Troubleshooting and Gotchas in Oracle VM Manager 2.1.2 [Article]
Read more
  • 0
  • 0
  • 37827

article-image-using-advanced-host-configurations-and-opsview-pro-features
Packt
09 Dec 2013
12 min read
Save for later

Using Advanced Host Configurations and Opsview Pro Features

Packt
09 Dec 2013
12 min read
(for more resources related to this topic, see here.) Using the advanced host configuration Opsview offers an advanced way of defining hosts, and we have already seen some of these, such as exceptions, the SNMP setup, and host attributes; however, there is more. The first one is the Other Addresses field that we can use to assign multiple IP addresses or hostnames to our host, and the second is the parent field that allows us to set up a structure that we can use to detect network outages. Monitoring multi-homed hosts Without the Other Addresses field, we would have to create unique hosts for each interface that we would like to monitor (in some cases, this can be a plus). This means that we need to maintain different configurations for each IP. If your hosts are set up in an environment with a separate management and production network for instance, using Other Addresses allows you to keep all the checks within a single host, giving you a single view of that host. To use this, go to settings | Basic | hosts, select your host to edit, and fill in any additional addresses that your host may have, as shown in the following screenshot (for clarity, we have used IPs but using hostnames is perfectly fine): To use these addresses in our service check, Opsview (such as host attributes) uses a macro to make them available; to use the first address, simply use the macro $ADDRESS1$, for the second use $ADDRESS2$, and so on. Remember the service check that we discussed while looking at host attributes. Well, here's the same service check, but now we want it to run against the third IP address. So, we input the correct macro and we are done. check_mysql -H $ADDRESS3$ -u %MYSQCREDENTIALS:1% -p %MYSQLCREDENTIALS:2% -d %MYSQLCREDENTIALS% Using parenting for network outage detection Let's assume that our Opsview server is connected to switchA. RouterA is also connected to switchA. So, if switchA fails from the Opsview server's point of view, RouterA becomes unreachable. Unreachable simply means that there is another issue that prevents us from determining the real state of our host. You can turn the notifications on and off for the Unreachable field in your Notification profile. Turning it off will prevent a lot of notifications during network outages. To set up this relationship, we first need to edit the host, switchA from settings Basic | Hosts, and we have defined Opsview as its parent, as shown in the following screenshot: Once submitted, we then edit the host, RouterA, and add switchA as its parent, as shown in the following screenshot: After applying the changes through the settings menu, we can see our newly set up relations from the Monitoring | Status Detail | Network screen, as shown in the following screenshot: Using parenting can really help while trying to figure out why a certain host (or hosts) have gone DOWN by letting Opsview detect if there is an issue with the network. It can also save you loads of notifications (which can be overwhelming if, for instance, a data center switch connecting hundreds of hosts fails). The fastest and easiest way of determining the path from Opsview to any host is to simply run traceroute from the Opsview server and duplicate the path in Opsview. Autodiscovery The first feature we will look at is the autodiscovery tool that allows you to scan your network for hosts that could be monitored by Opsview. There are two types of scans available from the feature: a basic network scan and a special VMware scan (more scan types may be added in the future). Firewalls If your network is protected (and divided) by firewalls, you might have trouble running scans (or get fewer results than you expected); this is caused by firewalls detecting the scan and marking it as unwanted traffic. If you experience issues, make sure that you check the firewall and verify that it is allowing traffic from the Opsview server. Network scan To start a scan, navigate to settings | Basic | Auto-Discovery and click on the Network Scan button to bring up the configuration menu for our new scan. There are two sections that can be used to perform our scan. The first section covers the basics such as a label for our scan, the IP addresses (you can use network statements such as 192.168.1.0/24), and a number of default settings, as shown in the following screenshot: The second section (Detection Mapping) covers the detection mechanisms which include detection of common network services (such as SMTP, WWW, and so on), agent-based detection, and agentless detection using WMI, SNMP, and VMware vSphere host detection, as shown in the following screenshot: Now, click on Save and you will see that a new job is created using our settings, and by clicking on our job, we can start the scan, edit, clone, or delete it. Depending on the number of IPs to scan and the number of services set up in the detection section scans, an estimated time for completion is shown once you click on Save. Once our job has finished, we can view the results by double-clicking on our job name, and we will be presented with a list of detected hosts and services. You can edit each host or edit in bulk and then import them into Opsview by selecting the hosts and clicking on Import into Opsview. You can then see your new hosts on the settings | Basic | Hosts screen. VMware scan A VMware scan is a quick way of finding VM guests running in your virtual environment and importing them into Opsview. Before we can run a VMware scan, there are some requirements we need to look at. First, we must have the VMware vSphere SDK for Perl installed on our Opsview server (which you can download from the VMware website: https://my.vmware.com/web/vmware/details?downloadGroup=SDKPERL550&productId=353). Next, each VM Guest should be running the VMware tools as we will use these to gather IP information about our guests from our VMware vSphere Hosts. And finally, we need our VMware hosts that we can scan for using the network scan and enabling the detection mapping for VMware. The VMware mapping is based on using the vSphere SDK to communicate with the VMware API; so make sure that the Opsview server can communicate with your vSphere servers using HTTPS. Shown in the following screenshot is an example of a detected VMware vSphere host: Click on VMware, enter the VMware credentials for the host, save it, and click on VMware scan from the Scan management tab to start a scan for VMs running on this host (or hosts if multiple vSphere hosts were detected). This uses the same principles as the VMware detection mapping and uses the VMware API to communicate with vSphere. Additionally, Opsview will automatically set the parent of the detected guests as the VMware host; so, you do not have to manually add the parent. Once completed, select and import the VMs after which you can view the new hosts from the settings | Basic | Hosts list. SNMP traps Most network devices are capable of sending out SNMP traps when certain events occur (this is not restricted to network equipment though). Using the SNMP trap receiver in Opsview allows you to catch these events and process them in Opsview. Please note that setting up and using SNMP traps is a complex task, and being familiar with the command line and SNMP tools in general is highly recommended. Traps received by Opsview are evaluated based on the originating host, and if this host has an SNMP trap service check assigned to it, it will be evaluated based on the rules of the service check (a host can have multiple SNMP trap service checks, and each service check can have multiple rules). To use SNMP traps in Opsview, we will need to configure our system so that any incoming traps are forwarded to Opsview. Configuration Depending on your operating system, you will need to install the SNMPD packages that are required for SNMP traps. On Debian/Ubuntu-based systems, run apt-get install snmpd to install the required packages. Once installed, we need to configure the following items so that we can use device-specific MIBs. Add the following line to your snmp.conf file (file and location might vary depending on the operating system) to add the /usr/local/nagios/snmp/load directory (this is the directory where we can add device-specific MIBs to be used with Opsview). mibdirs +/usr/local/nagios/snmp/load Next, we need to set up the trap receiver by adding these lines to the /etc/default/snmpd configuration file: TRAPDRUN=yes TRAPDOPTS='-t -m ALL -M /usr/share/snmp/mibs:/usr/local/nagios/snmp/ load -p /var/run/snmptrapd.pid' SNMPDOPTS='-u nagios -Lsd -Lf /dev/null -p/var/run/snmpd.pid' Now, we need to configure the SNMP trap daemon to forward any events received to Opsview; for this, we edit the snmptrapd.conf configuration file and add: traphandle default /usr/local/nagios/bin/snmptrap2nagios And finally, we need to allow the user running Opsview (the nagios user) to be able to restart SNMP and the SNMP trap daemons if we load new MIBs and so on by adding the following line to our sudoers file using the visudo command: nagios ALL=NOPASSWD: /usr/local/nagios/bin/snmpd reload Once completed, we can now start using the SNMP traps in Opsview. SNMP trap service check Opsview Pro does come with a number of predefined SNMP trap service checks and host templates and they will cover the basics, but you can create your own checks with your own rules as we will see here. Once configured, we can start creating SNMP trap service checks; only now we will have some additional options, as shown in the following screenshot: By clicking on the Edit rules link at the bottom of the screen, we can edit any rules assigned to this check. The rules form the basis of the SNMP trap system, and you can create multiple rules within one service check (the processing will stop when a rule that is considered TRUE is found and any subsequent rules are then skipped). The following screenshot shows an example of a group of rules that will be checked against (taken from the SNMP Trap - Link State service check): Exceptions If for some reason the devices are sending traps that Opsview can't process (due to lack of rules or missing MIBs), they will end up in the SNMP Trap Exceptions section located at settings | Advanced | SNMP Traps. From this menu, you can view traps that have failed to match and view debug information that can be used to fix any rules or help in creating rules. Rules Making rules for SNMP traps works by using lines, values, and tags to perform matching. So let's have a look at an example SMNP trap to see how we can create rules. Here's an example trap from a Cisco network device. This information will be similar to what you will find in the SNMP Trap Exceptions section. For clarity, we have added line numbers. cisco2611.lon.altinity 192.168.10.20 SNMPv2-MIB::sysUpTime.0 9:16:47:53.80 SNMPv2-MIB::snmpTrapOID.0 IF-MIB::linkUp IF-MIB::ifIndex.2 2 IF-MIB::ifDescr.2 Serial0/0 IF-MIB::ifType.2 ppp SNMPv2-SMI::enterprises.9.2.2.1.1.20.2 "PPP LCP Open" SNMP-COMMUNITY-MIB::snmpTrapAddress.0 192.168.10.20 SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 "public" SNMPv2-MIB::snmpTrapEnterprise.0 SNMPv2-SMI::enterprises.9.1.186 The first two lines are host information and used to map the trap to our host; we can use the remaining lines in our rules using the following macros. ${TRAPNAME} will map to the value snmpTrapOID.0 on the fourth line which in this case is IF-MIB::linkUp. ${Px} will map to the parameter on line x; so, for instance, ${P7} will map to the parameter (ifType) on the seventh line (any trailing numbers such as .2 are ignored). ${Vx} will map to the value on line x, so ${V6} will map to Serial0/0. You can also directly call the value of an OID by placing it in your rule; so, for instance, ${SNMP-COMMUNITY-MIB::snmpTrapCommunity} will map to public. Matching So now that we have seen how we can take the information in our traps and use them, we need to look at how we can match against them. For this, we can use simple Perl matching mechanisms such as eq or =~ (to do pattern matching). So, a comparison to check if the SNMP trap community string is set to be used, the string public could be expressed in these different forms: "${V10}" eq "public" "${SNMP-COMMUNITY-MIB::snmpTrapCommunity}" eq "public" Both statements are the same; the first one is less readable. It might be unwanted if you wish to make a lot of rules and be able to quickly see what each rule does. We can also combine matches in a single line, for instance, if we wish to check if the community is set to public and the interface reported is of a specific type. "${V10}" eq "public" && "${V7}" eq "ppp" Using the AND (&&) and OR (||) operators , we can create all kinds of combinations allowing for a finely tuned rule set. Creating rule sets is best done by making good use of the exceptions as they contain the trap in exactly the form in which it will be processed (line, parameters, and so on). So, if you are planning on adding a new type of device and you need to develop new rules, make good use of the various screens. Summary This article covers a lot of exciting features that Opsview offers its users to help them get the most out of monitoring. We addressed some of the challenges that we face today in increasingly complex multi-homed environments and how we can resolve them using Opsview. We also learned to use the advanced modules that come with Opsview Pro, such as autodiscovery for rapid deployments. Using autodiscovery, we can quickly scan our network (or VMware hosts) for new and unmonitored devices; using SNMP traps, we can have our devices inform us in case of trouble. resources for article: further resources on this subject: Apache Solr Configuration [article] Getting Started with Apache Solr [article] Making Big Data Work for Hadoop and Solr [article]
Read more
  • 0
  • 0
  • 2458

article-image-using-mongoid
Packt
09 Dec 2013
12 min read
Save for later

Using Mongoid

Packt
09 Dec 2013
12 min read
(For more resources related to this topic, see here.) Introducing Origin Origin is a gem that provides the DSL for Mongoid queries. Though at first glance, a question may seem to arise as to why we need a DSL for Mongoid queries; If we are finally going to convert the query to a MongoDB-compliant hash, then why do we need a DSL? Origin was extracted from Mongoid gem and put into a new gem, so that there is a standard for querying. It has no dependency on any other gem and is a standalone pure query builder. The idea was that this could be a generic DSL that can be used even without Mongoid! So, now we have a very generic and standard querying pattern. For example, in Mongoid 2.x we had the criteria any_in and any_of, and no direct support for the and, or, and nor operations. In Mongoid 2.x, the only way we could fire a $or or a $and query was like this: Author.where("$or" => {'language' => 'English', 'address.city' => 'London '}) And now in Mongoid 3, we have a cleaner approach. Author.or(:language => 'English', 'address.city' => 'London') Origin also provides good selectors directly in our models. So, this is now much more readable: Book.gte(published_at: Date.parse('2012/11/11')) Memory maps, delayed sync, and journals As we have seen earlier, MongoDB stores data in memory-mapped files of at most 2 GB each. After the data is loaded for the first time into the memory mapped files, we now get almost memory-like speeds for access instead of disk I/O, which is much slower. These memory-mapped files are preallocated to ensure that there is no delay of the file generation while saving data. However, to ensure that the data is not lost, it needs to be persisted to the disk. This is achieved by journaling. With journaling, every database operation is written to the oplog collection and that is flushed to disk every 100 ms. Journaling is turned on by default in the MongoDB configuration. This is not the actual data but the operation itself. This helps in better recovery (in case of any crash) and also ensures the consistency of writes. The data that is written to various collections are flushed to the disk every 60 seconds. This ensures that the data is persisted periodically and also ensures the speed of data access is almost as fast as memory. MongoDB relies on the operating system for the memory management of its memory-mapped files. This has the advantage of getting inherent OS benefits as the OS is improved. Also, there's the disadvantage of lack of control on how memory is managed by MongoDB. However, what happens if something goes wrong (server crashes, database stops, or disk is corrupted)? To ensure durability, whenever data is saved in files, the action is logged to a file in a chronological order. This is the journal entry, which is also a memory-mapped file but is synced with the disk every 100 ms. Using the journal, the database can be easily recovered in case of any crash. So, in the worst case scenario, we could potentially lose 100 ms of information. This is a fair price to pay for the benefits of using MongoDB. MongoDB journaling makes it a very robust and durable database. However, it also helps us decide when to use MongoDB and when not to use it. 100 ms is a long time for some services, such as financial core banking or maybe stock price updates. In such applications, MongoDB is not recommended. For most cases that are not related to heavy multi-table transactions like most financial applications MongoDB can be suitable. All these things are handled seamlessly, and we don't usually need to change anything. We can control this behavior via the configuration of MongoDB but usually it's not recommended. Let's now see how we save data using Mongoid. Updating documents and attributes As with ActiveModel specifications, save will update the changed attributes and return the updated object, otherwise it will return false on failure. The save! function will raise an exception on the error. In both cases, if we pass validate: false as a parameter to save, it will bypass the validations. A lesser-known persistence option is the upsert action. An upsert action creates a new document if it does not find it and overwrites the object if it finds it. A good reason to use upsert is in the find_and_modify action. For example, suppose we want to reserve a book in our Sodibee system, and we want to ensure that at any one point, there can be only one reservation for a book. In a traditional scenario: t1: Request-1 searches for a for a book which is not reserved and finds it t2: Now, it saves the book with the reservation information t3: Request-2 searches for a reservation for the same book and finds that the book is reserved t4: Request-2 handles the situation with either error or waits for reservation to be freed So far so good! However in a concurrent model, especially for web applications, it creates problems. t1: Request-1 searches for a book which is not reserved and finds it t2: Request-2 searches for a reservation for the same book and also gets back that book since it's not yet reserved t3: Request-1 saves the book with its reservation information t4: Request-2 now overwrites previous update and saves the book with its reservation information Now we have a situation where two requests think that the reservation for the book was successful and that is against our expectations. This is a typical problem that plagues most web applications. The various ways in which we can solve this is discussed in the subsequent sections. Write concern MongoDB helps us ensure write consistency. This means that when we write something to MongoDB, it now guarantees the success of the write operation. Interestingly, this is a configurable option and is set to acknowledged by default. This means that the write is guaranteed because it waits for an acknowledgement before returning success. In earlier versions of Mongoid, safe: true was turned off by default. This meant that success of the write operation was not guaranteed. The write concern is configured in Mongoid.yml as follows: development:sessions:default:hosts:- localhost:27017options:write:w: 1 The default write concern in Mongoid is configured with w: 1, which means that the success of a write operation is guaranteed. Let's see an example: class Authorinclude Mongoid::Documentfield :name, type: Stringindex( {name: 1}, {unique: true, background: true})end Indexing blocks read and write operations. Hence, its recommended to configure indexing in the background in a Rails application. We shall now start a Rails console and see how this reacts to a duplicate key index by creating two Author objects with the same name. irb> Author.create(name: "Gautam") => #<Author _id: 5143678345db7ca255000001, name: "Gautam"> irb> Author.create(name: "Gautam") Moped::Errors::OperationFailure: The operation: #<Moped::Protocol::Command @length=83 @request_id=3 @response_to=0 @op_code=2004 @flags=[] @full_collection_name="sodibee_development.$cmd" @skip=0 @limit=-1 @selector={:getlasterror=>1, :w=>1} @fields=nil> failed with error 11000: "E11000 duplicate key error index: sodibee_ development.authors.$name_1 dup key: { : "Gautam" }" As we can see, it has raised a duplicate key error and the document is not saved. Now, let's have some fun. Let's change the write concern to unacknowledged: development:sessions:default:hosts:- localhost:27017options:write:w: 0 The write concern is now set to unacknowledged writes. That means we do not wait for the MongoDB write to eventually succeed, but assume that it will. Now let's see what happens with the same command that had failed earlier. irb > Author.where(name: "Gautam").count=> 1irb > Author.create(name: "Gautam")=> #<Author _id: 5287cba54761755624000000, name: "Gautam">irb > Author.where(name: "Gautam").count=> 1 There seems to be a discrepancy here. Though Mongoid create returned successfully, the data was not saved to the database. Since we specified background: true for the name index, the document creation seemed to succeed as MongoDB had not indexed it yet, and we did not wait for acknowledging the success of the write operation. So, when MongoDB tries to index the data in the background, it realizes that the index criterion is not met (since the index is unique), and it deletes the document from the database. Now, since that was in the background, there is no way to figure this out on the console or in our Rails application. This leads to an inconsistent result. So, how can we solve this problem? There are various ways to solve this problem: We leave the Mongoid default write concern configuration alone. By default, it is w: 1 and it will raise an exception. This is the recommended approach as prevention is better than cure! Do not specify the background: true option. This will create indexes in the foreground. However, this approach is not recommended as it can cause a drop in performance because index creations block read and write access. Add drop_dups: true. This deletes data, so you have to be really careful when using this option. Other options to the index command create different types of indexes as shown in the following table: Index Type Example Description sparse index({twitter_name: 1}, { sparse: true}) This creates sparse indexes, that is, only the documents containing the indexed fields are indexed. Use this with care as you can get incomplete results. 2d 2dsphere index({:location => "2dsphere"}) This creates a two-dimensional spherical index. Text index MongoDB 2.4 introduced text indexes that are as close to free text search indexes as it gets. However, it does only basic text indexing—that is, it supports stop words and stemming. It also assigns a relevance score with each search. Text indexes are still an experimental feature in MongoDB, and they are not recommended for extensive use. Use ElasticSearch, Solr (Sunspot), or ThinkingSphinx instead. The following code snippet shows how we can specify a text index with weightage: index({ "name" => 'text',"last_name" => 'text'},{weights: {'name' => 10,'last_name' => 5,},name: 'author_text_index'}) There is no direct search support in Mongoid (as yet). So, if you want to invoke a text search, you need to hack around a little. irb> srch = Mongoid::Contextual::TextSearch.new(Author.collection,Author.all, 'john')=> #<Mongoid::Contextual::TextSearchselector: {}class: Authorsearch: johnfilter: {}project: N/Alimit: N/Alanguage: default>irb> srch.execute=> {"queryDebugString"=>"john||||||", "language"=>"english","results"=>[{"score"=>7.5, "obj"=>{"_id"=>BSON::ObjectId('51fc058345db7c843f00030b'), "name"=>"Bettye Johns"}}, {"score"=>7.5, "obj"=>{"_id"=>BSON::ObjectId('51fc058345db7c843f00046d'), "name"=>"John Pagac"}},{"score"=>7.5, "obj"=>{"_id"=>BSON::ObjectId('51fc058345db7c843f000578'),"name"=>"Jeanie Johns"}}, {"score"=>7.5, "obj"=>{"_id"=>BSON::ObjectId('51fc058445db7c843f0007e7')...{"score"=>7.5, "obj"=>{"_id"=>BSON::ObjectId('51fc058a45db7c843f0025f1'), "name"=>"Alford Johns"}}], "stats"=>{"nscanned"=>25,"nscannedObjects"=>0, "n"=>25, "nfound"=>25, "timeMicros"=>31103},"ok"=>1.0} By default, text search is disabled in MongoDB configuration. We need to turn it on by adding setParameter = textSearchEnabled=true in the MongoDB configuration file, typically /usr/local/mongo.conf. This returns a result with statistical data as well the documents and their relevance score. Interestingly, it also specifies the language. There are a few more things we can do with the search result. For example, we can see the statistical information as follows: irb> a.stats=> {"nscanned"=>25, "nscannedObjects"=>0, "n"=>25, "nfound"=>25,"timeMicros"=>31103} We can also convert the data into our Mongoid model objects by using project, as shown in the following command: > a.project(:name).to_a=> [#<Author _id: 51fc058345db7c843f00030b, name: "Bettye Johns",last_name: nil, password: nil>, #<Author _id: 51fc058345db7c843f00046d,name: "John Pagac", last_name: nil, password: nil>, #<Author _id:51fc058345db7c843f000578, name: "Jeanie Johns", last_name: nil, password:nil> ... Some of the important things to remember are as follows: Text indexes can be very heavy in memory. They can return the documents, so the result can be large. We can use multiple keys (or filters) along with a text search. For example, the index with index ({ 'state': 1, name: 'text'}) will mandate the use of the state for every text search that is specified. A search for "john doe" will result in a search for "john"or "doe"or both. A search for "john"and "doe" will search for all "john"and "doe"in a random order. A search for ""john doe"", that is, with escaped quotes, will search for documents containing the exact phrase "john doe". A lot more data can be found at http://docs.mongodb.org/manual/tutorial/search-for-text/ Summary This article provides an excellent reference for using Mongoid. The article has examples with code samples and explanations that help in understanding the various features of Mongoid. Resources for Article: Further resources on this subject: Installing phpMyAdmin [Article] Integrating phpList 2 with Drupal [Article] Documentation with phpDocumentor: Part 1 [Article]
Read more
  • 0
  • 0
  • 2570
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-why-hudson
Packt
06 Dec 2013
7 min read
Save for later

Why Hudson?

Packt
06 Dec 2013
7 min read
(For more resources related to this topic, see here.) Benefits of Hudson Hudson can be used to improve project health and automate much of the build and deployment process. Hudson adoption can benefit multiple roles in an IT organization. It is important to note that even though Hudson is written primarily in Java, it can be used to build and test a wide variety of projects, including but not limited to: iOS apps, Android apps, JavaScript apps, and Rails applications. Hudson can improve project health Hudson was first designed as a continuous integration server, a fact that is still evident in the project's web address: http://hudson-ci.org. Continuous integration is one of the practices in Extreme Programming. The goal of continuous integration is to identify and resolve integration problems early in the development process instead of later, when they are more difficult to resolve. Similarly, Hudson can be used for continuous deployment, which can help identify and resolve deployment problems early in the development process. By identifying integration issues earlier in the development process, the software design can be improved and problems can be dealt with before they grow even more difficult to resolve. Test-driven Development is another one of the practices in Extreme Programming. By ensuring that a project follows the Test-driven Development practice or, at the very least, has sufficient test coverage, Hudson can provide feedback in the form of test reports and notifications if a build or test fails. Analysis of the project code can be accomplished using Checkstyle, PMD, FindBugs, and Sonar plugins. These plugins ensure that the project follows the defined coding conventions and detects common bugs in the application's source code. Having the project code follow common coding standards makes the code easier for new team members to understand and easier to maintain. Finding and fixing software defects is much easier and less time consuming earlier, rather than later in the development process. Hudson can automate the build and deployment process The build process can, over time, become very large and complicated with many steps. A common problem that can arise is that a build will work on one developer's computer, but not on another's. A Hudson job can be seen as a formalization of the build process. The Hudson job creates build artifacts at scheduled times or manually, based on the user request. Having the build process formalized forces the IT team to keep it up-to-date with any changes in the application that is being developed. This creates a build that is repeatable and portable and removes the "but it builds on my computer" problem. Plugins for the deployment of build artifacts to an application server and publishing them to a repository are available. Using these plugins, the deployment process can also be formalized and automated. This will allow users to identify and correct deployment issues early in the development process. IT roles in relation to Hudson There are many roles in a typical Information Technology organization and there are four that can benefit from the adoption of Hudson: the project manager, the software developer, the tester, and the application server administrator. Depending on the size of the IT organization, these roles may span multiple departments or a single person may have more than one role. If the IT organization is large, with these roles functioning in different departments, Hudson can be the tool that brings these teams together to work toward the common goal of creating great software. Hudson provides the project manager with a dashboard overview of the project(s) they are responsible for. They can see the build status and history, as well as view test reports and test coverage, giving them the confidence that the project is healthy and moving forward. Getting quick feedback via the unit test reports and the build status that Hudson provides helps assure the software developer that they have not broken any existing code and that any features and/or bug fixes they are working on have not broken the build. Removing the burden of building the software for deployment allows the developer to focus on providing value to the customer by developing and improving software, instead of worrying about building and releasing the software. The tester can benefit from using Hudson by automating some of the testing using the Selenium plugin and by viewing the test reports, which eliminates much of the mundane and repeatable part of testing. Having builds available early and often will also help the tester get a head start on developing tests and actually beginning some testing. The application server administrator can benefit from using Hudson because continuously building and deploying the application will improve their confidence in the build process and reduce the risk of unpleasant surprises at the last minute. Hudson defines the build very clearly and this helps make the build repeatable and portable, which removes the requirement to manually build the application from the administrator. Hudson plugins and integrations One of the strengths of Hudson is its flexibility to extend itself using plugins. There are many useful Eclipse and community-supported plugins that extend Hudson's basic functionality. We can also extend Hudson's functionality ourselves by writing our own plugin. Hudson integrates with many existing development, testing, and build tools commonly used by IT organizations. This integration allows developers and testers to work with the tools that they are familiar with and also to utilize the additional capabilities that Hudson provides. Some of the tools Hudson integrates with are: Git, SVN, CVS, Ant, Maven, Gradle, JUnit, TestNG, Selenium, Checkstyle, PMD, and FindBugs. Hudson also provides a RESTful API to allow other systems access to its functionality. The API can be used for functions, such as retrieving Hudson results, triggering a new build, or creating a new job. The Hudson back story Hudson was created by Kohsuke Kawaguchi at Sun Microsystems as an open source continuous integration server and had its first release in February 2005. By 2008, Hudson had started to become a popular alternative to other continuous integration servers and won a Duke's Choice Award in the Developer Solutions category at Java One in May 2008. Oracle completed the acquisition of Sun Microsystems on January 27, 2010, which included ownership of the Hudson trademark and its intellectual property. Disagreements between Oracle and Kohsuke and other project contributors over project infrastructure and trademark control began in November 2010 and ended in February 2011 with the renaming (forking) of the Hudson project to a new project named Jenkins. Oracle and its partners have continued the development of Hudson, while Kohsuke and other project contributors continue work on the separate Jenkins project. In May 2011, Oracle began the process of transferring the Hudson project and trademarks to the Eclipse Foundation. The Hudson project was moved to the Eclipse Foundation and became a full Eclipse project on December 12, 2012 with the release of Hudson 3.0.0. Summary In this article, we have covered what Hudson is and how it can benefit an IT organization. We have also seen how Hudson can benefit different roles in an IT organization. We've covered the history of Hudson and what types of tools it can leverage. Resources for Article: Further resources on this subject: Service Oriented Java Business Integration - What's & Why's [Article] Integrating phpList 2 with WordPress [Article] Python Testing: Installing the Robot Framework [Article]
Read more
  • 0
  • 0
  • 1789

article-image-touch-events
Packt
26 Nov 2013
7 min read
Save for later

Touch Events

Packt
26 Nov 2013
7 min read
(For more resources related to this topic, see here.) The why and when of touch events These touch events come in a few different flavors. There are taps, swipes, rotations, pinches, and more complicated gestures available for you to make your users' experience more enjoyable. Each type of touch event has an established convention which is important to know, so your user has minimal friction when using your website for the first time: The tap is analogous to the mouse click in a traditional desktop environment, whereas, the rotate, pinch, and related gestures have no equivalence. This presents an interesting problem—what can those events be used for? Pinch events are typically used to scale views (have a look at the following screenshot of Google Maps accessed from an iPad, which uses pinch events to control the map's zoom level), while rotate events generally rotate elements on screen. Swipes can be used to move content from left to right or top to bottom. Multifigure gestures can be different as per your website's use cases, but it's still worthwhile examining if a similar interaction already exists, and thus an established convention. Web applications can benefit greatly from touch events. For example, imagine a paint-style web application. It could use pinches to control zoom, rotations to rotate the canvas, and swipes to move between color options. There is almost always an intuitive way of using touch events to enhance a web application. In order to get comfortable with touch events, it's best to get out there and start using them practically. To this end, we will be building a paint tool with a difference, that is, instead of using the traditional mouse pointer as the selection and drawing tool, we will exclusively use touch events. Together, we can learn just how awesome touch events are and the pleasure they can afford your users. Touch events are the way of the future, and adding them to your developer tool belt will mean that you can stay at the cutting edge. While MC Hammer may not agree with these events, the rest of the world will appreciate touching your applications. Testing while keeping your sanity (Simple) Touch events are awesome on touch-enabled devices. Unfortunately, your development environment is generally not touch-enabled, which means testing these events can be trickier than normal testing. Thankfully, there are a bunch of methods to test these events on non-touch enabled devices, so you don't have to constantly switch between environments. In saying that though, it's still important to do the final testing on actual devices, as there can be subtle differences. How to do it... Learn how to do initial testing with Google Chrome. Debug remotely with Mobile Safari and Safari. Debug further with simulators and emulators. Use general tools to debug your web application. How it works… As mentioned earlier, testing touch events generally isn't as straightforward as the normal update-reload-test flow in web development. Luckily though, the traditional desktop browser can still get you some of the way when it comes to testing these events. While you generally are targeting Mobile Safari on iOS and Chrome, or Browser on Android, it's best to do development and initial testing in Chrome on the desktop. Chrome has a handy feature in its debugging tools called Emulate touch events. This allows a lot of your mouse-related interactions to trigger their touch equivalents. You can find this setting by opening the Web Inspector, clicking on the Settings cog, switching to the Overrides tab, and enabling Emulate touch events (if the option is grayed out, simply click on Enable at the top of the screen). Using this emulation, we are able to test many touch interactions; however, there are certain patterns (such as scaling and rotating) that aren't really possible just using emulated events and the mouse pointer. To correctly test these, we need to find the middle ground between testing on a desktop browser and testing on actual devices. There's more… Remember the following about testing with simulators and browsers: Device simulators While testing with Chrome will get you some of the way, eventually you will want to use a simulator or emulator for the target device, be it a phone, tablet, or other touch-enabled device. Testing in Mobile Safari The iOS Simulator, for testing Mobile Safari on iPhone, iPod, and iPad, is available only on OS X. You must first download Xcode from the App Store. Once you have Xcode, go to Xcode | Preferences | Downloads | Components, where you can download the latest iOS Simulator. You can also refer to the following screenshot: You can then open the iOS Simulator from Xcode by accessing Xcode | Open Developer Tool | iOS Simulator. Alternatively, you can make a direct alias by accessing Xcode's package contents by accessing the Xcode icon's context menu in the Applications folder and selecting Show Package Contents. You can then access it at Xcode.app/Contents/Applications. Here you can create an alias, and drag it anywhere using Finder. Once you have the simulator (or an actual device); you can then attach Safari's Web Inspector to it, which makes debugging very easy. Firstly, open Safari and then launch Mobile Safari in either the iOS Simulator or on your actual device (ensure it's plugged in via its USB cable). Ensure that Web Inspector is enabled in Mobile Safari's settings via Settings | Safari | Advanced | Web Inspector. You can refer to the following screenshot: Then, in Safari, go to Develop | <your device name> | <tab name>. You can now use the Web Inspector to inspect your remote Mobile Safari instance as shown in the following screenshot: Testing in Mobile Safari in the iOS Simulator allows you to use the mouse to trigger all the relevant touch events. In addition, you can hold down the Alt key to test pinch gestures. Testing on Android's Chrome Testing on the Android on desktop is a little more complicated, due to the nature of the Android emulator. Being an emulator and not a simulator, its performance suffers (in the name of accuracy). It also isn't so straightforward to attach a debugger. You can download the Android SDK from http://developer.android.com/sdk. Inside the tools directory, you can launch the Android Emulator by setting up a new Android Virtual Device (AVD). You can then launch the browser to test the touch events. Keep in mind to use 10.0.2.2 instead of localhost to access local running servers. To debug with a real device and Google Chrome, official documentation can be followed at https://developers.google.com/chrome-developer-tools/docs/remote-debugging. When there isn't a built-in debugger or inspector, you can use generic tools such as Web Inspector Remote (Weinre). This tool is platform-agnostic, so you can use it for Mobile Safari, Android's Browser, Chrome for Android, Windows Phone, Blackberry, and so on. It can be downloaded from http://people.apache.org/~pmuellr/weinre. To start using Weinre, you need to include a JavaScript on the page you want to test, and then run the testing server. The URL of this JavaScript file is given to you when you run the weinre command from its downloaded directory. When you have Weinre running on your desktop, you can use its Web Inspector-like interface to do remote debugging and inspecting your touch events, you can send messages to console.log() and use a familiar interface for other debugging. Summary In this article the author has discussed about the touch events and has highlighted the limitations faced by such events when an unfavorable environment is encountered. He has also discussed the methods to test these events on non-touch enabled devices. Resources for Article: Further resources on this subject: Web Design Principles in Inkscape [Article] Top Features You Need to Know About – Responsive Web Design [Article] Sencha Touch: Layouts Revisited [Article]
Read more
  • 0
  • 0
  • 5477

Packt
26 Nov 2013
6 min read
Save for later

CodeIgniter MVC – The Power of Simplicity!

Packt
26 Nov 2013
6 min read
(For more resources related to this topic, see here.) "Simplicity Wins In Big!" Back in the 80s there was a programming Language ADA that according to many contracts was required to be used. ADA was so complex and hard compared to C/C++ to maintain. Today ADA fades like Pascal. C/C++ is the simplicity winner for real time systems arena. In Telecom for network devices management protocols there were two standards in the 90s: CMIP (Common Management Information Protocol) and SNMP (Simple Network Management Protocol). Initially (90s) all telecom Requirement Papers required CMIP support. Eventually after several years a research found that there's about 1:10 or 10x effort to develop and maintain a same system based CMIP compared to SNMP. SNMP is the simplicity winner in network management systems arena! In VoIP or Media over IP, the H.323 and SIP (Session Initiation Protocol) were competing protocols in early 2000. H.323 had the messages in a cryptic binary way. SIP makes it all textual XML fashioned, easy to understand via text editor. Today almost all end point devices powered SIP while H.323 becomes a niche protocol for the VoIP backbone. SIP is the simplicity winner in VoIP arena! Back in 2010 I was looking for a good PHP platform to develop Web Application for my startup 1st product Logodial Zappix (http://zappix.com). I got a recommendation to use DRUPAL for this. I've tried the platform and found it very heavy to manipulate and change for my exact user interaction flow and experience I had in mind. Many times I had to compromise and the overhead of the platform was indeed horrible. Just make Hello world App and tons of irrelevant code will get into the project. Try to make free JavaScript and you found yourself struggling with the platform disabling you from the creativity of client side JavaScript and its Add-ons. I've decided to look for a better platform for my needs. Later on I've heard about Zend Framework MVC (Model-View-Controller framework typed). I've tried to work with it as it is based MVC and a lot of OOP usage, but I've found it heavy... Documentation seems great at first sight, but the more I've used I, looking for vivid examples and explanations, I found myself in endless close circle loops of links. It was lacking a clear explanation and vivid examples. The filling was like every match box moving task, I'd required a semi-trailer of declarations and calls to handle making it... Though it was MVC typed which I greatly liked. Keeping on with my search, I was looking for simple but powerful MVC based PHP which is my favorite language for server side. One day in early 2011 I got a note from a friend that there's a light and cool platform named CodeIgniter (CI in brief). I've checked the documentation link http://ellislab.com/codeigniter/user-guide/ and was amazed from the very clean, simple, well organized and well explained browsing experience. Having Examples? Yes, lots of clear examples, with great community. It was so great and simple. I felt like those platform designers were doing the best effort to make the simplest and most vivid code, reusable and clean OOP fashion from the infrastructure to the last function. I've tried making web app for a trail, trying to load helpers, libraries and use them and greatly loved the experience. Fast forward, today I see a matured CodeIgniter as a Lego like playground that I know well. I've wrote tons of models, helpers, libraries, controllers and views. CodeIgniter Simplicity enables me to do things fast and, clear and well maintained and expandable. In time I've gathered the most useful helpers and libraries, Ajax server and Browser side solutions for reuse, good links to useful add on such as the free Grid Powered Plug-In for CI the http://www.grocerycrud.com/ that keep improving day by day. Today I see Codeigniter as a matured scalable (See at&t and sprint Call Center Web apps based CI), reusability and simplicity champion. The following is the high-level architecture of the Codeigniter MVC with the Controller/s as the hub the application session. The CI controller main use cases are: Handles requests from web browser as HTTP URI call, based on submitted parameters (for example Submitting a Login with the credentials) or with no-parameters (for example Home Page navigation). Handles Asynchronous Ajax requests from the Web Client mostly as JSON HTTP POST request and response. Serving CRON job requests that creates HTTP URI request, calling controller methods, similar to browser navigation, silently from the CRON PHP module. The CI Views main features: Rendered by a controller with optionally set of parameters (scalar, arrays, objects) Has full open access to all the helpers, libraries, models as their rendering controller has. Has the freedom to integrate any JavaScript / 3rd party Web Client side plug-ins. The CI helper/s main features and fashion: Flat functions sets protected from duplication risks Can be loaded for use by any controller and accessed by any rendered view. Can access any CI resource / library and others via the &get_instance() service. The CI Libraries main features and fashion: OOP classes that can expand other 3rd party classes (For example, see the example of the Google Map wrapper in the new Book). Can access any of the CI resources of other libraries, built-in services via the &get_instance(). Can be used by the CI project controllers and all their rendered views. The CI Model main features and fashion: Similar to Libraries but has access to the default database, that can be expanded to multi databases and any other CI resource via the &get_instance(). OOP classes that can expand other 3rd party classes (For example, See the example of the Google Map wrapper in the new Book). Can access any of the CI resources of other libraries, built-in services via the &get_instance(). It seems that CodeIgniter is continuously increasing its popularity as it has a simple yet high quality OOP core that enables great creativity, reusability, and code clarity naming conventions, which are easy to expand (user class extends CI class), while more third-party application plugins (packages of views and/or models and/or libraries and/or helpers). I found Codeigniter flexible, great reusability enabler, having light infrastructure, enables developer creativity powered active global community. For a day to day the CI code clarity, high performance capabilities, minimal controllable footprint (You decide what helpers/libraries/models to load for each controller). Above all CI blessed with very fast learning curve of PHP developers and many blogs and community sites to share knowledge and raise and resolve issues and changes. CodeIgniter is the simplicity winner I've found for Web Apps MVC Server side. Summary This article introduces the CodeIgniter framework, while initially getting started with web-based applications. Resources for Article: Further resources on this subject: Database Interaction with Codeigniter 1.7 [Article] User Authentication with Codeigniter 1.7 using Facebook Connect [Article] CodeIgniter 1.7 and Objects [Article]
Read more
  • 0
  • 0
  • 3025

article-image-apache-solr-php-integration
Packt
25 Nov 2013
7 min read
Save for later

Apache Solr PHP Integration

Packt
25 Nov 2013
7 min read
(For more resources related to this topic, see here.) We will be looking at installation on both Windows and Linux environments. We will be using the Solarium library for communication between Solr and PHP. This article will give a brief overview of the Solarium library and showcase some of the concepts and configuration options on Solr end for implementing certain features. Calling Solr using PHP code A ping query is used in Solr to check the status of the Solr server. The Solr URL for executing the ping query is http://localhost:8080/solr/collection1/admin/ping/?wt=json. Response of Solr ping query in browser We can use Curl to get the ping response from Solr via PHP code; a sample code for executing the previous ping query is as below $curl = curl_init("http://localhost:8080/solr/collection1/admin/ping/?wt=json"); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($curl); $data = json_decode($output, true); echo "Ping Status : ".$data["status"].PHP_EOL; Though Curl can be used to execute almost any query on Solr, but it is preferable to use a library which does the work for us. In our case we will be using Solarium. To execute the same query on Solr using the Solarium library the code is as follows. include_once("vendor/autoload.php"); $config = array("endpoint" => array("localhost" => array("host"=>"127.0.0.1", "port"=>"8080", "path"=>"/solr", "core"=>"collection1",) ) ); We have included the Solarium library in our code. And defined the connection parameters for our Solr server. Next we will need to create a Solarium client with the previous Solr configuration. And call the createPing() function to create the ping query. $client = new SolariumClient($config); $ping = $client->createPing(); Finally execute the ping query and get the result. $result = $client->ping($ping); $result->getStatus(); The output should be similar to the one shown below. Output of ping query using PHP Adding documents to Solr index To create a Solr index, we need to add documents to the Solr index using the command line, Solr web interface or our PHP program. But before we create a Solr index, we need to define the structure or the schema of the Solr index. Schema consists of fields and field types. It defines how each field will be treated and handled during indexing or during search. Let us see a small piece of code for adding documents to the Solr index using PHP and Solarium library. Create a solarium client. Create an instance of the update query. Create the document in PHP and finally add fields to the document. $client = new SolariumClient($config); $updateQuery = $client->createUpdate(); $doc1 = $updateQuery->createDocument(); $doc1->id = 112233445; $doc1->cat = 'book'; $doc1->name = 'A Feast For Crows'; $doc1->price = 8.99; $doc1->inStock = 'true'; $doc1->author = 'George R.R. Martin'; $doc1->series_t = '"A Song of Ice and Fire"'; Id field has been marked as unique in our schema. So we will have to keep different values for Id field for different documents that we add to Solr. Add documents to the update query followed by commit command. Finally execute the query. $updateQuery->addDocuments(array($doc1)); $updateQuery->addCommit(); $result = $client->update($updateQuery); Let us execute the code. php insertSolr.php After executing the code, a search for martin will give these documents in the result. http://localhost:8080/solr/collection1/select/?q=martin Document added to Solr index Executing search on Solr Index Documents added to the Solr index can be searched using the following piece of PHP code. $selectConfig = array( 'query' => 'cat:book AND author:Martin', 'start' => 3, 'rows' => 3,'fields' => array('id','name','price','author'), 'sort' => array('price' => 'asc') ); $query = $client->createSelect($selectConfig); $resultSet = $client->select($query); The above code creates a simple Solr query and searches for book in cat field and Martin in author field. The results are sorted in ascending order or price and fields returned are id, name of book, price and author of book. Pagination has been implemented as 3 results per page, so this query returns results for 2nd page starting from 3rd result. In addition to this simple select query, Solr also supports some advanced query modes known as dismax and edismax. With the help of these query modes, we can boost certain fields to give more importance to certain fields in our query. We can also use function queries to do some type of dynamic boosting based on values in fields. If no sorting is provided, the Solr results are sorted by the score of documents which are calculated based on the terms in the query and the matching terms in the documents in the index. Score is calculated for each document in the result set using two main factors - term frequency known as tf and inverse document frequency known as idf. In addition to these, Solr provides a way of narrowing down the results using filter queries. Also facets can be created based on fields in the index and it can be used by the end users to narrow down the results. Highlighting search results using PHP and Solr Solr can be used to highlight the fields returned in a search result based on the query. Here is a sample code for highlighting the results for search keyword harry. $query->setQuery('harry'); $query->setFields(array('id','name','author','series_t','score','last_modified')); Get the highlighting component from the query, set the fields to be highlighted and also set the html tags to be used for highlighting. $hl = $query->getHighlighting(); $hl->setFields('name,series_t'); $hl->setSimplePrefix('<strong>')->setSimplePostfix('</strong>'); Once the query is run and result set is received, we will need to retrieve the highlighted results from the result set. Here is the output for the highlighting code. Highlighted search results In addition to highlighting, Solr can be used to create a spelling suggester and a spell checker. Spelling suggester can be used to prompt input query to the end user as the user keeps on typing. Spell check can be used to prompt spelling corrections similar to 'did you mean' to the user. Solr can also be used for finding documents which are similar to a certain document based on words in certain fields. This functionality of Solr is known as more like this and is exposed via Solarium by the MoreLikeThis component. Solr also provides grouping of the result based on a particular query or a certain field. Scaling Solr Solr can be scaled to handle large number of search requests by using master slave architecture. Also if the index is huge, it can be sharded across multiple Solr instances and we can run a distributed search to get results for our query from all the sharded instances. Solarium provides a load balancing plug-in which can be used to load balance queries across master-slave architecture. Summary Solr provides an extensive list of features for implementing search. These features can be easily accessed in PHP using the Solarium library to build a full features search application which can be used to power search on any website. Resources for Article: Further resources on this subject: Apache Solr Configuration [Article] Getting Started with Apache Solr [Article] Making Big Data Work for Hadoop and Solr [Article]
Read more
  • 0
  • 0
  • 8984
article-image-article-exploring-rubymine
Packt
25 Nov 2013
8 min read
Save for later

Exploring RubyMine

Packt
25 Nov 2013
8 min read
(For more resources related to this topic, see here.) Managing your implants (Should know) Now, we will learn how to utilize RubyMine to manage your Gems and external libraries used for your Ruby on Rails programs. Getting ready Start RubyMine and open the HelloWorld project that we created earlier. We will be adding an implant to enhance your assimilation process into the collective. How to do it... We will now use a Gem in RubyMine by showing the following simple example using the Prawn Gem: Right-click on the HelloWorld project folder in the left project panel and add a new file to your project. Name it pdf.rb. Add the following code to this new file: require 'prawn' Prawn::Document.generate("hello.pdf") do |pdf| pdf.font "Courier" pdf.stroke_color = "ff0000" pdf.line_width = 5 pdf.stroke do pdf.circle([300, 300], 100); pdf.circle([350, 320], 20); pdf.circle([260, 325], 20); pdf.curve [270, 250], [340, 250], :bounds => [[270, 270],[275, 220]] end pdf.move_down(300) pdf.font_size = 36 pdf.fill_color "000000" pdf.draw_text("You will be assimilated!", :at => [40, 40]) pdf.line_width = 1 pdf.stroke_color = "0000ff" pdf.move_to([0, 0]) grid = 11 num_lines = 51 size = (num_lines - 1) * grid pdf.stroke do 51.times do |idx| pdf.line([0, idx*grid], [size, idx*grid]) pdf.line([idx*grid, 0], [idx*grid, size]) end end end Now, right-click on the open source file and select Run pdf. You should get an error similar to in 'require': cannot load such file -- prawn (LoadError). This means that you do not have the required technology to continue the assimilation process. We need to add some Ruby Gems to allow our program to continue. Open the Settings panel and select the Ruby SDK and Gems panel from the left-hand list. This is where we also changed the version of Ruby that we are using. This panel will allow us to install some specific Ruby Gems that we need. Hit the button Install Gems... and you will see a screen like the following: Start typing the name of the Gem you wish to install, which in this case is prawn and the search will begin immediately. Scroll to the right Gem. Select the Gem in the list at the left-hand side and then hit the button Install. RubyMine will then run the Gem system and install the Gem and all of its appropriate dependencies into your system. When it is complete, select the prawn gem in the list on the right and you will see the description panel filled with various aspects of the gem for your browsing pleasure. Once completed, go back and re-run the pdf.rb program. Since this program actually generates a PDF file, we need to find where it saved the file. In the project window on the left, hit the icon that looks like the following: This will synchronize the files inside the folder with the project list. You should now be able to see the file hello.pdf in the project window. Double-click on this and you will see this file in whichever application you have on your computer that displays PDF files. You should see something like the following: How it works The code that we typed in is a simple use of the Prawn Gem. It first requires the Gem code and then starts a block of code that will begin generating the hello.pdf file on the disk. Each command then sets properties of the text, size, colors, circles, and finally draws a grid of lines on the page. Creating your first progeny (Should know) Now it is time to create and run a simple Ruby on Rails application using RubyMine exclusively. Getting ready Open RubyMine and navigate to File | New Project. From this window, you can now select what type of project to begin with. RubyMine gives you several options that you can use later. Right now, select Rails application, as shown in the following screenshot: Hit OK and you will see the next settings window which allows you to select which version of Rails you would like to use in your project, along with the JavaScript library and database configurations. Select the checkbox for Preconfigure for selected database and choose the sqlite3 option, as shown in the following screenshot. Leave the rest as default and hit OK. How to do it... Now that you have created a new Rails project, RubyMine takes over and starts using Rails to generate all of the files and configuration necessary for a complete project, including running the command bundle install at the end. This will make sure that you have all the proper Gems installed for your Rails project. Now, we can run what we have and see that everything is installed correctly, using the following steps: At the top of the window, select the green arrow to run the Development: Progeny configuration. Running, in this case, means that it will start the default Rails webserver, Webrick, and begin listening on port 3000 for web browser requests. Once it is running, open your favorite browser and go to the address http://localhost:3000, and you should see the opening Rails Welcome Aboard screen. Click on the link About your application's environment, you can see some details about your installation including the various version numbers of Rails and Ruby, and the database that your application will be using. Now, we can build some features for our app. Let's begin by creating an interface to our database of species that we have already assimilated. For this, we can use the Rails generators to build the scaffolding of our application that gives us something to build on. All of the functionalities of Rails can be accessed from within the RubyMine environment, as shown in the following steps, so it is not necessary to go out to a command window at all: To run the generators, we just need to navigate to Tools | Run Rails Generator. As you type, the list is filtered to match your selection. Select the scaffold generator and hit Return: The following window gives us the opportunity to name our table and the various fields that it will contain. The database table will become the name of our model as well. Type the following into the top text box: Species name:string identification:integer assimilated:Boolean Leave the other settings at their default and hit OK, as shown in the following screenshot: Now if you reload your browser window, you should see an error like ActiveRecord:: PendingMigrationError. Oops! We forgot to do something after creating the code for the database tables. We need to run the migrations that will create the actual tables. Navigate to Tools | Run Rake Task… and start typing db:migrate. Just like the generator window, the various rake tasks will begin to be filtered by what you type. Hit Return and then select the defaults in the next window Latest migration and the migrations will be run for you. Now that the tables are created, point your browser to a new location, http://localhost:3000/species. You will see the index page for your Species database table, similar to the following screenshot: Click on the links and add some species to your database. The scaffolding that we generated, produced all of the CRUD (Create Read Update Delete) forms and screens necessary for managing our Species database table, without typing any commands in our terminal or leaving RubyMine at all. Of course it has no style, but who cares about style? We are the Borg and only care about technology! Ok. Maybe we can spruce it up a little bit. Lets add a Gem called Bourbon that helps with the following: Open the Gemfile from the project window and add the following line to it: gem 'bourbon' Now we need to install the Gem by running bundle install. We can do this directly from RubyMine by navigating to Tools | Bundler | Install. Hit the Install button on the window that shows and the Gem will be installed correctly. Now we can edit the CSS file that is in the App/Assets folder called species.css.scss. Open this file and add the following CSS code to the file: @import "bourbon"; p { @include linear-gradient(to top, white, steelblue); } Reload the page that shows one of the species that you created such as http://localhost:3000/species/1, as shown in the following screenshot. Now isn't that much better? There's more... Once complete, look at the configuration menu and you will notice that you now have some additional commands in this shortcut menu. RubyMine remembers the tasks and commands that you have executed for you to make it more efficient, as you will likely be running these commands often. Summary This is a technology that is worthy of assimilating to its fullest extent. In this article we covered Managing your implants and Creating your first progeny, which shows create and run a simple Ruby on Rails application using RubyMine. Resources for Article: Further resources on this subject: Getting Ready for RubyMotion [Article] Introducing RubyMotion and the Hello World app [Article] Xen Virtualization: Work with MySQL Server, Ruby on Rails, and Subversion [Article]
Read more
  • 0
  • 0
  • 2057

article-image-parallel-programming-patterns
Packt
25 Nov 2013
22 min read
Save for later

Parallel Programming Patterns

Packt
25 Nov 2013
22 min read
(For more resources related to this topic, see here.) Patterns in programming mean a concrete and standard solution to a given problem. Usually, programming patterns are the result of people gathering experience, analyzing the common problems, and providing solutions to these problems. Since parallel programming has existed for quite a long time, there are many different patterns for programming parallel applications. There are even special programming languages to make programming of specific parallel algorithms easier. However, this is where things start to become increasingly complicated. In this article, I will provide a starting point from where you will be able to study parallel programming further. We will review very basic, yet very useful, patterns that are quite helpful for many common situations in parallel programming. First is about using a shared-state object from multiple threads. I would like to emphasize that you should avoid it as much as possible. A shared state is really bad when you write parallel algorithms, but in many occasions it is inevitable. We will find out how to delay an actual computation of an object until it is needed, and how to implement different scenarios to achieve thread safety. The next two recipes will show how to create a structured parallel data flow. We will review a concrete case of a producer/consumer pattern, which is called as Parallel Pipeline. We are going to implement it by just blocking the collection first, and then see how helpful is another library from Microsoft for parallel programming—TPL DataFlow. The last pattern that we will study is the Map/Reduce pattern. In the modern world, this name could mean very different things. Some people consider map/reduce not as a common approach to any problem but as a concrete implementation for large, distributed cluster computations. We will find out the meaning behind the name of this pattern and review some examples of how it might work in case of small parallel applications. Implementing Lazy-evaluated shared states This recipe shows how to program a Lazy-evaluated thread-safe shared state object. Getting ready To start with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... For implementing Lazy-evaluated shared states, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Threading; using System.Threading.Tasks; Add the following code snippet below the Main method: static async Task ProcessAsynchronously() { var unsafeState = new UnsafeState(); Task[] tasks = new Task[4]; for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(unsafeState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var firstState = new DoubleCheckedLocking(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(firstState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var secondState = new BCLDoubleChecked(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(secondState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var thirdState = new Lazy<ValueToAccess>(Compute); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(thirdState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var fourthState = new BCLThreadSafeFactory(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(fourthState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); } static void Worker(IHasValue state) { Console.WriteLine("Worker runs on thread id {0}",Thread .CurrentThread.ManagedThreadId); Console.WriteLine("State value: {0}", state.Value.Text); } static void Worker(Lazy<ValueToAccess> state) { Console.WriteLine("Worker runs on thread id {0}",Thread .CurrentThread.ManagedThreadId); Console.WriteLine("State value: {0}", state.Value.Text); } static ValueToAccess Compute() { Console.WriteLine("The value is being constructed on athread id {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(1)); return new ValueToAccess(string.Format("Constructed on thread id {0}", Thread.CurrentThread.ManagedThreadId)); } class ValueToAccess { private readonly string _text; public ValueToAccess(string text) { _text = text; } public string Text { get { return _text; } } } class UnsafeState : IHasValue { private ValueToAccess _value; public ValueToAccess Value { get { if (_value == null) { _value = Compute(); } return _value; } } } class DoubleCheckedLocking : IHasValue { private object _syncRoot = new object(); private volatile ValueToAccess _value; public ValueToAccess Value { get { if (_value == null) { lock (_syncRoot) { if (_value == null) _value = Compute(); } } return _value; } } } class BCLDoubleChecked : IHasValue { private object _syncRoot = new object(); private ValueToAccess _value; private bool _initialized = false; public ValueToAccess Value { get { return LazyInitializer.EnsureInitialized( ref _value, ref _initialized, ref _syncRoot,Compute); } } } class BCLThreadSafeFactory : IHasValue { private ValueToAccess _value; public ValueToAccess Value { get { return LazyInitializer.EnsureInitialized(ref _value,Compute); } } } interface IHasValue { ValueToAccess Value { get; } } Add the following code snippet inside the Main method: var t = ProcessAsynchronously(); t.GetAwaiter().GetResult(); Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); Run the program. How it works... The first example show why it is not safe to use the UnsafeState object with multiple accessing threads. We see that the Construct method was called several times, and different threads use different values, which is obviously not right. To fix this, we can use a lock when reading the value, and if it is not initialized, create it first. It will work, but using a lock with every read operation is not efficient. To avoid using locks every time, there is a traditional approach called the double-checked locking pattern. We check the value for the first time, and if is not null, we avoid unnecessary locking and just use the shared object. However, if it was not constructed yet, we use the lock and then check the value for the second time, because it could be initialized between our first check and the lock operation. If it is still not initialized, only then we compute the value. We can clearly see that this approach works with the second example—there is only one call to the Construct method, and the first-called thread defines the shared object state. Please note that if the lazy- evaluated object implementation is thread-safe, it does not automatically mean that all its properties are thread-safe as well. If you add, for example, an int public property to the ValueToAccess object, it will not be thread-safe; you still have to use interlocked constructs or locking to ensure thread safety. This pattern is very common, and that is why there are several classes in the Base Class Library to help us. First, we can use the LazyInitializer.EnsureInitialized method, which implements the double-checked locking pattern inside. However, the most comfortable option is to use the Lazy<T> class that allows us to have thread-safe Lazy-evaluated, shared state, out of the box. The next two examples show us that they are equivalent to the second one, and the program behaves the same. The only difference is that since LazyInitializer is a static class, we do not have to create a new instance of a class as we do in the case of Lazy<T>, and therefore the performance in the first case will be better in some scenarios. The last option is to avoid locking at all, if we do not care about the Construct method. If it is thread-safe and has no side effects and/or serious performance impacts, we can just run it several times but use only the first constructed value. The last example shows the described behavior, and we can achieve this result by using another LazyInitializer.EnsureInitialized method overload. Implementing Parallel Pipeline with BlockingCollection This recipe will describe how to implement a specific scenario of a producer/consumer pattern, which is called Parallel Pipeline, using the standard BlockingCollection data structure. Getting ready To begin this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... To understand how to implement Parallel Pipeline using BlockingCollection, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Collections.Concurrent; using System.Linq; using System.Threading; using System.Threading.Tasks; Add the following code snippet below the Main method: private const int CollectionsNumber = 4; private const int Count = 10; class PipelineWorker<TInput, TOutput> { Func<TInput, TOutput> _processor = null; Action<TInput> _outputProcessor = null; BlockingCollection<TInput>[] _input; CancellationToken _token; public PipelineWorker( BlockingCollection<TInput>[] input, Func<TInput, TOutput> processor, CancellationToken token, string name) { _input = input; Output = new BlockingCollection<TOutput>[_input.Length]; for (int i = 0; i < Output.Length; i++) Output[i] = null == input[i] ? null : new BlockingCollection<TOutput>(Count); _processor = processor; _token = token; Name = name; } public PipelineWorker( BlockingCollection<TInput>[] input, Action<TInput> renderer, CancellationToken token, string name) { _input = input; _outputProcessor = renderer; _token = token; Name = name; Output = null; } public BlockingCollection<TOutput>[] Output { get; private set; } public string Name { get; private set; } public void Run() { Console.WriteLine("{0} is running", this.Name); while (!_input.All(bc => bc.IsCompleted) && !_token.IsCancellationRequested) { TInput receivedItem; int i = BlockingCollection<TInput>.TryTakeFromAny( _input, out receivedItem, 50, _token); if (i >= 0) { if (Output != null) { TOutput outputItem = _processor(receivedItem); BlockingCollection<TOutput>.AddToAny(Output,outputItem); Console.WriteLine("{0} sent {1} to next,on thread id {2}", Name, outputItem,Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); } else { _outputProcessor(receivedItem); } } else { Thread.Sleep(TimeSpan.FromMilliseconds(50)); } } if (Output != null) { foreach (var bc in Output) bc.CompleteAdding(); } } } Add the following code snippet inside the Main method: var cts = new CancellationTokenSource(); Task.Run(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); var sourceArrays = new BlockingCollection<int>[CollectionsNumber]; for (int i = 0; i < sourceArrays.Length; i++) { sourceArrays[i] = new BlockingCollection<int>(Count); } var filter1 = new PipelineWorker<int, decimal> (sourceArrays, (n) => Convert.ToDecimal(n * 0.97), cts.Token, "filter1" ); var filter2 = new PipelineWorker<decimal, string> (filter1.Output, (s) => String.Format("--{0}--", s), cts.Token, "filter2" ); var filter3 = new PipelineWorker<string, string> (filter2.Output, (s) => Console.WriteLine("The final result is {0} onthread id {1}", s, Thread.CurrentThread.ManagedThreadId), cts.Token,"filter3"); try { Parallel.Invoke( () => { Parallel.For(0, sourceArrays.Length * Count,(j, state) => { if (cts.Token.IsCancellationRequested) { state.Stop(); } int k = BlockingCollection<int>.TryAddToAny(sourceArrays, j); if (k >= 0) { Console.WriteLine("added {0} to source data onthread id {1}", j, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); } }); foreach (var arr in sourceArrays) { arr.CompleteAdding(); } }, () => filter1.Run(), () => filter2.Run(), () => filter3.Run() ); } catch (AggregateException ae) { foreach (var ex in ae.InnerExceptions) Console.WriteLine(ex.Message + ex.StackTrace); } if (cts.Token.IsCancellationRequested) { Console.WriteLine("Operation has been canceled!Press ENTER to exit."); } else { Console.WriteLine("Press ENTER to exit."); } Console.ReadLine(); Run the program. How it works... In the preceding example, we implement one of the most common parallel programming scenarios. Imagine that we have some data that has to pass through several computation stages, which take a significant amount of time. The latter computation requires the results of the former, so we cannot run them in parallel. If we had only one item to process, there would not be many possibilities to enhance the performance. However, if we run many items through the set of same computation stages, we can use a Parallel Pipeline technique. This means that we do not have to wait until all items pass through the first computation stage to go to the next one. It is enough to have just one item that finishes the stage, we move it to the next stage, and meanwhile the next item is being processed by the previous stage, and so on. As a result, we almost have parallel processing shifted by a time required for the first item to pass through the first computation stage. Here, we use four collections for each processing stage, illustrating that we can process every stage in parallel as well. The first step that we do is to provide a possibility to cancel the whole process by pressing the C key. We create a cancellation token and run a separate task to monitor the C key. Then, we define our pipeline. It consists of three main stages. The first stage is where we put the initial numbers on the first four collections that serve as the item source to the latter pipeline. This code is inside the Parallel.For loop, which in turn is inside the Parallel.Invoke statement, as we run all the stages in parallel; the initial stage runs in parallel as well. The next stage is defining our pipeline elements. The logic is defined inside the PipelineWorker class. We initialize the worker with the input collection, provide a transformation function, and then run the worker in parallel with the other workers. This way we define two workers, or filters, because they filter the initial sequence. One of them turns an integer into a decimal value, and the second one turns a decimal to a string. Finally, the last worker just prints every incoming string to the console. Everywhere we provide a running thread ID to see how everything works. Besides this, we added artificial delays, so the items processing will be more natural, as we really use heavy computations. As a result, we see the exact expected behavior. First, some items are being created on the initial collections. Then, we see that the first filter starts to process them, and as they are being processed, the second filter starts to work, and finally the item goes to the last worker that prints it to the console. Implementing Parallel Pipeline with TPL DataFlow This recipe shows how to implement a Parallel Pipeline pattern with the help of TPL DataFlow library. Getting ready To start with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe could be found at Packt site. How to do it... To understand how to implement Parallel Pipeline with TPL DataFlow, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. Add references to the Microsoft TPL DataFlow NuGet package. Right-click on the References folder in the project and select the Manage NuGet Packages... menu option. Now add your preferred references to the Microsoft TPL DataFlow NuGet package. You can use the search option in the Manage NuGet Packages dialog as follows: In the Program.cs file, add the following using directives: using System; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; Add the following code snippet below the Main method: async static Task ProcessAsynchronously() { var cts = new CancellationTokenSource(); Task.Run(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); var inputBlock = new BufferBlock<int>( new DataflowBlockOptions { BoundedCapacity = 5, CancellationToken = cts.Token }); var filter1Block = new TransformBlock<int, decimal>( n => { decimal result = Convert.ToDecimal(n * 0.97); Console.WriteLine("Filter 1 sent {0} to the nextstage on thread id {1}", result, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); return result; }, new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); var filter2Block = new TransformBlock<decimal, string>( n => { string result = string.Format("--{0}--", n); Console.WriteLine("Filter 2 sent {0} to the nextstage on thread id {1}", result, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); return result; }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); var outputBlock = new ActionBlock<string>( s => { Console.WriteLine("The final result is {0} on threadid {1}", s, Thread.CurrentThread.ManagedThreadId); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); inputBlock.LinkTo(filter1Block, new DataflowLinkOptions {PropagateCompletion = true }); filter1Block.LinkTo(filter2Block, new DataflowLinkOptions { PropagateCompletion = true }); filter2Block.LinkTo(outputBlock, new DataflowLinkOptions { PropagateCompletion = true }); try { Parallel.For(0, 20, new ParallelOptions {MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }, i => { Console.WriteLine("added {0} to source data on threadid {1}", i, Thread.CurrentThread.ManagedThreadId); inputBlock.SendAsync(i).GetAwaiter().GetResult(); }); inputBlock.Complete(); await outputBlock.Completion; Console.WriteLine("Press ENTER to exit."); } catch (OperationCanceledException) { Console.WriteLine("Operation has been canceled!Press ENTER to exit."); } Console.ReadLine(); } Add the following code snippet inside the Main method: var t = ProcessAsynchronously(); t.GetAwaiter().GetResult(); Run the program. How it works... In the previous recipe, we have implemented a Parallel Pipeline pattern to process items through sequential stages. It is quite a common problem, and one of the proposed ways to program such algorithms is using a TPL DataFlow library from Microsoft. It is distributed via NuGet, and is easy to install and use in your application. The TPL DataFlow library contains different type of blocks that can be connected with each other in different ways and form complicated processes that can be partially parallel and sequential where needed. To see some of the available infrastructure, let's implement the previous scenario with the help of the TPL DataFlow library. First, we define the different blocks that will be processing our data. Please note that these blocks have different options that can be specified during their construction; they can be very important. For example, we pass the cancellation token into every block we define, and when we signal the cancellation, all of them will stop working. We start our process with BufferBlock. This block holds items to pass it to the next blocks in the flow. We restrict it to the five-items capacity, specifying the BoundedCapacity option value. This means that when there will be five items in this block, it will stop accepting new items until one of the existing items pass to the next blocks. The next block type is TransformBlock. This block is intended for a data transformation step. Here we define two transformation blocks, one of them creates decimals from integers, and the second one creates a string from a decimal value. There is a MaxDegreeOfParallelism option for this block, specifying the maximum simultaneous worker threads. The last block is the ActionBlock type. This block will run a specified action on every incoming item. We use this block to print our items to the console. Now, we link these blocks together with the help of the LinkTo methods. Here we have an easy sequential data flow, but it is possible to create schemes that are more complicated. Here we also provide DataflowLinkOptions with the PropagateCompletion property set to true. This means that when the step completes, it will automatically propagate its results and exceptions to the next stage. Then we start adding items to the buffer block in parallel, calling the block's Complete method, when we finish adding new items. Then we wait for the last block to complete. In case of a cancellation, we handle OperationCancelledException and cancel the whole process. Implementing Map/Reduce with PLINQ This recipe will describe how to implement the Map/Reduce pattern while using PLINQ. Getting ready To begin with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... To understand how to implement Map/Reduce with PLINQ, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Collections.Generic; using System.IO; using System.Linq; Add the following code snippet below the Main method: private static readonly char[] delimiters =Enumerable.Range(0, 256). Select(i => (char)i).Where(c =>!char.IsLetterOrDigit(c)).ToArray(); private const string textToParse = @" Call me Ishmael. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen, and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me , that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off - then, I account it high time to get to sea as soon as I can. ― Herman Melville, Moby Dick. "; Add the following code snippet inside the Main method: var q = textToParse.Split(delimiters) .AsParallel() .MapReduce( s => s.ToLower().ToCharArray() , c => c , g => new[] {new {Char = g.Key, Count = g.Count()}}) .Where(c => char.IsLetterOrDigit(c.Char)) .OrderByDescending( c => c.Count); foreach (var info in q) { Console.WriteLine("Character {0} occured in the text {1}{2}", info.Char, info.Count, info.Count == 1 ? "time" : "times"); } Console.WriteLine(" -------------------------------------------"); const string searchPattern = "en"; var q2 = textToParse.Split(delimiters) .AsParallel() .Where(s => s.Contains(searchPattern)) .MapReduce( s => new [] {s} , s => s , g => new[] {new {Word = g.Key, Count = g.Count()}}) .OrderByDescending(s => s.Count); Console.WriteLine("Words with search pattern '{0}':",searchPattern); foreach (var info in q2) { Console.WriteLine("{0} occured in the text {1} {2}",info.Word, info.Count, info.Count == 1 ? "time" : "times"); } int halfLengthWordIndex = textToParse.IndexOf(' ',textToParse.Length/2); using(var sw = File.CreateText("1.txt")) { sw.Write(textToParse.Substring(0, halfLengthWordIndex)); } using(var sw = File.CreateText("2.txt")) { sw.Write(textToParse.Substring(halfLengthWordIndex)); } string[] paths = new[] { ".\" }; Console.WriteLine(" ------------------------------------------------"); var q3 = paths .SelectMany(p => Directory.EnumerateFiles(p, "*.txt")) .AsParallel() .MapReduce( path => File.ReadLines(path).SelectMany(line =>line.Trim(delimiters).Split (delimiters)),word => string.IsNullOrWhiteSpace(word) ? 't' :word.ToLower()[0], g => new [] { new {FirstLetter = g.Key, Count = g.Count()}}) .Where(s => char.IsLetterOrDigit(s.FirstLetter)) .OrderByDescending(s => s.Count); Console.WriteLine("Words from text files"); foreach (var info in q3) { Console.WriteLine("Words starting with letter '{0}'occured in the text {1} {2}", info.FirstLetter,info.Count, info.Count == 1 ? "time" : "times"); } Add the following code snippet after the Program class definition: static class PLINQExtensions { public static ParallelQuery<TResult> MapReduce<TSource,TMapped, TKey, TResult>( this ParallelQuery<TSource> source, Func<TSource, IEnumerable<TMapped>> map, Func<TMapped, TKey> keySelector, Func<IGrouping<TKey, TMapped>, IEnumerable<TResult>> reduce) { return source.SelectMany(map) .GroupBy(keySelector) .SelectMany(reduce); } } Run the program. How it works... The Map/Reduce functions are another important parallel programming pattern. It is suitable for a small program and large multi-server computations. The meaning of this pattern is that you have two special functions to apply to your data. The first of them is the Map function. It takes a set of initial data in a key/value list form and produces another key/value sequence, transforming the data to the comfortable format for further processing. Then we use another function called Reduce. The Reduce function takes the result of the Map function and transforms it to a smallest possible set of data that we actually need. To understand how this algorithm works, let's look through the recipe. First, we define a relatively large text in the string variable: textToParse. We need this text to run our queries on. Then we define our Map/Reduce implementation as a PLINQ extension method in the PLINQExtensions class. We use SelectMany to transform the initial sequence to the sequence we need by applying the Map function. This function produces several new elements from one sequence element. Then we choose how we group the new sequence with the keySelector function, and we use GroupBy with this key to produce an intermediate key/value sequence. The last thing we do is applying Reduce to the resulting grouped sequence to get the result. In our first example, we split the text into separate words, and then we chop each word into character sequences with the help of the Map function, and group the result by the character value. The Reduce function finally transforms the sequence into a key value pair, where we have a character and a number for the times it was used in the text ordered by the usage. Therefore, we are able to count each character appearance in the text in parallel (since we use PLINQ to query the initial data). The next example is quite similar, but now we use PLINQ to filter the sequence leaving only the words containing our search pattern, and we then get all those words sorted by their usage in the text. Finally, the last example uses file I/O. We save the sample text on the disk, splitting it into two files. Then we define the Map function as producing a number of strings from the directory name, which are all the words from all the lines in all text files in the initial directory. Then we group those words by the first letter (filtering out the empty strings) and use reduce to see which letter is most often used as the first word letter in the text. What is nice is that we can easily change this program to be distributed by just using other implementations of map and reduce functions, and we still are able to use PLINQ with them to make our program easy to read and maintain. Summary In this article we covered implementing lazy-evaluated shared states, implementing Parallel Pipeline using BlockingCollection and TPL DataFlow, and finally we covered the implementation of Map/Reduce with PLINQ. Resources for Article: Further resources on this subject: Simplifying Parallelism Complexity in C# [Article] Watching Multiple Threads in C# [Article] Low-level C# Practices [Article]
Read more
  • 0
  • 0
  • 38467

article-image-working-java-se-projects-should-know
Packt
25 Nov 2013
5 min read
Save for later

Working with Java SE projects (Should know)

Packt
25 Nov 2013
5 min read
(For more resources related to this topic, see here.) How to do it... The following steps will show you how to experiment with JRebel on a Java SE application: Create a simple Swing application and test it. Enable JRebel on your project. Try live code injection with JRebel. How it works... We will create a simple Swing application, a frame that contains a label and a button. The action associated with the button will update the label. We will use JRebel to change the button's action without recompiling or restarting the application. Start NetBeans and create a new Java application project. Create a package, delete the default main class, and use the NetBeans assistant to create a new JFrame object by navigating to File | New File | Swing GUI Forms | JFrame Form, and then choose a name and validate. The Projects view Use the Palette tab on your right to drag-and-drop a JLabel and a JButton to your JForm (these two components are located in the Swing Controls section, under the Label and Button names). The Palette tab Now, double-click on the button you have generated. You will be redirected to the jButton1ActionPerformed method of your JFrame object. private void jButton1ActionPerformed (java.awt.event.ActionEvent evt) { // TODO add your handling code here: } Insert a code to update JLabel of your form, as shown in the following code: private void jButton1ActionPerformed (java.awt.event.ActionEvent evt) { // TODO add your handling code here: jLabel1.setText("Hello World"); } The application is now ready for testing. You can test it by pressing F6 key. NetBeans will ask you for the name of the main class. Select the JFrame form and validate. Use the jButton1 button to update the label. The first Hello World window Do not close the application immediately, and return to the code editor to update the jButton1 button's action in order to display a new message and save the new code. private void jButton1ActionPerformed (java.awt.event.ActionEvent evt) { // TODO add your handling code here: // jLabel1.setText("Hello World"); // previous message jLabel1.setText("Hello Planet"); // new message } Hit the jButton1 button in your application again; the change is not effective. Actually, your application hasn't been updated and it can't reflect code changes immediately. You will have to restart your application to see the new behavior, and this is normal. Now, let's see how JRebel will accelerate the development. You may have noticed the presence of a JRebel node in the Projects view. Right-click on it and choose Generate rebel.xml. The JRebel XML The rebel.xml file will contain the path of the compiled classes. JRebel will use these compiled classes to update your running application. Also, that means we have to ensure the Compile on Save feature is turned on for your project. Every time you apply changes to a Java class, NetBeans will recompile it and JRebel will update your running application with it. To proceed, go to the Projects Properties panel and enable the Compile on Save feature. Enabling the Compile on Save feature To finish, you have to activate JRebel (locate the JRebel button on the NetBeans toolbar). Enabling the JRebel button Now, restart your application and hit the jButton1 button a first time. Return to the code editor, modify the button's action to display a new message, save, and carefully observe the NetBeans console; you will see two interesting messages: Firstly, JRebel indicates if your license is active Secondly, you can see a message that indicates a class which has been reloaded, as follows: 2013-07-28 15:08:03 JRebel: Reloading class 'demo.ant.OurJFrame'. 2013-07-28 15:08:03 JRebel: Reloading class 'demo.ant. OurJFrame$2'. 2013-07-28 15:08:03 JRebel: Reloading class 'demo.ant. OurJFrame$1'. Hit the jButton1 button again; the message changes without restarting the application. It works! You can now continue to update and save code in order to see the changes. Try to update the displayed message again, it works again; you don't need to restart your application again (except for some changes that are not supported by JRebel). There's more... Ant is not the only build system, so you may want to use JRebel with Maven-based projects. Maven- and Ant-based projects are handled the same way: generate a rebel.xml file, activate the Compile on Save feature, enable JRebel, and simply update your code without restarting your application. You don't have to deal with the Maven pom.xml file. Also, you will still see the two same JRebel messages in the NetBeans console. They are useful to check the JRebel license and class reloading. Last but not least, to activate the Compile On Save feature, the Compile On Save menu should be set to For application execution only (or better). Maven's Compile On Save feature Summary In this article, we learnt how to work with JRebel on the Ant Java SE projects. We also learnt the about Maven Java SE projects support. Resources for Article: Further resources on this subject: The Business Layer (Java EE 7 First Look) [Article] Developing Secure Java EE Applications in GlassFish [Article] Service Oriented Java Business Integration - What's & Why's [Article]
Read more
  • 0
  • 0
  • 3662
article-image-instant-optimizing-embedded-systems-using-busybox
Packt
25 Nov 2013
9 min read
Save for later

Instant Optimizing Embedded Systems Using BusyBox

Packt
25 Nov 2013
9 min read
(For more resources related to this topic, see here.) BusyBox Compiling BusyBox, the Swiss Army Knife of Embedded Linux, it can be compiled into a single binary for different architectures. Before compiling software, we must get a compiler and the corresponding libraries, a build host and a target platform, the build host is the one running the compiler, the target platform is the one running the target binary. Herein, the desktop development system is a 64 bit X86 Ubuntu systems, it will be used as our build host, and an ARM Android system will be used as our target platform. To compile BusyBox on X86-64 Ubuntu system for ARM, we need a cross compiler. The gcc-arm-linux-gnueabi cross compiler can be installed directly on Ubuntu: $ sudo apt-get install gcc-arm-linux-gnueabi On the other Linux distributions, Google's official NDK is a good choice if want to share Android's Bionic C library, but since Bionic C library lacks lots of POSIX C header files, if want to get most of BusyBox applets building, the prebuilt version of Linaro GCC with Glibc is preferable, we can download it from http://www.linaro.org/downloads/, for example: http://releases.linaro.org/13.04/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.7-2013.04-20130415_linux.tar.bz2. Before compiling, to simplify the configuration, enable the largest generic configuration with make defconfig and configure cross compiler: arm-linux-gnueabi-gcc with: make menuconfig. $ make defconfig $ make menuconfig Busybox Settings ---> Build Options ---> (arm-linux-gnueabi-) Cross Compiler prefix After configuration, we can simply compile it with: $ make Then, a BusyBox binary will be compiled for ARM: $ file busybox busybox: ELF 32-bit LSB executable, ARM, version 1(SYSV), dynamically linked (uses shared libs), stripped To list the shared libraries required by BusyBox binary for ARM, a command arm-linux-gnueabi-readelf should be used: $ arm-linux-gnueabi-readelf -d ./busybox grep "Shared library:" | cut -d'[' -f2 | tr -d ']'| libm.so.6 libc.so.6 ld-linux.so.3 To get the full path, we can get the library search path at first: $ arm-linux-gnueabi-ld --verbose grep SEARCH | tr ';' 'n' | cut -d'"' -f2 | tr -d '"'| /lib/arm-linux-gnueabi /usr/lib/arm-linux-gnueabi /usr/arm-linux-gnueabi/lib Then, we can find out that /usr/arm-linux-gnueabi/lib is the real search path in our platform and we can get the full path of the libraries as below: $ ls /usr/arm-linux-gnueabi/lib/{libm.so.6,libc.so.6,ld-linux.so.3} /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /usr/arm-linux-gnueabi/lib/libc.so.6/usr/arm-linux-gnueabi/lib/libm.so.6 By default, the binary is dynamically linked, to enable static linking, configure BusyBox as following: Busybox Settings ---> Build Options ---> [*] Build BusyBox as a static binary (no shared libs) If using a new Glibc to compile BusyBox with static linking, to avoid such error: inetd.c:(.text.prepare_socket_fd+0x7e): undefined reference to `bindresvport' We need to disable CONFIG_FEATURE_INETD_RPC: Networking Utilities ---> [*] inetd [ ] Support RPC services Then, recompile it with make. BusyBox Installation This section shows how to install the above compiled BusyBox binaries on an ARM Android system. The installation of BusyBox means to create soft links for all of its built-in applets, use wc applet as an example: $ ln -s busybox wc $ echo "Hello, Busybox." ./wc -w| 2 BusyBox can be installed at the earlier compiling stage or at run-time. To build a minimal embedded file system with BusyBox, we'd better install it at the compiling stage with 'make install' for it helps to create the basic directory architecture of a standard Linux root file system and create soft links to BusyBox under the corresponding directories. With this installation method, we need to configure the target installation directory as following, use ~/busybox-ramdisk/ directory as an example: Busybox Settings ---> Installation Options ("make install" behavior) ---> (~/busybox-ramdisk/) BusyBox installation prefix After installation, we may get such a list of the file and directories: $ ls ~/busybox-ramdisk/ bin linuxrc sbin usr But to install it on an existing ARM Android system, it may be easier to install BusyBox at run-time with its --install option. With --install, by default, hard links will be created, to create soft links (symbolic links), -s option should be appended. If want to create links across different file systems (E.g. in Android system, to install BusyBox to /system/bin but BusyBox itself is put in the /data directory), -s must be used. To use the -s option, BusyBox should be configured as below: Busybox Settings ---> General Configuration ---> [*] Support --install [-s] to install applet links at runtime Now, let’s introduce how to install the above compiled BusyBox binaries to an existing ARM Android system. To do so, the Android system must be rooted to make sure the /data and / directories are writable. We will not show how to root an Android device, please get help from your product maker. Or if no real rooted Android device available, the Android emulator (emulator) provided by ADT (Android Development Toolkit, http://developer.android.com/sdk/index.html) can be used to start a rooted Android system on a virtual ARM Android device. To create a virtual ARM Android device and to use the Android emulator, please read the online documents provided by Google on http://developer.android.com/tools/help/android.html and http://developer.android.com/tools/help/emulator.html. Now, let's assume a rooted Android system is already running there with the USB debugging option enabled for Android Debug Bridge (adb, http://developer.android.com/tools/help/adb.html) support, for example, to check if such a device is started, we can run: $ adb devices List of devices attached emulator-5554 device As we can see, a virtual Android device running on Android emulator: emulator-5554 is there. Now, we are able to show how to install the BusyBox binaries on the existing Android system. Since the dynamically linked and statically linked BusyBox binaries are different, we will introduce how to install them respectively. Install the statically linked Busybox binary To install the statically installed Busybox binary, we only need to upload the BusyBox binary itself: $ adb push busybox /data/ Afterwards, install it with the --install option, for example, install it to the /bin directory of the Andriod system: $ adb shell root@android:/ # mount -o remount,rw / root@android:/ # mkdir /bin/ root@android:/ # /data/busybox --install -s /bin To be able to create the /bin directory for installation, the / directory is remounted to be writable. After installation, soft links are created under /bin for all of the built-in applets. If the -s option is not used, it will fail to create the hard links across the /bin and /data directories, that's why we must use -s option, the failure log looks like: busybox: /bin/[: Invalid cross-device link busybox: /bin/[[: Invalid cross-device link busybox: /bin/acpid: Invalid cross-device link busybox: /bin/add-shell: Invalid cross-device link (...truncated...) To execute the just installed applets, use md5sum as an example: $ /bin/md5sum /bin/ls 19994347b06d5ef7dbcbce0932960395 /bin/ls To run the applets without the full path, the /bin directory should be appended to the PATH variable: $ export PATH=$PATH:/bin Then, all of the BusyBox applets can be executed directly, that means we have installed Busybox successfully. To make the settings permanently, the above commands can be added to a script and such a script can be run as an Android service. Install the statically linked Busybox binary To install the statically installed Busybox binary, we only need to upload the BusyBox binary itself: $ adb push busybox /data/ Afterwards, install it with the --install option, for example, install it to the /bin directory of the Andriod system: $ adb shell root@android:/ # mount -o remount,rw / root@android:/ # mkdir /bin/ root@android:/ # /data/busybox --install -s /bin To be able to create the /bin directory for installation, the / directory is remounted to be writable. After installation, soft links are created under /bin for all of the built-in applets. If the -s option is not used, it will fail to create the hard links across the /bin and /data directories, that's why we must use -s option, the failure log looks like: busybox: /bin/[: Invalid cross-device link busybox: /bin/[[: Invalid cross-device link busybox: /bin/acpid: Invalid cross-device link busybox: /bin/add-shell: Invalid cross-device link (...truncated...) To execute the just installed applets, use md5sum as an example: $ /bin/md5sum /bin/ls 19994347b06d5ef7dbcbce0932960395 /bin/ls To run the applets without the full path, the /bin directory should be appended to the PATH variable: $ export PATH=$PATH:/bin Then, all of the BusyBox applets can be executed directly, that means we have installed Busybox successfully. To make the settings permanently, the above commands can be added to a script and such a script can be run as an Android service. Install the dynamically linked BusyBox binary For a dynamically linked BusyBox, to install it, besides the installation of the BusyBox binary itself, the required dynamic linker/loader (ld-linux.so) and the dependent shared libraries (libc.so and libm.so) should be installed too. For the basic installation procedure are the same as the one for statically linked BusyBox, herein, we only introduce how to install the required ld-linux.so.3, libc.so.6 and libm.so.6. Without the above dynamic linker/loader and libraries, we may get such error while running the dynamically linked BusyBox: $ /data/busybox --install -s /bin /system/bin/sh: /data/busybox: No such file or directory Before installation, create another /lib directory on target Android system and then upload the above files to it: $ adb shell mkdir /lib $ adb push /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib/ $ adb push /usr/arm-linux-gnueabi/lib/libc.so.6 /lib/ $ adb push /usr/arm-linux-gnueabi/lib/libm.so.6 /lib/ With the above installation, the dynamically linked BusyBox binary should also be able to run and we are able to install and execute its applets as before: $ /data/busybox --install -s /bin As we can see, the installation of the dynamically linked BusyBox binary requires extra installation of the dependent linker/loader and libraries. For real embedded system development, if only the BusyBox binary itself uses the shared libraries, the static linking should be used instead at compiling to avoid the extra installation and the time-cost run-time linking, otherwise, if many binaries share the same libraries, to reduce the total size cost for the size critical embedded systems, dynamic linking may be preferable. Summary In this article we learned about BusyBox compiling and its installation. BusyBox is a free GPL-licensed toolbox aimed at the embedded world. It is a collection of the tiny versions of many common Unix utilities. Resources for Article : Further resources on this subject: Embedding Doctests in Python Docstrings [Article] The Business Layer (Java EE 7 First Look) [Article] Joomla! 1.6: Organizing and Managing Content [Article]
Read more
  • 0
  • 0
  • 23486

article-image-setting-and-managing-e-mails-and-batch-processing
Packt
25 Nov 2013
4 min read
Save for later

Setting Up and Managing E-mails and Batch Processing

Packt
25 Nov 2013
4 min read
(For more resources related to this topic, see here.) Setting Up and Managing E-mails and Batch Processing The batch framework processes more than the recurring system tasks; users can submit jobs from many places within AX. This allows them to continue with their primary tasks without having to wait for the operation to finish. An alert can be set up to alert them about the success or failure of the task. Using e-mails correctly makes the system look more professional and user friendly; instead of the basic text details in system-generated e-mails, they can be branded with your corporate identity and laid out in a more appealing manner. There are two methods by which e-mails are sent in AX: SMTP and MAPI. MAPI (Messaging Application Programming Interface) is a client-side method that opens a new message in your e-mail client (Microsoft Outlook, for example), potentially setting the recipients and subject from the data in AX. Attachments can also be added via MAPI (for example, while sending a report via an e-mail from AX). SMTP (Simple Mail Transfer Protocol) is a server-side method and is used for server-generated e-mails such as alerts and workflow notifications. MAPI is not always desirable due to its client-side dependence on an e-mail client, which causes problems when running the client as a remote app. A common modification is to replace it with SMTP as the e-mail is then sent by the server without requiring a client-side e-mail client. There are add-ons that achieve this and some can even autoroute the documents based on the routing information. The other advantage of SMTP server-side e-mails is that they can be richly formatted using HTML templates created through a built-in editor, and can use placeholders for information such as the details of a system alert. SMTP requires the mail server to act as a relay for AX, as is the case of Microsoft Exchange. Your SMTP server should be configured to allow Dynamics AX to relay e-mails through it. The batch framework allows many AX functions to be processed either as scheduled recurring jobs, or as once-only tasks to be processed asynchronously to the AX client by the AOS. Typically, the tasks performed by the batch framework are scheduled jobs (for example, nightly sales invoice posting), or a process triggered by a user for which the user does not require an immediate response (for instance, processing an MRP calculation). In this case, the user may request an alert of its completion. Although users usually prefer the comfort of a progress bar and a message to state that it has been completed, submitting it as a batch job for many tasks is far more efficient as it allows them to perform other tasks while the server processes the task. Developers also have the ability to use the batch framework to submit asynchronous requests from within a transaction, so as to improve the user response time. This may strike an element of fear in those who consider that the transactions should obey the ACID ( Atomic, Consistent, Isolation, and Durability) transaction principle; these will be for tasks where a compensation pattern can be implemented in order to handle an inconsistent state. A real-life example of this is the coffee shop queue, where you order and pay for your coffee, complete the transaction, and then wait for the coffee. If the coffee is not available, you would be compensated by the shop giving you your money back post transaction. Not all transactions can ACID principle; for example, posting a supplier payment that sends remittances by e-mail. If the transaction fails after the e-mail has been sent, the database transaction will be rolled back, leaving the e-mail in the supplier's inbox. There are some important yet not so obvious points to consider when working with the batch framework: The batch framework runs on the server tier, and therefore, on a Windows Server that hosts the AOS service. This means that the server should be able to access any file paths, printers, and so on. The tasks will run as the security context of the user who submitted the task, but any external access (for example, files) is performed using the AOS service account. This note is mainly for developers. The tasks will run in CIL; this means you may find that the old code is executed even when a change has been made to your X++ code. This includes reports that run interactively, all code that runs on the server tier, and certain code that is client-side and pushed to the server tier for performance. The only way to ensure that the new code is being run is to restart the AOS service.
Read more
  • 0
  • 0
  • 5313
Modal Close icon
Modal Close icon