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

How-To Tutorials

7019 Articles
article-image-including-charts-and-graphics-pentaho-reports-part-1
Packt
09 Nov 2009
8 min read
Save for later

Including Charts and Graphics in Pentaho Reports (Part 1)

Packt
09 Nov 2009
8 min read
Supported charts Pentaho Reporting relies on JFreeChart, an open source Java chart library, for charting visualization within reports. From within Report Designer, many chart types are supported. In the chart editor, two areas of properties appear when editing a chart. The first area of properties is related to chart rendering, and the second tabbed area of properties is related to the data that populates a chart. Following is the screenshot of the chart editor within Pentaho Report Designer: All chart types receive their data from three general types of datasets. The first type is known as a Category Dataset , where the dataset series and values are grouped by categories. A series is like a sub-group. If the exact category and series appear, the chart will sum the values into a single result. The following table is a simple example of a category dataset: Category Series Sale Price Store 1 Sales Cash $14 Store 1 Sales Credit $12 Store 2 Sales Cash $100 Store 2 Sales Credit $120 Pentaho Reporting builds a Category Dataset using the CategorySetDataCollector. Also available is the PivotCategorySetCollector, which pivots the category and series data. Collector classes implement Pentaho Reporting’s Function API. The second type of dataset is known as an XY Series Dataset, which is a two dimensional group of values that may be plotted in various forms. In this dataset, the series may be used to draw different lines, and so on. Here is a simple example of an XY series dataset : Series Cost of Goods (X) Sale Price (Y) Cash 10 14 Credit 11 12 Cash 92 100 Credit 105 120 Note that X is often referred to as the domain, and Y is referred to as the range. Pentaho Reporting builds an XY Series Dataset using the XYSeriesCollector. The XYZSeriesCollector also exists for three dimensional data. The third type of dataset is known as a Time Series Dataset , which is a two dimensional group of values that are plotted based on a time and date. The Time Series Dataset is more like an XY Series than a Category Dataset, as the time scale is displayed in a linear fashion with appropriate distances between the different time references. Time Series Sale Price May 05, 2009 11:05pm Cash $14 June 07, 2009 12:42pm Credit $12 June 14, 2009 4:20pm Cash $100 June 01, 2009 1:22pm Credit $120 Pentaho Reporting builds a Time Series Dataset using the TimeSeriesCollector. Common chart rendering properties Most charts share a common set of properties. The following properties are common across most charts. Any exceptions are mentioned as part of the specific chart type. Required Property Group Property name Description name The name of the chart object within the report. This is not displayed during rendering, but must be unique in the report. A default name is generated for each chart added to the report. data-source The dataset name for the chart, which is automatically populated with the name of the dataset in the Primary DataSource panel of the chart editor. no-data-message The message to display if no data is available to render the chart. Title Property Group Property name Description chart-title The title of the chart, which is rendered in the report. chart-title-field A field representing the chart title. title-font The chart title's font family, size, and style. Options Property Group Property name Description horizontal If set to True, the chart's X and Y axis are rotated horizontally. The default value is set to False. series-colors The color in which to render each series. The default for the first three series colors are red, blue, and green. General Property Group Property name Description 3-D If set to True, renders the chart in a 3D perspective. The default value is set to False. anti-alias If set to True, renders chart fonts as anti-aliased. The default value is set to True. bg-color Sets the background around the chart to the specified color. If not set, defaults to gray. bg-image Sets the background of the chart area to the specified image. If not set, the background of the chart area defaults to white. The chart area is the area within the axes of the chart. Supported image types include PNG, JPG, and GIF file formats. show-border If set to True, displays a border around the chart. The default value is set to True. border-color Sets the border to the specified color. If not set, defaults to black. plot-border If set to False, clears the default rendering value of the chart border. plot-bg-color Sets the plot background color to the specified color. If not set, defaults to white. plot-fg-alpha Sets the alpha value of the plot foreground colors relative to the plot background. The default value is set to 1.0. plot-bg-alpha Sets the alpha value of the plot background color relative to the chart background color. The default value is set to 1.0.   Legend Property Group Property name Description show-legend If set to True, displays the legend for the chart. The default value is set to False. location The location of the legend in relation to the chart, which may be set to top, bottom, left, or right. The default location is bottom. legend-border If set to True, renders a border around the legend. The default value is set to True. legend-font The type of Java font to render the legend labels in. legend-bg-color Sets the legend background color. If not set, defaults to white. legend-font-color Sets the legend font color. If not set, defaults to black. Advanced Property Group Property name Description dependencyLevel The dependency level field informs the reporting engine what order the chart should be executed in relation to other items in the report. This is useful if you are using special functions that may need to execute prior to generating the chart. The default value is set to 0. Negative values execute before 0, and positive values execute after 0.   Common category series rendering properties The following properties appear in charts that render category information: Options Property Group Property name Description stacked If set to True, the series values will appear layered on top of one another instead of being displayed relative to one another. stacked-percent If set to True, determines the percentages of each series, and renders the bar height based on those percentages. The property stacked must be set to True for this property to have an effect. General Property Group Property name Description gridlines If set to True, displays category grid lines. This value is set to True by default. X-Axis Property Group Property name Description label-rotation If set, adjusts the inline item label rotation value. The value should be specified in degrees. If not specified, labels are rendered horizontally. You must have show-labels set to true for this value to be relevant. date-format If the item value is a date, a Java date format string may be provided to format the date appropriately. Please see Java's SimpleDateFormat JavaDoc for formatting details. numeric-format If the item value is a decimal number, a Java decimal format string may be provided to format the number appropriately. Please see Java's DecimalFormat JavaDoc for formatting details. text-format The label format used for displaying category items within the chart. This property is required if you would like to display the category item values. The following parameters may be defined in the format string to access details of the item: {0}: To access the Series Name detail of an item {1}: To access the Category detail of an item {2}: To access the Item value details of an item To display just the item value, set the format string to "{2}". x-axis-title If set, displays a label describing the category axis. show-labels If set to true, displays x-axis labels in the chart. x-axis-label-width Sets the maximum category label width ratio, which determines the maximum length each category label should render in. This might be useful if you have really long category names. x-axis-label-rotation If set, adjusts the category item label rotation value. The value should be specified in degrees. If not specified, labels are rendered horizontally. x-font The font to render the category axis title and labels in. Y-Axis Property Group Property name Description y-axis-title If set, displays a label along the value axis of the chart. label-rotation If set, determines the upward angle position of the label, where the value passed into JFreeChart is the mathematical pie over the value. Unfortunately, this property is not very flexible and you may find it difficult to use. y-tick-interval The numeric interval value to separate range ticks in the chart. y-font The font to render the range axis title in. y-sticky-0 If the range includes zero in the axis, making it sticky will force truncation of the axis to zero if set to True. The default value of this property is True. y-incl-0 If set to True, the range axis will force zero to be included in the axis. y-min The minimum value to render in the range axis. y-max The maximum value to render in the range axis. y-tick-font The font to render the range tick value in. y-tick-fmt-str The DecimalFormat string to render the numeric range tick value. enable-log-axis If set to true, displays the y-axis as a logarithmic scale. log-format If set to true, will present the logarithmic scale in a human readable view.
Read more
  • 0
  • 0
  • 5208

article-image-useful-maven-plugins-part-2
Packt
09 Nov 2009
12 min read
Save for later

Useful Maven Plugins: Part 2

