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 - Programming

1081 Articles
article-image-bpel4people
Packt
08 Sep 2010
10 min read
Save for later

BPEL4People

Packt
08 Sep 2010
10 min read
Introduction BPEL4People has been developed to provide extensive support for human interactions in BPEL processes and to standardize the human interactions. Originally, the BPEL4People specification was defined by IBM and SAP. Other companies, such as Oracle, Active Endpoints, and Adobe have also joined. Today, this specification has being advanced within the OASIS BPEL4People Technical Committee. The BPEL4People specification contains two parts: BPEL4People version 1.0, which introduces BPEL extensions to address human interactions in BPEL Web Services Human Task (WS-HumanTask) version 1.0 introduces the definition of human tasks BPEL4People is defined in a way that it is layered on top of the BPEL language. We will now have a brief look at the WS-HumanTask and then at the BPEL4People. Brief look at WS-HumanTask The WS-HumanTask specification introduces Human Tasks to BPEL. Human Tasks are services, implemented by humans. A Human Task has two interfaces. One interface exposes the service offered by the task, like a translation service or an approval service. The second interface allows people to deal with tasks, for example to query for human tasks waiting for them, and to work on these tasks. This is very similar to human tasks in WebSphere, with two main differences—WS-HumanTask standardizes tasks among different vendors, and WS-HumanTask introduces new activities for specifying the properties of human tasks. In WebSphere, we had to use the Integration Developer GUI instead. WS-HumanTask makes a distinction between Human Tasks and notifications. Notifications are a special type of Human Task that allows the sending of information about noteworthy business events to users. Notifications are always delivered one-way. There is no response from notifications expected. Overall structure The overall structure of the human interactions definition is as follows: <?xml version="1.0" encoding="UTF-8"?><htd:humanInteractions targetNamespace="anyURI" expressionLanguage="anyURI"? queryLanguage="anyURI"?> <htd:extensions>? <htd:extension namespace="anyURI" mustUnderstand="yes|no"/>+ </htd:extensions> <htd:import namespace="anyURI"? location="anyURI"? importType="anyURI" />* <htd:logicalPeopleGroups>? <htd:logicalPeopleGroup name="NCName" reference="QName"?>+ <htd:parameter name="NCName" type="QName" />* </htd:logicalPeopleGroup></htd:logicalPeopleGroups><htd:tasks>? <htd:task name="NCName">+ ... </htd:task> </htd:tasks><htd:notifications>? <htd:notification name="NCName">+ ... </htd:notification> </htd:notifications></htd:humanInteractions> Human Tasks The most important is the definition of the Human Task. The definition includes the following: Interface Priority People assignments Delegation Presentation elements Outcome Search priorities Renderings Deadlines (start and competition deadlines) The WS-HumanTask specification foresees the following syntax to define a human task: <htd:task name="NCName"> <htd:interface portType="QName" operation="NCName" responsePortType="QName"? responseOperation="NCName"?/> <htd:priority expressionLanguage="anyURI"?>? integer-expression </htd:priority> <htd:peopleAssignments> ... </htd:peopleAssignments> <htd:delegation potentialDelegatees= "anybody|nobody|potentialOwners|other"/>? <htd:from>? ... </htd:from> </htd:delegation> <htd:presentationElements> ... </htd:presentationElements> <htd:outcome part="NCName" queryLanguage="anyURI">? queryContent </htd:outcome> <htd:searchBy expressionLanguage="anyURI"?>? expression </htd:searchBy> <htd:renderings>? <htd:rendering type="QName">+ ... </htd:rendering> </htd:renderings> <htd:deadlines>? <htd:startDeadline>* ... </htd:startDeadline> <htd:completionDeadline>* ... </htd:completionDeadline> </htd:deadlines> </htd:task> Escalations Within the deadlines, escalations can be defined. An example of defining an escalation is shown as follows: <htd:escalation name="highPrio"> <htd:condition> <![CDATA[ (htd:getInput("OrderRequest")/amount < 1000 && htd:getInput("OrderRequest")/prio <= 10) ]]> </htd:condition> <htd:notification name="ClaimApprovalOverdue"> <htd:interface portType="tns:ClaimsHandlingPT" operation="escalate" /> <htd:peopleAssignments> <htd:recipients> <htd:from logicalPeopleGroup="Manager"> <htd:argument name="region"> htd:getInput("OrderRequest")/region </htd:argument> </htd:from> </htd:recipients> </htd:peopleAssignments> <htd:presentationElements> <htd:name> Order approval overdue. </htd:name> </htd:presentationElements> </htd:notification> </htd:escalation> In a similar way, a reassignment could be done. Notifications Notifications are defined with the following: Interface Priority People assignments Presentation elements Renderings An example is shown as follows: <htd:notification name="NCName"> <htd:interface portType="QName" operation="NCName"/> <htd:priority expressionLanguage="anyURI"?>? integer-expression </htd:priority> <htd:peopleAssignments> <htd:recipients> ... </htd:recipients> <htd:businessAdministrators>? ... </htd:businessAdministrators> </htd:peopleAssignments> <htd:presentationElements> ... </htd:presentationElements> <htd:renderings>? ... </htd:renderings> </htd:notification> Programming interface The WS-HumanTask specification also defines the API for applications that are involved with the life cycle of a human task or a notification. It provides several types of operations, including: Participant operations, such as operation for claiming tasks, starting, stopping, suspending tasks, completing tasks, setting priority, delegating, and so on Simple query operations, such as getMyTasks and getMyTaskAbstracts Advanced query operation, which provides several possibilities for retrieving the tasks Administrative operations for nominating and activating tasks, and setting generic human roles The specification also defined XPath extension functions to retrieve Human Task properties. Now that we are familiar with WS-HumanTask, let us have a brief look at the BPEL4People specification. Brief look at BPEL4People BPEL4People is a BPEL extension, which adds several activities to the BPEL language. The most important extensions introduced in BPEL4People are people activities and people links. People activities are used to define human interactions. For each people activity, the BPEL server must create work items and distribute them to users eligible to execute them. People activities can have input and output variables and can specify deadlines. This is very similar to what we have seen in the WebSphere support for human tasks. To specify the implementation of people activities, BPEL4People introduces tasks. Tasks specify actions that users must perform. Tasks can have descriptions, priorities, deadlines, and other properties. Tasks can be represented in-line, or using WS-HumanTask. To associate people activities and the related tasks with users or groups of users, BPEL4People introduces people links. They associate users with one or more people activities. People links are usually associated with generic human roles, such as process initiator, process stakeholders, owners, and administrators. Overall structure The overall structure of BPEL4People extensions is as follows: <bpel:process ... > ... <bpel:extensions> <bpel:extension namespace="http://www.example.org/BPEL4People" mustUnderstand="yes"/> <bpel:extension namespace="http://www.example.org/WS-HT" mustUnderstand="yes"/> </bpel:extensions> <bpel:import importType="http://www.example.org/WS-HT" …/> <b4p:humanInteractions>? <htd:logicalPeopleGroups>? <htd:logicalPeopleGroup name="NCName">+ ... </htd:logicalPeopleGroup> </htd:logicalPeopleGroups> <htd:tasks>? <htd:task name="NCName">+ ... </htd:task> </htd:tasks> <htd:notifications>? <htd:notification name="NCName">+ ... </htd:notification> </htd:notifications> </b4p:humanInteractions> <b4p:peopleAssignments> ...</b4p:peopleAssignments> ...<bpel:extensionActivity> <b4p:peopleActivity name="NCName" ...> ... </b4p:peopleActivity> </bpel:extensionActivity> ...</bpel:process> Let us have a look at the new elements: The element <b4p:humanInteractions><b4p:/humanInteractions> contains declarations of elements from the WS-HumanTask namespace, such as <htd_logicalpeoplegroups></htd_logicalpeoplegroups>, <htd_tasks></htd_tasks>, and <htd_notifications></htd_notifications>. The element <htd_logicalpeoplegroup></htd_logicalpeoplegroup> specifies a logical people group used in an inline human task or a people activity. The <htd_task></htd_task> element is used to provide the definition of an inline human task. The <htd_notification></htd_notification> element is used to provide the definition of an inline notification. The element <b4p_peopleassignments></b4p_peopleassignments> is used to assign people to process-related generic human roles. The new activity <b4p_peopleactivity></b4p_peopleactivity> is used to model human interactions within BPEL processes. People assignments BPEL4People defines generic human roles. These roles define what a person or a group of people can do with the process instance. The specification defines three process-related generic human roles: Process initiator: Person that triggered the process instance Process stakeholders: People who can influence the progress of a process instance, for example, by adding ad-hoc attachments, forwarding a task, or simply observing the progress of the process instance Business administrators: People allowed to perform administrative actions on the business process instances The syntax of people assignments looks like this: <b4p:peopleAssignments> <b4p:processInitiator>? <htd:from ...> ... </htd:from> </b4p:processInitiator> <b4p:processStakeholders>? <htd:from ...> ... </htd:from> </b4p:processStakeholders> <b4p:businessAdministrators>? <htd:from ...> ... </htd:from> </b4p:businessAdministrators> </b4p:peopleAssignments> People activities People activities are used to integrate human interactions within BPEL processes. A people activity can be integrated with an inline Human Task or with a standalone Human Task. An inline task can be defined as part of a people activity. A standalone Human Task is defined separately and can be used several times. To specify Human Tasks, we use the WS-HumanTask specification. The overall syntax is as follows: <b4p:peopleActivity name="NCName" inputVariable="NCName"? outputVariable="NCName"? isSkipable="xsd:boolean"? standard-attributes> standard-elements ( <htd:task>...</htd:task> | <b4p:localTask>...</b4p:localTask> | <b4p:remoteTask>...</b4p:remoteTask> | <htd:notification>...</htd:notification> | <b4p:localNotification>...</b4p:localNotification> | <b4p:remoteNotification>...</b4p:remoteNotification> ) <b4p:scheduledActions>? ... </b4p:scheduledActions> <bpel:toParts>? <bpel:toPart part="NCName" fromVariable="BPELVariableName"/>+ </bpel:toParts> <bpel:fromPart part="NCName" toVariable="BPELVariableName"/>+ <bpel:fromPart>? </bpel:fromParts> <b4p:attachmentPropagation fromProcess="all|none" toProcess="all|newOnly|none"/>? </b4p:peopleActivity> Summary In this article, we have covered the BPEL4People and WS-HumanTask specifications. These specifications have standardized the approach to BPEL human interactions and made it portable through different SOA process servers. We have overviewed both specifications and have seen that there are no major conceptual differences between the current Oracle support and the approach taken in specifications. At the time of writing, it has not been clear how much support these specifications will get from SOA platform vendors. Further resources on this subject: Human Interactions in BPEL [Article] Business Processes with BPEL [Article] Web Services, SOA, and WS-BPEL Technologies [Article] SOA—Service Oriented Architecture [Article] Oracle Web Services Manager: Authentication and Authorization [Article]
Read more
  • 0
  • 0
  • 1942

article-image-load-testing-using-visual-studio-2008-part-2
Packt
01 Oct 2009
9 min read
Save for later

Load Testing Using Visual Studio 2008: Part 2

Packt
01 Oct 2009
9 min read
Editing load tests The load can contain one or more scenarios for testing. The scenarios can be edited any time during the design. To edit a scenario, select the scenario you want to edit and right-click to edit the test mix, browser mix, or network mix in the existing scenario or add a new scenario to the load test. The context menu has different options for editing as shown here: The Add Scenario... will open the same wizard, which we used before adding the scenario to the load test. We can keep adding the scenarios as much as we need. The scenario properties window also helps us modify some properties such as the Think Profile and the Think Time Between Test Iteration and the scenario Name. The Add Tests... option is used for adding more tests to the test mix from the tests list in the project. We can add as many tests as required to be part of the test mix. The Edit Test Mix... option is used for editing the test mix in the selected scenario. This option will open a dialog with the selected tests and distribution. Using this Edit Test Mix window we can: Change the test mix model listed in the drop–down. Add new tests to the list and modify the distribution percentage. Select an initial test that executes before other tests for each virtual server. The browse option next to it opens a dialog showing all the tests from the project from which we can select the initial test. Similar to the initial test, we can choose a test which is the final test to run during the test execution. The same option is used here to select the test from the list of available tests. The Edit Browser Mix... option opens the Edit Browser Mix dialog from where you can select the new browser to be included to the browser mix and delete or change the existing browsers selected in the mix. The Edit Network Mix... option opens the Edit Network Mix dialog from where you can add new browsers to the list and modify the distribution percentages. We can change or delete the existing network mix. For changing the existing load pattern, select the Load Pattern under the Scenarios and open the Properties window which shows the current patterns properties. You can change or choose any pattern from the available patterns in the list as shown in the following screenshots: The Run Settings can be multiple for the load tests, but at any time only one can be active. To make the run settings active, select Run Settings, right-click and select Set as Active. The properties of the run settings can be modified directly using the properties window. The properties that can be modified include results storage, SQL tracing, test iterations, timings, and the web test connections. Adding context parameters The web tests can have context parameters added to them. The context parameter is used in place of the common values of multiple requests in the web test. For example, every request has the same web server name, which can be replaced by the context parameters. So whenever the web server changes, we can just change the context parameter value, which replaces all the requests with the new server name. We know that the load test can have web tests and unit tests in the list. If there is a change in the web server for the load test other than what we used for web tests then we will end up modifying the context parameter values in all the web tests used in the load tests. Instead of this, we can include another context parameter in the load test with the same name used in the web tests. The context parameter added to the load test will override the same context parameter used in the web tests. To add new context parameter to the load test, select the Run Settings and right-click to choose the Add Context Parameter option, which adds a new context parameter. For example, the context parameter used in the web test has the web server value as this.Context.Add("WebServer1", "http://localhost:49459"); Now to overwrite this in load tests, add a new context parameter with the same name as shown below: Results store All information collected during the load test run is stored in the central result store. The load test results store contains the data collected by the performance counters and the violation information and errors that occurred during the load test. The result store is the SQL server database created using the script loadtestresultsrepository.sql, which contains all the SQL queries to create the objects required for the result store. If there are no controllers involved in the test and if it is the local test, we can create the results store sql database using SQL Express. Running the script creates the store using SQL Express. Running this script once on the local machine is enough for creating the result store. This is a global central store for all the load tests in the local machine. To create the store, open the visual studio command prompt and run the command with the actual drive where you have installed the visual studio. cd c:Program FilesMicrosoft Visual Studio 9.0Common7IDE In the same folder, run the following command which creates the database store SQLCMD /S localhostsqlexpress /i loadtestresultsrepository.sql If you have any other SQL Server and if you want to use that to have the result store then you can run the script on that server and use that server in connection parameters for the load test. For example, if you have the SQL Server name as SQLServer1 and if the result store has to be created in that store, then run the command as below: SQLCMD /S SQLServer1 -U <user name> -P <password> -iloadtestresultsrepository.sql All these commands create the result store database in the SQL Server. If you look at the tables created in the store, it would look like this: If you are using a controller for the load tests, the installation of the controller itself takes care of creating the results store on the controller machine. The controller can be installed using the Visual Studio 2008 Team Test Load agent Product. To connect to the SQL Server result store database, select the Test option from the Visual Studio IDE and then select the Administer Test Controller window. This option would be available only in the controller machine. If the result store is on a different machine or the controller machine, select the controller from the list or select <Local-No controller>, if it is in the local machine without any controller. Then select the Load Test Results store using the browse button and close the Administer test Controller window. The controllers are used for administering the agent computers and these controller and agents form the rig. Multiple agents are required to simulate a large number of loads from different locations. All the performance data collected from all these agents are saved at the central result store at the controller or any global store configured at the controller. Running the load test Load tests are run like any other test in Visual Studio. Visual Studio also provides multiple options for running the load test. One is through the Test View window where all the tests are listed. We can select the load test, right-click and choose the option Run Selection option, which starts the load tests to run. The second option is to use the Test List Editor. Select the load test from the test list in the test lists editor and choose the option to run the selected tests from the test list editor toolbar. The third option is the built-in run option in the load test editor toolbar. Select the load test from the project and open the load test. This opens the load test in the load test editor. The toolbar for this load test editor has the option to run the currently opened load test. The fourth option is through the command line command. MS Test command line utility is used for running the test. This utility is installed along with the Visual Studio Team System for Test. Open the Visual Studio command prompt. From the folder where the load test resides, run the following command to start the load test mstest /testcontainer:LoadTest1.loadtest In all the above cases, the load test editor will show the progress during the test run. But the other option does not show the progress instead stores the result to the result store repository. It can be loaded later to see the test result and analyze it. You can follow these steps to open the last run tests: Open the menu option Test | Windows | Test Runs. From the Connect drop-down, select the location for the test results store. On selecting this, you can see the trace files of the last run tests getting loaded in the window. Select the test run name from the list and double-click to open the test results for the selected run. Double-click the test result shown in the Results window that connects to the store repository, fetches the data for the selected test result, and presents in the load test window. The end result of the load test editor window will look like the one shown in the following screenshot with all the performance counter values and the violation points. More details about the graph are given under the Graphical View subsection.
Read more
  • 0
  • 0
  • 1938

article-image-animation-silverlight-4
Packt
20 Apr 2010
8 min read
Save for later

Animation in Silverlight 4

Packt
20 Apr 2010
8 min read
Silverlight sports a rich animation system that is surprisingly easy to use. The animation model in Silverlight is time based, meaning that movements occur based on a set timeline. At the heart of every animation is a StoryBoard, which contains all the animation data and independent timeline. Silverlight controls can contain any number of Storyboards. StoryBoards contain one or more Key frame elements, which are responsible for making objects on screen change position, color, or any number of properties. There are four general types of Key frames in Silverlight 4: Linear, Discrete, Spline, and Easing. The table below illustrates what each one does: Very different than Flash The animation model in Silverlight is markedly different than the one found in Adobe Flash. Animations in Flash are frame-based, whereas in Silverlight they are time-based. The term StoryBoard comes from the motion picture industry, where scenes are drawn out before they are filmed. Time for action – animation time The client would like to transform their text-only logo into something a little more elaborate. The designers have once again given us a XAML snippet of code exported from their graphic design tool. We will need to do the following: Open up the CakeORama logo project in Blend. Blend should have automatically loaded the MainControl.xaml file and your screen should look like this: In the Objects and Timeline tab, you'll see a list of objects that make up this vector drawing. There is Path object for every character. Let's add an animation. On the Object and Timeline tab, click the plus sign (+) to create a new StoryBoard. In the Create Storyboard Resource dialog, type introAnimationStoryboard into the text box and click OK. You'll notice a couple of changes to your screen. For one, the art board is surrounded by a red border and a notification that: intoAnimationStoryboard timeline recording is on just like in this screenshot: If you take a look at the Objects and Timeline tab, you'll see the timeline for our newly created introAnimationStoryboard: Let's add a key frame at the very beginning. The vertical yellow line is the play head, which marks where you currently are in the timeline. Select the canvas1 object. You can switch to the Animation Workspace in Blend by pressing F6. Click on the square icon with a green plus sign to create a new Key frame here at position 0. A white oval appears representing the Key frame that you just created. It should look similar to the following screenshot: Move the play head to 0.7 seconds, by clicking on the tick mark to the immediate left of the number 1. Click the same button you did in step 9 to create a new key frame here so that your timeline looks like this: Move the play head back to zero. Make sure the canvas1 object is still selected, click and drag the logo graphic up, so that all of it is in the grey area. This moves the logo "off stage". Hit the play button highlighted in the below screenshot, to preview the animation and enjoy the show! Now all we need to do is tell Silverlight to run the animation when our control loads, but first we need to get out of recording mode. To do this, click the x button on the Objects and Timeline tab. Click on [UserControl] in the Objects and Timeline tab. On the Properties tab, you'll see an icon with a lightning bolt on it. Click on it to see the events associated with a UserControl object: To wire up an event handler for the Loaded event, type UserControl_Loaded in the text box next to Loaded, as shown in the next screenshot: Once you hit Enter, the code behind will immediately pop up with your cursor inside the event handler method. Add this line of code to the method: introAnimationStoryboard.Begin(); Run the solution via the menu bar or by pressing F5. You should see the logo graphic smoothly and evenly animate into view. If for some reason the animation doesn't get displayed, refresh the page in your browser. You should see it now. What just happened? You just created your first animation in Silverlight. First you created a Storyboard and then added a couple of Key frames. You changed the properties of the canvas on one key frame and Silverlight automatically interpolated them in between points to create a nice smooth animation. If your animation didn't show up on the initial page load but did when you reloaded the page, then you've just experienced how seriously the Silverlight animation engine respects time. Since our animation length is relatively short (0.7 seconds) it's possible that more than that amount of time elapsed from the call of the Begin method, to the amount of time it took for your computer to render it. Silverlight noticed that and "jumped" ahead to that part of the timeline to keep everything on schedule. Just like we did before, let's take a look at the XAML to get a better feel of what's really going on. You'll find the Storyboard XAML in the UserControl.Resources section towards the top of the document. Don't worry if the values are slightly different in your project: <Storyboard x_Name="introAnimationStoryboard"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="canvas1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"><EasingDoubleKeyFrame KeyTime="00:00:00" Value="-229"/><EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="0"/> </DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="canvas1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/><EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="0"/> </DoubleAnimationUsingKeyFrames></Storyboard> There are a couple of things going on here, so let's dissect the animation XAML starting with the Storyboard declaration which creates a Storyboard and assigns the name we gave it in the dialog box: <Storyboard x_Name="introAnimationStoryboard"> That's easy enough, but what about the next node? This line tells the Storyboard that we will be modifying a Double value starting at 0 seconds. It also further specifies a target for our animation: canvas1 and a property on our target: <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="canvas1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"> Clear enough, but what does the TargetProperty value mean? Here is that value highlight below. (UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y) We know that the net effect of the animation is that the logo moves from above the visible area back to its original position. If we're familiar with X, Y coordinates, where X represents a horizontal coordinate and Y a vertical coordinate, then the TranslateTransform.Y part makes sense. We are changing or, in Silverlight terms, transforming the Y property of the canvas. But what's all this TransformGroup about? Take a look at our canvas1 node further down in the XAML. You should see the following lines of XAML that weren't there earlier: <Canvas.RenderTransform> <TransformGroup> <ScaleTransform /> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup></Canvas.RenderTransform> Blend automatically inserted them into the Canvas when we created the animation. They have no properties. Think of them as stubbed declarations of these objects. If you remove them, Silverlight will throw an exception at runtime like the one below complaining about not being able to resolve TargetProperty: Clearly this code is important, but what's really going on here? The TranslateTransform object is a type of Transform object which determines how an object can change in Silverlight. They are packaged in a TransformGroup, which can be set in the RenderTransform property on any object descending from UIElement, which is the base class for any kind of visual element. With that bit of knowledge, we now see that (TransformGroup.Children)[3] refers to the fourth element in a zero-based collection. Not so coincidentally, the TranslateTransform node is the fourth item inside the TransformGroup in our XAML. Changing the order of the transforms in the XAML will also cause an exception at runtime. That line of XAML just tells the Silverlight runtime that we're going to animation, now we tell it how and when with our two EasingDoubleKeyFrame nodes: <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-229"/><EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="0"/> The first EasingDoubleKeyFrame node tells Silverlight that, at zero seconds, we want the value to be -229. This corresponds to when the logo was above the visible area. The second EasingDoubleKeyFrame node tells Silverlight that at 0.7 seconds, we want the value of the property to be 0. This corresponds to the initial state of the logo, where it was before any transformations were applied. Silverlight handles all changes to the value in between the start and the end point. Silverlight's default frame rate is 60 frames per second, but Silverlight will adjust its frame rate based on the hardware that it is running on. Silverlight can adjust the amount by which it changes the values to keep the animation on schedule. If you had to reload the web page to see the animation run, then you've already experienced this. Once again, notice how few lines (technically only one line) of procedural code you had to write.
Read more
  • 0
  • 0
  • 1938

Packt
21 Oct 2009
6 min read
Save for later

Binding Web Services in ESB—Web Services Gateway

Packt
21 Oct 2009
6 min read
Web Services Web services separate out the service contract from the service interface. This feature is one of the many characteristic required for an SOA-based architecture. Thus, even though it is not mandatory that we use the web service to implement an SOA-based architecture, yet it is clearly a great enabler for SOA. Web services are hardware, platform, and technology neutral The producers and/or consumers can be swapped without notifying the other party, yet the information can flow seamlessly. An ESB can play a vital role to provide this separation. Binding Web Services A web service's contract is specified by its WSDL and it gives the endpoint details to access the service. When we bind the web service again to an ESB, the result will be a different endpoint, which we can advertise to the consumer. When we do so, it is very critical that we don't lose any information from the original web service contract. Why Another Indirection? There can be multiple reasons for why we require another level of indirection between the consumer and the provider of a web service, by binding at an ESB. Systems exist today to support business operations as defined by the business processes. If a system doesn't support a business process of an enterprise, that system is of little use. Business processes are never static. If they remain static then there is no growth or innovation, and it is doomed to fail. Hence, systems or services should facilitate agile business processes. The good architecture and design practices will help to build "services to last" but that doesn't mean our business processes should be stable. Instead, business processes will evolve by leveraging the existing services. Thus, we need a process workbench to assemble and orchestrate services with which we can "Mix and Match" the services. ESB is one of the architectural topologies where we can do the mix and match of services. To do this, we first bind the existing (and long lasting) services to the ESB. Then leverage the ESB services, such as aggregation and translation, to mix and match them and advertise new processes for businesses to use. Moreover, there are cross service concerns such as versioning, management, and monitoring, which we need to take care to implement the SOA at higher levels of maturity. The ESB is again one way to do these aspects of service orientation. HTTP HTTP is the World Wide Web (www) protocol for information exchange. HTTP is based on character-oriented streams and is firewall-friendly. Hence, we can also exchange XML streams (which are XML encoded character streams) over HTTP. In a web service we exchange XML in the SOAP (Simple Object Access Protocol) format over HTTP. Hence, the HTTP headers exchanged will be slightly different than a normal web page interaction. A sample web service request header is shown as follows: GET /AxisEndToEnd/services/HelloWebService?WSDL HTTP/1.1User-Agent: Java/1.6.0-rcHost: localhost:8080Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2Connection: keep-alivePOST /AxisEndToEnd/services/HelloWebService HTTP/1.0Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Host: localhost:8080Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 507 The first line contains a method, a URI and an HTTP version, each separated by one or more blank spaces. The succeeding lines contain more information regarding the web service exchanged. ESB-based integration heavily leverages the HTTP protocol due to its open nature, maturity, and acceptability. We will now look at the support provided by the ServiceMix in using HTTP. ServiceMix's servicemix-http Binding external web services at the ESB layer can be done in multiple ways but the best way is to leverage JBI components such as the servicemix-http component within ServiceMix. We will look in detail at how to bind the web services onto the JBI bus. servicemix-http in Detail servicemix-http is used for HTTP or SOAP binding of services and components into the ServiceMix NMR. For this ServiceMix uses an embedded HTTP server based on the Jetty. The following are the two ServiceMix components: org.apache.servicemix.components.http.HttpInvoker org.apache.servicemix.components.http.HttpConnector As of today, these components are deprecated and the functionality is replaced by the servicemix-http standard JBI component. A few of the features of the servicemix-http are as follows: Supports SOAP 1.1 and 1.2 Supports MIME with attachments Supports SSL Supports WS-Addressing and WS-Security Supports WSDL-based and XBean-based deployments Support for all MEPs as consumers or providers Since servicemix-http can function both as a consumer and a provider, it can effectively replace the previous HttpInvoker and HttpConnector component. Consumer and Provider Roles When we speak of the Consumer and Provider roles for the ServiceMix components, the difference is very subtle at first sight, but very important from a programmer perspective. The following figure shows the Consumer and Provider roles in the ServiceMix ESB: The above figure shows two instances of servicemix-http deployed in the ServiceMix ESB, one in a provider role and the other in the consumer role. As it is evident, these roles are with respect to the NMR of the ESB. In other words, a consumer role implies that the component is a consumer to the NMR whereas a provider role implies the NMR is the consumer to the component. Based on these roles, the NMR will take responsibility of any format or protocol conversions for the interacting components. Let us also introduce two more parties here to make the role of a consumer and a provider clear—a client and a service. In a traditional programming paradigm, the client interacts directly with the server (or service) to avail the functionality. In the ESB model, both the client and the service interact with each other only through the ESB. Hence, the client and the service need peers with their respective roles assigned, which in turn will interact with each other. Thus, the ESB consumer and provider roles can be regarded as the peer roles for the client and the service respectively. Any client request will be delegated to the consumer peer who in turn interacts with the NMR. This is because the client is unaware of the ESB and the NMR protocol or format. However, the servicemix-http consumer knows how to interact with the NMR. Hence any request from the client will be translated by the servicemix-http consumer and delivered to the NMR. On the service side also, the NMR needs to invoke the service. But the server service is neutral of any specific vendor's NMR and doesn't understand the NMR language as such. A peer provider role will help here. The provider receives the request from the NMR, translates it into the actual format or protocol of the server service and invokes the service. Any response will also follow the reverse sequence.
Read more
  • 0
  • 0
  • 1936