Packt
09 Nov 2009
12 min read
The Build Helper plugin Within Maven, there are a number of common tasks which plugins can perform to alter the current project for changes occurring during the build. We have seen the inclusion of new resources in the Remote Resources plugin, and the attachment of a new artifact from the Shade plugin. It is also possible to have a plugin generate new source code and include it for compilation, even though the directory is not included in the POM file. The role of the Build Helper plugin is to provide a set of goals that can help achieve a collection of small but common tasks for which it would not be worth writing a custom plugin. Adding source directories Maven's inability to have multiple source directories in the project model has often been called into question. However, as time has progressed the request has died down as the idea of a standardized source structure took hold. The Build Helper plugin offers the ability to add another source directory or test source directory to that configured in the POM. This is not necessarily to allow a workaround for the deliberate limitation in the project model, but rather to facilitate other use cases that require it. The most common need to use this technique is to assist with the migration of a project in an existing layout to Maven temporarily. Even with this capability it is still recommended not to add multiple source directories without a particular reason—apart from breaking with convention, you may find that some tools that operate based on the values in the POM will not recognize the additional directories as containing source code. The following example illustrates the addition of a source directory: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.1</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>src/main/more-java</source> </sources> </configuration> </execution> </executions></plugin> The need to use the Build Helper plugin for adding sources is now becoming more rare. Maven plugins that generate source code would be likely to add the extra directory to the project internally without the need for additional configuration. If some other means is used to generate the sources—for example, from a scripting plugin—it is common for the scripting plugin to have a way to add the source directory with fewer configurations than using the Build Helper plugin. However, if the need does arise, the Build Helper plugin will prove itself useful. Attaching arbitrary artifacts A similar scenario that can occur is the generation of additional artifacts that need to be attached to the build process. This means they use the same POM to define them, but are different types of related build artifacts, with their own classifier. The artifacts are installed and deployed to the repository alongside the original. Typically, this will be in the form of another JAR file, possibly generated by one of the scripting plugins that did not attach the artifact itself. However, it could be used for any number of files that need to be stored in the repository alongside the main artifact. Consider the example of deploying the license to the repository—if you were to run the install phase on the given project, you would be able to have the license installed into the local repository alongside the main artifact and its POM. In reality, this particular configuration may be overkill, especially if the licenses are identical across many projects, or can be derived from the POM. However, depending on your deployment needs this possibility can be helpful in ensuring the repository contains the information about an artifact that you need, at the time it was deployed, in addition to any extra build artifacts that might be generated. In our example application, we generated the license in two places—in all the Java modules, and the final distribution. Deploying it along with the final distribution makes some sense, so let's add it to the distribution/pom.xml file: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.1</version> <configuration> <artifacts> <artifact> <file> target/maven-shared-archive-resources/LICENSE </file> <type>txt</type> <classifier>license</classifier> </artifact> </artifacts> </configuration> <executions> <execution> <goals> <goal>attach-artifact</goal> </goals> </execution> </executions></plugin> This goal will execute after the packaging has occurred, but before installation so that it can be attached to the installation (and deployment) process. The file to attach is the license generated earlier by the Remote Resources plugin and is given an extension of .txt and classifier of -license. When running the install phase, we now see the file being processed: [INFO] [build-helper:attach-artifact {execution: default}][INFO] [enforcer:enforce {execution: default}][INFO] [install:install][INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/pom-transformed.xml to /Users/brett/.m2/repository/com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT.pom[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/centrepoint-1.0-SNAPSHOT-bin.zip to /Users/brett/.m2/repository/com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT-bin.zip[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/centrepoint-1.0-SNAPSHOT-bin.tar.gz to /Users/brett/.m2/repository/com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT-bin.tar.gz[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/maven-shared-archive-resources/LICENSE to /Users/brett/.m2/repository/com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT-license.txt Other goals The Build Helper plugin also contains some other goals in the latest release at the time of writing (v1.1) of more specific interest: remove-project-artifact: To clean the local repository of artifacts from the project being built to preserve space and remove outdated files. This may occur if the build no longer produces those files, or if it is necessary to remove older versions. reserve-network-port: Many networked applications may want to use a network port that doesn't conflict with other test cases. This goal can help reserve unique ports to use in the tests. This is useful for starting servers in integration tests and then referencing them in the test cases. However, note that it won't be available when running such tests in a non-Maven environment such as the IDE. The goals available in the Build Helper plugin may increase over time, so if you have some small, common adjustments to make it is a good place to look to first for those utilities. The AntRun plugin and scripting languages Maven was designed to be extended through plugins. Because of the fact that this is so strongly encouraged, there are now many plugins available for a variety of tasks, and the need to write your own customizations, particularly for common tasks, is reduced. However, no two projects are the same, and in some projects, there are likely to be some customizations that will need to be made that are not covered by an existing plugin. While it is virtuous to write a plugin for such cases so that it can be reused in multiple projects, it is also very reasonable to use some form of scripting for short, one off customizations. One simple option is to use the AntRun plugin. Ant still contains the largest available set of build tasks to cover the types of customizations that you might need in your build, and through this plugin you can quickly string together some of these tasks within the Maven life cycle to achieve the outcome that you need. Running simple tasks We have already used the AntRun plugin in the distribution module of the example application. This snippet was used to copy some configuration files into place and create a logs directory, ready for the Assembly plugin to create the archive from: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.1</version> <executions> <execution> <id>config</id> <phase>process-resources</phase> <configuration> <tasks> <copy todir="${project.build.directory}/generated- resources/appassembler/jsw/centrepoint/conf"> <fileset dir="src/main/conf" /> </copy> <mkdir dir="${project.build.directory}/generated- resources/appassembler/jsw/centrepoint/logs" /> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions></plugin> This shows how quick and useful the AntRun plugin can be for simple tasks. However, it also contains a number of other features that can be of benefit to the build for more significant tasks. Interacting with the Maven project As we mentioned in the section, The Build Helper plugin, you can tell the plugin to map some directories to new source directories. This functionality is identical to that of the Build Helper plugin, but is more conveniently located when the directories are being generated by Ant tasks. This can be useful because even though tools are increasingly supplying native Maven plugins in addition to Ant tasks, you might come across a source generation tool that only has an Ant task. In this scenario, you can use the AntRun plugin to run the tool, generate the source code, and use the sourceRoot parameter to have that directory added back into the build life cycle. In addition to injecting source directories back into the life cycle, the AntRun plugin also injects Maven project information into Ant's context. Probably the most important of these is the availability of the project's and plugin's dependencies as Ant path references: maven.compile.classpath: The dependencies in the compile scope (this syntax will look familiar to those that used Maven 1's built in Ant-based files) maven.runtime.classpath: The dependencies in the runtime scope (including the above) maven.test.classpath: The dependencies in the test scope (including both of the above) maven.plugin.classpath: The dependencies of the AntRun plugin itself, including any added via the POM Though we have not needed it in the example application, to illustrate how these two options would work, consider if you needed to use the XJC Ant task from JAXB to generate some sources. JAXB is a Java-to-XML binding framework that can be used to generate Java source code from XML schema (among many other things), using its XJC tool. Though it serves as a suitable example here, you would not be faced with this issue with JAXB itself, as it now offers a Maven plugin. In this example, you might add the following configuration to an AntRun execution in a POM file: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.3</version> <executions> <execution> <id>xjc</id> <phase>generate-sources</phase> <configuration> <tasks> <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask" classpathref="maven.plugin.classpath" /> <xjc destdir="${project.build.directory}/xjc" schema="src/main/jaxb/schema.xsd"> <classpath refid="maven.compile.classpath" /> </xjc> </tasks> <sourceRoot>${project.build.directory}/xjc</sourceRoot> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-xjc</artifactId> <version>2.1.9</version> </dependency> </dependencies></plugin> We see here that the XJC Task is defined using the plugin classpath to locate the task and its dependencies (and that task's artifact is added as a plugin dependency to accommodate this). Additional built-in Ant tasks would also be added as plugin dependencies (such as ant-nodeps). AntRun and Ant versions While in some cases they might be compatible, generally you should use the same version of the Ant optional tasks as the version of Ant itself. The version of Ant used by the plugin is predetermined by what it has been built against. In AntRun v1.3, that is Ant 1.7.1. To use a different version of Ant, consider a different version of the AntRun plugin. Next, the task is run—being passed the project's dependencies and schema to generate the source code from. The source code is output to target/xjc, which is also added as a source directory by the AntRun plugin because of the configuration specified. As the task runs in the generate-sources phase, it is available for compilation in the same way as any other source code. Again, the configuration of AntRun here has been relatively simple, and is completely integrated with the Maven artifact handling and build life cycle such that it would not likely be needed to write a plugin to wrap the tool completely if you were faced with this decision in your environment.
Read more
  • 0
  • 0
  • 7273

article-image-simple-item-selector-using-jquery
Packt
09 Nov 2009
4 min read
Save for later

Simple Item Selector Using jQuery

Packt
09 Nov 2009
4 min read
(For more resources on jQuery, see here.) Adding jQuery to your page You can download the latest version of jQuery from jQuery site (http://jquery.com/) and can be added as a reference to your web pages accordingly. You can reference a local copy of jQuery using <script> tag in the page. Either you can reference your local copy or you can directly reference remote copy from jQuery.com or Google Ajax API (http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js) Prerequisite Knowledge In order to understand the code, one should have the basic knowledge of HTML, CSS, JavaScript and basic knowledge of jQuery. Ingredients Used HTML CSS jQuery Photoshop (Used for Designing of Image Buttons and Backgrounds) Preview / Download If you would like to see the working example, please do click here http://www.developersnippets.com/snippets/jquery/item_selector/item_selector.html). And if you would like to download the snippet, click here (http://www.developersnippets.com/snippets/jquery/item_selector/item_selector.zip) Figure 1: Snapshot of "Simple Item Selector using jQuery" Figure 2: Overview of div containers and image buttons used Successfully tested The above application has been successfully tested on various browsers like IE 6.0, IE 7, IE 8, Mozilla Firefox (Latest Version), Google Chrome and Safari Browser (4.0.2) respectively. HTML Code Below is the HTML code with comments for you to understand it better. <!-- Container --><div id="container"> <!-- From Container --> <div class="from_container"> <select id="fromSelectBox" multiple="multiple"> <option value="1">Adobe</option> <option value="2">Oracle</option> <option value="3">Google</option> <option value="4">Microsoft</option> <option value="5">Google Talk</option> <option value="6">Google Wave</option> <option value="7">Microsoft Silver Light</option> <option value="8">Adobe Flex Professional</option> <option value="9">Oracle DataBase</option> <option value="10">Microsoft Bing</option> </select><br /> <input type="image" src="images/selectall.jpg" class="selectall" onclick="selectAll('fromSelectBox')" /><input type="image" src="images/deselectall.jpg" class="deselectall" onclick="clearAll('fromSelectBox')" /> </div> <!-- From Container [Close] --> <!-- Buttons Container --> <div class="buttons_container"> <input type="image" src="images/topmost.jpg" id="topmost" /><br /> <input type="image" src="images/moveup.jpg" id="moveup" /><br /> <input type="image" src="images/moveright.jpg" id="moveright" /><br /> <input type="image" src="images/moveleft.jpg" id="moveleft" /><br /> <input type="image" src="images/movedown.jpg" id="movedown" /><br /> <input type="image" src="images/bottommost.jpg" id="bottommost" /><br /> </div> <!-- Buttons Container [Close] --> <!-- To Container --> <div class="to_container"> <select id="toSelectBox" multiple="multiple"></select><br /> <input type="image" src="images/selectall.jpg" class="selectall" onclick="selectAll('toSelectBox')" /><input type="image" src="images/deselectall.jpg" class="deselectall" onclick="clearAll('toSelectBox')" /> </div> <!-- To Container [Close] --> <!-- To Container --> <div class="ascdes_container"> <input type="image" src="images/ascending.jpg" id="ascendingorder" style="margin:1px 0px 2px 0px;" onclick="ascOrderFunction()" /><br /> <input type="image" src="images/descending.jpg" id="descendingorder" onclick="desOrderFunction()" /> </div> <!-- To Container [Close] --> <div style="clear:both"></div></div><!-- Container [Close] -->
Read more
  • 0
  • 0
  • 2945

article-image-using-javascript-effects-joomla
Packt
06 Nov 2009
7 min read
Save for later

Using JavaScript Effects with Joomla!

Packt
06 Nov 2009
7 min read
Customizing Google Maps Google Maps has a comprehensive API for interacting with maps on your website. MooTools can be used to load the Google Maps engine at the correct time. It can also act as a bridge between the map and other HTML elements on your site. To get started, you will first need to get an API key to use Google Maps on your domain. You can sign up for a free key at http://code.google.com/apis/maps/signup.html. Even if you are working on your local computer, you still need the key. For instance, if the base URL of your Joomla installation is http://localhost/joomla, you will enter localhost as the domain for your API key. Once you have an API key ready, create the file basicmap.js in the /components/com_js folder, and fill it with the following code: window.addEvent('domready', function() { if (GBrowserIsCompatible()) { var map = new GMap2($('map_canvas')); map.setCenter(new GLatLng(38.89, -77.04), 12); window.onunload=function() { GUnload(); }; }}); The entire script is wrapped within a call to the MooTools-specific addEvent() member function of window. Because we want this code to execute once the DOM is ready, the first parameter is the event name 'domready'. The second parameter is an anonymous function containing our code. What does the call to function() do?Using function() in JavaScript is a way of creating an anonymous function. This way, you can create functions that are used in only one place (such as event handlers) without cluttering the namespace with a needless function name. Also, the code within the anonymous function operates within its own scope; this is referred to as a closure. Closures are very frequently used in modern JavaScript frameworks, for event handling and other distinct tasks. Once inside of the function, GBrowserIsCompatible() is used to determine if the browser is capable of running Google Maps. If it is, a new instance of GMap2() is declared and bound to the HTML element that has an id of 'map_canvas' and is stored into map. The call to $('map_canvas') is a MooTools shortcut for document.GetElementById(). Next, the setCenter() member function of map is called to tell Google Maps where to center the map and how far to zoom in. The first parameter is a GLatLng() object, which is used to set the specific latitude and longitude of the map's center. The other parameter determines the zoom level, which is set to 12 in this case. Finally, the window.onunload event is set to a function that calls GUnload(). When the user navigates away from the page, this function removes Google Maps from memory, to prevent memory leaks. With our JavaScript in place, it is now time to add a function to the controller in /components/com_js/js.php that will load it along with some HTML. Add the following basicMap() function to this file: function basicMap(){ $key = 'DoNotUseThisKeyGetOneFromCodeDotGoogleDotCom'; JHTML::_('behavior.mootools'); $document =& JFactory::getDocument(); $document->addScript('http://maps.google.com/maps?file=api&v= 2&key=' . $key); $document->addScript( JURI::base() . 'components/com_js/basicmap.js'); ?> <div id="map_canvas" style="width: 500px; height: 300px"></div> <?php} The basicMap() function starts off by setting $key to the API key received from Google. You should replace this value with the one you receive at http://code.google.com/apis/maps/signup.html. Next, JHTML::_('behavior.mootools'); is called to load MooTools into the <head> tag of the HTML document. This is followed by getting a reference to the current document object through the getDocument() member function of JFactory. The addScript() member function is called twice—once to load in the Google Maps API (using our key), then again to load our basicmap.js script. (The Google Maps API calls in all of the functions and class definitions beginning with a capital 'G'.) Finally, a <div> with an id of 'map_canvas' is sent to the browser. Once this function is in place and js.php has been saved, load index.php?option=com_js&task=basicMap in the browser. Your map should look like this: We can make this map slightly more interesting by adding a marker to a specific address. To do so, add the highlighted code below to the basicmap.js file: window.addEvent('domready', function() { if (GBrowserIsCompatible()) { var map = new GMap2($('map_canvas')); map.setCenter(new GLatLng(38.89, -77.04), 12); var whitehouse = new GClientGeocoder(); whitehouse.getLatLng('1600 Pennsylvania Ave NW', function(latlng) { marker = new GMarker( latlng ); marker.bindInfoWindowHtml('<strong>The White House</strong>'); map.addOverlay(marker); }); window.onunload=function(){ GUnload(); }; }}); This code sets whitehouse as an instance of the GClientGeocoder class. Next, the getLatLng() member function of GClientGeocoder is called. The first parameter is the street address to be looked up. The second parameter is an anonymous function where the GLatLng object is passed once the address lookup is complete. Within this function, marker is set as a new GMarker object, which takes the passed-in latlng object as a parameter. The bindInfoWindowHTML() member function of GMarker is called to add an HTML message to appear in a balloon above the marker. Finally, the maker is passed into the addOverlay() member function of GMap2, to place it on the map. Save basicmap.js and then reload index.php?option=com_js&task=basicMap. You should now see the same map, only with a red pin. When you click on the red pin, your map should look like this: Interactive Maps These two different maps show the basic functionality of getting Google Maps on your own website. These maps are very basic; you could easily create them at maps.google.com then embed them in a standard Joomla! article with the HTML code they provide you. However, you would not have the opportunity to add functions that interact with the other elements on your page. To do that, we will create some more HTML code and then write some MooTools-powered JavaScript to bridge our content with Google Maps. Open the /components/com_js/js.php file and add the following selectMap() function to the controller: function selectMap(){ $key = 'DoNotUseThisKeyGetOneFromCodeDotGoogleDotCom'; JHTML::_('behavior.mootools'); $document =& JFactory::getDocument(); $document->addScript('http://maps.google.com/maps?file=api&v =2&key=' . $key); $document->addScript( JURI::base() . 'components/com_js/selectmap.js'); ?> <div id="map_canvas" style="width: 500px; height: 300px"></div> <select id="map_selections"> <option value="">(select...)</option> <option value="1200 K Street NW">Salad Surprises</option> <option value="1221 Connecticut Avenue NW">The Daily Dish</option> <option value="701 H Street NW">Sushi and Sashimi</option> </select><?php} This function is almost identical to basicMap() except for two things—selectmap.js is being added instead of basicmap.js, and a <select> element has been added beneath the <div>. The <select> element has an id that will be used in the JavaScript. The options of the <select> element are restaurants, with different addresses as values. The JavaScript code will bind a function to the onChange event so that the marker will move as different restaurants are selected.
Read more
  • 0
  • 0
  • 5030

article-image-including-charts-and-graphics-pentaho-reports-part-2
Packt
29 Oct 2009
6 min read
Save for later

Including Charts and Graphics in Pentaho Reports (Part 2)

Packt
29 Oct 2009
6 min read
Ring chart The ring chart is identical to the pie chart, except that it renders as a ring versus a complete pie. In addition to sharing all the properties similar to the pie chart, it also defines the following rendering property : Options Property Group Property name Description section-depth This property defines the percentage of the radius to render the section as. The default value is set to 0.5. Ring chart example For this example, simply open the defined pie chart example and select the Ring chart type. Also, set the section-depth to 0.1, in order to generate the following effect: Multi pie chart The multi pie chart renders a group of pie charts, based on a category dataset. This meta-chart renders individual series data as a pie chart, each broken into individual categories within the individual pie charts. The multi pie chart utilizes the common properties defined above, including the category dataset properties. In addition to the standard set of properties, it also defines the following two properties: Options Property Group Property name Description label-format This label defines how each item within a chart is rendered. The default value is set to "{0}". The format string may also contain any of the following: {0}: To render the item name {1}: To render the item value {2}: To render the item percentage in relation to the entire pie chart by-row This value defaults to True. If set to False, the series and category fields are reversed, and individual charts render series information. Note that the horizontal, series-color, stacked and stacked-percent properties do not apply to this chart type. Multi pie chart example This example demonstrates the distribution of purchased item types, based on payment type. To begin, create a new report. You'll reuse the bar chart's SQL query. Now, place a new Chart element into the Report Header. Edit the chart, selecting Multi Pie as the chart type. To configure the dataset for this chart, select ITEMCATEGORY as the category-column. Set the value-columns property to QUANTITY and the series-by-field to PAYMENTTYPE. Waterfall chart The waterfall chart displays a unique stacked bar chart that spans categories. This chart is useful when comparing categories to one another. The last category in a waterfall chart normally equals the total of all the other categories to render appropriately, but this is based on the dataset, not the chart rendering. The waterfall chart utilizes the common properties defined above, including the category dataset properties. The stacked property is not available for this chart. There are no additional properties defined for the waterfall chart. Waterfall chart example In this example, you'll compare by type, the quantity of items in your inventory. Normally, the last category would be used to display the total values. The chart will render the data provided with or without a summary series, so you'll just use the example SQL query from the bar chart example. Add a Chart element to the Report Header and select Waterfall as the chart type. Set the category-column to ITEMCATEGORY, the value-columns to QUANTITY, and the series-by-value property to Quantity. Now, apply your changes and preview the results. Bar line chart The bar line chart combines the bar and line charts, allowing visualization of trends with categories, along with comparisons. The bar line chart is unique in that it requires two category datasets to populate the chart. The first dataset populates the bar chart, and the second dataset populates the line chart. The bar line chart utilizes the common properties defined above, including the category dataset properties. This chart also inherits the properties from both the bar chart, as well as the line chart. This chart also has certain additional properties, which are listed in the following table: Required Property Group Property name Description bar-data-source The name of the first dataset required by the bar line chart, which populates the bars in the chart. This value is automatically populated with the correct name. line-data-source The name of the second dataset required by the bar line chart, which populates the lines in the chart. This value is automatically populated with the correct name. Bar Options Property Group Property name Description ctgry-tick-font Defines the Java font that renders the Categories. Line Options Property Group Property name Description line-series-color Defines the color in which to render each line series. line-tick-fmt Specifies the Java DecimalFormat string for rendering the Line Axis Labels lines-label-font Defines the Java font to use when rendering line labels. line-tick-font Defines the Java font to use when rendering the Line Axis Labels. As part of the bar line chart, a second y-axis is defined for the lines. The property group Y2-Axis is available with similar properties as the standard y-axis. Bar line chart example To demonstrate the bar line chart, you'll reuse the SQL query from the area chart example. Create a new report, and add a Chart element to the Report Header. Edit the chart, and select Bar Line as the chart type. You'll begin by configuring the first dataset. Set the category-column to ITEMCATEGORY, the value-columns to COST, and the series-by-value property to Cost. To configure the second dataset, set the category-column to ITEMCATEGORY, the value-columns to SALEPRICE, and the series-by-value property to Sale Price. Set the x-axis-label-width to 2.0, and reduce the x-font size to 7. Also, set show-legend to True. You're now ready to preview the bar line chart. Bubble chart The bubble chart allows you to view three dimensions of data. The first two dimensions are your traditional X and Y dimensions, also known as domain and range. The third dimension is expressed by the size of the individual bubbles rendered. The bubble chart utilizes the common properties defined above, including the XY series dataset properties. The bubble chart also defines the following properties: Options Property Group Property name Description max-bubble-size This value defines the diameter of the largest bubble to render. All other bubble sizes are relative to the maximum bubble size. The default value is 0, so this value must be set to a reasonable value for rendering of bubbles to take place. Note that this value is based on pixels, not the domain or range values. The bubble chart defines the following additional dataset property: Required Property Group Property name Description z-value-columns This is the data source column to use for Z value, which specifies the bubble diameter relative to the maximum bubble size. Bubble chart example In this example, you need to define a three dimensional SQL query to populate the chart. You'll use inventory information, and calculate Item Category Margin: SELECT"INVENTORY"."ITEMCATEGORY","INVENTORY"."ONHAND","INVENTORY"."ONORDER","INVENTORY"."COST","INVENTORY"."SALEPRICE","INVENTORY"."SALEPRICE" - "INVENTORY"."COST" MARGINFROM"INVENTORY"ORDER BY"INVENTORY"."ITEMCATEGORY" ASC Now that you have a SQL query to work with, add a Chart element to the Report Header and select Bubble as the chart type. First, you'll populate the correct dataset fields. Set the series-by-field property to ITEMCATEGORY. Now, set the X, Y, and Z value columns to ONHAND, SALEPRICE, and MARGIN. You're now ready to customize the chart rendering. Set the x-title to On Hand, the y-title to Sales Price, the max-bubble-size to 100, and the show-legend property to True. The final result should look like this:
Read more
  • 0
  • 0
  • 4011

article-image-how-bridge-client-server-gap-using-ajax-part-i
Packt
28 Oct 2009
18 min read
Save for later

How to Bridge the Client-Server Gap using AJAX (Part I)

Packt
28 Oct 2009
18 min read
Technically, AJAX is an acronym standing for Asynchronous JavaScript and XML. The technologies involved in an AJAX solution include: JavaScript, to capture interactions with the user or other browser-related events The XMLHttpRequest object, which allows requests to be made to the server without interrupting other browser tasks XML files on the server, or often other similar data formats such as HTML or JSON More JavaScript, to interpret the data from the server and present it on the page Many frameworks have sprung up to assist developers in taming it, because of the inconsistencies in the browsers' implementations of the XMLHttpRequest object; jQuery is no exception. Let us see if AJAX can truly perform miracles. Loading data on demand Underneath all the hype and trappings, AJAX is just a means of loading data from the server to the web browser, or client, without a visible page refresh. This data can take many forms, and we have many options for what to do with it when it arrives. We'll see this by performing the same basic task in many ways. We are going to build a page that displays entries from a dictionary, grouped by the starting letter of the dictionary entry. The HTML defining the content area of the page will look like this: <div id="dictionary"></div> Yes, really! Our page will have no content to begin with. We are going to use jQuery's various AJAX methods to populate this <div> with dictionary entries. <div class="letters"> <div class="letter" id="letter-a"> <h3><a href="#">A</a></h3> </div> <div class="letter" id="letter-b"> <h3><a href="#">B</a></h3> </div> <div class="letter" id="letter-c"> <h3><a href="#">C</a></h3> </div> <div class="letter" id="letter-d"> <h3><a href="#">D</a></h3> </div></div> As always, a real-world implementation should use progressive enhancement to make the page function without requiring JavaScript. Here, to simplify our example, the links do nothing until we add behaviors to them with jQuery. As always, a real-world implementation should use progressive enhancement to make the page function without requiring JavaScript. Here, to simplify our example, the links do nothing until we add behaviors to them with jQuery. Adding a few CSS rules, we get a page that looks like this: Now we can focus on getting content onto the page. Appending HTML AJAX applications are often no more than a request for a chunk of HTML. This technique, sometimes referred to as AHAH (Asynchronous HTTP and HTML), is almost trivial to implement with jQuery. First we need some HTML to insert, which we'll place in a file called a.html alongside our main document. This secondary HTML file begins: <div class="entry"> <h3 class="term">ABDICATION</h3> <div class="part">n.</div> <div class="definition"> An act whereby a sovereign attests his sense of the high temperature of the throne. <div class="quote"> <div class="quote-line">Poor Isabella's Dead, whose abdication</div> <div class="quote-line">Set all tongues wagging in the Spanish nation.</div> <div class="quote-line">For that performance 'twere unfair to scold her:</div> <div class="quote-line">She wisely left a throne too hot to hold her.</div> <div class="quote-line">To History she'll be no royal riddle &mdash;</div> <div class="quote-line">Merely a plain parched pea that jumped the griddle.</div> <div class="quote-author">G.J.</div> </div> </div></div><div class="entry"> <h3 class="term">ABSOLUTE</h3> <div class="part">adj.</div> <div class="definition"> Independent, irresponsible. An absolute monarchy is one in which the sovereign does as he pleases so long as he pleases the assassins. Not many absolute monarchies are left, most of them having been replaced by limited monarchies, where the sovereign's power for evil (and for good) is greatly curtailed, and by republics, which are governed by chance. </div></div> The page continues with more entries in this HTML structure. Rendered on its own, this page is quite plain:   Note that a.html is not a true HTML document; it contains no <html>, <head>, or <body>, all of which are normally required. We usually call such a file a snippet or fragment; its only purpose is to be inserted into another HTML document, which we'll accomplish now: $(document).ready(function() { $('#letter-a a').click(function() { $('#dictionary').load('a.html'); return false; });}); The .load() method does all our heavy lifting for us! We specify the target location for the HTML snippet by using a normal jQuery selector, and then pass the URL of the file to be loaded as a parameter to the method. Now, when the first link is clicked, the file is loaded and placed inside <div id="dictionary">. The browser will render the new HTML as soon as it is inserted:   Note that the HTML is now styled, whereas before it was plain. This is due to the CSS rules in the main document; as soon as the new HTML snippet is inserted, the rules apply to its tags as well. When testing this example, the dictionary definitions will probably appear instantaneously when the button is clicked. This is a hazard of working on our applications locally; it is hard to account for delays in transferring documents across the network. Suppose we added an alert box to display after the definitions are loaded: $(document).ready(function() { $('#letter-a a').click(function() { $('#dictionary').load('a.html'); alert('Loaded!'); return false; });}); However, when this particular code is tested on a production web server, the alert will quite possibly have come and gone before the load has completed, due to network lag. This happens because all AJAX calls are by default asynchronous. Otherwise, we'd have to call it SJAX, which hardly has the same ring to it! Asynchronous loading means that once the HTTP request to retrieve the HTML snippet is issued, script execution immediately resumes without waiting. Sometime later, the browser receives the response from the server and handles it. This is generally desired behavior; it is unfriendly to lock up the whole web browser while waiting for data to be retrieved. If actions must be delayed until the load has been completed, jQuery provides a callback for this. An example will be provided below.   Working with JavaScript objects Pulling in fully-formed HTML on demand is very convenient, but there are times when we want our script to be able to do some processing of the data before it is displayed. In this case, we need to retrieve the data in a structure that we can traverse with JavaScript. With jQuery's selectors, we could traverse the HTML we get back and manipulate it, but it must first be inserted into the document. A more native JavaScript data format can mean even less code. Retrieving a JavaScript object As we have often seen, JavaScript objects are just sets of key-value pairs, and can be defined succinctly using curly braces ({}). JavaScript arrays, on the other hand, are defined on the fly with square brackets ([]). Combining these two concepts, we can easily express some very complex and rich data structures. The term JavaScript Object Notation (JSON) was coined by Douglas Crockford to capitalize on this simple syntax. This notation can offer a concise alternative to the sometimes-bulky XML format: { "key": "value", "key 2": [ "array", "of", "items" ]} For information on some of the potential advantages of JSON, as well as implementations in many programming languages, visit http://json.org/ . We can encode our data using this format in many ways. We'll place some dictionary entries in a JSON file we'll call b.json, which begins as follows: [ { "term": "BACCHUS", "part": "n.", "definition": "A convenient deity invented by the...", "quote": [ "Is public worship, then, a sin,", "That for devotions paid to Bacchus", "The lictors dare to run us in,", "And resolutely thump and whack us?" ], "author": "Jorace" }, { "term": "BACKBITE", "part": "v.t.", "definition": "To speak of a man as you find him when..." }, { "term": "BEARD", "part": "n.", "definition": "The hair that is commonly cut off by..." }, To retrieve this data, we'll use the $.getJSON() method, which fetches the file and processes it, providing the calling code with the resulting JavaScript object. Global jQuery functions To this point, all jQuery methods that we've used have been attached to a jQuery object that we've built with the $() factory function. The selectors have allowed us to specify a set of DOM nodes to work with, and the methods have operated on them in some way. This $.getJSON() function, however, is different. There is no logical DOM element to which it could apply; the resulting object has to be provided to the script, not injected into the page. For this reason, getJSON() is defined as a method of the global jQuery object (a single object called jQuery or $ defined once by the jQuery library), rather than of an individual jQuery object instance (the objects we create with the $() function). If JavaScript had classes like other object-oriented languages, we'd call $.getJSON() a class method. For our purposes, we'll refer to this type of method as a global function; in effect, they are functions that use the jQuery namespace so as not to conflict with other function names. To use this function, we pass it the file name as before: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json'); return false; });}); This code has no apparent effect when we click the link. The function call loads the file, but we have not told JavaScript what to do with the resulting data. For this, we need to use a callback function. The $.getJSON() function takes a second argument, which is a function to be called when the load is complete. As mentioned before, AJAX calls are asynchronous, and the callback provides a way to wait for the data to be transmitted rather than executing code right away. The callback function also takes an argument, which is filled with the resulting data. So, we can write: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { }); return false; });}); Here we are using an anonymous function as our callback, as has been common in our jQuery code for brevity. A named function could equally be provided as the callback. Inside this function, we can use the data variable to traverse the data structure as necessary. We'll need to iterate over the top-level array, building the HTML for each item. We could do this with a standard for loop, but instead we'll introduce another of jQuery's useful global functions, $.each(). Instead of operating on a jQuery object, this function takes an array or map as its first parameter and a callback function as its second. Each time through the loop, the current iteration index and the current item in the array or map are passed as two parameters to the callback function. $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { $('#dictionary').empty(); $.each(data, function(entryIndex, entry) { var html = '<div class="entry">'; html += '<h3 class="term">' + entry['term'] + '</h3>'; html += '<div class="part">' + entry['part'] + '</div>'; html += '<div class="definition">'; html += entry['definition']; html += '</div>'; html += '</div>'; $('#dictionary').append(html); }); }); return false; });}); Before the loop, we empty out <div id="dictionary"> so that we can fill it with our newly-constructed HTML. Then we use $.each() to examine each item in turn, building an HTML structure using the contents of the entry map. Finally, we turn this HTML into a DOM tree by appending it to the <div>. This approach presumes that the data is safe for HTML consumption; it should not contain any stray < characters, for example. All that's left is to handle the entries with quotations, which takes another $.each() loop: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { $('#dictionary').empty(); $.each(data, function(entryIndex, entry) { var html = '<div class="entry">'; html += '<h3 class="term">' + entry['term'] + '</h3>'; html += '<div class="part">' + entry['part'] + '</div>'; html += '<div class="definition">'; html += entry['definition']; if (entry['quote']) { html += '<div class="quote">'; $.each(entry['quote'], function(lineIndex, line) { html += '<div class="quote-line">' + line + '</div>'; }); if (entry['author']) { html += '<div class="quote-author">' + entry['author'] + '</div>'; } html += '</div>'; } html += '</div>'; html += '</div>'; $('#dictionary').append(html); }); }); return false; });}); With this code in place, we can click the B link and confirm our results:   The JSON format is concise, but not forgiving. Every bracket, brace, quote, and comma must be present and accounted for, or the file will not load. In most browsers, we won't even get an error message; the script will just silently fail. Executing a script Occasionally we don't want to retrieve all the JavaScript we will need when the page is first loaded. We might not know what scripts will be necessary until some user interaction occurs. We could introduce <script> tags on the fly when they are needed, but a more elegant way to inject additional code is to have jQuery load the .js file directly. Pulling in a script is about as simple as loading an HTML fragment. In this case, we use the global function $.getScript(), which, like its siblings, accepts a URL locating the script file: $(document).ready(function() { $('#letter-c a').click(function() { $.getScript('c.js'); return false; });}); Scripts fetched in this way are run in the global context of the current page. This means they have access to all globally-defined functions and variables, notably including jQuery itself. We can therefore mimic the JSON example to prepare and insert HTML on the page when the script is executed, and place this code in c.js:. var entries = [ { "term": "CALAMITY", "part": "n.", "definition": "A more than commonly plain and..." }, { "term": "CANNIBAL", "part": "n.", "definition": "A gastronome of the old school who..." }, { "term": "CHILDHOOD", "part": "n.", "definition": "The period of human life intermediate..." }, { "term": "CLARIONET", "part": "n.", "definition": "An instrument of torture operated by..." }, { "term": "COMFORT", "part": "n.", "definition": "A state of mind produced by..." }, { "term": "CORSAIR", "part": "n.", "definition": "A politician of the seas." }];var html = '';$.each(entries, function() { html += '<div class="entry">'; html += '<h3 class="term">' + this['term'] + '</h3>'; html += '<div class="part">' + this['part'] + '</div>'; html += '<div class="definition">' + this['definition'] + '</div>'; html += '</div>';});$('#dictionary').html(html); Now clicking on the C link has the expected result: Loading an XML document XML is part of the acronym AJAX, but we haven't actually loaded any XML yet. Doing so is straightforward, and mirrors the JSON technique fairly closely. First we'll need an XML file d.xml containing some data we wish to display, excerpted here: <?xml version="1.0" encoding="UTF-8"?><entries> <entry term="DEFAME" part="v.t."> <definition> To lie about another. To tell the truth about another. </definition> </entry> <entry term="DEFENCELESS" part="adj."> <definition> Unable to attack. </definition> </entry> <entry term="DELUSION" part="n."> <definition> The father of a most respectable family, comprising Enthusiasm, Affection, Self-denial, Faith, Hope, Charity and many other goodly sons and daughters. </definition> <quote author="Mumfrey Mappel"> <line>All hail, Delusion! Were it not for thee</line> <line>The world turned topsy-turvy we should see; </line> <line>For Vice, respectable with cleanly fancies, </line> <line>Would fly abandoned Virtue's gross advances. </line> </quote> </entry> <entry term="DIE" part="n."> <definition> The singular of "dice." We seldom hear the word, because there is a prohibitory proverb, "Never say die." At long intervals, however, some one says: "The die is cast," which is not true, for it is cut. The word is found in an immortal couplet by that eminent poet and domestic economist, Senator Depew: </definition> <quote> <line>A cube of cheese no larger than a die</line> <line>May bait the trap to catch a nibbling mie.</line> </quote> </entry></entries> This data could be expressed in many ways, of course, and some would more closely mimic the structure we established for the HTML or JSON used earlier. Here, however, we're illustrating some of the features of XML designed to make it more readable to humans, such as the use of attributes for term and part rather than tags. $(document).ready(function() { $('#letter-d a').click(function() { $.get('d.xml', function(data) { }); return false; });}); This time it's the $.get() function that does our work. In general, this function simply fetches the file at the supplied URL and provides the plain text to the callback. However, if the response is known to be XML because of its server-supplied MIME type, the callback will be handed the XML DOM tree. Fortunately, as we have already seen, jQuery has substantial DOM traversing capabilities. We can use the normal .find(), .filter() and other traversal methods on the XML document just as we would on HTML: $(document).ready(function() { $('#letter-d a').click(function() { $.get('d.xml', function(data) { $('#dictionary').empty(); $(data).find('entry').each(function() { var $entry = $(this); var html = '<div class="entry">'; html += '<h3 class="term">' + $entry.attr('term') + '</h3>'; html += '<div class="part">' + $entry.attr('part') + '</div>'; html += '<div class="definition">'; html += $entry.find('definition').text(); var $quote = $entry.find('quote'); if ($quote.length) { html += '<div class="quote">'; $quote.find('line').each(function() { html += '<div class="quote-line">' + $(this).text() + '</div>'; }); if ($quote.attr('author')) { html += '<div class="quote-author">' + $quote.attr('author') + '</div>'; } html += '</div>'; } html += '</div>'; html += '</div>'; $('#dictionary').append($(html)); }); }); return false; });}); This has the expected effect when the D link is clicked: This is a new use for the DOM traversal methods we already know, shedding some light on the flexibility of jQuery's CSS selector support. CSS syntax is typically used to help beautify HTML pages, and thus selectors in standard .css files use HTML tag names such as div and body to locate content. However, jQuery can use arbitrary XML tag names, such as entry and definition here, just as readily as the standard HTML ones. The advanced selector engine inside jQuery facilitates finding parts of the XML document in much more complicated situations, as well. For example, suppose we wanted to limit the displayed entries to those that have quotes that in turn have attributed authors. To do this, we can limit the entries to those with nested <quote> elements by changing entry to entry:has(quote). Then we can further restrict the entries to those with author attributes on the <quote> elements by writing entry:has(quote[author]). The line with the initial selector now reads: $(data).find('entry:has(quote[author])').each(function() { This new selector expression restricts the returned entries correspondingly:    
Read more
  • 0
  • 0
  • 2659
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-your-first-application-aptana-radrails
Packt
28 Oct 2009
7 min read
Save for later

Your First Application in Aptana RadRails

Packt
28 Oct 2009
7 min read
Here we are! programming in a powerful language specially designed for the Web and using an IDE that promises to help us with many of the mechanical tasks involved in the coding. If you have been already programming with Rails, you probably know that if we take advantage of scaffolding we can have a simple web application for table maintenance in a matter of minutes (yes/no typo here, it really takes just a few minutes). And we are even talking about the database table creation process. If we wanted to add validations, a nice design, and some more complexity we would be talking about a few hours. Still pretty impressive, depending from which programming language (or framework) you are coming. The truth is, creating the wireframe of your application in Rails is quick and easy enough even from the command line, but we'll be learning in this article how to do it a bit more comfortably by using RadRails for creating your models, controllers, database migrations, and for starting your server and test your application. Basic Views Most of the time when working with our IDE we will be using the Editor Area. Apart from that, two of the views we will be working with more frequently are the Ruby Explorer—the enhanced equivalent of the Rails Navigator, if you were using RadRails Classic—and the Console. Both of these views are fairly easy to use, but since they will be present at almost every point of the development process, it's interesting to get familiar with them from the beginning. The Ruby Explorer View If you have already opened the Rails perspective, then you should be seeing the Ruby Explorer at the left of your workbench. This view looks like a file-tree pane. At the root level, you will find a folder for each of the projects in your workspace. By clicking on the icon to the left of the project name, you will unfold its files and folders. The Ruby files can be expanded too, displaying the modules, classes, variables, and methods defined in the selected file. By clicking on any of these elements you will be taken directly to the line in which it is defined. Before navigating through the contents of a project, we have to open it. Just right-click on its name and choose Open Project. When opening a project, Eclipse will ask you if you want to open the referenced projects. By default, your projects don't have any references and that's the most common scenario when working with a Rails application. If you want, you can include references to other projects on the workspace so you can open and close them together. To view and change the project references, you can right-click on the project name, then select Properties. Notice you can also get here from the Project menu by selecting Properties. In the properties dialog, you have to select Project References. Here you will see a list of all the available projects in the workspace. Just check or uncheck all the projects you want to reference. Once your project is open, the mechanism for navigating the contents is pretty straightforward. You can open or close any sub-folders and you can right-click on any item to get a context menu. From this menu you can perform common file operations like creating, renaming, or deleting a file. We will see more details about creating new files when talking about the Editor Area. There is also a Properties option from where you can change the encoding for a particular file, or the file attributes (read only, for example). The Properties option is also available at the project level. Also in the context menu, you can see there is a Tail option. This will work like the tail command in UNIX, displaying the contents of a file as it's changing. This option is especially useful for a quick monitoring of the log files of your application. You can also find in the context menu two options with the names Compare With and Replace With. If you select either of them, you will see a new menu in which there is an option named Local history. This functionality is really interesting. You can compare your current version against an older version of the same file, or you could replace the contents with a previous one. This can be a life-saver because when using it on a folder the local history will contain copies even of deleted files. Comparing a file against another copy is a powerful tool, which can also be used when working with repositories or to compare different files between them. Let's try it and see how it works. Open any of the files in your project tree by double-clicking on the file name. Now go to the Editor Area and add some lines with Mumbo-Jumbo text. After you are done, click on the save icon of the toolbar or select Save in the File menu. Now let's go back to the Ruby Explorer, double-click on the file name and select Compare With | Local History. You will see there are some entries here, one for each time we saved the file. If this was the first time you worked with the file, then there will be only two versions, the original and the one you just saved. Double-click on the oldest local version you have. Now a new editor will be opened. The editor is divided into three panes, the top one displaying structural differences, the bottom-left one with the code of the current version, and the bottom-right one with the old version of the code. At the top pane, you will see the structural differences between the versions being compared. For every added or deleted method or variable—at instance or class level, you will see the name of the element with an icon displaying a plus or a minus sign. If a method exists in both versions, but its content was changed, the name will be displayed without any additional icons. When reviewing the differences/changes you will see the editors at both sides are linked with a line representing the parts that are not equal between the files. When you are on a given change/difference you can select the icon for 'copying current change from right to left' (or the other way round, depending in which of the files the change is), which will override the contents of the left editor with those of the right. You can also just manually edit or copy/paste in your editor as usual. There is an interesting icon labeled 'Copy all non-conflicting changes from right to left' that will do exactly as it promises. Any changes that can be automatically merged, will be incorporated to your editor. Depending on the differences between the files, the icon could be the contrary 'Copy all non-conflicting changes from left to right'. When you finish comparing or modifying your current editor, remember to save the contents of the editor in order to keep your changes. If you just wanted to review the changes without any modifications, you can directly scroll down the editors, use the 'Previous' or 'Next' icons, or use the quick marks by the right margin. You can also compare two files instead of comparing a file against an older version. Go to the Ruby Explorer and select one of the files, then hold down the control key and select another one. With both files selected, you right-click and select Compare With and then Each Other. Once opened, the compare editor works exactly the same as when comparing with an old version of the same file.
Read more
  • 0
  • 0
  • 2406

article-image-external-tables-oracle-10g11g-database-part-2
Packt
28 Oct 2009
13 min read
Save for later

External Tables in Oracle 10g/11g Database: Part 2

Packt
28 Oct 2009
13 min read
Data transformation with External Tables One of the main uses of the External Tables is their support of the ETL process, allowing the user to perform a data load that is transformed to the target format without an intermediate stage table. Let's read an External Table whose contents are: This data can be loaded in a single command to multiple tables. Let's create several tables with the same structure: SQL> desc amount_jan Name Null? Type ----------------- -------- ------------ REGION VARCHAR2(16) AMOUNT NUMBER(3) Now issue the command to send the data from the external table to the different tables. INSERT ALL INTO AMOUNT_JAN (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_FEB (REGION, AMOUNT) VALUES(COUNTRY, FEB) INTO AMOUNT_MAR (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_APR (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_MAY (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_JUN (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_JUL (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_AUG (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_SEP (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_OCT (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_NOV (REGION, AMOUNT) VALUES(COUNTRY, JAN) INTO AMOUNT_DEC (REGION, AMOUNT) VALUES(COUNTRY, JAN)SELECT COUNTRY, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DECFROM REGION_REVENUE; In this example, we will perform a conditional insert to different tables depending on the value of the amount column. We will first create three tables, one for low, another for average, and a third for high amounts: SQL> create table low_amount( 2 region varchar2(16), 3 month number(2), 4 amount number(3));Table created.SQL> create table high_amount as select * from low_amount;Table created. Now we can read the External Table and have the data inserted conditionally to one of three mutually exclusive targets. INSERT ALL WHEN ( JAN <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '01', JAN ) WHEN ( FEB <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '02', FEB ) WHEN ( MAR <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '03', MAR ) WHEN ( APR <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '04', APR ) WHEN ( MAY <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '05', MAY ) WHEN ( JUN <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '06', JUN ) WHEN ( JUL <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '07', JUL ) WHEN ( AUG <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '08', AUG ) WHEN ( SEP <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '09', SEP ) WHEN ( OCT <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '10', OCT ) WHEN ( NOV <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '11', NOV ) WHEN ( DEC <= 500 ) THEN INTO LOW_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '12', DEC ) WHEN ( JAN > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '01', JAN ) WHEN ( FEB > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '02', FEB ) WHEN ( MAR > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '03', MAR ) WHEN ( APR > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '04', APR ) WHEN ( MAY > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '05', MAY ) WHEN ( JUN > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '06', JUN ) WHEN ( JUL > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '07', JUL ) WHEN ( AUG > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '08', AUG ) WHEN ( SEP > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '09', SEP ) WHEN ( OCT > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '10', OCT ) WHEN ( NOV > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '11', NOV ) WHEN ( DEC > 500 ) THEN INTO HIGH_AMOUNT( REGION, MONTH, AMOUNT) VALUES ( COUNTRY, '12', DEC )SELECT COUNTRY, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DECFROM REGION_REVENUE; Extending the alert.log analysis with External Tables Reading the alert.log from the database is a useful feature which can help you to find any outstanding error messages reported in this file. create table ALERT_LOG ( text_line varchar2(512)) organization external ( type ORACLE_LOADER default directory BACKGROUND_DUMP_DEST access parameters( records delimited by newline nobadfile nodiscardfile nologfile ) location( 'alert_beta.log') ); Once the External Table has been created, the alert.log file can be queried just like any other regular table. SQL> select text_line from alert_log 2 where text_line like 'ORA-%';TEXT_LINE-----------------------------------------------------------------ORA-1109 signalled during: ALTER DATABASE CLOSE NORMAL...ORA-00313: open failed for members of log group 1 of thread 1ORA-00312: online log 1 thread 1: '/u01/oracle/oradata/beta/redo01.log'ORA-27037: unable to obtain file statusORA-00313: open failed for members of log group 2 of thread 1ORA-00312: online log 2 thread 1: '/u01/oracle/oradata/beta/redo02.log'ORA-27037: unable to obtain file statusORA-00313: open failed for members of log group 3 of thread 1ORA-00312: online log 3 thread 1: '/u01/oracle/oradata/beta/redo03.log'ORA-27037: unable to obtain file status Querying the alert.log file up to this phase is useful just to see the contents of the file and look for basic ORA-% strings. This could also be achieved by using the alert.log link in the Enterprise Manager (EM). The alert.log file can be queried by means of the EM, but as this can only be viewed from the EM in an interactive mode, you can only rely on the preset alerts. If further automatic work needs to be done, then it is useful to do some more work with the alert analysis tool. A temporary table can be used to store the contents of the ALERT_LOG table, along with an extra TIMESTAMP column, so it can be queried in detail in an EM-like manner. create global temporary table TMP_ALERT_LOG ( LINE_NO NUMBER(6), TIMESTAMP DATE, TEXT_LINE VARCHAR2(512))on commit preserve rows; A bit of PLSQL programming is necessary so the ALERT_LOG file can be modified and inserted into the TMP_ALERT_LOG, (enabling further queries can be done). declarecursor alertLogCur is select ROWNUM, TEXT_LINE from ALERT_LOG;currentDate date;altertLogRec ALERT_LOG.TEXT_LINE%TYPE;testDay varchar2(10);begincurrentDate := sysdate;for alertLogInst in alertLogCur loop -- fetch row and determine if this is a date row testDay := substr(alertLogInst.text_line, 1, 3); if testDay = 'Sun' or testDay = 'Mon' or testDay = 'Tue' or testDay = 'Wed' or testDay = 'Thu' or testDay = 'Fri' or testDay = 'Sat' then -- if this is a date row, it sets the current logical record date currentDate := to_date( alertlogInst.text_line, 'Dy Mon DD HH24:MI:SS YYYY'); end if; insert into TMP_ALERT_LOG values( alertLogInst.rownum, currentDate, alertLogInst.text_line );end loop;end;/ As the contents of the alert.log end up in a temporary table, more than one DBA can query it at the same time, or restrict the DBA's accessibilities. There is no need to manage the purge and maintenance of the table after the session has ended, it can be indexed and there is little overhead by means of this procedure. Moreover, as this is a temporary object, minimum redo log information is generated. Once the external ALERT_LOG and the temporary ALERT_LOG tables have been created, it is possible to perform, not only filters by date (provided by Enterprise Manager) but also any query against the alert.log file. SELECT TIMESTAMP, TEXT_LINEFROM TMP_ALERT_LOGWHERE TIMESTAMP IN ( SELECT TIMESTAMP FROM TMP_ALERT_LOG WHERE TEXT_LINE LIKE 'ORA-%')AND TIMESTAMP BETWEEN SYSDATE-30 AND SYSDATEORDER BY LINE_NO; Further treatment can be done on this concept to look for specific error messages, analyze specific time frames and perform drill down analysis. This procedure can be extended to read the trace files or any other text file from the database. Reading the listener.log from the database One particular extension of the above procedure is to read the listener.log file. This file has a specific star-delimited field file format which can be advantageous, and eases the read by means of the Loader driver. The file format is as follows: 21-JUL-2008 00:39:50 * (CONNECT_DATA=(SID=beta)(CID=(PROGRAM=perl)(HOST=alpha.us.oracle.com)(USER=oracle))) * (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.10)(PORT=8392)) * establish * beta * 021-JUL-2008 00:39:56 * (CONNECT_DATA=(SID=beta)(CID=(PROGRAM=perl)(HOST=alpha.us.oracle.com)(USER=oracle))) * (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.10)(PORT=8398)) * establish * beta * 021-JUL-2008 00:40:16 * service_update * beta * 021-JUL-2008 00:41:19 * service_update * beta * 021-JUL-2008 00:44:43 * ping * 0 The file has a format that can be deduced from the above data sample: TIMESTAMP * CONNECT DATA [* PROTOCOL INFO] * EVENT [* SID] * RETURN CODE As you can see this format, even though it is structured, it may have a different number of fields, so at loading time this issue must be considered. In order for us to map this table to the database, we should consider the variable number of fields to have the External Table created. We'll create a temporary table so that this doesn't create an additional transactional overhead. Now, let's create an External Table based on this format that points to $ORACLE_HOME/network/log: create directory NETWORK_LOG_DIRas '$ORACLE_HOME/network/log'; Now, let's create the external table: create table LISTENER_LOG ( TIMESTAMP date, CONNECT_DATA varchar2(2048), PROTOCOL_INFO varchar2(64), EVENT varchar2(64), SID varchar2(64), RETURN_CODE number(5))organization external ( type ORACLE_LOADER default directory NETWORK_LOG_DIR access parameters ( records delimited by NEWLINE nobadfile nodiscardfile nologfile fields terminated by "*" LDRTRIM reject rows with all null fields ( "TIMESTAMP" char date_format DATE mask "DD-MON-YYYY HH24:MI:SS ", "CONNECT_DATA", "PROTOCOL_INFO", "EVENT", "SID", "RETURN_CODE" ) ) location ('listener.log'))reject limit unlimited; The structure of interest is specified above, so there will be several rows rejected. Seeing as this file is not fully structured, you will find some non formatted information; the bad file and the log file are not meaningful in this context. Another application of the LISTENER_LOG External Table is usage trend analysis. This query can be issued to detect usage peak hours. SQL> select to_char(round(TIMESTAMP, 'HH'), 'HH24:MI') HOUR, 2 lpad('#', count(*), '#') CX 3 from listener_log 4 group by round(TIMESTAMP, 'HH') 5 order by 1;HOUR CX----- ------------------------------------------------14:00 ###15:00 ##########################16:00 ######################17:00 #####################18:00 #####################19:00 ############### Reading the listener.log file this way allows the DBA not only to keep track of the listener behavior, but also it allows a security administrator to easily spot hacking attempts. Let's find out who is trying to access the database with sqlplus.exe. SQL> select timestamp, protocol_info 2 from listener_log 3 where connect_data like '%sqlplus.exe%' 4 /TIMESTAMP PROTOCOL_INFO-------------------- --------------------------------------------------------01-SEP-2008 14:30:37 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.101)(PORT=3651))01-SEP-2008 14:31:08 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.101)(PORT=3666))01-SEP-2008 14:31:35 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.101)(PORT=3681)) The use of External Tables to analyze the listener.log can be used not only to have an in-database version of the listener.log perform periodic and programmatic analysis of the listener behavior, but also to determine usage trends and correlate information with the audit team so that unauthorized connection programs can be easily and quickly spotted. Further useful applications can be found by reading the listener.log file. There are two fields that must be further parsed to get information out of them, but parsing those fields goes beyond the scope of this article. The structure that the analysis should consider is detailed next: Connect String SID: The Database Oracle SID, which is populated if the connection was performed by SID, otherwise it is NULL. CID: It contains two subfields, PROGRAM and HOST. SERVER: This field indicates the connection type, either dedicated or shared. SERVICE_NAME: This field is populated when the connection is performed by a Service instead of SID. COMMAND: The command issued by the user. SERVICE: Present only when listener commands are issued. FAILOVER_MODE: In Real Application Clusters (RAC) environments this field is used if the client performed a connection due to a failover. It shows the failover mode used. Protocol PROTOCOL: Indicates the used to perform the connection; this will be TCP most of the times. HOST: This is the client's IP Address. PORT: The port number of the oracle server used to establish the connection. Mapping XML files as External Tables XML has become a de facto information exchange format, which is why oracle has included the XML Database (XDB) feature from 9.2.0. However, it requires the data to be actually loaded into the database before it can be processed. An External Table allows the user to take a quick look at the contents of the external file prior to performing any further processing. In this example an External Table is created out of an XML file. This file is read by means of a CLOB field, and some further XDB commands can be issued against the external XML file to extract and view data. Let's create the external XML file first: create table EMPLOYEES_XML (xmlFile CLOB)organization external ( type ORACLE_LOADER default directory EXTTABDIR access parameters ( fields (xmllob char terminated by ',') column transforms (xmlFile from lobfile(xmllob)) ) location('employees.dat'))reject limit unlimited; The employees.dat file contains the file name of the XML file to load as an external CLOB file. This file, for the purpose of the demo, contains the file name: employees.xml. Now the file can be queried from the database as if it was a regular table with a single XML column. Dynamically changing the external reference When managing External Tables, there should be an easy way to redefine the external source file. It is enough to change the External Table properties by means of an ALTER TABLE command. Let's create a stored procedure that performs this task by means of a dynamically generated DDL command. This procedure, named Change_External_Table redefines the location property. Using a stored program unit is a flexible way to perform this task. create procedure change_external_table( p_table_name in varchar2, p_file_name in varchar2) isbeginexecute immediate 'alter table '|| p_table_name|| ' location ('''|| p_file_name|| ''')' ;exceptionwhen othersthenraise_application_error(sqlcode,sqlerrm) ;end ;/ Oracle 11g External Table enhancements External Tables work the same in 10g and in 11g, so there are no differences when working with these two versions. When working with Data Pump External Tables, and one single row proves defective, the data set reading operation is aborted. An enhancement in this 11g release prevents the data load aborting, thus saving reprocessing time. Summary Managing data with External Tables is a means not only for mapping external flat files as regular (but limited) tables inside the database, but also a tool to more efficiently perform administrative tasks such as programmatically processing database log files such as the alert.log or the listener.log files. It can be used to easily view external XML formatted files from inside the database without actually loading the file to the database. It can also be used as a means of unloading data in temporary external storage to exchange data among different Oracle versions. This particular feature allows the user to easily build an Oracle Datamart that allows the pre-formatting and summarization of data from the source, enabling it to be directly inserted into the target data warehouse.
Read more
  • 0
  • 0
  • 2900

article-image-telecommunications-and-network-security-concepts-cissp-exam
Packt
28 Oct 2009
5 min read
Save for later

Telecommunications and Network Security Concepts for CISSP Exam

Packt
28 Oct 2009
5 min read
Transport layer The transport layer in the TCP/IP model does two things: it packages the data given out by applications to a format that is suitable for transport over the network, and it unpacks the data received from the network to a format suitable for applications. The process of packaging the data packets received from the applications is known as encapsulation. The output of such a process is known as datagram. Similarly, the process of unpacking the datagram received from the network is known as abstraction A transport section in a protocol stack carries the information that is in the form of datagrams, Frames and Bits. Transport layer protocols There are many transport layer protocols that carry the transport layer functions. The most important ones are: Transmission Control Protocol (TCP): It is a core Internet protocol that provides reliable delivery mechanisms over the Internet. TCP is a connection-oriented protocol. User Datagram Protocol (UDP): This protocol is similar to TCP, but is connectionless. A connection-oriented protocol is a protocol that guarantees delivery of datagram (packets) to the destination application by way of a suitable mechanism. For example, a three-way handshake syn, syn-ack, ack in TCP. The reliability of datagram delivery of such protocol is high. A protocol that does not guarantee the delivery of datagram, or packets, to the destination is known as connectionless protocol. These protocols use only one-way communication. The speed of the datagram's delivery by such protocols is high. Other transport layer protocols are as follows: Sequenced Packet eXchange (SPX): SPX is a part of the IPX/SPX protocol suit and used in Novell NetWare operating system. While Internetwork Packet eXchange (IPX) is a network layer protocol, SPX is a transport layer protocol. Stream Control Transmission Protocol (SCTP): It is a connection-oriented protocol similar to TCP, but provides facilities such as multi-streaming and multi-homing for better performance and redundancy. It is used in Unix-like operating systems. Appletalk Transaction Protocol (ATP): It is a proprietary protocol developed for Apple Macintosh computers. Datagram Congestion Control Protocol (DCCP): As the name implies, it is a transport layer protocol used for congestion control. Applications include Internet telephony and video or audio streaming over the network. Fiber Channel Protocol (FCP): This protocol is used in high-speed networking such as Gigabit networking. One of its prominent applications is Storage Area Network (SAN). SAN is network architecture that's used for attaching remote storage devices such as tape drives, disk arrays, and so on to the local server. This facilitates the use of storage devices as if they were local devices. In the following sections we'll review the most important protocols—TCP and UDP. Transmission Control Protocol (TCP) TCP is a connection-oriented protocol that is widely used in Internet communications. As the name implies, a protocol has two primary functions. The primary function of TCP is the transmission of datagram between applications, while the secondary function is related to controls that are necessary for ensuring reliable transmissions. Protocol / Service Transmission Control Protocol (TCP) Layer(s) TCP works in the transport layer of the TCP/IP model Applications Applications where the delivery needs to be assured such as email, World Wide Web (WWW), file transfer, and so on use TCP for transmission Threats Service disruption Vulnerabilities Half-open connections Attacks Denial-of- service attacks such as TCP SYN attacks Connection hijacking such as IP Spoofing attacks Countermeasures Syn cookies Cryptographic solutions   A half-open connection is a vulnerability in TCP implementation. TCP uses a three-way handshake to establish or terminate connections. Refer to the following illustration: In a three-way handshake, first the client (workstation) sends a request to the server (www.some_website.com). This is known as an SYN request. The server acknowledges the request by sending SYN-ACK and, in the process, creates a buffer for that connection. The client does a final acknowledgement by sending ACK. TCP requires this setup because the protocol needs to ensure the reliability of packet delivery. If the client does not send the final ACK, then the connection is known as half-open. Since the server has created a buffer for that connection, certain amounts of memory or server resources are consumed. If thousands of such half-open connections are created maliciously, the server resources may be completely consumed resulting in a denial-of-service to legitimate requests. TCP SYN attacks are technically establishing thousands of half-open connections to consume the server resources. Two actions can be taken by an attacker. The attacker, or malicious software, will send thousands of SYN to the server and withhold the ACK. This is known as SYN flooding. Depending on the capacity of the network bandwidth and the server resources, in a span of time the entire resources will be consumed. This will result in a denial-of-service. If the source IP were blocked by some means, then the attacker, or the malicious software, would try to spoof the source IP addresses to continue the attack. This is known as SYN spoofing. SYN attacks, such as SYN flooding and SYN spoofing, can be controlled using SYN cookies with cryptographic hash functions. In this method, the server does not create the connection at the SYN-ACK stage. The server creates a cookie with the computed hash of the source IP address, source port, destination IP, destination port, and some random values based on an algorithm, which it sends as SYN-ACK. When the server receives an ACK, it checks the details and creates the connection. A cookie is a piece of information, usually in a form of text file, sent by the server to client. Cookies are generally stored on a client's computer and are used for purposes such as authentication, session tracking, and management. User Datagram Protocol (UDP) UDP is a connectionless protocol similar to TCP. However, UDP does not provide delivery guarantee of data packets.  
Read more
  • 0
  • 0
  • 4517

article-image-enabling-spring-faces-support
Packt
28 Oct 2009
9 min read
Save for later

Enabling Spring Faces support

Packt
28 Oct 2009
9 min read
The main focus of the Spring Web Flow Framework is to deliver the infrastructure to describe the page flow of a web application. The flow itself is a very important element of a web application, because it describes its structure, particularly the structure of the implemented business use cases. But besides the flow which is only in the background, the user of your application is interested in the Graphical User Interface (GUI). Therefore, we need a solution of how to provide a rich user interface to the users. One framework which offers components is JavaServer Faces (JSF). With the release of Spring Web Flow 2, an integration module to connect these two technologies, called Spring Faces has been introduced. This article is no introduction to the JavaServer Faces technology. It is only a description about the integration of Spring Web Flow 2 with JSF. If you have never previously worked with JSF, please refer to the JSF reference to gain knowledge about the essential concepts of JavaServer Faces. JavaServer Faces (JSF)—a brief introductionThe JavaServer Faces (JSF) technology is a web application framework with the goal to make the development of user interfaces for a web application (based on Java EE) easier. JSF uses a component-based approach with an own lifecycle model, instead of a request-driven approach used by traditional MVC web frameworks. The version 1.0 of JSF is specified inside JSR (Java Specification Request) 127 (http://jcp.org/en/jsr/detail?id=127). To use the Spring Faces module, you have to add some configuration to your application. The diagram below depicts the single configuration blocks. These blocks are described in this article. The first step in the configuration is to configure the JSF framework itself. That is done in the deployment descriptor of the web application—web.xml. The servlet has to be loaded at the startup of the application. This is done with the <load-on-startup>1</load-on-startup> element. <!-- Initialization of the JSF implementation. The Servlet is not used at runtime --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> For the work with the JavaServer Faces, there are two important classes. These are the javax.faces.webapp.FacesServlet and the javax.faces.context.FacesContext classes.You can think of FacesServlet as the core base of each JSF application. Sometimes that servlet is called an infrastructure servlet. It is important to mention that each JSF application in one web container has its own instance of the FacesServlet class. This means that an infrastructure servlet cannot be shared between many web applications on the same JEE web container.FacesContext is the data container which encapsulates all information that is necessary around the current request.For the usage of Spring Faces, it is important to know that FacesServlet is only used to instantiate the framework. A further usage inside Spring Faces is not done. To be able to use the components from Spring Faces library, it's required to use Facelets instead of JSP. Therefore, we have to configure that mechanism. If you are interested in reading more about the Facelets technology, visit the Facelets homepage from java.net with the following URL: https://facelets.dev.java.net. A good introduction inside the Facelets technology is the http://www.ibm.com/developerworks/java/library/j-facelets/ article, too. The configuration process is done inside the deployment descriptor of your web application—web.xml. The following sample shows the configuration inside the mentioned file. <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value></context-param> As you can see in the above code, the configuration parameter is done with a context parameter. The name of the parameter is javax.faces.DEFAULT_SUFFIX. The value for that context parameter is .xhtml. Inside the Facelets technology To present the separate views inside a JSF context, you need a specific view handler technology. One of those technologies is the well-known JavaServer Pages (JSP) technology. Facelets are an alternative for the JSP inside the JSF context. Instead, to define the views in JSP syntax, you will use XML. The pages are created using XHTML. The Facelets technology offers the following features: A template mechanism, similar to the mechanism which is known from the Tiles framework The composition of components based on other components Custom logic tags Expression functions With the Facelets technology, it's possible to use HTML for your pages. Therefore, it's easy to create the pages and view them directly in a browser, because you don't need an application server between the processes of designing a page The possibility to create libraries of your components The following sample shows a sample XHTML page which uses the component aliasing mechanism of the Facelets technology. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html > <body> <form jsfc="h:form"> <span jsfc="h:outputText" value="Welcome to our page: #{user.name}" disabled="#{empty user}" /> <input type="text" jsfc="h:inputText" value="#{bean.theProperty}" /> <input type="submit" jsfc="h:commandButton" value="OK" action="#{bean.doIt}" /> </form> </body></html> The sample code snippet above uses the mentioned expression language (for example, the #{user.name} expression accesses the name property from the user instance) of the JSF technology to access the data. What is component aliasingOne of the mentioned features of the Facelets technology is that it is possible to view a page directly in a browser without that the page is running inside a JEE container environment. This is possible through the component aliasing feature. With this feature, you can use normal HTML elements, for example an input element. Additionally, you can refer to the component which is used behind the scenes with the jsfc attribute. An example for that is <input type="text" jsfc="h:inputText" value="#{bean.theProperty}" /> . If you open this inside a browser, the normal input element is used. If you use it inside your application, the h:inputText element of the component library is used     The ResourceServlet One main part of the JSF framework are the components for the GUI. These components often consist of many files besides the class files. If you use many of these components, the problem of handling these files arises. To solve this problem, the files such as JavaScript and CSS (Cascading Style Sheets) can be delivered inside the JAR archive of the component. If you deliver the file inside the JAR file, you can organize the components in one file and therefore it is easier for the deployment and maintenance of your component library. Regardless of the framework you use, the result is HTML. The resources inside the HTML pages are required as URLs. For that, we need a way to access these resources inside the archive with the HTTP protocol. To solve that problem, there is a servlet with the name ResourceServlet (package org.springframework.js.resource). The servlet can deliver the following resources: Resources which are available inside the web application (for example, CSS files) Resources inside a JAR archive The configuration of the servlet inside web.xml is shown below: <servlet> <servlet-name>Resource Servlet</servlet-name> <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class> <load-on-startup>0</load-on-startup></servlet> <servlet-mapping> <servlet-name>Resource Servlet</servlet-name> <url-pattern>/resources/*</url-pattern></servlet-mapping> It is important that you use the correct url-pattern inside servlet-mapping. As you can see in the sample above, you have to use /resources/*. If a component does not work (from the Spring Faces components), first check if you have the correct mapping for the servlet. All resources in the context of Spring Faces should be retrieved through this Servlet. The base URL is /resources. Internals of the ResourceServlet ResourceServlet can only be accessed via a GET request. The ResourceServlet servlet implements only the GET method. Therefore, it's not possible to serve POST requests. Before we describe the separate steps, we want to show you the complete process, illustrated in the diagram below: For a better understanding, we choose an example for the explanation of the mechanism which is shown in the previous diagram. Let us assume that we have registered the ResourcesServlet as mentioned before and we request a resource by the following sample URL: http://localhost:8080/ flowtrac-web-jsf/resources/css/test1.css. How to request more than one resource with one requestFirst, you can specify the appended parameter. The value of the parameter is the path to the resource you want to retrieve. An example for that is the following URL: http://localhost:8080/ flowtracweb-jsf/resources/css/test1.css?appended=/css/test2.css. If you want to specify more than one resource, you can use the delimiter comma inside the value for the appended parameter. A simple example for that mechanism is the following URL: http://localhost:8080/ flowtrac-web-jsf/resources/css/test1.css?appended=/css/test2.css, http://localhost:8080/flowtrac-web-jsf/resources/css/test1.css?appended=/css/test3.css. Additionally, it is possible to use the comma delimiter inside the PathInfo. For example: http://localhost:8080/flowtrac-web-jsf/resources/css/test1.css,/css/test2.css. It is important to mention that if one resource of the requested resources is not available, none of the requested resources is delivered. This mechanism can be used to deliver more than one CSS in one request. From the view of development, it can make sense to modularize your CSS files to get more maintainable CSS files. With that concept, the client gets one CSS, instead of many CSS files. From the view of performance optimization, it is better to have as few requests for rendering a page as possible. Therefore, it makes sense to combine the CSS files of a page. Internally, the files are written in the same sequence as they are requested. To understand how a resource is addressed, we separate the sample URL into the specific parts. The example URL is a URL on a local servlet container which has an HTTP connector at port 8080. See the following diagram for the mentioned separation: The table below describes the five sections of the URL that are shown in the previous diagram:
Read more
  • 0
  • 1
  • 26934
article-image-working-report-builder-microsoft-sql-server-2008-part-1
Packt
28 Oct 2009
16 min read
Save for later

Working with the Report Builder in Microsoft SQL Server 2008: Part 1

Packt
28 Oct 2009
16 min read
The Microsoft SQL Server 2008 Reporting Services Report Builder 2.0 tool can be installed from a standalone installer available at this Microsoft site, http://download.microsoft.com/download/a/f/6/af64f194-8b7e-4118-b040-4c515a7dbc46/ReportBuilder.msi. The same file is also available from a collection of download files when you access the Microsoft SQL Server 2008 Feature Pack, October 2008 at http://www.microsoft.com/downloads/details.aspx?FamilyId=228DE03F-3B5A-428A-923F-58A033D316E1&displaylang=en. Report Builder overview In the present version of SQL Server 2008 [Enterprise Evaluation edition] there  are two Report Builders available. Report Builder 1.0, which has remained as a program that can be launched from the Report Manager, and the new Report Builder 2.0, which is a stand alone report authoring tool that needs to be independently launched. Although Report Builder 1.0 can access Report Models built with Visual Studio 2008 and the Report Manager, it cannot be used to create reports using those models. It also does not work with Reports generated by Visual Studio 2008/BIDS/Report Builder 2.0. The errors can be summarized as follows: When you try to access the Report Server 2008 from the link provided on the Report Builder 1.0 interface you get the following error message: Specifying credentials in a URL is not supported When you try to open a report created using VS2008/BIDS/ReportBuilder2.0 using the Open Report… and Open File… navigational items in Report Builder 1.0 you get the following error message: System.IO.StreamReader: The Report element was not found Report Builder 1.0 allows you to access Report Models created with VS2008/BIDS/Report Manager and even allows you create a report in design view but this report cannot be processed on the Report Server. If you try to do so, you get the following error message: MemoryStream length must be non-negative and less than 2^31-1-origin. Parameter name: offset; Remote GDI stream version: ?. Expected version: 11.0.1 In this article the Report Builder 2.0 interface will be described along with the new features that are incorporated into this version. Report Builder 2.0 is admirably suited to address all items in the Report Definition Language of 2008. One of the important features of Report Builder 2.0 is the empowerment it provides business users to create ad hoc reports using the Report Models built on the databases they use. In this article you will be learning mostly about the Report Builder 2.0  interface details and working with it to create reports or modify them. It may be noted that Report Builder generates 2008 compliant RDL files as described in http://download.microsoft.com/download/6/5/7/6575f1c8-4607-48d2-941d-c69622e11c32/RDL_spec_08.pdf and therefore, cannot work with reports generated using 2005 technology. Report Builder 2.0 user interface description Report Builder is a report authoring tool and the basic procedure for authoring a report consists of the following steps: Report planning Connecting to a source of data Extracting a dataset from source Designing the report and data binding Previewing the report Although deploying the report is not included in the above, Report Builder can deploy the report as well. It is not always necessary to deploy a completed report, as any part of a report definition file can be deployed. This makes modifying a report on the server very flexible. In the following sections, the various parts of the Report Builder interface will be described starting at the very top and going to the bottom of the interface The menu for file operations Report Builder 2.0 can be accessed from Start | All Programs | Microsoft SQL Server 2008 Report Builder | Report Builder 2.0. This brings up the Report Builder Interface 2.0 as shown with the design area containing two icons: Table or Matrix and Chart. Each of these will launch a  related wizard which will step you through the various tasks. The Report Builder 2.0 interface is very similar to Office 2007. More than one instance of Report Builder can be launched. At the very top of the following screen shown you have the undo and redo controls as well as a save icon. When you click on the save icon the Save as Report window gets displayed as shown. Here you provide a name for the report. The default save extension is  *.rdl and it will be saved to the report server. It may also be persisted to a folder on your machine. Clicking on the Office Button (top left) opens a drop-down window shown in the following screenshot: In this window, you can carry out a number of tasks such as creating a new report, opening an existing report, saving a report, and saving a report with a different name. The Save button saves it to the default location seen earlier and Save as invokes the same window to save the report with a different name as seen earlier displying the report server instance as the Save to location. The Recent Documents pane shows the more recent reports created with this tool. New allows you to create a new report. When you click on Open, the following Open Report window gets displayed with the default location http://Hodentek2:8080/ReportServer_SANGAM/My Reports. You will also notice the message: This folder is not available because the My Reports feature is not enabled on the computer. Also the Open Reports window allows you look for reports with the extension .rdl. Therefore, unless the My Reports feature is enabled, this window is unusable. This is supposed to be possible from Report Manager but there are no controls in Report Manager that would do this. An alternative was suggested by one of the MSDN forum moderators (see http://social.msdn.microsoft.com/forums/en-US/sqlreportingservices/thread/6c695160-29e8-4185-be6d-5fe027a6975c/). Hands-on exercise (Part 2) will describe how you may enable My Reports. The idea of My Reports is similar to My Documents where each user can keep his reports. When the Options button (in the previous screenshot) is clicked it opens the window Report Builder Options window with two tabbed pages Settings and Resource shown as follows: Here you can view, as well as modify, Report Builder settings. The defaults are more than adequate to work with the examples in this book. Clicking on the Resources button brings up this interesting window which enables you to interact with Microsoft regarding SSRS activities, concerns, community, and so on. If you are serious about Reporting Services, these are very valuable links. The About button when clicked can provide you with Report Builder version information. The ribbon The main menu consists of Home, Insert, and View menu items which are part of the "ribbon". The ribbon introduced by Microsoft in Office 2007 is actually a container for other toolbar items. The ribbon is the replacement for the classic menus, toolbars, and is supposed to be more efficient and discoverable by the user. In fact you see a lot more on the "ribbon" than in the classic menu. Home The next figure shows the Home menu with its toolbar arranged from left to right and divided into sections. The Run toolbar item with the title Views when clicked would run the report open in the design view (in fact, even without a report open in the design view, the report can be run. The result would be the current date and time getting displayed in the center of the screen of an untitled report which has just ExecutionTime as the only item in the report). The Font, Paragraph, Border, and Number toolbar sections become enabled if parts of a report need editing. The formatting of textboxes in the report, the formatting of numbers in the report, and the alignment of components in the layout can all be independently managed using these toolbar items. Insert When you click on the Insert menu item on the "ribbon", the tabbed page for this item is displayed as shown in the following screenshot: It has four sections: Data Regions, Report Items, Subreports, and Header & Footer. These are all the normal items that are used either individually or together to make up a report. There can be more than one data region in a report. Data Regions In the Data Regions section you have both the Tablix (Table, Matrix, and List) and the graphic controls that can be bound to data—the Chart and the Gauge. Gauge is new in SQL Server Reporting Services 2008. Chart and gauge implementations are the off shoot of collaboration with Dundas (http://www.dundas.com/). Report Builder is built in such a way that the dataset must be defined before any of the data regions are added to the report body. For the purpose of describing the various data regions in this section, it is assumed (in order to get the screen shots shown here) that a dataset has been defined and the default wizards on the design surface have been removed. Table The Table is meant for displaying data retrieved from a database either all data detailed in groups or a combination (some grouped and some detailed) of both. It has a fixed number of columns which can be adjusted at design time. The table length expands to accommodate the rows. Data can be grouped by a single field or by multiple fields. Expression designer can be used in grouping as well. The grouping is carried out by creating row groups. Static rows can be added for row headings (labels) and totals. Aggregates for groups can be added. Both detailed data as well as grouped data can be hidden initially and the user can interactively reveal the data needed by drill downs. When you click on Insert | Table | Insert Table and then click on the design surface you can add a table to the design area. The table appears as shown with handles to adjust its dimensions. The table can be dragged to any other location on the design surface (the body of the report) as well. After placing the table, which by default has three columns and two rows, when you click on any other part of the design area you will see the table as shown. When you hover over the cell marked Data on the table you will see a little icon. This icon is a minimized version of the dataset fields. The grayed out feature that surrounds the table indicate the position of the rows and columns of the table. It also shows such other features as whether it is a detail, or whether it is a group. In the case of group, within a group the feature would indicate the nesting schematically as well. When you want to increase the size of a column or a row you can drag the double headed arrow that gets displayed when your cursor is placed between two columns or between two cells as shown. When you click on the dataset icon in the cell Data you get a drop-down list containing the fields in the dataset as shown. You can choose any of the fields to occupy the cell you clicked and the corresponding header will be added to the table. In this particular dataset there are nine fields and you can choose any of them to occupy the cell. When you right-click on a cell, a drop-down menu will be available. It can be used for the following: Work with the highlighted textbox (each cell of the table is a textbox) including to copy, cut, delete, and paste contents. Work with the properties of the Textbox. Populate the textbox with an expression using the expression builder. The expression builder gets displayed when fx Expression is clicked. Use Select to select the body or the Tablix. Insert a new column or a new row. Columns can be added to the right or the left of the clicked cell and rows can be added above or below the clicked cell. Delete columns and rows. Add a group. Both row and column groups can be added. When you click on the properties of the textbox, the Text Box Properties window is displayed. The textbox has several properties which are arranged on the left as a list with each item having its own page as shown. The Help button on any of the pages will take you directly to the definition of the properties and is extremely useful. In the General page, you can make changes to the elements in the Name, Value, and Sizing options page as shown. The Value is one which you choose among the column values (from the drop-down) from the dataset. You may also add a text for the ToolTip, which will display this text when the report is generated and this cell is accessed by hovering over it in the report. Alternatively you can set the Value and Tooltip using fx—the button that brings up the Expression window. In the Number page you can set the number and date data type formatting options for the cell that contains a number or a date. This is what you normally would find in most Microsoft products such as Excel and Access. In the Alignment page you can choose the vertical and horizontal alignments as well as the padding of the textbox content from the edges of the cell. Similarly the Font and Border properties are the same ones you find in most Microsoft products. The Fill property lets you add or change background color to the report as well as add a graphic element. The graphic element can be embedded, external, or originate from a database (being one of the fields accessed). Expressions can be developed to set a desired color for the Fill. The Visibility of the textbox can be any of Show, Hide, Show or Hide based on an expression. In each of these cases the visibility can be toggled when another table cell is clicked (which can be chosen). This page also gives access to the Expression window which is similar to the MS Access expression builder. The Interactive Sorting page allows you to define interactive sorting options on  the textbox. Matrix Matrix provides a similar functionality (roughly speaking rows against columns) to cross-tab reports in MS Access (http://aspalliance.com/1041_Creating_a_Crosstab_Report_in_Visual_Studio_2005_Using_Crystal_Reports.all) and Pivot Table dynamic views (http://www.aspfree.com/c/a/MS-SQL-Server/On-Accessing-Data-From-An-OLAP-Server-Using-MS-Excel/3/). The matrix should have at least one row group and one column group. The matrix can expand both ways to accommodate the data, horizontally for column groups and vertically for row groups. The matrix cells (intersection of rows and columns) display summary information (aggregates). When you click on Insert Matrix in the Insert menu and drop it on the design area of Report Builder 2.0, it gets displayed as shown in the following figure: Now if you click inside the boundary of the (2x2) empty matrix you will see more features of the matrix as shown in the following screenshot. The basic elements are the ColumnGroup (Column Groups), the RowGroup (Row Groups), and the Data. The group information is also displayed as shown by overlaid lines pointing to them. There needs to be a minimum of one group and one column for the matrix and there could be a hierarchy of column and row groups. The row and column group cells have their own properties which can be displayed when you right-click on them as shown in the next screenshot for the row group. When you right-click on the cell marked Rows, the following drop-down menu  pops up. In addition to the properties that you can set for the textbox in that cell, you have additional submenu items that work with the grouping and totaling. These are part of representing data in a matrix. Each of the Tablix for the Rows and Columns has the additional submenu items which are shown here for the Rows. Similar ones apply for the Columns as well. These are useful when you want to create nested groups. With the Matrix design interface in SQL Server 2005 this would not have been possible. Add Group Row Group Parent Group... Child Group... -------------------- Adjacent Above Adjacent Below Row Group Delete Group Group Properties Add Total Before After In addition to the above, each of the items Rows and Columns cells has the following items as well. These specify how new columns and rows are inserted with reference to the current cell as shown. The differences are due to the geometrical positions that are allowed for the new columns or rows as shown. For the "Columns" cell: Insert Column Inside Group-Left Inside Group-Right ------------------ Outside Group-Left Outside Group-Right Insert Row Inside Group-Above Inside Group-Below ------------------ Outside Group_Above For the "Rows" cell: Insert Column Inside Group-Left Inside Group-Right ------------------ Outside Group-Left Insert Row Inside Group-Above Inside Group-Below ------------------ Outside Group_Above Outside Group_Below Besides using a cell as a starting point, one could also use the rows as a whole or column as a whole to add further structure as shown in the next figure. Of course you need to use the proper submenu option to arrive at a particular matrix structure. Clicking at the indicated points would let you choose the structure you want for your matrix. If you click at the location shown for the Tablix you could choose to the delete the whole matrix. The Tablix graphical arrangement gives you the maximum flexibility in extending the matrix in 2-dimensions. List The list data region repeats for each row of data. List element provides a single container for the data which can be used to generate what are called Free Form Reports. In this kind of report there is no rigid structure such as a table for the data. You can also place a list inside another list or even a chart inside a list. You can drag a column from a dataset and drop it into the list. You can work with the list using the properties of the Rectangle it contains as well as its Tablix properties. As described earlier, the design interface is very flexible and you can leverage all features provided by the Tablix structure like displaying details and adding groups either independent, or nested. The properties pages described earlier allow you to sort and filter grouped data. When you drop a List on the design surface you will see just a single cell as shown. You can change its dimensions to suit your needs. When you click on the List you can access its handles as shown: When you add a List, there is one column and one row (just one cell). This can be extended in both directions by choosing the appropriate submenu items. These can be displayed by right-clicking on the handles as shown:
Read more
  • 0
  • 0
  • 7158

article-image-working-complex-associations-using-cakephp
Packt
28 Oct 2009
6 min read
Save for later

Working with Complex Associations using CakePHP

Packt
28 Oct 2009
6 min read
Defining Many-To-Many Relationship in Models In the previous article in this series on Working with Simple Associations using CakePHP, we assumed that a book can have only one author. But in real life scenario, a book may also have more than one author. In that case, the relation between authors and books is many-to-many. We are now going to see how to define associations for a many-to-many relation. We will modify our existing code-base that we were working on in the previous article to set up the associations needed to represent a many-to-many relation. Time for Action: Defining Many-To-Many Relation Empty the database tables: TRUNCATE TABLE `authors`;TRUNCATE TABLE `books`; Remove the author_id field from the books table: ALTER TABLE `books` DROP `author_id` Create a new table, authors_books:; CREATE TABLE `authors_books` (`author_id` INT NOT NULL ,`book_id` INT NOT NULL Modify the Author (/app/models/author.php) model: <?phpclass Author extends AppModel{ var $name = 'Author'; var $hasAndBelongsToMany = 'Book';}?> Modify the Book (/app/models/book.php) model: <?phpclass Book extends AppModel{ var $name = 'Book'; var $hasAndBelongsToMany = 'Author';}?> Modify the AuthorsController (/app/controllers/authors_controller.php): <?phpclass AuthorsController extends AppController { var $name = 'Authors'; var $scaffold;}?> Modify the BooksController (/app/controllers/books_controller.php): <?phpclass BooksController extends AppController { var $name = 'Books'; var $scaffold;}?> Now, visit the following URLs and add some test data into the system:http://localhost/relationship/authors/ and http://localhost/relationship/books/ What Just Happened? We first emptied the database and then dropped the field author_id from the books table. Then we added a new join table authors_books that will be used to establish a many-to-many relation between authors and books. The following diagram shows how a join table relates two tables in many-to-many relation: In a many-to-many relation, one record of any of the tables can be related to multiple records of the other table. To establish this link, a join table is used—a join table contains two fields to hold the primary-keys of both of the records in relation. CakePHP has certain conventions for naming a join table—join tables should be named after the tables in relation, in alphabetical order, with underscores in between. The join table between authors and books tables should be named authors_books, not books_authors. Also by Cake convention, the default value for the foreign keys used in the join table must be underscored, singular name of the models in relation, suffixed with _id. After creating the join table, we defined associations in the models, so that our models also know about the new relationship that they have. We added hasAndBelongsToMany (HABTM) associations in both of the models. HABTM is a special type of association used to define a many-to-many relation in models. Both the models have HABTM associations to define the many-to-many relationship from both ends. After defining the associations in the models, we created two controllers for these two models and put in scaffolding in them to see the association working. We could also use an array to set up the HABTM association in the models. Following code segment shows how to use an array for setting up an HABTM association between authors and books in the Author model: var $hasAndBelongsToMany = array( 'Book' => array( 'className' => 'Book', 'joinTable' => 'authors_books', 'foreignKey' => 'author_id', 'associationForeignKey' => 'book_id' ) ); Like, simple relationships, we can also override default association characteristics by adding/modifying key/value pairs in the associative array. The foreignKey key/value pair holds the name of the foreign-key found in the current model—default is underscored, singular name of the current model suffixed with _id. Whereas, associationForeignKey key/value pair holds the foreign-key name found in the corresponding table of the other model—default is underscored, singular name of the associated model suffixed with _id. We can also have conditions, fields, and order key/value pairs to customize the relationship in more detail. Retrieving Related Model Data in Many-To-Many Relation Like one-to-one and one-to-many relations, once the associations are defined, CakePHP will automatically fetch the related data in many-to-many relation. Time for Action: Retrieving Related Model Data Take out scaffolding from both of the controllers—AuthorsController (/app/controllers/authors_controller.php) and BooksController (/app/controllers/books_controller.php). Add an index() action inside the AuthorsController (/app/controllers/authors_controller.php), like the following: <?phpclass AuthorsController extends AppController { var $name = 'Authors'; function index() { $this->Author->recursive = 1; $authors = $this->Author->find('all'); $this->set('authors', $authors); }}?> Create a view file for the /authors/index action (/app/views/authors/index.ctp): <?php foreach($authors as $author): ?><h2><?php echo $author['Author']['name'] ?></h2><hr /><h3>Book(s):</h3><ul><?php foreach($author['Book'] as $book): ?><li><?php echo $book['title'] ?></li><?php endforeach; ?></ul><?php endforeach; ?> Write down the following code inside the BooksController (/app/controllers/books_controller.php): <?phpclass BooksController extends AppController { var $name = 'Books'; function index() { $this->Book->recursive = 1; $books = $this->Book->find('all'); $this->set('books', $books); }}?> Create a view file for the action /books/index (/app/views/books/index.ctp): <?php foreach($books as $book): ?><h2><?php echo $book['Book']['title'] ?></h2><hr /><h3>Author(s):</h3><ul><?php foreach($book['Author'] as $author): ?><li><?php echo $author['name'] ?></li><?php endforeach; ?></ul><?php endforeach; ?> Now, visit the following URLs:http://localhost/relationship/authors/http://localhost/relationship/books/ What Just Happened? In both of the models, we first set the value of $recursive attributes to 1 and then we called the respective models find('all') functions. So, these subsequent find('all') operations return all associated model data that are related directly to the respective models. These returned results of the find('all') requests are then passed to the corresponding view files. In the view files, we looped through the returned results and printed out the models and their related data. In the BooksController, this returned data from find('all') is stored in a variable $books. This find('all') returns an array of books and every element of that array contains information about one book and its related authors. Array ( [0] => Array ( [Book] => Array ( [id] => 1 [title] => Book Title ... ) [Author] => Array ( [0] => Array ( [id] => 1 [name] => Author Name ... ) [1] => Array ( [id] => 3 ... 54 54 ... ...) Same for the Author model, the returned data is an array of authors. Every element of that array contains two arrays: one contains the author information and the other contains an array of books related to this author. These arrays are very much like what we got from a find('all') call in case of the hasMany association.
Read more
  • 0
  • 0
  • 7049

article-image-installing-alfresco-software-development-kit-sdk
Packt
28 Oct 2009
6 min read
Save for later

Installing Alfresco Software Development Kit (SDK)

Packt
28 Oct 2009
6 min read
Obtaining the SDK If you are running the Enterprise network, it is likely that the SDK has been provided to you as a binary. Alternatively, you can check out the Enterprise source code and build it yourself. In the Enterprise SVN repository, specific releases are tagged. So if you wanted 2.2.0, for example, you'd check out V2.2.0-ENTERPRISE-FINAL. The Enterprise SVN repository for the Enterprise network is password-protected. Consult your Alfresco representative for the URL, port, and credentials that are needed to obtain the Enterprise source code. Labs network users can either download the SDK as a binary from SourceForge (https://sourceforge.net/project/showfiles.php?group_id=143373&package_id=189441) or check out the Labs source code and build it. The SVN URL for the Labs source code is svn://svn.alfresco.com. In the Labs repository, nothing is tagged. You must check out HEAD. Step-by-Step: Building Alfresco from Source Regardless of whether you are using Enterprise or Labs, if you've decided to build from the source it is very easy to do it. At a high level, you simply check out the source and then run Ant. If you've opted to use the pre-compiled binaries, skip to the next section. Otherwise, let's use Ant to create the same ZIP/TAR file that is available on the download page. To do that, follow these steps: Check out the source from the appropriate SVN repository, as mentioned earlier. Set the TOMCAT_HOME environment variable to the root of your Apache Tomcat install directory. Navigate to the root of the source directory, then run the default Ant target: ant build.xml ant build.xml It will take a few minutes to build everything. When it is done, run the distribute task like this: ant -f continuous.xml distribute Again, it may take several minutes for this to run. When it is done, you should see several archives in the build|dist directory. For example, running this Ant task for Alfresco 3.0 Labs produces several archives. The subset relevant to the article includes: alfresco-labs-sdk-*.tar.gz alfresco-labs-sdk-*.zip alfresco-labs-tomcat-*.tar.gz alfresco-labs-tomcat-*.zip alfresco-labs-war-*.tar.gz alfresco-labs-war-*.zip alfresco-labs-wcm-*.tar.gz alfresco-labs-wcm-*.zip You should extract the SDK archive somewhere handy. The next step will be to import the SDK into Eclipse. Setting up the SDK in Eclipse Nothing about Alfresco requires you to use Eclipse or any other IDE. But Eclipse is very widely used and the Alfresco SDK distribution includes Eclipse projects that can easily be imported into Eclipse, so that's what these instructions will cover. In addition to the Alfresco JARs, dependent JARs, Javadocs, and source code, the SDK bundle has several Eclipse projects. Most of the Eclipse projects are sample projects showing how to write code for a particular area of Alfresco. Two are special, however. The SDK AlfrescoEmbedded project and the SDK AlfrescoRemote project reference all of the JARs needed for the Java API and the Web Services API respectively. The easiest way to make sure your own Eclipse project has everything it needs to compile is to import the projects bundled with the SDK into your Eclipse workspace, and then add the appropriate SDK projects to your project's build path. Step-by-Step: Importing the SDK into Eclipse Every developer has his or her own favorite way of configuring tools. If you are going to work with multiple versions of Alfresco, you should use version-specific Eclipse workspaces. For example, you might want to have a workspace-alfresco-2.2 workspace as well as a workspace-alfresco-3.0 workspace, each with the corresponding Alfresco SDK projects imported. Then, if you need to test customizations against a different version of the Alfresco SDK, all you have to do is switch your workspace, import your customization project if it isn't in the workspace already, and build it. Let's go ahead and set this up. Follow these steps: In Eclipse, select File|Switch Workspace or specify a new workspace location. This will be your workspace for a specific version of the Alfresco SDK so use a name such as workspace-alfresco-3.0. Eclipse will restart with an empty workspace. Make sure the Java compiler compliance level preference is set to 5.0 (Window|Preferences|Java|Compiler). If you forget to do that, Eclipse won't be able to build the projects after they are imported. Select File|Import|Existing Projects into Workspace. For the root directory, specify the directory where the SDK was uncompressed. For the root directory, specify the directory where the SDK was uncompressed. You want the root SDK directory, not the Samples directory. Select all of the projects that are listed and click Import. After the import, Eclipse should be able to build all projects cleanly. If not, double-check the compiler compliance level. If that is set but there are still errors, make sure you imported all SDK projects including SDK AlfrescoEmbedded and SDK AlfrescoRemote. Now that the files are in the workspace, take a look at the Embedded project. That's quite a list of dependent JAR files! The Alfresco-specific JARs all start with alfresco-. It depends on what you are doing, of course, but the JAR that is referenced most often is likely to be alfresco-repository.jar because that's where the bulk of the API resides. The SDK comes with zipped source code and Javadocs, which are both useful references (although the Javadocs are pretty sparse). It's a good idea to tell Eclipse where those files are, so you can drill in to the Alfresco source when debugging. To do that, right-click on the Alfresco JAR, and then select Properties. You'll see panels for Java Source Attachment and Javadoc Location that you can use to associate the JAR with the appropriate source and Javadoc archives. The following image shows the Java Source Attachment for alfresco-repository.jar: The following image shows the Javadoc Location panel for alfresco-repository.jar. Source and Javadoc are provided for each of the Alfresco JARs, as shown in the following table. Note that source and Javadoc for everything is available. This is open source software after all, not just all bundled with the SDK: Alfresco JAR Source archive Javadoc archive alfresco-core.jar Src|core-src.zip Doc|api|core-doc.zip alfresco-remote-api.jar Src|remote-api-src.zip Doc|api|remote-api-doc.zip alfresco-web-client.jar src|web-client-src.zip doc|api|web-client-doc.zip alfresco-repository.jar src|repository-src.zip doc|api|repository-doc.zip    
Read more
  • 0
  • 0
  • 2601
article-image-extending-application-using-microsoft-dynamics-nav-2009-part-1
Packt
28 Oct 2009
11 min read
Save for later

Extending the Application using Microsoft Dynamics NAV 2009 (Part 1)

Packt
28 Oct 2009
11 min read
Learning to fish Give a man a fish and you feed him for a day; teach him to use the Internet, and he won't bother you for weeks! This is going to be a real challenge for the one that wants to play with the new technology that Web services enablement brings, but is a little unsure where to start. A good number of people that are experienced NAV consultants and C/AL developers are going to need to learn some new technologies if they want to start experimenting with the new extensibility options in Dynamics NAV 2009, or even simply understand what options are available for their new solution designs or sales presentations. This article is going to be all about practical examples—real sample applications that you can create for yourself. Some of these examples start off with one set of requirements that evolve as we progress through the design process. The examples are deliberately kept this way to help you to understand that the path to your final working solution is not always the shortest. Sometimes you get an idea for an application and as you proceed with the design, you think of things that would be better or easier to use. Sometimes your initial design simply won't work when you start to try it out. It's important to realize that designs are not precious and it's OK to change your mind. There are a couple of important issues to consider: always ensure you are solving the business problem, and don't get carried away gold-plating your design. Keep it simple, and once it is working and meets the initial requirements, you can then go back and add the bells and whistles (but you'd better check with whoever is paying the bills first). If you aren't a .NET programmer, and you have never created a web site or Web service in your life, this article is not a place to tell you the best way to do these things, but instead is a place to show you that with a very limited knowledge of .NET, a web browser to do some research, and enough time, you can create pretty much anything you can imagine. First of all, let's get some theory out of the way so that we have a basic understanding of what we're dealing with. What's a Web service? Web services have been around for a few years now but they are new to NAV (well, sort of— but more on that later). A good way to distinguish between technical and non-technical NAV consultants is to ask them if NAV supports Web services and watch to see if their eyes glaze over. There's no wonder some NAV consultants struggle to understand Web services as a concept; if you're not a developer and you have never worked with Web services, learning the basics might be more than a little bit scary. Here's a typical definition you might find on the Web; don't be put off by the geek-speak. A scary geeky definition of a Web service A 'Web service' (also Web Service) is defined by the W3C as 'a software system designed to support interoperable machine-to-machine interaction over a network'. Web services are frequently just Web APIs that can be accessed over a network, such as the Internet, and executed on a remote system hosting the requested services. There are a lot of acronyms and jargon phrases to learn if you want to talk the talk, but let's take a look at what a Web service is in simple terms. To start with, let's consider a comparison between web sites, something we are all familiar with, and Web services. One might like to think that a Web service is to a computer what a web site is to a person. If you want to know what's on TV tonight, you can type the URL for a TV Listings site into a web browser and bring up a page with details. It's not going to take you long to find the required information, but what if you wanted to write a computer program to send an e-mail when your favorite TV show was about to start, how would you go about that? This is a more complex problem, we know the data is there on the web site, freely available to all humans, but we can't just tell our computer to go off and read the web site (well we can—but deciphering it may require a fair amount of clever programming). Wouldn't it be great if there was a computer-friendly version of the data on the web site that allowed computers to ask for information and get answers back? Wouldn't it be great if you could write your program to make the call to this service without the need to install any special software components on your computer? Yes, it is great, and that's why Web services came into being and have now become so popular. It's not just for the Web It's not immediately obvious why we would want to expose our precious company data that we keep locked up in our ERP system on the Web, but just because they're called Web services doesn't mean they're just for the World Wide Web. Let's consider the intranet compared to the internet. It didn't take long for companies to realize that the popularity of internet sites and the ease of use that everyone was experiencing through the world wide web could provide great benefits within the boundaries of a company's safe internal network—a kind of mini-internal-internet or intranet. For Dynamics NAV, the analogy between Web Sites and Web services works even better when we consider an intranet. What if different departments could pull data directly from the ERP system and use it in their own specialist applications? This is where the real value of Web services enablement in Dynamics NAV 2009 comes into its own. It is now possible to take any functionality from within the ERP solution and expose it to other applications as Web services; it's not just possible, it's dead easy! What can we do with them? OK, so it's easy to expose NAV functionality, so what? Well if you can call any Codeunit or Page from within NAV with pretty much any software package that you can extend, there are limitless possibilities to create fantastic productivity applications for the business. Here are just a few examples: Let staff submit their expenses from Excel, or from their mobile phone, without needing to re-key them into the finance system. Allow users to create new customer accounts from within Word or from an intranet web page. Provide a Vista Sidebar gadget that shows the number of documents requiring approval and allows the user to approve the document without needing to open the ERP. Provide a simple single-task Windows application that will let staff see where stock is. These examples are just a few that spring immediately to mind, but if you have the know-how, you can do pretty much anything. So how easy is it to expose NAV functionality as a Web service? Let's find out. Calling a NAV Web service There is a great series of articles on MSDN by Manuel Oliveira that explain how to expose NAV functionality as a Web service. If you have never read these, you may want to skim through them after reading this example to see just how easy we have it with the new version of NAV. Talking with NAV—the hard way! Visit http://msdn.microsoft.com/en-us/library/ms952182.aspx and http://msdn.microsoft.com/en-us/library/ms952079.aspx for a couple of examples that explain the multiple hoops we needed to jump through in order to access NAV functionality using Web services. That's before NAV 2009 came along! Since these early examples of NAV extensibility, the Windows Communication Framework has made things easier, and Kris Rafnsson has provided a blog posting and sample application that allows you to call NAV functionality as a Web service without using message queues. This example is pretty amazing, but there is still a fair amount of work required to get this up and running and build new solutions. Although this is a big improvement on the Message Queue approach, it is nothing compared to the simplicity and elegance of the NAV 2009 Web services enablement. You can read through Kris's post at http://blogs.msdn.com/nav/archive/2008/04/15/using-web-services-toaccess-microsoft-dynamics-nav-5-0.aspx. In Manuel's first example (although not actually a Web service), he creates a simple NAV function that will accept a text string and return the text string back but converted to upper case. This example spans 15 printed pages and uses a lot of geeky stuff. As a bare minimum, we are going to need a Codeunit to expose and a .NET program to call the thing, so let's forget about these and just compare the components that are needed to take care of the plumbing: Microsoft Message Queue Navision Communication Component XMLDOM automation control Navision Application Server A lot of complicated C/AL code using InStreams and OutStreams and XML manipulation Manuel's examples were written in 2004 and, although they're very well written, the whole thing is just too hard! After reading the articles, you'll understand why there hasn't been a glut of NAV components on the market using Web services exposed by NAV. Our example by contrast requires the following (again ignoring the Codeunit we are exposing and the .NET program needed to call it): Dynamics NAV 2009 Business Web services A new record in a table with a check in a box Creating a Web service Let's start by creating our very simple Codeunit. In this example, I have created Codeunit 50001 called NAV Codeunit, which has a single function called ConvertStrToUpperCase that takes a 50 character text field and returns a 50 character text field that has been converted to upper case. It wasn't absolutely necessary for this example, but I put some code in the OnRun() trigger of the Codeunit that will demonstrate the Codeunit working when run. Here is the output from running the Codeunit in NAV: Now we can expose this Codeunit as a Web service. In the Classic client, select Administration | IT Administration | General Setup | Web Services. This is just a regular NAV form, so fill in the details on a new record with Object Type as Codeunit, Object ID as 50001, and Service Name as NAV Codeunit. To publish the Web service, tick the Published field. I just happened to give the Web service the same name as the Codeunit, but this is not necessary, you can call it whatever you like. We have now exposed NAV functionality as a Web service—how easy was that? Calling the Web service The .NET program to call the Web service is going to be a little harder. We're going to create a simple C# console application using Microsoft Visual Studio 2008 Professional Edition. (This is installed on the Marketing Beta release of the product which all partners can download from PartnerSource.) Create a new Console Application, let's call this one SayHelloToNAV2009. The project gets created with a Program.cs file with enough code generated for you to allow the project to compile and run. There's no way I can teach you to program in C# in this article, there are whole books dedicated to the subject; instead what I'll do is give you the details you need to be able to recreate our examples for yourself. If you like what you see, maybe you'll go on to do some more .NET programming and your next book will be one on C#. The great thing about .NET languages and Visual Studio is there's a huge amount of knowledge freely available on the Web. The first thing we need to do is add our Web service to the project. To do this, right-click on the References node in the Solution Explorer window and select Add Service Reference. Visual Studio 2005 is differentThese instructions are for adding a web reference using Visual Studio 2008. In 2005, things work a little differently. Instead of selecting References | Add Service Reference | Advanced | Add Web Reference, you simply selected Add Reference | Add Web Reference. In the dialog that is displayed, click the Advanced button, and then click the Add Web Reference button. In the Add Web Reference dialog form, enter http://nav-srv-01:7047/DynamicsNAV/ws/CRONUS_International_Ltd/Services as the URL for the Web service. This will display the group of Web services that are exposed by NAV. Where do I find that URL? The format of the URL is quite straightforward. Let's break it up into chunks.
Read more
  • 0
  • 0
  • 2791

article-image-extending-application-using-microsoft-dynamics-nav-2009-part-2
Packt
28 Oct 2009
20 min read
Save for later

Extending the Application using Microsoft Dynamics NAV 2009 (Part 2)

Packt
28 Oct 2009
20 min read
Sidebar gadget A sidebar gadget is a simple single-tasked tool that sits in the sidebar on Windows Vista. If you don't have Windows Vista, you're out of luck and won't be able to run this sample. You can explore the free gadgets available for download at http://gallery.live.com/. Typical gadgets include: RSS Feed Readers News Readers Weather Reports Clocks Performance Monitoring Tools Mini Notepads Photo Slideshows Hopefully you get the idea. We're going to create a sidebar gadget that will use the Web service capabilities of Dynamics NAV 2009 to display a cue (a stack of documents similar to those shown in the RoleTailored client), based upon the document approvals features that have been available since NAV 5.0. We want to display a document stack that represents the number of documents requiring approval from the current user and will allow the user to select the type of document as a configuration setting. In our example, clicking the document stack will show a list of documents and clicking an individual document will launch the RoleTailored client. There's no reason why you can't take this example and extend it to include the ability to display the actual documents and carry out the approval, all from the comfort of your Windows Vista desktop. Design time When we start to de sign NAV solutions, we use our knowledge of the standard application to create a solution that fits nicely within the NAV paradigm. We try to emulate the way the standard application solves common business problems and use the components that are used by the product team in a consistent manner. Designing applications for .NET, or in this case for a sidebar gadget, follows the same conventions. First of all we need to understand a little bit about what makes a sidebar gadget so that we can know the constraints of our design. What are little gadgets made of? There is an excellent tutorial on MSDN Magazine's web site by Donavon West that tells you how to build a sidebar gadget for displaying MSDN Magazine articles in a news-ticker format with the ability to click an article to see more details and click another link to read the full article on the Web. We're going to use that article and the gadget provided for download as the basis for exploring what a gadget is, which will in turn help us to design our own gadget. You can read Donavon West's MSDN Magazine article at: http://msdn.microsoft.com/en-nz/magazine/cc163370(en-us).aspx You can download the Gadget from: http://gallery.live.com/liveItemDetail.aspx?li=b21af41e-b846-46d9-a873-ac12a3c65ab3 Essentially a gadget is little more than a mini web page (HTML file with some supporting resources such as images and JavaScript) and an XML definition file called gadget.xml. When we're writing a sidebar gadget for Windows Vista, the HTML page is rendered in Microsoft Internet Explorer 7, so there is no need to worry about cross-browser support. Which is nice. If you download the gadget and save it somewhere instead of installing it, you will see an icon for the gadget like this: Before we can use this gadget there is a little problem that needs to be fixed—unfortunately it is pointing to an RSS Feed URL that is not valid and therefore the gadget doesn't work correctly. Donavon explains that a sidebar gadget is simply a collection of files that are stored in a ZIP or CAB file with a .gadget extension, so we can rename the file with a .zip extension and we should be able to open it as a folder. If you open the compressed folder, or extract it, you will see the following files: There is a file called local.js that we will need to edit in order to fix the problem. Gadgets support multi-language capabilities and if your language matches the folder names shown, you are going to need to open that folder and edit the local.js thatit contains. The languages supported by this gadget are as follows:   Folder Name Language de German (Standard) es Spanish (Spain) fr French (Standard) it Italian (Standard) ja Japanese kr I don't think this is a valid language code, so we'll just ignore this. pt Portuguese (Portugal) ru Russian zh-CN Chinese (PRC) zh-TW Chinese (Taiwan) You can get a full list of language codes at http://msdn.microsoft.com/en-us/library/ms533052(VS.85).aspx According to the tutorial, whenever the sidebar tries to load a file, it searches for the file in folders in the following order: Full locale (en-us, es-us, ja-jp) Language portion of the locale (en, es, ja) Gadget root folder So what does this mean? If your locale has a language component that is one of the folders listed in the table, you are going to need to edit the local.js within that folder in order for the gadget to work correctly. When you edit the local.js file (any text editor will do), you will see the following: If you copy the feedUrl string and paste it into a web browser address bar, you will see a runtime error telling you this is not a valid address. A little bit of digging soon reveals an address that we can use for the gadget: http://msdn.microsoft.com/en-nz/magazine/rss/default(en-us).aspx?issue=1 You need to replace the old URL with the new one so that your line in the fi le looks like the following: LOCAL.feedUrl = 'http://msdn.microsoft.com/en-nz/magazine/rss/ default(en-us).aspx?issue=1'; Now we can rename the file back to a .gadget extension and install it. This is to help us examine the main components of a sidebar gadget so we can consider how we will design our own gadget. The gadget The most obvious part of a gadget is the gadget itself. This is the gadget's main HTML page that is provided in the base src property of our gadget.xml file. For us, we want this to show a single document cue that represents the number of approval entries that are awaiting action for the current user. We want the main docked gadget to look something like this: The image is meant to look like a cue from an Activities Part in a Role Center. The pencil sketch is there to give you an idea. Since the 22 approval actions could be for multiple different document types, we will have some text underneath the stack of documents that tells us how many of each of the different document types there are. It could either fade in and out, or scroll horizontal like a marquee. That takes care of the docked state of the gadget. When we undock it, we can get a larger area to play with, so it would be nice if the undocked state showed one stack of documents for each of the approval document types with the name of the document type shown underneath. This may be a little time-consuming, so maybe we'll add that to version 2. For now the undocked image will be the same as the docked image. There are a couple of other pages that need to be considered: Flyouts and Options dialog. Flyouts When you click on a part of gadget, you can activate a flyout, which is basically a web page that gets displayed at the side of the gadget. The flyout file is specified by setting System.Gadget.Flyout.file to the name of the flyout HTML file. In the case of our MSDN Ticker gadget, the flyout looks like the following: For our flyout, we are going to show a list of approval entries with the ability to click a hyperlink to open the approval entries screen. An obvious next extension to this gadget is to provide the ability to approve, reject, or delegate the approval entry directly from the gadget without needing to open the RoleTailored client. For now, we'll concentrate on making this work with our NAV Web service. After taking a quick look at the fields available on the approval entry screen, our flyout will look something like the following: It's a simple table showing the documents with a document type and number, the ID of the sender and the amount that the document is for. Options There is one more part of the gadget to consider for our design and that is the options dialog page. Let's take a look at that for the MSDN Magazine Ticker sample gadget. When I hover my mouse over the gadget, a mini tool bar appears allowing me to close the gadget, show the options, and drag the gadget to a different position. Click the spanner to show the options page. As you can see it's just another little web page with some options on it. You need to instruct the gadget to enable the options icon by setting System.Gadget.settingsUI to the name of the options HTML file, generally in the gadget initialization area of our script. Donavon's article explains how this is done, and provides sample code for how to set up a callback function for when the options dialog closes (so your gadget can read the new user preferences). For our gadget we are going to need a place where we can enter the URL for our Web service. For more advanced options, we could possibly provide the ability to specify how often the gadget will call the Web service. Our options page will look something like this: These pencil sketches are just there to convey the intended layout of the pages; it's a lot quicker to scribble something on a piece of paper (for us) than to start playing around with graphics programs and although they're a little rough, if you squint at them, you can sort of work out what's intended in the final solution. Remember it's important to get an understanding of the design at this stage but it doesn't need to look great; form follows function. The tricky bits Now that we' ve done the high-level design for our sidebar gadget, and we know that a sidebar gadget is just a series of HTML pages, we can start to look at the technical design. There are a couple of tricky bits to take care of: how are we going to call our Web service from within what is essentially a web page, and how are we going to take our list of documents requiring approval and convert them into the table and graphics we want to display. The great thing about sidebar gadgets and the way they are constructed is that you can simply rename the file and take a look at how they are doing what they do (and, of course, you can borrow ideas and code). If you search on the Web, you'll find quite a few examples of sidebar gadgets that call Web services, so there're plenty of examples to look at. Let's pick an example from Microsoft that uses the Exchange 2007 Web service to display email, calendar, and task information. You can download it from: http://www.microsoft.com/downloads/details.aspx?FamilyID=F9A0D33CC894-4EA1-AD20-4E418C715175&displaylang=en A quick search for Exchange Web services Gadget will help you locate it. Actually finding this gadget was a stroke of luck because it does pretty much everything we are after: It has a setup page with a time interval on it. It calls a Web service to find how many items there are in a folder and shows a summary. It displays a flyout with a more detailed view of the folder contents. Finding good examples on the Internet and learning from them is a key skill for doing this kind of development. Just a little bit of SOAP Calling a NAV Web service from within a Visual Studio.NET project is dead easy as we've already seen. We just add our Web service as a web reference and Visual Studio does all the hard work for us. It creates a proxy class that allows us to call the member functions and access the properties of the service as though it was a piece of code that we had written ourselves and not just some black box at the end of a URL. But how do we do this when we don't have Visual Studio? Essentially a Web service is just some text sent over the Internet that generates a response (which is also text). It just so happens that the text being sent and received is formatted as XML which is handy because there is lots of support for reading XML text. Web services typically use a protocol called Simple Object Access Protocol (or SOAP) to allow any system that can post a request to a URL (and read a response message) to call to a function exposed by the Web service. In order to do this for our sidebar gadget, we need two things: we need to know how to send and receive our request, and we need to know what the SOAP request should look like. Figuring out the HTTP call and response handling isn't too hard and you can do this by looking at the Exchange Web service gadget source code or, once again, searching the Internet. Looking at how Microsoft did it in their Exchange Web service gadget shows us we can use the native Microsoft.XMLHTTP object provided by Internet Explorer (remember that a sidebar gadget runs in Internet Explorer only, so we don't need to worry about cross-browser support) to make an HTTP post to our Web service and read the response. Finding the XML for the SOAP request that is needed to invoke a NAV Web service is going to be a little trickier. If we do a Web search for 'how to view a soap request in Visual Studio?', it doesn't take much to find a link to a freeware product called Fiddler that will allow me to inspect messages to and from my web server. Here is the URL: http://www.fiddler2.com/fiddler2/ If we use this tool on the simple example we started the chapter with, we can see the SOAP request is: And the response is: We can guess we could have worked out this request and response format by reading the WSDL (pronounced 'wiz-dal'), that we get when we type the URL to the Codeunit in our web browser; however, we can think that using Visual Studio to test calling our Web service is by far the easiest way, and using the Fiddler tool to be able to inspect and copy the SOAP Envelope XML has got to be better than thinking. Now before we get too carried away trying to create a series of Web service calls to allow us to pull data from a page type Web service, we're going to create a simple proof-of-concept web page that will make a JavaScript call to this NAV Web service with our ConvertStrToUpperCase function. An HTML page that calls a NAV Codeunit This next script is 72 lines of text. The point of the exercise is to show how easy it is to do things in the .NET world even when you don't know what you're doing. Here is the code in full; we'll go through it in detail later: <HTML> <HEAD> <TITLE>Hello NAV 2009 With JavaScript</TITLE> </HEAD> <BODY> <b>Input: </b>hello nav2009!<br/> <div id="resultContainer"><b>Output: </b></div> <FORM Name="Form1" ACTION=""> <INPUT TYPE=BUTTON VALUE="Call NAV" NAME="BtnHello" OnClick="Hello NAV2009()"> </FORM> <SCRIPT LANGUAGE="JavaScript"> <!-- function HelloNAV2009 () { var data = ""; data += '<?xml version="1.0" encoding="utf-8"?>'; data += '<soap:Envelope '; data += ' '; data += ' >'; data += ' <soap:Body>'; data += ' <ConvertStrToUpperCase '; data += ' >'; data += ' <p_Str>hello nav2009!</p_Str>'; data += ' </ConvertStrToUpperCase>'; data += ' </soap:Body>'; data += '</soap:Envelope>'; var xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); var url = 'http://ds-srv-01:7047/DynamicsNAV/ws/CRONUS_ International_Ltd/Codeunit/NAV_Codeunit'; xmlHttpRequest.open("POST", url, false); xmlHttpRequest.SetRequestHeader("Content-Type", "text/xml"); xmlHttpRequest.SetRequestHeader("SOAPAction", "urn:microsoftdynamics- schemas/codeunit/NAV_Codeunit:ConvertStrToUpperCase"); xmlHttpRequest.onreadystatechange = readResponse; xmlHttpRequest.send(data); function readResponse() { if (xmlHttpRequest.readyState == 4) { var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.loadXML(xmlHttpRequest.responseText); resultText = xmlDoc.getElementsByTagName("return_value")[0]. childNodes[0].nodeValue; xmlDoc = null; resultContainerElement = document.getElementById("resultContaine r"); if (resultContainerElement != null) { resultContainerElement.innerHTML = "<b>Output: </b>" + resultText; } xmlHttpRequest = null; } } } //--> </SCRIPT> </BODY> </HTML> You can download the HelloNAV2009.html file from www.teachmenav.com (or http://www.packtpub.com/support). You may need to edit the file on the line where the url variable is assigned to point to the Web service URL available on your computer. When you open the file in your browser, you will need to allow the blocked content in order for the example to run. When you click the Call NAV button, the screen updates to show the following: Wooohooo! It works! OK, let's take a look at what's going on in the code. First of all we assign our variable called data to the XML for the SOAP request body (this is found by using the Fiddler application earlier). That block of code is not included for analysis, so let's move on. This next block of code creates an instance of the Microsoft.XMLHTTP object that we are going to use to make the HTTP post and read the response. var xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); var url = 'http://ds-srv-01:7047/DynamicsNAV/ws/CRONUS_International_ Ltd/Codeunit/NAV_Codeunit'; xmlHttpRequest.open("POST", url, false); xmlHttpRequest.SetRequestHeader("Content-Type", "text/xml"); xmlHttpRequest.SetRequestHeader("SOAPAction", "urn:microsoft-dynamicsschemas/Codeunit/NAV_Codeunit:ConvertStrToUpperCase"); The highlighted text in the code caused a good deal of grief. Without the SOAPAction request header, the response always contained the WSDL definition of the Web service (the XML document that is shown when you type the Web service URL into the address bar on your browser). Once again this was the missing bit if we look at the results of the Fiddler application trace of .NET application we wrote at the start of this chapter. The following code will hookup the readResponse function to the xmlHttpRequest so that the response can be read when the call is finished. I borrowed this code from the Exchange Web service gadget (although I had to wade up to my armpits in functions in order to find the code that actually did the business). xmlHttpRequest.onreadystatechange = readResponse; xmlHttpRequest.send(data); function readResponse() { if (xmlHttpRequest.readyState == 4) { var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.loadXML(xmlHttpRequest.responseText); This next bit of code assigns the resultText variable to the contents of the SOAP response and it took a while to figure out. This example has been taken from the W3 schools site by searching for Microsoft.XMLDOM (http://www.w3schools.com/Xml/xml_dom.asp). resultText = xmlDoc.getElementsByTagName("return_value") [0].childNodes[0].nodeValue; The code is reading the text result from the SOAP envelope. A real example will have to do a lot more with this XML document but for now, this does the job. Finally, we dispose of some objects and then inject the result text in to the body of our HTML page using the innerHTML property for our resultContainer div class. xmlDoc = null; resultContainerElement = document.getElementById("resultContainer"); if (resultContainerElement != null) { resultContainerElement.innerHTML = "<b>Output: </b>" + resultText; } xmlHttpRequest = null; I now know that we've broken the back of the problem. We have successfully called a NAV Web service from a web page (which is essentially all a sidebar gadget is). The next tricky bit is to see how to use a page Web service to get the records back that match our documents requiring approval. We'll use the same approach of first writing the code in .NET as a console application and then after we have this working the easy way, we'll convert the code into JavaScript. After that, it's just a case of tidying everything up and making it look pretty. Hey, Good Lookin' If there's one thing you need for a sidebar gadget, it's nice graphics. Vista is a beautiful operating system and, to be honest, if a gadget doesn't look good, we don't want it on our desktop. The idea is to use a single image and position the images on top of each other and create the image by taking a document and flipping it and applying perspective. Here are the document stacks. The images were created using Photoshop (and a lot of professional skill), and the original image that the stack is built from actually has the Microsoft Dynamics NAV logo at the top (how's that for attention to detail?) Here's the image of the document: HTML is used to render these documents as a stack with the number floating over the top, and the HTML to produce the previous image can be found on the www.teachmenav.com site under the Simple Document Stack sample for this article. We would generate the HTML dynamically based upon the number of documents requiring approval. The HTML used to generate the previous image is manipulated to give 12 document stacks that will be used by the application. The largest stack is 10 images high but this would be used to represent 31 or more documents. The question mark on the final empty stack shown in the following image will be used when the gadget gets no response from the Web service or has not been properly configured. Now we have nearly everything we need to be able to put together the sidebar gadget. There's just one piece of the puzzle missing; we need to be able to call a Web service to tell us how many documents we have for approval and also return the details of those documents, the rest is just applying more of what we know and writing a lot of code. We've covered calling a page Web service in an earlier example, so I won't go into details here but we do need to know what we are calling. As you know Web services from NAV can be based on either Codeunits or Pages, so which should we use? The temptation may be to use a Page Web service as this will allow us to bring back the Approval Entry records for the current user, but we need to do far more than read the records. Our first interaction will be to get a count of the records for approval so we can display the gadget; we don't want the gadget to have a lot of work to do in order to draw its initial state, so ideally we want a quick call that will return just the number of documents and maybe the document name. If you remember from the beginning, our gadgets are meant to be simple, single-tasked applications, so we want a single document approval gadget to work for any one document type. This way our users can have multiple gadgets on their desktop if they want to be notified on multiple document types. We can achieve this by using a Codeunit type Web service and have one of the parameters an identifier of the type of document we are interested in. The following is an overview of the functions we will need.
Read more
  • 0
  • 0
  • 4458
Modal Close icon
Modal Close icon