article-image-configuration
Packt
21 Jul 2014
12 min read
Save for later

Configuration

Packt
21 Jul 2014
12 min read
(For more resources related to this topic, see here.) Configuration targets In this section, we look at the different layers that can be configured. The layers are: SYSTEM: This layer is system-wide and found in /etc/gitconfig GLOBAL: This layer is global for the user and found in ~/.gitconfig LOCAL: This layer is local to the current repository and found in .git/config Getting ready We will use the jgit repository for this example, as shown in the following command: $ git clone https://git.eclipse.org/r/jgit/jgit $ cd jgit How to do it... In the previous example, we saw how we could use the command git config --list to list configuration entries. This list is actually made from three different levels of configuration that Git offers: system-wide configuration, SYSTEM; global configuration for the user, GLOBAL; and local repository configuration, LOCAL. For each of these configuration layers, we can query the existing configuration. On a Windows box with a default installation of the Git extensions, the different configuration layers will look approximately like the following: $ git config --list --system core.symlinks=false core.autocrlf=true color.diff=auto color.status=auto color.branch=auto color.interactive=true pack.packsizelimit=2g help.format=html http.sslcainfo=/bin/curl-ca-bundle.crt sendemail.smtpserver=/bin/msmtp.exe diff.astextplain.textconv=astextplain rebase.autosquash=true $ git config --list --global merge.tool=kdiff3 mergetool.kdiff3.path=C:/Program Files (x86)/KDiff3/kdiff3.exe diff.guitool=kdiff3 difftool.kdiff3.path=C:/Program Files (x86)/KDiff3/kdiff3.exe core.editor="C:/Program Files (x86)/GitExtensions/GitExtensions.exe" fileeditor core.autocrlf=true credential.helper=!"C:/Program Files (x86)/GitExtensions/GitCredentialWinStore/git-credential-winst ore.exe" user.name=Aske Olsson user.email=aske.olsson@switch-gears.dk $ git config --list --local core.repositoryformatversion=0 core.filemode=false core.bare=false core.logallrefupdates=true core.symlinks=false core.ignorecase=true core.hidedotfiles=dotGitOnly remote.origin.url=https://git.eclipse.org/r/jgit/jgit remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* branch.master.remote=origin branch.master.merge=refs/heads/master We can also query a single key and limit the scope to one of the three layers, by using the following command: $ git config --global user.email aske.olsson@switch-gears.dk We can set the e-mail address of the user to a different one for the current repository: $ git config --local user.email aske@switch-gears.dk Now, listing the GLOBAL layer user.email will return aske.olsson@switch-gears.dk, listing LOCAL gives aske@switch-gears.dk, and listing user.email without specifying the layer gives the effective value that is used in the operations on this repository, in this case, the LOCAL value aske@switch-gears.dk. The effective value is the value, which takes precedence when needed. When two or more values are specified for the same key, but on different layers, the lowest layer takes precedence. When a configuration value is needed, Git will first look in the LOCAL configuration. If not found here, the GLOBAL configuration is queried. If it is not found in the GLOBAL configuration, the SYSTEM configuration is used. If none of this works, the default value in Git is used. In the previous example, user.email is specified in both the GLOBAL and LOCAL layers. Hence, the LOCAL layer will be used. How it works... Querying the three layers of configuration simply returns the content of the configuration files: /etc/gitconfig for system-wide configuration, ~/.gitconfig for user-specific configuration, and .git/config for repository-specific configuration. When not specifying the configuration layer, the returned value will be the effective value. There's more... Instead of setting all the configuration values on the command line by the key value, it is possible to set them by just editing the configuration file directly. Open the configuration file in your favorite editor and set the configuration you need, or use the built-in git config -e repository to edit the configuration directly in the Git-configured editor. You can set the editor to the editor of your choice either by changing the $EDITOR environment variable or with the core.editor configuration target, for example: $ git config --global core.editor vim Querying the existing configuration In this example, we will look at how we can query the existing configuration and set the configuration values. Getting ready We'll use jgit again by using the following command: $ cd jgit How to do it... To view all the effective configurations for the current Git repository, run the following command: $ git config --list user.name=Aske Olsson user.email=askeolsson@switch-gears.dk core.repositoryformatversion=0 core.filemode=false core.bare=false core.logallrefupdates=true remote.origin.url=https://git.eclipse.org/r/jgit/jgit remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* branch.master.remote=origin branch.master.merge=refs/heads/master The previous output will of course reflect the user running the command. Instead of Aske Olsson as the name and the e-mail, the output should reflect your settings. If we are just interested in a single configuration item, we can just query it by its section.key or section.subsection.key: $ git config user.name Aske Olsson $ git config remote.origin.url https://git.eclipse.org/r/jgit/jgit How it works... Git's configuration is stored in plaintext files, and works like a key-value storage. You can set/query by key and get the value back. An example of the text-based configuration file is shown as follows (from the jgit repository): $ cat .git/config [core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true [remote "origin"] url = https://git.eclipse.org/r/jgit/jgit fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master There's more... It is also easy to set configuration values. Just use the same syntax as when querying the configuration except add an argument to the value. To set a new e-mail address on the LOCAL layer, we can execute the following command line: git config user.email askeolsson@example.com The LOCAL layer is the default if nothing else is specified. If you require whitespaces in the value, you can enclose the string in quotation marks, as you would do when configuring your name: git config user.name "Aske Olsson" You can even set your own configuration, which does not have any effect on the core Git, but can be useful for scripting/builds and so on: $ git config my.own.config "Whatever I need" List the value $ git config my.own.config Whatever I need It is also very easy to delete/unset configuration entries: $ git config --unset my.own.config List the value $ git config my.own.config Templates In this example, we will see how to create a template commit message that will be displayed in the editor when creating a commit. The template is only for the local user and not distributed with the repository in general. Getting ready In this example, we will use the example repository: $ git clone https://github.com/dvaske/data-model.git $ cd data-model We'll use the following code as a commit message template for commit messages: Short description of commit Longer explanation of the motivation for the change Fixes-Bug: Enter bug-id or delete line Implements-Requirement: Enter requirement-id or delete line Save the commit message template in $HOME/.gitcommitmsg.txt. The filename isn't fixed and you can choose a filename of your liking. How to do it... To let Git know about our new commit message template, we can set the configuration variable commit.template to point at the file we just created with that template; we'll do it globally so it is applicable to all our repositories: $ git config --global commit.template $HOME/.gitcommitmsg.txt Now, we can try to change a file, add it, and create a commit. This will bring up our preferred editor with the commit message template preloaded: $ git commit Short description of commit Longer explanation of the motivation for the change Fixes-Bug: Enter bug-id or delete line Implements-Requirement: Enter requirement-id or delete line # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: another-file.txt # ~ ~ ".git/COMMIT_EDITMSG" 13 lines, 396 characters We can now edit the message according to our commit and save to complete the commit. How it works... When commit.template is set, Git simply uses the content of the template file as a starting point for all commit messages. This is quite convenient if you have a commit-message policy as it greatly increases the chances of the policy being followed. You can even have different templates tied to different repositories, since you can just set the configuration at the local level. A .git directory template Sometimes, having a global configuration isn't enough. You will also need to trigger the execution of scripts (aka Git hooks), exclude files, and so on. It is possible to achieve this with the template option set to git init. It can be given as a command-line option to git clone and git init, or as the $GIT_TEMPLATE_DIR environment variable, or as the configuration option init.templatedir. It defaults to /usr/share/git-core/templates. The template option works by copying files in the template directory to the .git ($GIT_DIR) folder after it has been created. The default directory contains sample hooks and some suggested exclude patterns. In the following example, we'll see how we can set up a new template directory, and add a commit message hook and exclude file. Getting ready First, we will create the template directory. We can use any name we want, and we'll use ~/.git_template, as shown in the following command: $ mkdir ~/.git_template Now, we need to populate the directory with some template files. This could be a hook or an exclude file. We will create one hook file and an exclude file. The hook file is located in .git/hooks/name-of-hook and the exclude file in .git/info/exclude. Create the two directories needed hooks and info, as shown in the following command: $ mkdir ~/.git_template/{hooks,info} To keep the sample hooks provided by the default template directory (the Git installation), we copy the files in the default template directory to the new one. When we use our newly created template directory, we'll override the default one. So, copying the default files to our template directory will make sure that except for our specific changes the template directory is similar to the default one, as shown in the following command: $ cd ~/.git_template/hooks $ cp /usr/share/git-core/templates/hooks/* . We'll use the commit-msg hook as the example hook: #!/bin/sh MSG_FILE="$1" echo "nHi from the template commit-msg hook" >> $MSG_FILE The hook is very simple and will just add Hi from the template commit-msg hook to the end of the commit message. Save it as commit-msg in the ~/.git_template/hooks directory and make it executable by using the following command: chmod +x ~/.git_template/hooks/commit-msg Now that the commit message hook is done, let's also add an exclude file to the example. The exclude file works like the .gitignore file, but is not tracked in the repository. We'll create an exclude file that excludes all the *.txt files, as follows: $ echo *.txt > ~/.git_template/info/exclude Now, our template directory is ready for use. How to do it... Our template directory is ready and we can use it, as described earlier, as a command-line option, an environment variable or, as in this example, to be set as a configuration: $ git config --global init.templatedir ~/.git_template Now, all Git repositories we create using init or clone will have the default files of the template directory. We can test if it works by creating a new repository as follows: $ git init template-example $ cd template-example Let's try to create a .txt file and see what git status tells us. It should be ignored by the exclude file from the template directory: $ echo "this is the readme file" > README.txt $ git status The exclude file worked! You can put in the file endings yourself or just leave it blank and keep to the .gitignore files. To test if the commit-msg hook also works, let us try to create a commit. First, we need a file to commit. So, let's create that and commit it as follows: $ echo "something to commit" > somefile $ git add somefile $ git commit –m "Committed something" We can now check the history with git log: $ git log -1 commit 1f7d63d7e08e96dda3da63eadc17f35132d24064 Author: Aske Olsson <aske.olsson@switch-gears.dk> Date: Mon Jan 6 20:14:21 2014 +0100 Committed something Hi from the template commit-msg hook How it works... When Git creates a new repository, either via init or clone, it will copy the files from the template directory to the new repository when creating the directory structure. The template directory can be defined either by a command-line argument, environment variable, or configuration option. If nothing is specified, the default template directory will be used (distributed with the Git installation). By setting the configuration as a --global option, the template directory defined will apply to all of the user's (new) repositories. This is a very nice way to distribute the same hooks across repositories, but it also has some drawbacks. As the files in the template directory are only copied to the Git repositories, updates to the template directory do not affect the existing repositories. This can be solved by running git init in each existing repository to reinitialize the repository, but this can be quite cumbersome. Also, the template directory can enforce hooks on some repositories where you don't want them. This is quite easily solved by simply deleting the hook files in .git/hooks of that repository.
Read more
  • 0
  • 0
  • 1929

article-image-interface
Packt
09 Mar 2017
18 min read
Save for later

The Interface

Packt
09 Mar 2017
18 min read
In this article by Tim Woodruff, authors of the book Learning ServiceNow, No matter what software system you're interested in learning about, understanding the interface is likely to be the first step toward success. ServiceNow is a very robust IT service management tool, and has an interface to match. Designed both to be easy to use, and to support a multitude of business processes and applications (both foreseen and unforeseen), it must be able to bend to the will of the business, and be putty in the hands of a capable developer. (For more resources related to this topic, see here.) You'll learn all the major components of the UI (user interface), and how to manipulate them to suit your business needs, and look good doing it. You'll also learn some time-saving tips, tricks, and UI shortcuts that have been built into the interface for power users to get around more quickly. This article will cover the key components of the user interface, including: The content and ServiceNow frames The application navigator UI settings and personalization We recommend that you follow along in your own development instance as you read through this section, to gain a more intimate familiarity with the interface. Frames ServiceNow is a cloud platform that runs inside your browser window. Within your browser, the ServiceNow interface is broken up into frames. Frames, in web parlance, are just separately divided sections of a page. In ServiceNow, there are two main frames: the ServiceNow frame, and the content frame.  Both have different controls and display different information. This section will show you what the different frames are, what they generally contain, and the major UI elements within them. The ServiceNow frame consists of many UI elements spanning across both the top, and left side of the ServiceNow window in your browser. ServiceNow frame Technically, the ServiceNow frame can be further broken up into two frames: The banner frame along the top edge of the interface, and the application navigator along the left side. Banner frame The banner frame runs along the top of every page in ServiceNow, save for a few exceptions. It's got room for some branding and a logo, but the more functional components for administrators and developers is on the right. There, you'll find: System settings cog Help and documentation button Conversations panel button Instance search button Profile/session dropdown System settings In your developer instance, on the far-top-right, you will see a sort of cog or sprocket. That is a universal sort of the Settings menu icon. Clicking on that icon reveals the System settings menu. This menu is broken down into several sections: General Theme Lists Forms Notifications Developer (Admins only) Fig 1.1: System Settings The settings in this menu generally apply only to the current user who's signed in, so you can freely toggle and modify these settings without worrying about breaking anything. In the General tab (as seen in the preceding figure) of the System settings UI, you'll find toggles to control accessibility options, compact the user interface, select how date/time fields are shown, select your time-zone, and even an option to display a printer-friendly version of the page you're on. In Geneva, you'll also see an option to Wrap Longer Text in List Columns and Compact list date/time. On the Theme tab (in the preceding figure), you'll find several pre-made ServiceNow themes with names like System and Blues. One of the first things that a company often does when deploying ServiceNow, is to create a custom-branded theme. We'll go over how to do that in a later section, and you'll be able to see your custom themes there. The Lists tab (not available in Geneva) contains the option to wrap longer text in list columns (which was under the General tab in Geneva), as well as options to enable striped table rows (which alternates rows in a table between contrasting shades of gray, making it easier to follow with the eye from left to right) and modern cell styles. All options in the Lists tab except Wrap longer text in list columns require the List V3 plugin to be enabled before they'll show up, as they only apply to List V3. If you've installed a fresh ServiceNow instance using Helsinki or a later version, the List V3 plugin will be enabled by default. However, if you've upgraded from Geneva or an earlier version, to Helsinki, you'll be on List V2 by default, and list V3 will need to be enabled. This, and any other plugins, can be enabled from System Definition | Plugins in the application navigator. The Forms tab contains settings to enable tabbed forms, as well as to control how and when related lists load. Related lists are lists (like tables in a spreadsheet) of related that appear at the bottom of forms. Forms are where key data about an individual record are displayed. The Notifications tab (not available in Geneva) allows you to choose whether to get notifications on your mobile device, desktop toast notifications, e-mail notifications, or audio notifications. Finally, the Developer tab (only available to users with the admin role) is where you can find settings relating to application and update set-based development. By default, your selected update set should say Default [Global], which means that any configuration changes you make in the instance will not be captured in a portable update set that you can move between instances. We'll go into detail about what these things mean later on. For now, follow along with the following steps in your developer instance using your Administrator account, as we create a new update set to contain any configuration changes we'll be making in this article: If you don't already have the System Settings menu open, click on the System Settings gear in the top-right of the ServiceNow interface. If you haven't already done so, click on the Developer tab on the bottom-left. Next, navigate to the Local Update Setstable. In the main section of the System Settings dialog, you should see the third row down labeled Update Sets. To the right of that should be a dropdown with Default [Global] selected, followed by three buttons. The first button () is called a Reference icon. Clicking it will take you to the currently selected update set (in this case, Default). The second button () will take you to the list view, showing you all of the local update sets. The third button will refresh the currently selected update set, in case you've changed update sets in another window or tab. Click on the second button, to navigate to the Local Update Sets list view. Click on the blue New button at the top-left of the page to go to the new update set form. Give this update set a name. Let's enter Article 1 into the Name field. Fill out the Description by writing in something like Learning about the ServiceNow interface! Leave State and Release date to their default values. Click Submit and Make Current. Alternately, you could click Submitor right-click the header and click Save, then return to the record and click the Make This My Current Set related link. Now that we've created an update set, any configuration changes we make will be captured and stored in a nice little package that we can back out or move into another instance to deploy the same changes. Now let's just confirm that we've got the right update set selected: Once again, click on the System Settings gear at the top-right of the ServiceNow window, and open the Developer tab. If the selected update set still shows as Default, click the Refresh button (the third icon to the right of the selected update set). If the update set still shows as Default, just select your new Article1 update set from the Update Set drop-down list. Help Next on the right side of the banner frame, is the Help icon. Clicking on this icon opens up the Help panel on the right side of the page. The Help menu has three sections: What's New, User Guide, and Search Documentation. Or, if you're in Geneva, it shows only What's New and Search Product Documentation. Clicking What's New just brings up the introduction to your instance version, with a couple of examples of the more prominent new features over the previous version. The User Guidewill redirect you to an internal mini-guide with some useful pocket-reference types of info in Helsinki. It's very slim on the details though, so you might be better off searching the developer site (http://developer.servicenow.com) or documentation (http://docs.servicenow.com ) if you have any specific questions. Speaking of the documentation site, Search Documentation is essentially a link. Clicking this link from a form or list will automatically populate a query relating to the type of record(s) you were viewing. Conversations Moving further left in the banner frame, you'll find the Conversations button. This opens up the Conversations side-bar, showing an (initially blank) list of the conversations you've recently been a part of. You can enter text in the filter box to filter the conversation list by participant name. Unfortunately, it doesn't allow you to filter/search by message contents at this point. You can also click the Plus icon to initiate a new conversation with a user of your choice. Global text search The next link to the right in the banner frame is probably the most useful one of all – the global text search. The global text search box allows you to enter a term, ticket number, or keyword and search a configurable multitude of tables. As an example of this functionality, let's search for a user that should be present in the demo data that came with your developer instance: Click on the Search icon (the one that looks like a magnifying glass). It should expand to the left, displaying a search keyword input box. In that input box, type in abel tuter. This is the name of one of the demo users that comes with your developer instance. Press Enter, and you should see the relevant search results divided into sections. Entering an exact ticket number for a given task (such as an incident, request, or problem ticket) will take you directly to that ticket rather than showing the search results. This is a great way to quickly navigate to a ticket you've received an e-mail notification about, or for a service desk agent to look up a ticket number provided by a customer. The search results from the Global Text Search are divided into search groups. The default groups are Tasks, Live Feed, Policy, and People & Places. To the right of each search group is a list of the tables that the search is run against for that group. The Policy search group, for example, contains several script types, including Business Rules, UI Actions, Client Scripts, and UI Policies. Profile The last item on our list of banner-frame elements, is the profile link. This will show your photo/icon (if you've uploaded one), and your name. As indicated by the small down-facing arrow to the right of your name (or System Administrator), clicking on this will show a little drop-down menu. This menu consists of up to four main components: Profile Impersonate User Elevate Roles Logout The Profile link in the dropdown will take you directly to the Self Service view of your profile. This is generally not what Administrators want, but it's a quick way for users to view their profile information. Impersonate User is a highly useful tool for administrators and developers, allowing them to view the instance as though they were another user, including that user's security permissions, and viewing the behavior of UI policies and scripts when that user is logged in. Elevate Roles is an option only available when the High Security plugin is enabled (which may or may not be turned on by default in your organization). Clicking this option opens a dialog that allows you to check a box, and re-initialize your session with a special security role called security_admin (assuming you have this role in your instance). With high security settings enabled, the security_admin role allows you to perform certain actions, such as modifying ACLs (Access Control Lists – security rules), and running background scripts (scripts you can write and execute directly on the server). Finally, the Logout link does just what you'd expect: logs you out. If you have difficulty with a session that you can't log out, you can always log out by visiting /logout.do on your instance. For example: http://your-instance.service-now.com/logout.do/. The application navigator The application navigator is one of the UI components with which you will become most familiar, as you work in ServiceNow. Nearly everything you do will begin either by searching in the Global Text Search box, or by filtering the application navigator. The contents of the Application Navigator consists of Modules nested underneath application menu. The first application menu in the application navigator is Self-Service. This application menu is generally what's available to a user who doesn't have any special roles or permissions. Underneath this application menu, you'll see various modules such as Homepage, Service Catalog, Knowledge, and so on. The Self-Service application menu, and several modules under it. When you hear the term application as it relates to ServiceNow, you might think of an application on your smartphone. Applications in ServiceNow and applications on your smartphone both generally consist of packaged functionality, presented in a coherent way. However in ServiceNow, there are some differences. For example, an application header might consist only of links to other areas in ServiceNow, and contain no new functionality of its' own. An application might not even necessarily have an application header. Generally, we refer to the major ITIL processes in ServiceNow as applications (Incident, Change, Problem, Knowledge, and so on) – but these can often consist of various components linked up with one another; so the functionality within an application need not necessarily be packaged in a way that it's closed off from the rest of the system. You'll often be given instructions to navigate to a particular module in a way similar to this: Self-Service | My Requests. In this example, the left portion (Self-Service) is the application menu header, and the right portion (My Requests) is the module. Filter text box The filter text box in the Application Navigator allows you to enter a string to – you guessed it – filter the Application Navigator list with! It isn't strictly a search, it's just filtering the list of items in the application navigator, which means that the term you enter must appear somewhere in the name of either an application menu, or a module. So if you enter the term Incident, you'll see modules with names like Incidents and Watched Incidents, as well as every module inside the Incident application menu. However, if you enter Create Incident, you won't get any results. This is because the module for creating a new Incident, is called Create New, inside the Incident module, and the term Create Incident doesn't appear in that title. In addition to filtering the application navigator, the filter text box has some hidden shortcuts that ServiceNow wizards use to fly around the interface with the speed of a ninja. Here are a few pro tips for you: Once you've entered a term into the filter text box in the application navigator, the first module result is automatically selected. You can navigate to it by pressing Enter. Enter a table name followed by .list and then press Enter to navigate directly to the default list view for that table. For example, entering sc_req_item.list [Enter] will direct you to the list view for the sc_req_item (Requested Item) table. Enter a table name followed by either .form, or .do and then press Enter to take you directly to the default view of that table's form (allowing you to quickly create a new record). For example, entering sc_request.form [Enter] will take you to the New Record intake form for the sc_request (Request) table. Each table has a corresponding form, with certain fields displayed by default. Use either .FORM or .LIST in caps, to navigate to the list or form view in a new tab or window!  Opening a list or form in a new tab (either using this method, by middle-clicking a link, or otherwise) breaks it out of the ServiceNow frame, showing only the Content frame. Try it yourself: Enter sys_user.list into the application navigator filter text field in your developer instance, and press Enter. You should see the list of all the demo users in your instance! No matter which application navigator tab you have selected when you start typing in the filter text box, it will always show you results from the all applications tab, with any of your favorites that match the filter showing up first. Favorites Users can add favorites within the Application Navigator by clicking the star icon, visible on the right when hovering over any application menu or module in the application navigator. Adding a favorite will make it come up first when filtering the application navigator using any term that it matches. It'll also show up under your favorites list, which you can see by clicking the tab at the top of the application navigator, below the filter text box, with the same star icon you see when adding a module to your favorites. Let's try out favorites now by adding some favorites that an admin or developer is likely to want to come back to on frequent occasions. Add the following modules to your favorites list by filtering the application navigator by the module name, hovering over the module, and clicking the star icon on the right: Workflow | Workflow Editor System Definition | Script Includes System Definition | Dictionary System Update Sets | Local Update Sets System Logs | System Log | All This one (All) is nested under a module (System Log) that doesn't point anywhere, but it is just there to serve as a separator for other modules. It's not much use searching for All, so try searching for System Log! Now that we've got a few favorites, let's rename them so they're easier to identify at a glance. While we're at it, we'll give them some new icons as well: Click the favorites tab in the application navigator, and you should see your newly added favorites in the list. At the bottom-right of the application navigator in the ServiceNow frame, click on Edit Favorites. Click on the favorite item called Workflow – Workflow Editor. This will select it so you can edit it in the content frame on the right: 01-10-Editing workflow favorite.png In the Name field, give it something simpler, such as Workflow Editor. Then choose a color and an icon. I chose white, and the icon that looks like a flowchart. I also removed my default Home favorite, but you don't have to. Here is what my favorites look like after I make my modifications: 01-11-Favorites after customizing.png Another way to add something to your favorites is to drag it there. Certain specific elements in the ServiceNow UI can be dragged directly into your Favorites tab. Let's give it a try! Head over to the Incident table by using the .list trick. In your developer instance, enter incident.list into the filter text box in the application navigator; and then press Enter. Click on the Filter icon at the top-left of the Incident list, and filter the Incident list using the condition builder. Add some conditions so that it only displays records where Active is true, and Assigned to is empty. Then click on Run. 01-12-Incident condition for favorites.png The list should now be filtered, after you hit Run. You should see just a few incidents in the list. Now, at the top-left of the Incident table, to the left of the Incidents table label, click on the hamburger menu (yeah, that's really what it's called). It looks like three horizontal bars atop one another. In that menu, click on Create Favorite. Choose a good name, like Unassigned Incidents, and an appropriate icon and color. Then click Done. You should now have an Unassigned Incidents favorite listed! Finally, if you click on the little white left-facing arrow at the bottom-left of the application navigator, you'll notice that whichever navigator tab you have selected, your favorites show up in a stacked list on the left. This gives you a bit more screen real-estate for the content frame. Summary In this article, we learned about: How content is organized on the screen, within frames – the banner frame, Application Navigator, and content frame. How to access the built-in help and documentation for ServiceNow. How to use the global text search functionality, to find the records we're looking for. What it means to elevate roles or impersonate a user. How to get around the Application Navigator, including some pro tips on getting around like a power user from the filter text box. How to use favorites and navigation history within ServiceNow, to our advantage. What UI settings are available, and how to personalize our interface. Resources for Article: Further resources on this subject: Getting Things Done with Tasks [article] Events, Notifications, and Reporting [article] Start Treating your Infrastructure as Code [article]
Read more
  • 0
  • 0
  • 1925
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
Packt
23 Sep 2014
8 min read
Save for later

JavaScript Promises – Why Should I Care?

Packt
23 Sep 2014
8 min read
This article by Rami Sarieddine, the author of the book JavaScript Promises Essentials, introduces JavaScript promises and reasons why should you care about promises when comparing it to the common way of doing things asynchronously. (For more resources related to this topic, see here.) Why should I care about promises? What do promises have to do with all of this? Well, let's start by defining promises. "A promise represents the eventual result of an asynchronous operation." - Promises/A+ specification, http://promisesaplus.com/ So a promise object represents a value that may not be available yet, but will be resolved at some point in the future. Promises have states and at any point in time, can be in one of the following: Pending: The promise's value is not yet determined and its state may transition to either fulfilled or rejected. Fulfilled: The promise was fulfilled with success and now has a value that must not change. Additionally, it must not transition to any other state from the fulfilled state. Rejected: The promise is returned from a failed operation and must have a reason for failure. This reason must not change and the promise must not transition to any other state from this state. A promise may only move from the pending state to the fulfilled state or from the pending state to the rejected state. However, once a promise is either fulfilled or rejected, it must not transition to any other state and its value cannot change because it is immutable. The immutable characteristic of promises is super important. It helps evade undesired side-effects from listeners, which can cause unexpected changes in behavior, and in turn allows promises to be passed to other functions without affecting the caller function. From an API perspective, a promise is defined as an object that has a function as the value for the property then. The promise object has a primary then method that returns a new promise object. Its syntax will look like the following: then(onFulfilled, onRejected); The following two arguments are basically callback functions that will be called for completion of a promise: onFulfilled: This argument is called when a promise is fulfilled onRejected: This argument is called when a promise has failed Bear in mind that both the arguments are optional. Moreover, non-function values for the arguments will be ignored, so it might be a good practice to always check whether the arguments passed are functions before executing them. It is worth noting that when you research promises, you might come across two definitions/specs: one based on Promises/A+ and an older one based on Promises/A by CommonJS. The new promise returned by the then method is resolved when the given onFulfilled or onRejected callback is completed. The implementation reflects a very simple concept: when a promise is fulfilled, it has a value, and when it is rejected, it has a reason. The following is a simple example of how to use a promise: promise.then(function (value){    var result = JSON.parse(data).value;    }, function (reason) {    alert(error.message); }); The fact that the value returned from the callback handler is the fulfillment value for the returned promise allows promise operations to be chained together. Hence, we will have something like the following: $.getJSON('example.json').then(JSON.parse).then(function(response) {    alert("Hello There: ", response); }); Well, you guessed it right! What the previous code sample does is chain the promise returned from the first then() call to the second then() call. Hence, the getJSON method will return a promise that contains the value of the JSON returned. Thus, we can call a then method on it, following which we will invoke another then call on the promise returned. This promise includes the value of JSON.parse. Eventually, we will take that value and display it in an alert. Can't I just use a callback? Callbacks are simple! We pass a function, it gets invoked at some point in the future, and we get to do things asynchronously. Additionally, callbacks are lightweight since we need to add extra libraries. Using functions as higher-order objects is already built into the JavaScript programming language; hence, we do not require additional code to use it. However, asynchronous programming in JavaScript can quickly become complicated if not dealt with care, especially callbacks. Callback functions tend to become difficult to maintain and debug when nested within long lines of code. Additionally, the use of anonymous inline functions in a callback can make reading the call stack very tedious. Also, when it comes to debugging, exceptions that are thrown back from within a deeply nested set of callbacks might not propagate properly up to the function that initiated the call within the chain, which makes it difficult to determine exactly where the error is located. Moreover, it is hard to structure a code that is based around callbacks as they roll out a messy code like a snowball. We will end up having something like the following code sample but on a much larger scale: function readJSON(filename, callback) {    fs.readFile(filename, function (err, result) {        if (err) return callback(err);        try {            result = JSON.parse(result, function (err, result) {                fun.readAsync(result, function (err, result) {                    alert("I'm inside this loop now");                    });                 alert("I'm here now");                });            } catch (ex) {        return callback(ex);        }    callback(null, result);    }); } The sample code in the previous example is an excerpt of a deeply nested code that is sometimes referred to as the pyramid of doom. Such a code, when it grows, will make it a daunting task to read through, structure, maintain, and debug. Promises, on the other hand, provide an abstraction to manage interactions with asynchronous APIs and present a more managed approach towards asynchronous programming in JavaScript when compared to the use of callbacks and event handlers. We can think of promises as more of a pattern for asynchronous programming. Simply put, the promises pattern will allow the asynchronous programming to move from the continuation-passing style that is widespread to one where the functions we call return a value, called a promise that will represent the eventual results of that particular operation. It allows you to go from: call1(function (value1) {    call2(value1, function(value2) {        call3(value2, function(value3) {            call4(value3, function(value4) {                // execute some code            });        });    }); }); To: Promise.asynCall(promisedStep1) .then(promisedStep2) .then(promisedStep3) .then(promisedStep4) .then(function (value4) {    // execute some code }); If we list the properties that make promises easier to work with, they will be as follows: It is easier to read as in cleaner method signatures It allows us to attach more than one callback to a single promise It allows for values and errors to be passed along, and bubble up to the caller function It allows for chaining of promises What we can observe is that promises bring functional composition to synchronous capabilities by returning values, and error bubbling by throwing exceptions to the asynchronous functions. These are capabilities that we take for granted in the synchronous world. The following sample (dummy) code shows the difference between using callbacks to compose asynchronous functions communicating with each other and promises to do the same. The following is an example with callbacks:    $("#testInpt").click(function () {        firstCallBack(function (param) {            getValues(param, function (result) {                alert(result);            });        });    }); The following is a code example that converts the previous callback functions to promise-returning functions that can be chained to each other:    $("#testInpt").clickPromise() // promise-returning function    .then(firstCallBack)    .then(getValues)    .then(alert); As we have seen, the flat chains that promises provide allow us to have code that is easier to read and eventually easier to maintain when compared to the traditional callback approach. Summary Promises are a pattern that allows for a standardized approach in asynchronous programming, which enables developers to write asynchronous code that is more readable and maintainable. Resources for Article: Further resources on this subject: REST – Where It Begins [Article] Uploading multiple files [Article] Grunt in Action [Article]
Read more
  • 0
  • 0
  • 1915

article-image-working-jrockit-runtime-analyzer-sequel
Packt
03 Jun 2010
7 min read
Save for later

Working with JRockit Runtime Analyzer- A Sequel

Packt
03 Jun 2010
7 min read
Code The Code tab group contains information from the code generator and the method sampler. It consists of three tabs —the Overview, Hot Methods, and Optimizations tab. Overview This tab aggregates information from the code generator with sample information from the code optimizer. This allows us to see which methods the Java program spends the most time executing. Again, this information is available virtually "for free", as the code generation system needs it anyway. For CPU-bound applications, this tab is a good place to start looking for opportunities to optimize your application code. By CPU-bound, we mean an application for which the CPU is the limiting factor; with a faster CPU, the application would have a higher throughput.   In the first section, the amount of exceptions thrown per second is shown. This number depends both on the hardware and on the application—faster hardware may execute an application more quickly, and consequently throw more exceptions. However, a higher value is always worse than a lower one on identical setups. Recall that exceptions are just that, rare corner cases. As we have explained, theJVM typically gambles that they aren't occurring too frequently. If an application throws hundreds of thousands exceptions per second, you should investigate why. Someone may be using exceptions for control flow, or there may be a configuration error. Either way, performance will suffer. In JRockit Mission Control 3.1, the recording will only provide information about how many exceptions were thrown. The only way to find out where the exceptions originated is unfortunately by changing the verbosity of the log. An overview of where the JVM spends most of the time executing Java code can be found in the Hot Packages and Hot Classes sections. The only difference between them is the way the sample data from the JVM code optimizer is aggregated. In Hot Packages, hot executing code is sorted on a per-package basis and in Hot Classes on a per-class basis. For more fine-grained information, use the Hot Methods tab. As shown in the example screenshot, most of the time is spent executing code in the weblogic.servlet.internal package. There is also a fair amount of exceptions being thrown. Hot Methods This tab provides a detailed view of the information provided by the JVM code optimizer. If the objective is to find a good candidate method for optimizing the application, this is the place to look. If a lot of the method samples are from one particular method, and a lot of the method traces through that method share the same origin, much can potentially be gained by either manually optimizing that method or by reducing the amount of calls along that call chain. In the following example, much of the time is spent in the method com.bea.wlrt.adapter.defaultprovider.internal.CSVPacketReceiver.parseL2Packet(). It seems likely that the best way to improve the performance of this particular application would be to optimize a method internal to the application container (WebLogic Event Server) and not the code in the application itself, running inside the container. This illustrates both the power of the JRockit Mission Control tools and a dilemma that the resulting analysis may reveal—the answers provided sometimes require solutions beyond your immediate control.   Sometimes, the information provided may cause us to reconsider the way we use data structures. In the next example, the program frequently checks if an object is in a java. util.LinkedList. This is a rather slow operation that is proportional to the size of the list (time complexity O(n)), as it potentially involves traversing the entire list, looking for the element. Changing to another data structure, such as a HashSet would most certainly speed up the check, making the time complexity constant (O(1)) on average, given that the hash function is good enough and the set large enough.   Optimizations This tab shows various statistics from the JIT-compiler. The information in this tab is mostly of interest when hunting down optimization-related bugs in JRockit. It shows how much time was spent doing optimizations as well as how much time was spent JIT-compiling code at the beginning and at the end of the recording. For each method optimized during the recording, native code size before and after optimization is shown, as well as how long it took to optimize the particular method.   Thread/Locks The Thread/Locks tab group contains tabs that visualize thread- and lock-related data. There are five such tabs in JRA—the Overview, Thread, Java Locks, JVM Locks, and Thread Dumps tab. Overview The Overview tab shows fundamental thread and hardware-related information, such as the number of hardware threads available on the system and the number of context switches per second.   A dual-core CPU has two hardware threads, and a hyperthreaded core also counts as two hardware threads. That is, a dual-core CPU with hyperthreading will be displayed as having four hardware threads. A high amount of context switches per second may not be a real problem, but better synchronization behavior may lead to better total throughput in the system. There is a CPU graph showing both the total CPU load on the system, as well as the CPU load generated by the JVM. A saturated CPU is usually a good thing — you are fully utilizing the hardware on which you spent a lot of money! As previously mentioned, in some CPU-bound applications, for example batch jobs, it is normally a good thing for the system to be completely saturated during the run. However, for a standard server-side application it is probably more beneficial if the system is able to handle some extra load in addition to the expected one. The hardware provisioning problem is not simple, but normally server-side systems should have some spare computational power for when things get hairy. This is usually referred to as overprovisioning, and has traditionally just involved buying faster hardware. Virtualization has given us exciting new ways to handle the provisioning problem. Threads This tab shows a table where each row corresponds to a thread. The tab has more to offer than first meets the eye. By default, only the start time, the thread duration, and the Java thread ID are shown for each thread. More columns can be made visible by changing the table properties. This can be done either by clicking on the Table Settings icon, or by using the context menu in the table. As can be seen in the example screenshot, information such as the thread group that the thread belongs to, allocation-related information, and the platform thread ID can also be displayed. The platform thread ID is the ID assigned to the thread by the operating system, in case we are working with native threads. This information can be useful if you are using operating system-specific tools together with JRA.   Java Locks This tab displays information on how Java locks have been used during the recording. The information is aggregated per type (class) of monitor object.   This tab is normally empty. You need to start JRockit with the system property jrockit.lockprofiling set to true, for the lock profiling information to be recorded. This is because lock profiling may cause anything from a small to a considerable overhead, especially if there is a lot of synchronization. With recent changes to the JRockit thread and locking model, it would be possible to dynamically enable lock profiling. This is unfortunately not the case yet, not even in JRockit Flight Recorder. For R28, the system property jrockit.lockprofiling has been deprecated and replaced with the flag -XX:UseLockProfiling. JVM Locks This tab contains information on JVM internal native locks. This is normally useful for the JRockit JVM developers and for JRockit support. An example of a native lock would be the code buffer lock that the JVM acquires in order to emit compiled methods into a native code buffer. This is done to ensure that no other code generation threads interfere with that particular code emission. Thread Dumps The JRA recordings normally contain thread dumps from the beginning and the end of the recording. By changing the Thread dump interval parameter in the JRA recording wizard, more thread dumps can be made available at regular intervals throughout the recording.  
Read more
  • 0
  • 0
  • 1914

article-image-developing-applications-jboss-and-hibernate-part-2
Packt
19 Jan 2010
6 min read
Save for later

Developing Applications with JBoss and Hibernate: Part 2

Packt
19 Jan 2010
6 min read
Adding a web client to your project There are several ways to test our Hibernate application. The simplest of all is adding a web application, which is packaged in an enterprise application along with the Hibernate application. Create a new dynamic web project named HibernateWeb. The first step, before adding servlets and JSPs is linking the HibernateProject libraries to your web application, otherwise, you will not be able to reference the Hibernate POJOs. Right-click on your project and select Properties. Reach the Java Build Path option and select the tab Projects. From there add HibernateProject. Let's move on. This project will contain a main servlet that acts as a controller, and a few JPSs for the client view. We will start by adding com.packtpub.hibernateWeb.HibernateServlet to our project. In the following snippet, you can see the core section of the servlet. Here, we will not detail the Controller logic, which is straightforward if you have some rudiments of the MVC pattern; rather we want to highlight the most interesting part of it, which is how to query and persist Hibernate objects. public class HibernateServlet extends HttpServlet {private SessionFactory getSessionFactory() {return (SessionFactory)getServletContext().getAttribute("sessionFactory");}public void init() { [1]if (getSessionFactory() != null) {return;}InitialContext ctx;try {ctx = new InitialContext();factory = (SessionFactory)ctx.lookup("java:/hibernate/SessionFactory");getServletContext().setAttribute("sessionFactory", factory);}catch (NamingException e) {e.printStackTrace();}}private String saveEmployee(HttpServletRequest request) {Session hsession=null;String name=request.getParameter("name");String salary=request.getParameter("salary");String departmentId=request.getParameter("departmentId");try {hsession = getSessionFactory().openSession();hsession.beginTransaction();Query query = hsession.createQuery("from Department d whered.departmentId = :departmentId"); [2]query.setInteger("departmentId", new Integer(departmentId));Department dep = (Department) query.uniqueResult();Employee emp = new Employee();emp.setDepartment(dep);emp.setEmployeeName(name);emp.setEmployeeSalary(Integer.parseInt(salary));hsession.save(emp); [3]hsession.getTransaction().commit();}catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace();hsession.getTransaction().rollback();}finally {if (hsession.isOpen())hsession.close();}return employeeList(request);}private String employeeList(HttpServletRequest request) {Session hsession=null;Department dep;try {hsession = getSessionFactory().openSession();Query query = hsession.createQuery("select p from Employee pjoin fetch p.department c"); [4]List <Employee>list = query.list();request.setAttribute("employee", list);}catch (Exception e) {e.printStackTrace();}finally {if (hsession.isOpen())hsession.close();}return "/listEmployees.jsp";}private String saveDepartment(HttpServletRequest request) {String depName=request.getParameter("depName");Session hsession=null;Department dep;try {hsession = getSessionFactory().openSession();hsession.beginTransaction();dep = new Department();dep.setDepartmentName(depName);hsession.save(dep); [5]hsession.getTransaction().commit();}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();hsession.getTransaction().rollback();}finally {if (hsession.isOpen())hsession.close();}return employeeList(request);}} As you can see from the preceding code, we recover the SessionFactory from the JNDI tree in the init() [1] method of the servlet. Instances of SessionFactory are thread-safe and typically shared throughout an application, so we store it in the ServletContext and share it among all servlet instances. The SessionFactory is subsequently used to start a Hibernate session, which is not thread-safe and should only be used for a single transaction or unit of work in an application. In order to store our Employee, in the saveEmployee method, we first retrieve the corresponding Department from our schema [2], and finally the Employee is saved [3] and the transaction is committed. The list of employees is fetched by the employeeList method. Notice we are using a join fetch statement to retrieve all the employees [4], which will be routed to the listEmployees.jsp view. Why? The answer is that with the default fetch mode (Lazy), once the Hibernate session is closed, the client will not be able to navigate through the department field of the Employee. The common solution to this issue is switching to the EAGER fetch mode that reads the related fields (in our case department) in memory, as soon as we query the Employee table. You have more than one option to achieve this. One possible solution, if you don't want to change the default fetch mode for the Employee table, is to build an ad hoc query that forces Hibernate to read also the fields in relation with the Employee table. "select p from Employee p join fetch p.department c" If you prefer to use the XML class files to configure the fetch mode, you can also change the lazy="true" attribute in the employee-department relationship. The last method, saveDepartment [5] takes care to persist a new Department in the corresponding table. We complete our excursus on the web tier with the listEmployees.jsp that is used to display a tabular view of the employees: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><html><script language="JavaScript">function doSubmit(url) {document.module.action = url;document.module.submit();}</script><body><table border="1"><tr><th>Name</th><th>Salary</th> <TH>department</th></tr><c:forEach items="${employee}" var="emp"><tr><td> <c:out value="${emp.employeeName}"/> </td><td> <c:out value="${emp.employeeSalary}"/></td><td> <c:out value="${emp.department.departmentName}"/></td></tr></c:forEach></table><form name="module" method="POST"><input type="button" value ="New Employee"onClick="doSubmit('actionServlet?op=newEmployee')"><input type="button" value ="New Department"onClick="doSubmit('actionServlet?op=newDepartment')"></form></body></html> This page uses JSP 2.0 Expression Language (EL) to iterate through the list of employees, as highlighted in the last code snippet. We have also hightlighted the taglib directive, at the beginning of the page. This directive will be used to resolve the JSTL core set of libraries that ships with JBoss AS in the server/xxx/deploy/jbossweb.sar/jstl.jar library. (Eclipse does not contain references to this library when you create a web project; you have to add jstl.jar to your build path, otherwise Eclipse will mark it as an error. However, that's only a visual annoyance because the JBoss Web container has got everything it needs to run JSTL.) The complete web application is available on the Packtpub website (http://www.packtpub.com) and includes two additional JSPs for entering the employee (newEmployee.jsp) and department (newDepartment.jsp) data, plus one placeholder index.jsp that merely forwards to the Hibernate servlet.
Read more
  • 0
  • 0
  • 1903

article-image-consuming-adapter-outside-biztalk-server
Packt
22 Oct 2009
3 min read
Save for later

Consuming the Adapter from outside BizTalk Server

Packt
22 Oct 2009
3 min read
In addition to infrastructure-related updates such as the aforementioned platform modernization, Windows Server 2008 Hyper-V virtualization support, and additional options for fail over clustering, BizTalk Server also includes new core functionality. You will find better EDI and AS2 capabilities for B2B situations and a new platform for mobile development of RFID solutions. One of the benefits of the new WCF SQL Server Adapter that I mentioned earlier was the capability to use this adapter outside of a BizTalk Server solution. Let's take a brief look at three options for using this adapter by itself and without BizTalk as a client or service. Called directly via WCF service reference If your service resides on a machine where the WCF SQL Server Adapter (and thus, the sqlBinding) is installed, then you may actually add a reference directly to the adapter endpoint. I have a command-line application, which serves as my service client. If we right-click this application, and have the WCF LOB Adapter SDK installed, then Add Adapter Service Reference appears as an option. Choosing this option opens our now-beloved wizard for browsing adapter metadata. As before, we add the necessary connection string details and browse the BatchMaster table and opt for the Select operation. Unlike the version of this wizard that opens for BizTalk Server projects, notice the Advanced options button at the bottom. This button opens a property window that lets us select a variety of options such as asynchronous messaging support and suppression of an accompanying configuration file. After the wizard is closed, we end up with a new endpoint and binding in our existing configuration file, and a .NET class containing the data and service contracts necessary to consume the service. We should now call this service as if we were calling any typical WCF service. Because the auto-generated namespace for the data type definition is a bit long, I first added an alias to that namespace. Next, I have a routine, which builds up the query message, executes the service, and prints a subset of the response. using DirectReference = schemas.microsoft.com.Sql._2008._05.Types.Tables.dbo; … private static void CallReferencedSqlAdapterService() { Console.WriteLine("Calling referenced adapter service");TableOp_dbo_BatchMasterClient client = new TableOp_dbo_BatchMasterClient("SqlAdapterBinding_TableOp_dbo_BatchMaster"); try{string columnString = "*";string queryString = "WHERE BatchID = 1";DirectReference.BatchMaster[] batchResult =client.Select(columnString, queryString);Console.WriteLine("Batch results ...");Console.WriteLine("Batch ID: " + batchResult[0].BatchID.ToString());Console.WriteLine("Product: " + batchResult[0].ProductName);Console.WriteLine("Manufacturing Stage: " + batchResult[0].ManufStage);client.Close(); Console.ReadLine(); } catch (System.ServiceModel.CommunicationException){client.Abort(); } catch (System.TimeoutException) { client.Abort(); } catch (System.Exception) { client.Abort(); throw; } } Once this quick block of code is executed, I can confirm that my database is accessed and my expected result set returned.
Read more
  • 0
  • 0
  • 1899
article-image-configuring-and-securing-virtual-private-cloud
Packt
16 Sep 2015
7 min read
Save for later

Configuring and Securing a Virtual Private Cloud

Packt
16 Sep 2015
7 min read
In this article by Aurobindo Sarkar and Sekhar Reddy, author of the book Amazon EC2 Cookbook, we will cover recipes for: Configuring VPC DHCP options Configuring networking connections between two VPCs (VPC peering) (For more resources related to this topic, see here.) In this article, we will focus on recipes to configure AWS VPC (Virtual Private Cloud) against typical network infrastructure requirements. VPCs help you isolate AWS EC2 resources, and this feature is available in all AWS regions. A VPC can span multiple availability zones in a region. AWS VPC also helps you run hybrid applications on AWS by extending your existing data center into the public cloud. Disaster recovery is another common use case for using AWS VPC. You can create subnets, routing tables, and internet gateways in VPC. By creating public and private subnets, you can put your web and frontend services in public subnet, your application databases and backed services in a private subnet. Using VPN, you can extend your on-premise data center. Another option to extend your on-premise data center is AWS Direct Connect, which is a private network connection between AWS and you're on-premise data center. In VPC, EC2 resources get static private IP addresses that persist across reboots, which works in the same way as DHCP reservation. You can also assign multiple IP addresses and Elastic Network Interfaces. You can have a private ELB accessible only within your VPC. You can use CloudFormation to automate the VPC creation process. Defining appropriate tags can help you manage your VPC resources more efficiently. Configuring VPC DHCP options DHCP options sets are associated with your AWS account, so they can be used across all your VPCs. You can assign your own domain name to your instances by specifying a set of DHCP options for your VPC. However, only one DHCP Option set can be associated with a VPC. Also, you can't modify the DHCP option set after it is created. In case your want to use a different set of DHCP options, then you will need to create a new DHCP option set and associate it with your VPC. There is no need to restart or relaunch the instances in the VPC after associating the new DHCP option set as they can automatically pick up the changes. How to Do It… In this section, we will create a DHCP option set and then associate it with your VPC. Create a DHCP option set with a specific domain name and domain name servers. In our example, we execute commands to create a DHCP options set and associate it with our VPC. We specify domain name testdomain.com and DNS servers (10.2.5.1 and 10.2.5.2) as our DHCP options. $ aws ec2 create-dhcp-options --dhcp-configuration Key=domain-name,Values=testdomain.com Key=domain-name-servers,Values=10.2.5.1,10.2.5.2 Associate the DHCP option and set your VPC (vpc-bb936ede). $ aws ec2 associate-dhcp-options --dhcp-options-id dopt-dc7d65be --vpc-id vpc-bb936ede How it works… DHCP provides a standard for passing configuration information to hosts in a network. The DHCP message contains an options field in which parameters such as the domain name and the domain name servers can be specified. By default, instances in AWS are assigned an unresolvable host name, hence we need to assign our own domain name and use our own DNS servers. The DHCP options sets are associated with the AWS account and can be used across our VPCs. First, we create a DHCP option set. In this step, we specify the DHCP configuration parameters as key value pairs where commas separate the values and multiple pairs are separated by spaces. In our example, we specify two domain name servers and a domain name. We can use up to four DNS servers. Next, we associate the DHCP option set with our VPC to ensure that all existing and new instances launched in our VPC will use this DHCP options set. Note that if you want to use a different set of DHCP options, then you will need to create a new set and again associate them with your VPC as modifications to a set of DHCP options is not allowed. In addition, you can let the instances pick up the changes automatically or explicitly renew the DHCP lease. However, in all cases, only one set of DHCP options can be associated with a VPC at any given time. As a practice, delete the DHCP options set when none of your VPCs are using it and you don't need it any longer. Configuring networking connections between two VPCs (VPC peering) In this recipe, we will configure VPC peering. VPC peering helps you connect instances in two different VPCs using their private IP addresses. VPC peering is limited to within a region. However, you can create VPC peering connection between VPCs that belong to different AWS accounts. The two VPCs that participate in VPC peering must not have matching or overlapping CIDR addresses. To create a VPC connection, the owner of the local VPC has to send the request to the owner of the peer VPC located in the same account or a different account. Once the owner of peer VPC accepts the request, the VPC peering connection is activated. You will need to update the routes in your route table to send traffic to the peer VPC and vice versa. You will also need to update your instance security groups to allow traffic from–to the peer VPC. How to Do It… Here, we present the commands to creating a VPC peering connection, accepting a peering request, and adding the appropriate route in your routing table. Create a VPC peering connection between two VPCs with IDs vpc-9c19a3f4 and vpc-0214e967. Record VpcPeeringConnectionId for further use $ aws ec2 create-vpc-peering-connection --vpc-id vpc-9c19a3f4 --peer-vpc-id vpc-0214e967 Accept VPC peering connection. Here, we will accept the VPC peering connection request with ID pcx-cf6aa4a6. $ aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id pcx-cf6aa4a6 Add a route in the route table for the VPC peering connection. The following command create route with destination CIDR (172.31.16.0/20) and VPC peer connection ID (pcx-0e6ba567) in route table rtb-7f1bda1a. $ aws ec2 create-route --route-table-id rtb-7f1bda1a --destination-cidr-block 172.31.16.0/20 --vpc-peering-connection-id pcx-0e6ba567 How it works… First, we request a VPC peering connection between two VPCs: a requester VPC that we own (i.e., vpc-9c19a3f4) and a peer VPC with that we want to create a connection (vpc-0214e967). Note that the peering connection request expires after 7 days. In order tot activate the VPC peering connection, the owner of the peer VPC must accept the request. In our recipe, as the owner of the peer VPC, we accept the VPC peering connection request. However, note that the owner of the peer VPC may be a person other than you. You can use the describe-vpc-peering-connections to view your outstanding peering connection requests. The VPC peering connection should be in the pending-acceptance state for you to accept the request. After creating the VPC peering connection, we created a route in our local VPC subnet's route table to direct traffic to the peer VPC. You can also create peering connections between two or more VPCs to provide full access to resources or peer one VPC to access centralized resources. In addition, peering can be implemented between a VPC and specific subnets or instances in one VPC with instances in another VPC. Refer to Amazon VPC documentation to set up the most appropriate peering connections for your specific requirements. Summary In this article, you learned configuring VPC DHCP options as well as configuring networking connections between two VPCs. The book Amazon EC2 Cookbook will cover recipes that relate to designing, developing, and deploying scalable, highly available, and secure applications on the AWS platform. By following the steps in our recipes, you will be able to effectively and systematically resolve issues related to development, deployment, and infrastructure for enterprise-grade cloud applications or products. Resources for Article: Further resources on this subject: Hands-on Tutorial for Getting Started with Amazon SimpleDB [article] Amazon SimpleDB versus RDBMS [article] Amazon DynamoDB - Modelling relationships, Error handling [article]
Read more
  • 0
  • 0
  • 1898

article-image-getting-your-hands-dirty-jpdl-part-1
Packt
06 Jan 2010
9 min read
Save for later

Getting Your Hands Dirty with jPDL: Part 1

Packt
06 Jan 2010
9 min read
This example will introduce us to all the basic jPDL nodes used in common situations for modeling real world scenarios. That's why this article will cover the following topics: Introduction to the recruiting example Analyzing the example requirements Modeling a formal description Adding technical details to our formal description Running our processes The idea of this article is to show you a real process implementation. We will try to cover every technical aspect involved in development in order to clarify not only your doubts about modeling, but also about the framework behavior. How is this example structured? In this article, we will see a real case where a company has some requirements to improve an already existing, but not automated process. The current process is being handled without a software solution, practically we need to see how the process works everyday to find out the requirements for our implementation. The textual/oral description of the process will be our first input, and we will use it to discover and formalize our business process definition. Once we have a clear view about the situation that we are modeling, we will draw the process using GPD, and analyze the most important points of the modeling phase. Once we have a valid jPDL process artifact, we will need to analyze what steps are required for the process to be able to run in an execution environment. So, we will add all the technical details in order to allow our process to run. At last, we will see how the process behaves at runtime, how we can improve the described process, how we can adapt the current process to future changes, and so on. Key points that you need to remember In these kind of examples, you need to be focused on the translation that occurs from the business domain to the technical domain. You need to carefully analyze how the business requirements are transformed to a formal model description that can be optimized. Another key point here, is how this formal description of our business scenario needs to be configured (by adding technical details) in order to run and guide the organization throughout its processes. I also want you to focus on the semantics of each node used to model our process. If you don't know the exact meaning of the provided nodes, you will probably end up describing your scenario with the wrong words. You also need to be able to distinguish between a business analyst model, which doesn't know about the jPDL language semantics and a formal jPDL process definition. At the same time, you have to be able to do the translations needed between these two worlds. If you have business analysts trained in jPDL, you will not have to do these kind of translations and your life will be easier. Understanding the nodes' semantics will help you to teach the business analysts the correct meaning of jPDL processes. Analyzing business requirements Here we will describe the requirements that need to be covered by the recruiting team inside an IT company. These requirements will be the first input to be analyzed in order to discover the business process behind them. These requirements are expressed in a natural language, just plain English. We will get these requirements by talking to our clients—in this case, we will talk to the manager of an IT company called MyIT Inc. in order to find out what is going on in the recruiting process of the company. In most cases, this will be a business analyst's job, but you need to be aware of the different situations that the business scenario can present as a developer. This is very important, because if you don't understand how the real situation is sub-divided into different behavioral patterns, you will not be able to find the best way to model it. You will also start to see how iterative this approach is. This means that you will first view a big picture about what is going on in the company, and then in order to formalize this business knowledge, you will start adding details to represent the real situation in an accurate way. Business requirements In this section, we will see a transcription about our talk with the MyIT Inc. manager. However, we first need to know the company's background and, specifically, how it is currently working. Just a few details to understand the context of our talk with the company manager would be sufficient. The recruiting department of the MyIT Inc. is currently managed without any information system. They just use some simple forms that the candidates will have to fill in at different stages during the interviews. They don't have the recruiting process formalized in any way, just an abstract description in their heads about how and what tasks they need to complete in order to hire a new employee when needed. In this case, the MyIT Inc. manager tells us the following functional requirements about the recruiting process that is currently used in the company: We have a lot of demanding projects, that's why we need to hire new employees on a regular basis. We already have a common way to handle these requests detected by project leaders who need to incorporate new members into their teams. When a project leader notices that he needs a new team member, he/she will generate a request to the human resources department of the company. In this request, he/she will specify the main characteristics needed by the new team member and the job position description. When someone in the human resources team sees the request, they will start looking for candidates to fulfill the request. This team has two ways of looking for new candidates: By publishing the job position request in IT magazines By searching the resume database that is available to the company When a possible candidate is found through these methods, a set of interviews will begin. The interviews are divided into four stages that the candidate needs to go through in order to be hired. These stages will contain the following activities that need to be performed in the prescribed order: Initial interview: The human resources team coordinates an initial interview with each possible candidate found. In this interview, a basic questionnaire about the candidate's previous jobs and some personal data is collected. Technical interview: During the technical interview stage, each candidate is evaluated only with the technical aspects required for this particular project. That is why a project member will conduct this interview. Medical checkups: Some physical and psychological examinations need to be done in order to know that the candidate is healthy and capable to do the required job. This stage will include multiple checkups which the company needs to determine if the candidate is apt for the required task. Final acceptance: In this last phase the candidate will meet the project manager. The project manager is in charge of the final resolution. He will decide if the candidate is the correct one for that job position. If the outcome of this interview is successful, the candidate is hired and all the information needed for that candidate to start working is created. If a candidate reaches the last phase and is successfully accepted, we need to inform the recruiting team that all the other candidate's interviews need to be aborted, because the job position is already fulfilled. At this point, we need to analyze and evaluate the manager's requirements and find a graphical way to express these stages in order to hire a new employee. Our first approach needs to be simple and we need to validate it with the MyIT Inc. manager. Let's see the first draft of our process: With this image, we were able to describe the recruiting process. This is our first approach that obviously can be validated with the MyIT Inc. manager. This is our first draft that tells us how our process will appear and it's the first step in order to define which activities will be included in our model and which will not. In real implementations, these graphs can be made with Microsoft Visio, DIA (Open Source project), or just by hand. The main idea of the first approach is to first have a description that can be validated and understood by every MyIT Inc. employee. This image is only a translation of the requirements that we hear from the manager using common sense and trying to represent how the situation looks in real life. In this case, we can say that the manager of the MyIT Inc. can be considered as the stakeholder and the Subject Matter Expert (SME), who know how things happen inside the company. Once the graph is validated and understood by the stakeholder, we can use our formal language jPDL to create a formal model about this discovered process. The idea at this point, is to create a jPDL process definition and discard the old graph. From now on we will continue with the jPDL graphic representation of the process. Here you can explain to the manager that all the new changes that affect your process will go directly to the jPDL defined process. Until now our artifact has suffered the following transformations: The final artifact (the jPDL process definition) will let us begin the implementation of all the technical details needed by the process in order to run in an execution environment. So, let's analyze how the jPDL representation will look for this first approach in the following figure: At this point we don't add any technical details, we just draw the process. One key point to bear in mind in this phase is that we need to understand which node we will use to represent each activity in our process definition. Remember that each node provided by jPDL has its own semantics and meanings. You also need to remember that this graph needs to be understood by the manager, so you will use it in the activity name business language. For this first approach we use state nodes to represent that each activity will happen outside the process execution. In other words, we need to inform the process when each activity ends. This will mean that the next activity in the chain will be executed. From the process perspective, it only needs to wait until the human beings in the company do their tasks.
Read more
  • 0
  • 0
  • 1894

article-image-supervision-and-monitoring
Packt
02 Nov 2016
8 min read
Save for later

Supervision and Monitoring

Packt
02 Nov 2016
8 min read
In this article by Piyush Mishra, author of the book Akka Cookbook, we will learn about supervision and monitoring of Akka actors. (For more resources related to this topic, see here.) Using supervision and monitoring, we can write fault-tolerant systems, which can run continuously for days, months, and years without stopping. Fault tolerance is a property of the systems which are intended to be always responsive rather than failing completely in case of a failure. Such systems are known as fault tolerance systems or resilient systems. In simple words, a fault-tolerant system is one which is destined to continue as more or less fully operational, with perhaps a reduction in throughput or an increase in response time because of partial failure of its components. Even if a components fails, the whole system never gets shut down, instead, it remains operational and responsive with just a decreased throughput. Similarly, while designing a distributed system, we need to care about what would happen if one or more it's components go down. So, the system design should itself be such that the system is able to take appropriate action to resolve the issue. In this article, we will cover the following recipe: Creating child actors of a parent actor Overriding the life cycle hooks of an actor Sending messages to actors and collecting responses Creating child actors of a parent actor In this recipe, we will learn how to create child actors of an actor. Akka follows a tree-like structure to create actors, and it is also the recommended practice. By following such practices, we can handle failures in actors as the parent can take care of it. Lets see how to do it. Getting ready We need to import the Hello-Akka project in the IDE of our choice. The Akka actor dependency that we added in build.sbt is sufficient for most of the recipes in this article, so we will skip the Getting ready section in our further recipes. How to do it… Create a file named ParentChild.scala in package com.packt.chapter2. Add the following imports to the top of the file: import akka.actor.{ActorSystem, Props, Actor} Create messages for sending to actors. case object CreateChild case class Greet(msg: String) Define a child actor as follows: class ChildActor extends Actor { def receive = { case Greet(msg) => println(s"My parent[${self.path.parent}] greeted to me [${self.path}] $msg") } } Define a parent actor as follows, and create a child actor in its context: class ParentActor extends Actor { def receive = { case CreateChild => val child = context.actorOf(Props[ChildActor], "child") child ! Greet("Hello Child") } } Create an application object as shown next: object ParentChild extends App { val actorSystem = ActorSystem("Supervision") val parent = actorSystem.actorOf(Props[ParentActor], "parent") parent ! CreateChild } Run the preceding application, and you will get the following output: My parent[akka://Supervision/user/parent] greeted to me [akka://Supervision/user/parent/child] Hello Child     How it works… In this recipe, we created a child actor, which receives a message, Greet, from the parent actor. We see the parent actor create a child actor using context.actorOf. This method creates a child actor under the parent actor. We can see the path of the actor in the output clearly. Overriding life cycle hooks of an actor Since we are talking about supervision and monitoring of actors, you should understand the life cycle hooks of an actor. In this recipe, you will learn how to override the life cycle hooks of an actor when it starts, stops, prestarts, and postrestarts. How to do it… Create a file called ActorLifeCycle.scala in package com.packt.chapter2. Add the following imports to the top of the file: import akka.actor import akka.actor.SupervisorStrategy import akka.util.Timeout. import scala.concurrent.Await import scala.concurrent.duration import akka.pattern.ask Create the following messages to be sent to the actors: case object Error case class StopActor(actorRef: ActorRef) Create an actor as follows, and override the life cycle methods: class LifeCycleActor extends Actor { var sum = 1 override def preRestart(reason: Throwable, message: Option[Any]): Unit = { println(s"sum in preRestart is $sum") } override def preStart(): Unit = println(s"sum in preStart is $sum") def receive = { case Error => throw new ArithmeticException() case _ => println("default msg") } override def postStop(): Unit = { println(s"sum in postStop is ${sum * 3}") } override def postRestart(reason: Throwable): Unit = { sum = sum * 2 println(s"sum in postRestart is $sum") } } Create a supervisor actor as follows: class Supervisor extends Actor { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException => Restart case t => super.supervisorStrategy.decider.applyOrElse(t, (_: Any) => Escalate) } def receive = { case (props: Props, name: String) => sender ! context.actorOf(props, name) case StopActor(actorRef) => context.stop(actorRef) } } Create a test application as shown next, and run the application. object ActorLifeCycle extends App { implicit val timeout = Timeout(2 seconds) val actorSystem = ActorSystem("Supervision") val supervisor = actorSystem.actorOf(Props[Supervisor], "supervisor") val childFuture = supervisor ? (Props(new LifeCycleActor), "LifeCycleActor") val child = Await.result(childFuture.mapTo[ActorRef], 2 seconds) child ! Error Thread.sleep(1000) supervisor ! StopActor(child) } Create another test application as follows, and run it. object ActorLifeCycle extends App { implicit val timeout = Timeout(2 seconds) val actorSystem = ActorSystem("Supervision") val supervisor = actorSystem.actorOf(Props[Supervisor], "supervisor") val childFuture = supervisor ? (Props(new LifeCycleActor), "LifeCycleActor") val child = Await.result(childFuture.mapTo[ActorRef], 2 seconds) child ! Error Thread.sleep(1000) supervisor ! StopActor(child) } On running the preceding test application, you will get the following output: sum in preStart is 1 sum in preRestart is 1 sum in postRestart is 2 [ERROR] [07/01/2016 00:49:57.568] [Supervision-akka.actor.default-dispatcher-5] [akka://Supervision/user/supervisor/LifeCycleActor] null java.lang.ArithmeticException at com.packt.chapter2.LifeCycleActor$ $anonfun$receive$2.applyOrElse(ActorLifeCycle.scala:51) sum in postStop is 6 How it works… In this preceding recipe, we create an actor, which maintains sum as a state, and we modify its life cycle hooks. We create this actor under the parent supervisor, which handles the ArthimaticException in the child actor. Let's see what happens in life cycle hooks. When an actor starts, it calls the preStart method, so we see the following output: "sum in preStart is 1". When an actor throws an exception, it sends a message to the supervisor, and the supervisor handles the failure by restarting that actor. It clears out the accumulated state of the actor, creates a fresh new actor means, and then restores the last value assigned to the state of old actor to the preRestart value. After that postRestart method is called, and whenever the actor stops, the supervisor calls the postStop. Sending messages to actors and collecting responses In this recipe, you will learn how a parent sends messages to its child, and collects responses from them. To step through this recipe, we need to import the Hello-Akka project in the IDE. How to do it… Create a file, SendMesagesToChilds.scala, in package com.packt.chapter2. Add the following imports to the top of the file: import akka.actor.{ Props, ActorSystem, Actor, ActorRef } Create messages to be sent to the actors as follows: case class DoubleValue(x: Int) case object CreateChild case object Send case class Response(x: Int) Define a child actor. It doubles the value sent to it. class DoubleActor extends Actor { def receive = { case DoubleValue(number) => println(s"${self.path.name} Got the number $number") sender ! Response(number * 2) } } Define a parent actor. It creates child actors in its context, sends messages to them, and collects responses from them. class ParentActor extends Actor { val random = new scala.util.Random var childs = scala.collection.mutable.ListBuffer[ActorRef]() def receive = { case CreateChild => childs ++= List(context.actorOf(Props[DoubleActor])) case Send => println(s"Sending messages to child") childs.zipWithIndex map { case (child, value) => child ! DoubleValue(random.nextInt(10)) } case Response(x) => println(s"Parent: Response from child $ {sender.path.name} is $x") } } Create a test application as follows, and run it: object SendMessagesToChild extends App { val actorSystem = ActorSystem("Hello-Akka") val parent = actorSystem.actorOf(Props[ParentActor], "parent") parent ! CreateChild parent ! CreateChild parent ! CreateChild parent ! Send } On running the preceding test application, you will get the following output: $b Got the number 6 $a Got the number 5 $c Got the number 8 Parent: Response from child $a is 10 Parent: Response from child $b is 12 Parent: Response from child $c is 16 How it works… In this last recipe, we create a child actor called DoubleActor, which doubles the value it gets. We also create a parent actor, which creates a child actor when it receives a CreateChild message, and maintains it in the list. When the parent actor receives the message Send, it sends a random number to the child, and the child, in turn, sends a response to the parent. Summary In this article, you learned how to supervise and monitor Akka actors as well as create child actors of an actor. We also discussed how to override the life cycle hooks of an actor. Lastly, you learned how a parent sends messages to its child and collects responses from them. Resources for Article: Further resources on this subject: Introduction to Akka [article] Creating First Akka Application [article] Making History with Event Sourcing [article]
Read more
  • 0
  • 0
  • 1885
article-image-windows-development-using-visual-studio-2008
Packt
16 Oct 2009
11 min read
Save for later

Windows Development Using Visual Studio 2008

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

article-image-practical-dart
Packt
22 May 2015
20 min read
Save for later

Practical Dart

Packt
22 May 2015
20 min read
This article is written by Martin Sikora, the author of Dart Essentials. This article will focus on the most common features of Dart that you'll use every day for your next Dart project. In this article, we'll look at: Future-Based API, Dart's built-in library for working with asynchronous calls Creating Ajax requests in Dart How packages work in Dart The whole article is intended to be very practical. We'll create a small app that reads a JSON dictionary and lets you search among all the terms in it. To make it more complicated, we'll implement a so-called fuzzy search algorithm, which doesn't search exact matches but the same order of characters instead. (For more resources related to this topic, see here.) The documentation search app We're going to write an app that can search among many terms and show some simple detail for each of them. The search input field will have an autocomplete feature with a list of all the terms that match our search string. Particularly, we'll use the documentation for PHP with 9,047 functions and write a fuzzy search algorithm that will search in it. Fuzzy search is used in IDEs such as PHPStorm or PyCharm and also in the popular text editor Sublime Text. It doesn't search just for the strings that start with your search term but it checks whether the order of characters in your term and in the checked string is the same. For example, if you type docfrg, it will find DocumentFragment because the letters in DocumentFragment are in the same order as docfrg. This is very handy because when there are a lot of functions with the same prefix, you can start typing with just the first character and then jump to the middle of the word and it's very likely that there won't be many functions with the same characters. This is quite common for PHP because there are a lot of functions that start with mysql or str_. If you're looking for a function called str_replace, you can type just splc. We'll load the entire dictionary with Ajax as a JSON string and decode it to a Map object. Dart uses the Future-Based API for all asynchronous calls including Ajax, so we should talk about it first. The Future-Based API Dart, as well as JavaScript, uses asynchronous calls a lot. A common pitfall of this approach in JavaScript is that it tends to make many nested function calls with callbacks: async1(function() { // do something async2(function() {    // do something    async3(function() {      // do something      callback();    }); }, callback); }); The downsides of this approach are obvious: It makes it hard to read and debug code, so-called callback hell. Each nested function can access variables from all parent scopes. This leads to variable shadowing and also prevents the JavaScript interpreter from deallocating unused variables. When working with a larger amount of data (for example, asynchronous calls when reading files), even simple script can use the entire available memory and cause the browser to crash. Future in Dart stands for an object that represents a value that will exist sometime in the future. Dart uses Future objects in nearly all their APIs, and we're going to use it in order to avoid passing callbacks around. An example of using Future is HttpRequest.getString(), which returns a Future object immediately and makes an asynchronous Ajax call: HttpRequest.getString('http://...').then(onDataReady); To work with the data returned from a Future object, we use the then() method, which takes the callback function as an argument that can return another Future object as well. If we want to create asynchronous behavior similar to that in the preceding example, we use the Completer class, which is a part of dart:async package. This class has a property called future, which represents our Future object and the complete() method, which resolves the Future object with some value. To keep the same order of function calls, we'll chain the then() methods of each Future object: import 'dart:async';   Future async1() { var completer = new Completer(); // Simulate long lasting async operation. new Future.delayed(const Duration(seconds: 2), () {    // Resolve completer.future with this value. This will also    // call callback passed to then() method for this Future.    completer.complete('delayed call #1'); }); // Call to [Completer.complete()] resolves the Future object return completer.future; }   Future async2(String val) { // Print result from the previous async call. print(val); // Then create a new Completer and schedule // it for later execution. var completer = new Completer(); // Simulate long lasting async operation. new Future.delayed(const Duration(seconds: 3), () {    completer.complete('delayed call #2'); }); return completer.future; }   Future async3(String val) { // Return another Future object. }   void main() { // Chain async calls. Each function returns a Future object. async1()    .then((String val) => async2(val))    .then((String val) => async3(val))    .then((String val) => print(val)); } We got rid of nested calls and have quite straightforward, shallow code. APIs similar to Dart's Future are very common among most JavaScript frameworks. Maybe you've already seen $.Deferred() in jQuery or $q.defer() in AngularJS. Future objects can also handle error states with catchError() that are emitted by a Completer object with completeError(). Another usage of Future is when we want a function to be called asynchronously, which is internally scheduled at the end of the event queue: new Future(() { // function body }); Sometimes, this is useful when you want to let the browser process all the events before executing more computationally intensive tasks that could make the browser unresponsive for a moment. For more in-depth information about Dart's event loop, see . Using keywords async and await Dart 1.9 introduced two new keywords, async and await, that significantly simplify the usage of asynchronous calls with the Future-Based API. Async The async keyword is used to mark a function's body, which immediately returns a Future object that is executed later and its return value is used to complete the Future object just like we saw previously when using the Completer class: Future<String> hello() async { return 'Hello, World!'; } In practice, you don't have to specify the Future<String> return type because even Dart Editor knows that the async function returns a Future object, so we'll omit it most of the time. This saves some writing but its real power comes in combination with await. Await With Future, the only way to chain (or simulate synchronous) calls is to use the then()method multiple times, as we saw earlier. But there's a new keyword await that is able to pause the execution of the current VM's thread and wait until Future is completed: String greetings = await hello(); The completed value of Future is then used as a value for the entire expression await hello(). In comparison to the preceding example of multiple asynchronous calls, we could use just: print(await async3(await async2(await async1()))); The only limitation here is that await must be used inside an asynchronous function (for example, defined with async) in order not to block the main execution thread. If the expression with await raises an exception, it's propagated to its caller. We're going to use async and await a lot here, but it's good to know how to use the "original" Future-Based API with the Future and Complete classes, because it will take some time for developers of third-party libraries to update their code with async and await. Dart 1.9 actually introduced even more keywords such as await-for, yield, async*, and a few more (also called generators), but these aren't very common and we're not going to discuss them here. If you want to know more about them, refer to https://www.dartlang.org/articles/beyond-async/. Creating Ajax requests in Dart Nearly every app these days uses Ajax. With libraries such as jQuery, it's very easy to make Ajax calls, and Dart is no different. Well, maybe the only difference is that Dart uses the Future-Based API. Creating an Ajax call and getting the response is this easy: String url = 'http://domain.com/foo/bar';Future ajax = HttpRequest.getString(url); ajax.then((String response) { print(response); });   // Or even easier with await. // Let's assume we're inside an asynchronous function. String response = await HttpRequest.getString(url); That's all. HttpRequest.getString() is a static method that returns a Future<String> object. When the response is ready, the callback function is called with the response as a string. You can handle an error state with catchError() method or just wrap the await expression with the try-catch block. By default, getString() uses the HTTP GET method. There are also more general static methods such as HttpRequest.request(), which returns Future<HttpRequest>, where you can access return code, response type, and so on. Also, you can set a different HTTP method if you want. To send form data via the POST method, the best way is to use HttpRequest.postFormData(), which takes a URL and a Map object with form fields as arguments. In this article, we'll use Ajax to load a dictionary for our search algorithm as JSON, and we'll also see JSONP in action later. Dart packages Every Dart project that contains the pubspec.yaml file is also a package. Our search algorithm is a nice example of a component that can be used in multiple projects, so we'll stick to a few conventions that will make our code reusable. Dart doesn't have namespaces like other languages, such as PHP, Java, or C++. Instead, it has libraries that are very similar in concept. We'll start writing our app by creating a new project with the Uber Simple Web Application template and creating two directories. First, we create /lib in the project's root. Files in this directory are automatically made public for anyone using our package. The second directory is /lib/src, where we'll put the implementation of our library, which is going to be private. Let's create a new file in /lib/fuzzy.dart: // lib/fuzzy.dart library fuzzy; part 'src/fuzzy_search.dart'; This creates a library called fuzzy. We could put all the code for this library right into fuzzy.dart, but that would be a mess. We'd rather split the implementation into multiple files and use the part keyword to tell Dart to make all the functions and classes defined in lib/src/fuzzy_search.dart public. One library can use the part keyword multiple times. Similar to object properties, everything that starts with the _ underscore is private and not available from the outside. Then, in lib/src/fuzzy_search.dart, we'll put just the basic skeleton code right now: // lib/src/fuzzy_search.dart part of fuzzy; class FuzzySearch { /* ... */ } The part of keyword tells Dart that this file belongs to the fuzzy library. Then, in main.dart, we need to import our own library to be able to use the FuzzySearch class: // web/main.dart import 'package:Chapter_02_doc_search/fuzzy.dart'; // ... later in the code create an instance of FuzzySearch. var obj = new FuzzySearch(); Note that the fuzzy.dart file is inside the lib directory, but we didn't have to specify it. The package importer is actually not working with directory names but package names, so Chapter_02_doc_search here is a package name from pubspec.yaml and not a directory, although these two have the same name. For more in-depth information about pubspec.yaml files, refer to https://www.dartlang.org/tools/pub/pubspec.html. You should end up with a structure like this: Note that the package has a reference to itself in the packages directory. One package can be a library and a web app at the same time. If you think about it, it's not total nonsense, because you can create a library and ship it with a demo app that shows what the library does and how to use it. You can read more about Dart packages at https://www.dartlang.org/tools/pub/package-layout.html. Writing the fuzzy search algorithm We can move on with writing the fuzzy search algorithm. A proper name for this algorithm would be probably approximate string matching, because our implementation is simpler than the canonical and we don't handle typos. Try to read the code: // lib/src/fuzzy_search.dartpart of fuzzy;   class FuzzySearch { List<String> list; FuzzySearch(this.list); List<String> search(String term) {    List<String> results = [];       if (term.isEmpty) {      return [];    }       // Iterate entire list.    List<String> result = list.where((String key) {      int ti = 0; // term index      int si = 0; // key index      // Check order of characters in the search      // term and in the string key.      for (int si = 0; si < key.length; si++) {        if (term[ti] == key[si]) {          ti++;          if (ti == term.length) {            return true;          }        }      }      return false;    }).toList(growable: false);       // Custom sort function.    // We want the shorter terms to be first because it's more    // likely that what you're looking for is there.    result.sort((String a, String b) {      if (a.length > b.length) {        return 1;      } else if (a.length == b.length) {        return 0;      }       return -1;    });       return result; } } The app itself will require a simple HTML code (we're omitting obvious surrounding code, such as <html> or <head>): <body> <input type="search" id="search" disabled> <ul id="autocomplete-results"></ul>   <div id="detail">    <h1></h1>    <div></div> </div>   <script type="application/dart" src="main.dart"></script> <script data-pub-inline src="packages/browser/dart.js"></script> </body> We don't want to hardcode the dictionary, so we'll load it using Ajax. JSON file with all search terms, and it looks like this: { ... "strpos": {    "desc": "Find the numeric position of the first occurrence       of 'needle' in the 'haystack' string.",    "name": "strpos" },    ... "pdo::commit": {    "desc": "...",    "name": "PDO::commit" }, ... } The key for each item is its lowercased name. In Dart, this JSON will be represented as: Map<String, Map<String, String>> Now, we'll write a static method that creates an instance of our app and the main() function: import 'dart:html'; import 'dart:convert'; import 'dart:async'; import 'package:Chapter_02_doc_search/fuzzy.dart';   class DocSearch { static fromJson(Element root, String url) async {    String json = await HttpRequest.getString(url);  Map decoded = JSON.decode(json);    return new DocSearch(root, decoded); }   DocSearch(Element root, [Map<String, dynamic> inputDict] {    // Rest of the constructor. } // The rest of the class goes here. }     main() async { try {    await DocSearch.fromJson(querySelector('body'), 'dict.json'); } catch(e) {    print("It's broken."); } } Note how we're creating an instance of DocSearch and are declaring main() as asynchronous. We call a DocSearch.fromJson()static method, which returns a Future object (the async keyword does this for us automatically), which is completed with an instance of DocSearch when the Ajax call is finished and when we decoded JSON into a Map object. The source code for this example contains both Dart 1.9 implementation with async and await and pre 1.9 version with the raw Future and Completer classes. Handling HTML elements You can see that if we hardcoded our dictionary, we could call the constructor of DocSearch like with any other class. We can now look at the constructor particularly: // web/main.dart class DocSearch { Element _root; InputElement _input; UListElement _ul; FuzzySearch _fuzzy; Map<String, dynamic> _dict; static Future fromJson(Element root, String url) async {    /* The same as above. */ } DocSearch(Element root, [Map<String, dynamic> inputDict]) {    _root = root;    dict = inputDict;    _input = _root.querySelector('input');    _ul = _root.querySelector('ul');       // Usage of ".." notation.    _input      ..attributes.remove('disabled')      ..onKeyUp.listen((_) => search(_input.value))      ..onFocus.listen((_) => showAutocomplete());       _ul.onClick.listen((Event e) {      Element target = e.target;      showDetail(target.dataset['key']);    });       // Pass only clicks that are not into <ul> or <input>.    Stream customOnClick = document.onClick.where((Event e) {      Element target = e.target;      return target != _input && target.parent != _ul;    });    customOnClick.listen((Event e) => hideAutocomplete()); }   /* The rest of the class goes here. */ } To set multiple properties to the same object, we can use the double dot operator. This lets you avoid copying and pasting the same object name over and over again. This notation is equal to: _input.attributes.remove('disabled') _input.onKeyUp.listen((_) => search(_input.value)) _input.onFocus.listen((_) => showAutocomplete()); Of course, we can use it for more nested properties as well: elm.attributes ..remove('whatever') ..putIfAbsent('value', 'key') In the constructor, we're creating a custom Stream object, as we talked about earlier in this article. This stream passes only clicks outside our <ul> and <input> elements, which represent autocomplete container and a search input filed, respectively. We need to do this because we want to be able to hide the autocomplete when the user clicks outside of the search field. Using just onBlur in the input field (the lost focus event) wouldn't work as we wanted, because any click in the autocomplete would hide it immediately without emitting onClick inside the autocomplete. This is a nice place for custom streams. We could also make our stream a public property and let other developers bind listeners to it. In vanilla JavaScript, you would probably do this as an event that checks both conditions and emits a second event and then listen only to the second event. The rest of the code is mostly what we've already seen, but it's probably good idea to recap it in context. From now on, we'll skip obvious things such as DOM manipulation unless there's something important. We're also omitting CSS files because they aren't important to us: // web/main.dart class DocSearch { /* Properties are the same as above. */ static fromJson(Element root, String url) async { /* ... */ } DocSearch(Element root, [Map<String, dynamic> inputDict]) {     /* ... */ }   // Custom setter for dict property. When we change // the dictionary that this app uses, it will also change // the search list for the FuzzySearch instance. void set dict(Map<String, dynamic> dict) {    _dict = dict;    if (_fuzzy == null) {      _fuzzy = new FuzzySearch(_dict.keys.toList());    } else {      _fuzzy.list = _dict.keys.toList();    } } void search(String term) {    if (term.length > 1) {      int start = new DateTime.now().millisecondsSinceEpoch;      List<String> results =          _fuzzy.search(_input.value.toLowerCase());      int end = new DateTime.now().millisecondsSinceEpoch;      // Debug performance. Note the usage of interpolation.      print('$term: ${(end - start).toString()} ms');        renderAutocomplete(results);    } else {      hideAutocomplete();    } } void renderAutocomplete(List<String> list) {    if (list.length == 0) hideAutocomplete();    }    // We'll use DocumentFragment as we talked about earlier.    // http://jsperf.com/document-fragment-test-peluchetti    DocumentFragment frag = new DocumentFragment();       list.forEach((String key) {      LIElement li = new LIElement();      li.text = _dict[key]['name'];      // Same as creating 'data-key' attribute or using data()      // method in jQuery.      li.dataset['key'] = key;      frag.append(li);    });       _ul.children.clear();    _ul.append(frag.clone(true));  showAutocomplete(); } void showDetail(String key) {    Map<String, String> info = _dict[key];    _root.querySelector('#detail > h1').text = info['name'];       String desc = info['desc']      ..replaceAll('\n\n', '</p><p>')      ..replaceAll('\_', '_');    _root.querySelector('#detail > div').innerHtml =        '<p>' + desc + '</p>';       hideAutocomplete(); } void showAutocomplete() { _ul.style.display = 'block'; } void hideAutocomplete() { _ul.style.display = 'none'; } } Note that we defined a custom setter for the dict property, so when we change it from anywhere in the code, it also changes the list property in the instance of the FuzzySearch class. Dart allows writing both custom getters and setters: void set property(<T> newValue) { // Custom logic here. } <T> get property { // Custom logic here. // return an instance of <T> } Finally, we can test it in the browser: When you type at least two characters in the search field, it opens autocomplete with suggested function names. You can click on one of them; it closes the autocomplete and shows a simple detail window with its name and description. You can open Developer Tools and see how much time it took for Dart to traverse the entire 9,047 string list (it's about 25 ms in Intel Core Duo 2.5 GHz). As we're already creating the FuzzySearch class as a reusable library, it would be nice if we could use it not just in Dart but also in JavaScript. Summary This article focused on a very practical aspect of Dart. From Streams and the Future-Based API to Ajax, Dart 1.9 took a significant step forward in simplifying the usage of asynchronous APIs using new async and await keywords. If you don't find yourself familiar with the Future-Based API, at least try to understand the new async and await features and try to compare Dart's approach to an asynchronous code to what you already know from JavaScript. Resources for Article: Further resources on this subject: Handling the DOM in Dart [article] Handle Web Applications [article] Dart with JavaScript [article]
Read more
  • 0
  • 0
  • 1868
Modal Close icon
Modal Close icon