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-writing-your-first-lines-coffeescript
Packt
29 Aug 2013
9 min read
Save for later

Writing Your First Lines of CoffeeScript

Packt
29 Aug 2013
9 min read
(For more resources related to this topic, see here.) Following along with the examples I implore you to open up a console as you read this article and try out the examples for yourself. You don't strictly have to; I'll show you any important output from the example code. However, following along will make you more comfortable with the command-line tools, give you a chance to write some CoffeeScript yourself, and most importantly, will give you an opportunity to experiment. Try changing the examples in small ways to see what happens. If you're confused about a piece of code, playing around and looking at the outcome will often help you understand what's really going on. The easiest way to follow along is to simply open up a CoffeeScript console. Just run this from the command line to get an interactive console: coffee If you'd like to save all your code to return to later, or if you wish to work on something more complicated, you can create files instead and run those. Give your files the .coffee extension , and run them like this: coffee my_sample_code.coffee Seeing the compiled JavaScript The golden rule of CoffeeScript, according to the CoffeeScript documentation, is: It's just JavaScript. This means that it is a language that compiles down to JavaScript in a simple fashion, without any complicated extra moving parts. This also means that it's easy, with a little practice, to understand how the CoffeeScript you are writing will compile into JavaScript. Your JavaScript expertise is still applicable, but you are freed from the tedious parts of the language. You should understand how the generated JavaScript will work, but you do not need to actually write the JavaScript. To this end, we'll spend a fair amount of time, especially in this article, comparing CoffeeScript code to the compiled JavaScript results. It's like peeking behind the wizard's curtain! The new language features won't seem so intimidating once you know how they work, and you'll find you have more trust in CoffeeScript when you can check in on the code it's generating. After a while, you won't even need to check in at all. I'll show you the corresponding JavaScript for most of the examples in this article, but if you write your own code, you may want to examine the output. This is a great way to experiment and learn more about the language! Unfortunately, if you're using the CoffeeScript console to follow along, there isn't a great way to see the compiled output (most of the time, it's nice to have all that out of sight—just not right now!). You can see the compiled JavaScript in several other easy ways, though. The first is to put your code in a file and compile it. The other is to use the Try CoffeeScript tool on http://coffeescript.org/. It brings up an editor right in the browser that updates the output as you type. CoffeeScript basics Let's get started! We'll begin with something simple: x = 1 + 1 You can probably guess what JavaScript this will compile to: var x;x = 1 + 1; Statements One of the very first things you will notice about CoffeeScript is that there are no semicolons. Statements are ended by a new line. The parser usually knows if a statement should be continued on the next line. You can explicitly tell it to continue to the next line by using a backslash at the end of the first line: x = 1+ 1 It's also possible to stretch function calls across multiple lines, as is common in "fluent" JavaScript interfaces: "foo" .concat("barbaz") .replace("foobar", "fubar") You may occasionally wish to place more than one statement on a single line (for purely stylistic purposes). This is the one time when you will use a semicolon in CoffeeScript: x = 1; y = 2 Both of these situations are fairly rare. The vast majority of the time, you'll find that one statement per line works great. You might feel a pang of loss for your semicolons at first, but give it time. The calluses on your pinky finger will fall off, your eyes will adjust to the lack of clutter, and soon enough you won't remember what good you ever saw in semicolons. Variables CoffeeScript variables look a lot like JavaScript variables, with one big difference: no var! CoffeeScript puts all variables in the local scope by default. x = 1y = 2z = x + y compiles to: var x, y, z;x = 1;y = 2;z = x + y; Believe it or not, this is one of my absolute top favorite things about CoffeeScript. It's so easy to accidentally introduce variables to the global scope in JavaScript and create subtle problems for yourself. You never need to worry about that again; from now on, it's handled automatically. Nothing is getting into the global scope unless you want it there. If you really want to put a variable in the global scope and you're really sure it's a good idea, you can easily do this by attaching it to the top-level object. In the CoffeeScript console, or in Node.js programs, this is the global object: global.myGlobalVariable = "I'm so worldly!" In a browser, we use the window object instead: window.myGlobalVariable = "I'm so worldly!" Comments Any line that begins with a # is a comment. Anything after a # in the middle of a line will also be a comment. # This is a comment."Hello" # This is also a comment Most of the time, CoffeeScripters use only this style, even for multiline comments. # Most multiline comments simply wrap to the# next line, each begun with a # and a space. It is also possible (but rare in the CoffeeScript world) to use a block comment, which begins and ends with ###. The lines in between these characters do not need to begin with a #. ###This is a block comment. You can get artistic in here.<(^^)>### Regular comments are not included in the compiled JavaScript, but block comments are, delineated by /* */. Calling functions Function invocation can look very familiar in CoffeeScript: console.log("Hello, planet!") Other than the missing semicolon, that's exactly like JavaScript, right? But function invocation can also look different: console.log "Hello, planet!" Whoa! Now we're in unfamiliar ground. This will work exactly the same as the previous example, though. Any time you call a function with arguments, the parentheses are optional. This also works with more than one argument: Math.pow 2, 3 While you might be a little nervous writing this way at first, I encourage you to try it and give yourself time to become comfortable with it. Idiomatic CoffeeScript style eliminates parentheses whenever it's sensible to do so. What do I mean by "sensible"? Well, imagine you're reading your code for the first time, and ask yourself which style makes it easiest to comprehend. Usually it's most readable without parentheses, but there are some occasions when your code is complex enough that judicious use of parentheses will help. Use your best judgment, and everything will turn out fine. There is one exception to the optional parentheses rule. If you are invoking a function with no arguments, you must use parentheses: Date.now() Why? The reason is simple. CoffeeScript preserves JavaScript's treatment of functions as first-class citizens. myFunc = Date.now #=> myFunc holds a function object that hasn't been executedmyDate = Date.now() #=> myDate holds the result of the function's execution CoffeeScript's syntax is looser, but it must still be unambiguous. When no arguments are present, it's not clear whether you want to access the function object or execute the function. Requiring parentheses makes it clear which one you want, and still allows both kinds of functionality. This is part of CoffeeScript's philosophy of not deviating from the fundamentals of the JavaScript language. If functions were always executed instead of returned, CoffeeScript would no longer act like JavaScript, and it would be hard for you, the seasoned JavaScripter, to know what to expect. This way, once you understand a few simple concepts, you will know exactly what your code is doing. From this discussion, we can extract a more general principle: parentheses are optional, except when necessary to avoid ambiguity . Here's another situation in which you might encounter ambiguity: nested function calls. Math.max 2, 3, Math.min 4, 5, 6 Yikes! What's happening there? Well, you can easily clear this up by adding parentheses. You may add parentheses to all the function calls, or you may add just enough to resolve the ambiguity: # These two calls are equivalentMath.max(2, 3, Math.min(4, 5, 6))Math.max 2, 3, Math.min(4, 5, 6) This makes it clear that you wish min to take 4 and 5 as arguments. If you wished 6 to be an argument to max instead, you would place the parentheses differently. # These two calls are equivalentMath.max(2, 3, Math.min(4, 5), 6)Math.max 2, 3, Math.min(4, 5), 6 Precedence Actually, the original version I showed you is valid CoffeeScript too! You just need to understand the precedence rules that CoffeeScript uses for functions. Arguments are assigned to functions from the inside out . Another way to think of this is that an argument belongs to the function that it's nearest to. So our original example is equivalent to the first variation we used, in which 4, 5, and 6 are arguments to min: # These two calls are equivalentMath.max 2, 3, Math.min 4, 5, 6Math.max 2, 3, Math.min(4, 5, 6) The parentheses are only absolutely necessary if our desired behavior doesn't match CoffeeScript's precedence—in this case, if we wanted 6 to be a argument to max. This applies to an unlimited level of nesting: threeSquared = Math.pow 3, Math.floor Math.min 4, Math.sqrt 5 Of course, at some point the elimination of parentheses turns from the question of if you can to if you should. You are now a master of the intricacies of CoffeeScript function-call parsing, but the other programmers reading your code might not be (and even if they are, they might prefer not to puzzle out what your code is doing). Avoid parentheses in simple cases, and use them judiciously in the more complicated situations.
Read more
  • 0
  • 0
  • 2248

article-image-top-features-youll-want-know-about
Packt
12 Jun 2013
10 min read
Save for later

Top features you'll want to know about

Packt
12 Jun 2013
10 min read
(For more resources related to this topic, see here.) 1 – Track changes and production revisions (for Adobe Story Plus only) It is important to keep track of any changes you or someone else may make to a document. It's easy to save over the previous version with the new one, but what if you want to compare the previous and current versions to one another? You are able to track any and all revisions through this feature. Called revision styles, all revisions become associated with a unique style for easier identification. Track changes Before moving to revisions, we need to be able to know how to insert and track changes made to a document. This is how it is done: When in the AUTHORING view, in the document, go to the Review tab in the top tool bar. Check Start Tracking Changes to enable it, and uncheck it to disable: When it is checked, any new content you add will be in red text and highlighted: There is a speech bubble on the right-hand side of the addition, which allows for the person making the change to add a comment. Click on the icon to open the comment window: When you place the cursor over the inserted change, a new bubble will appear telling you who made the change and when. On the far right-hand side, you can either accept or reject the change: Production revisions You have to be in the Authoring view in order to make a revision. Production revisions highlight certain pages where changes have been made. The script becomes locked and all changes are highlighted in the revision style you choose. On the title page, a note is inserted on the bottomright corner giving the date of the last revision. This is also done on the footer of every page where there is a change. The color changes and borders will not be exported in a PDF. Before starting a revision, make sure that you have done the following: Act on all tracked changes in your document by accepting or rejecting them. Disable track changes after completing accepting/rejecting tracked changes. Now, after completing the preceding steps, follow these steps: Select Production | Start Revision. In the Active Revision drop-down, choose a revision style: This style will be used for the markups in the revision. Make sure that you haven't already used the chosen style for a previous revision document. Click Start Revision. Creating a revision style Follow these steps to create your revision style: Select Production | Manage Revisions. Click on the + icon. Enter a name for the style The following options can be tailored according to your needs: Revision Color: Used to choose a color from the color menu. This color will then be applied to all the revised text and the border of the individual pages that contain the revisions. The border color will not be displayed in a printed or exported document. Mark: The default mark is displayed on the right of the revised content. You can change this mark by choosing any symbol of your liking. Date: The revision date. Revision Text Style: The chosen formatting option is used to display revised text. Click Done and your new style will be available from now on. Deleting or modifying existing revisions Let's take a look at how we can delete or modify already existing revisions: Select the style that you want to delete or modify. You can do either of the following: Click on the - sign to delete the style To modify, simply edit its values and click Done Display options for revisions Adobe Story also provides some display options for revisions, here's how we can set them up: Select Production | Manage Revisions. In Viewing Options, the following display options can be personalized according to your needs: Show Markup For: The options are Select All or Active. This will let you choose whether you want to have all the markups shown for all revisions or just the active ones. Mark Position: The mark you set in Revision Style is set to the right-hand side by default; you can also change its position. Show Date In Script Header and Footer: If you do not want to display the date, disable this option. Locking or unlocking scene numbers When you lock scene numbers, you prevent the renumbering of existing scenes whenever a new scene is added during production revisions. When you do insert a new scene, Adobe Story will apply a number to the scene preceding it. For example, if you add a new scene in between scene 4 and 5, it will be numbered 4A. Here's how we can lock and unlock scene numbers: Select Production | Manage Scene Numbers. Select the Keep Existing Scene Number option to lock all current scenes. To unlock, deselect Keep Existing Scene Number. Omitting or unomitting scenes Adobe Story allows you to remove a scene without affecting the scene numbers remaining in the script. The word OMITTED will appear at the location of the scene you've chosen to omit. You can, at a later date, unomit the scene if you chose and recover the content. To omit a scene, simply place your cursor on the scene and then select Production | Omit Scene. To unomit a scene, place your cursor on the omitted scene and then select Production | Unomit Scene. Printing production revisions If you want to print your revisions, it is easy to do so; just follow these steps: Select File | Print. Choose any one of the following option: Entire Script All ChangedPages Revision To print in color, select the Print Revised Text In Color option. Identifying the total number of revised pages Here's how we can identify the total number of revised pages: Select Production | Manage Revisions. In Viewing Options, select All and click Done. 2 – Tagging Along with the advent of the "cloud" concept, tagging individual words to content has become something of a norm in today's online society. Adobe Story has incorporated a similar system. With tagging, you can tag words and phrases in your scripts automatically, or manually by using the Tagging Panel option. For example, "boom" can be tagged as "sound effect". Tagging panel To open the panel, you must be first in the AUTHORING view. Select View | Tagging Panel. The panel will open on the right-hand side of the document. To add tags to the panel, enter the name of the tag in the field next to the Create button: To delete a tag from the tagging panel, select the tag and then click on the Delete this Tag link: Tagging automatically You must be in the online mode for the Autotagging feature to work. It will not work in the offline mode. The Autotagging feature is only available for English scripts. This is how it's done: Select File | Tagging | Start Autotagging. Or select it from the drop-down menu option in the Tagging panel: Once you enable Autotagging, the script will be locked. You will have to wait until the process has completed before being able to edit the document; the following screenshot shows the message being displayed: Tagging manually Select View | Tagging Panel. Choose the word or phrase you would like to tag. If what you're choosing has already been tagged, it will be appended to the tag list for the word or phrase. Select a tag from Taglist in the Tagging panel. Do either of the following: Select the Show In Bold option if you want the tagged words or phrases to be displayed in bold. Select the Show Color option if you would prefer Story to display the selected color (you can choose a color for each tag with a color palette on the righthand of the tag in the Taglist panel) to the tag: Finding words or phrases by their specific tag Follow these steps to search for words or phrases with a specific tag: Disable visibility for all tags. Enable visibility for the tag that you want to search. To do this, simply click on the eye icon on the left-hand side of the tagged word: Use the arrow icons in the Tagging panel in order to navigate through the tags in the script. Only the visible tags will be shown. Viewing tags associated with a word or phrase To view tags associated with a word or a phrase, you can do either of the following: Select the word/phrase. The tags associated with the word/phrase will be highlighted in the Tagging panel. Scroll through the panel in order to view the tags associated with it: Move your mouse over the word/phrase. The information will be displayed in the tool tip: Hold Ctrl (Cmd on Mac) and double-click to view the associated tags: Removing tags Over the word you wish to edit, hold Ctrl (Cmd on Mac) and double-click to bring up the Applied Tags panel. Click on the Remove This Tag icon for the chosen tag. Click Close. To remove all the tags, select File | Tagging | Remove All Tags. To remove all the manual tags, select File | Tagging | Remove All Manual Tags. To remove all the auto tags, select File | Tagging | Remove Auto Tags. 3 – Application for iOS-based devices Adobe Story has an application for iOS-based devices. This application is available currently only in English. It allows you to read and review Adobe Story scripts and documents. It does not support AV (Audio Visual) scripts, Multicolumn scripts, and TV scripts as of yet. Logging in Before you start, make sure you have registered yourself with Adobe Story using the web or desktop application. Use the same combination of e-mail address and password used on the full application with the iOS version. Accept the TOU before attempting to log in. If you want to log out, select Account and then select Log Out. Viewing documents, scene outline, and scenes The ten most recently read files will be displayed upon logging in to the Adobe Story application. To view all the documents, click Categories. To view the scene outline, select the script in the Recent Files or Categories view. To view the contents of a scene, select the scene in the scene outline. Use the arrow icons to move among the scenes. To view Notifications, in the Recent Files view, select Notifications. A list of notifications is displayed. Highlighted notifications are for new ones. Reviewing scripts As long as you have author, co-author, or reviewer permissions, you will be able to review a script. Open the script and navigate to the scene. Do one of the following: Double-click to select the content that you want to comment on. Click on Comment, or on the Add Comment button. To comment on the content that has already been commented on, enter your comment in the Write New Comment textbox. To navigate comments, use the arrow icons. Click Post. Viewing or deleting comments In the scene containing the comments, select Comments. The comment list is displayed. The paragraph containing the comment is highlighted when you select on a comment in the list. Select Delete after clicking on the desired comment. Summary In this article we learned about three of Adobe Story's key features. We learned about track changes and production revisions. we learned about tagging, and learned about more about Adobe Story in iOS devices. There is a whole lot more to learn as far as the features in Adobe Story is concerned. Resources for Article : Further resources on this subject: Integrating Scala, Groovy, and Flex Development with Apache Maven [Article] Exporting SAP BusinessObjects Dashboards into Different Environments [Article] An Introduction to Flash Builder 4-Network Monitor [Article]
Read more
  • 0
  • 0
  • 2245

article-image-sage-act-2011-creating-quick-report
Packt
24 Feb 2011
6 min read
Save for later

Sage ACT! 2011: Creating a Quick Report

Packt
24 Feb 2011
6 min read
  Sage ACT! 2011 Dashboard and Report Cookbook Introduction The ACT! program provides two different types of reports: Quick reports and Standard reports. The standard report requires that a template be prepared in advance. The template may be brand new, an existing template, or a modified version of an existing template. While the standard report's template design is very flexible, it does require significant effort to design and organize the template. For complex reporting needs or reports that are frequently required, the standard reports are the best. This article shows how to run the various quick reports available in the ACT! program. You'll be shown how to set up, control headers and footers and run the various quick reports. The ease of creating a quick report makes them ideal for single use reports. The configuration of a quick report can't be saved so if a quick report configuration is frequently required, you should consider creating a standard report template instead. The ACT! Demo database is used for the tasks in this article. Setting preferences for the quick reports The preferences for all the quick reports can be individually set in the ACT! general preferences. Unless blocked, they can be set at the time you run the quick report. Here we will set the preferences for the contact list quick reports. Getting ready Because we are setting global preferences, there isn't any preparation required other than to have an ACT! database open. How to do it... From any screen in the ACT! program, click on the Tools menu and choose Preferences.... In the Preferences dialog, click on the Communication tab. In the Printing section, click on the Quick Print Preferences... button. In the Views section, select Contact List. For Print orientation, click on the radio button for Landscape. For Print sizing, click on the radio button for Actual size. For Other options, check Same font in my list view. Check Show Quick Print Options when printing. Click the Header Options button. Check Page Number, Print Date, Print Time, and My Record. Click OK. Click Footer Options button. Uncheck all options and click OK. Click OK to close the Quick Print Preferences dialog. Click OK to close the Preferences dialog. How it works... At this point, we are setting the general options for the Quick Print reports. In the Quick Print Preferences dialog Views section, all of the possible Quick Print report possibilities are shown and each can be configured separately. This task used the Contact List Quick Report as an example. The Portrait - Landscape option determines the orientation of the printed report. As a general rule the Print Sizing option should be set to actual size because the fit to page option shrinks the report both horizontally and vertically to fit on one page. Used with the Contact List Quick Report could result in a final report that was not legible. The font selection would most likely be the same as used on the contact list view, but it does provide for changing the desired font. The header and footer options are the same and typically one or the other would be used but not both. The My record option prints the name of the user running the report. The Show Quick Print options when printing allow for adjusting the report options when running the report. Unchecked, the report will go directly to the printer. There's more... The Quick Reports don't provide any means for setting the page margins. While the Fit to page option should typically be set to Actual size for a list view Quick Report, you will likely want to use the Fit to page option when doing a Quick Print of a detail view. Selecting and organizing the columns for a Contact List Quick Report In this task, we continue working with the Contact List Quick Report. The contact list is able to display all the fields in the contact table. While possible, in most cases this would be impractical. To create a meaningful report you need to decide which fields you want to show in the report. Because you will be printing the contact list, make sure the contact list is showing the fields that you want and that they are arranged in the desired order. In this task we will set up a name and address list. Getting ready There isn't any preparation required for the Contact List Quick Report other than having an ACT! database open. How to do it... In the navigation bar, on the right-hand side of the screen, click on Contacts. In the tool bar, click on List View button. Anywhere in the List View, right-click and select Customize Columns.... In the Customize Columns dialog, add fields to the list by clicking in the desired field in the Available fields box and then clicking the top arrow button (points right >). Remove unwanted fields by clicking on the field in the Show as columns in this order box and then clicking on the second from the top arrow button (points left <). Adjust the order of the fields by clicking on a field in the Show as columns in this order box and click on the Move Up or Move Down buttons to move the field to the desired location. Click the OK button to close and save the field configuration. In the title bar of the contact list, point the cursor to the division between columns and the cursor becomes a double ended arrow. Drag the division line to adjust the column width. Adjust the remaining columns in the same manner. How it works... Because the Quick Reports are basically screen image reports, it's necessary to make the screen look the way you want the report to look. For the Contact List Quick Report (and most list reports) this requires selecting the fields (columns) that you want in the report and arranging and sizing them so they look the way you want them to look on the printed report. The Customize Columns dialog provides the mechanism for selecting the fields to include and to position them in the desired order. Sizing the columns is a bit harder. The columns divisions can be dragged to widen or narrow a column. The column being sized is the column to the left of the column division. There's more... The Quick Reports don't provide any means for directly filtering the output. The best means of filtering the contacts included in the Contact List Quick Report is to use a lookup of the contacts to include in the report. You can also apply a simple sort on the contact list by clicking on the column title of the column you want to use for sorting. Each time you click on the column title, you reverse the sort order.
Read more
  • 0
  • 0
  • 2241

article-image-saying-hello-java-ee
Packt
03 Aug 2016
27 min read
Save for later

Saying Hello to Java EE

Packt
03 Aug 2016
27 min read
To develop a scalable, distributed, well-presented, complex, and multi-layered enterprise application is complicated. The development becomes even worse if the developer is not well aware of the software development fundamentals. Instead of looking at a bigger scenario, if we cut it down into parts and later combine them, it becomes easy for understanding as well as for developing. Each technology has some basics which we cannot overlook. Rather, if we overlook them, it will be the biggest mistake; the same is applicable to Java EE. In this article by TejaswiniMandar Jog, author of the book Learning Modular Java Programming, we are going to explore the following: Java EE technologies Why servlet and JSP? Introduction to Spring MVC Creating a sample application through Spring MVC (For more resources related to this topic, see here.) The enterprise as an application To withstand the high, competitive, and daily increasing requirements, it's becoming more and more difficult nowadays to develop an enterprise application. The difficulty is due to more than one kind of service, requirement of application to be robust and should support concurrency, security, and many more. Along with these things, enterprise applications should provide an easy user interface but good look and feel for different users. In the last article, we discussed enterprise applications. The discussion was more over understanding the terminology or the aspect. Let's now discuss it in terms of development, and what developers look forward to: The very first thing even before starting the development is: what we are we developing and why? Yes, as a developer we need to understand the requirements or the expectations from the application. Developers have to develop an application which will meet the requirements. The application should be efficient and with high quality so as to sustain in the market. The application code should be reliable and bug-free to avoid runtime problems. No application is perfect; it's a continuous process to update it for new demands. Develop an application in such a way that it is easy to update. To meet high expectations, developers write code which becomes complicated to understand as well as to change. Each one of us wants to have a new and different product, different from what is on the market. To achieve this, designers make an over-clumsy design which is not easy to change in the future. Try to avoid over-complexity both in design and business logic. When development starts, developers look forward to providing a solution, but they have to give thought to what they are developing and how the code will be organized in terms of easy maintenance and future extension. Yes, we are thinking about modules which are doing a defined task and those which are less dependent. Try to write a module which will be loosely coupled and highly cohesive. Today we are using enterprise applications through different browsers, such as Internet Explorer, Mozilla, or Firefox. We are even using mobile browsers for the same task. This demands an application that has been developed to withstand the number of platforms and browsers. Going through all this discussion, many technologies come to mind. We will go through one such platform which covers the maximum of the above requirements: the Java Enterprise Edition (Java EE) platform. Let's dive in and explore it!! The Java EE platform Sun Microsystems released the Java EE platform in 2000, which was formerly known as the J2EE specification. It defines the standards for developing component-based enterprise applications easily. The concrete implementation is provided by application servers such as Weblogic and GlassFish, and servlet containers such as Tomcat. Today we have Java EE 8 on the market. Features of the Java EE platform The following are the various features of the Java EE platform: Platform independency: Different types of information which the user needs in day-to-day life is spread all over the network on a wide range of platforms. Java EE is well adapted to support, and use this widely spread multiple format information on different platforms easily. Modularity: The development of enterprise applications is complex and needs to be well organized. The complexity of the application can be reduced by dividing it into different, small modules which perform individual tasks, which allows for easy maintenance and testing. They can be organized in separate layers or tiers. These modules interact with each other to perform a business logic. Reusability: Enterprise applications need frequent updates to match up client requirements. Inheritance, the fundamental aspect of an object-oriented approach, offers reusability of the components with the help of functions. Java EE offers modularity which can be used individually whenever required. Scalability: To meet the demands of the growing market, the enterprise application should keep on providing new functionalities to the users. In order to provide these new functionalities, the developers have to change the application. They may add new modules or make changes in already existing ones. Java EE offers well-managed modules which make scalability easy. The technologies used in Java EE are as follows: Java servlet Java Server Pages Enterprise Java Bean Java Messaging API XML Java Transaction API Java Mail Web Services The world of dotcoms In the 1990s, many people started using computers for a number of reasons. For personal use, it was really good. When it came to enterprise use, it was helpful to speed up the work. But one main drawback was; how to share files, data or information? The computers were in a network but if someone wanted to access the data from any computer then they had to access it personally. Sometimes, they had to learn the programs on that computer, which is not only very time-consuming but also unending. What if we can use the existing network to share the data remotely?? It was a thought put forward by a British computer scientist, Sir Tim Berners-Lee. He thought of a way to share the data through the network by exploring an emerging technology called hypertext. In October 1990, Tim wrote three technologies to fulfill sharing using Hyper Text Markup Language (HTML), Uniform Resource Identifier (URI), and Hyper Text Transfer Protocol (HTTP): HTML is a computer language which is used in website creation. Hypertext facilitates clicking on a link to navigate on the Internet. Markups are HTML tags defining what to do with the text they contain. URIs defines a resource by location or name of resource, or both. URIs generally refer to a text document or images. HTTP is the set of rules for transferring the files on the Web. HTTP runs on the top of TCP/IP. He also wrote the first web page browser (World Wide Webapp) and the first web server (HTTP). The web server is where the application is hosted. This opened the doors to the new amazing world of the "dotcom". This was just the beginning and many more technologies have been added to make the Web more realistic. Using HTTP and HTML, people were able to browse files and get content from remote servers. A little bit of user interaction or dynamicity was only possible through JavaScript. People were using the Web but were not satisfied; they needed something more. Something which was able to generate output in a totally dynamic way, maybe displaying the data which had been obtained from the data store. Something which can manipulate user input and accordingly display the results on the browser. Java developed one technology: Common Gateway Interface (CGI). As CGI was a small Java program, it was capable of manipulating the data at the server side and producing the result. When any user made a request, the server forward the edit to CGI, which was an external program. We got an output but with two drawbacks: Each time the CGI script was called, a new process was created. As we were thinking of a huge number of hits to the server, the CGI became a performance hazard. Being an external script, CGI was not capable of taking advantage of server abilities. To add dynamic content which can overcome the above drawbacks and replace CGI, the servletwas developed by Sun in June 1997. Servlet – the dynamicity Servlets are Java programs that generate dynamic output which will be displayed in the browser and hosted on the server. These servers are normally called servlet containers or web servers. These containers are responsible for managing the lifecycle of the servlets and they can take advantage of the capabilities of servers. A single instance of a servlet handles multiple requests through multithreading. This enhances the performance of the application. Let's discuss servlets in depth to understand them better. The servlet is capable of handling the request (input) from the user and generates the response (output) in HTML dynamically. To create a servlet, we have to write a class which will be extended from GenericServlet or HttpServlet. These classes have service() as a method, to handle request and response. The server manages the lifecycle of a servlet as follows: The servlet will be loaded on arrival of a request by the servers. The instance will be created. The init() will be invoked to do the initialization. The preceding steps will be performed only once in the life cycle of the servlet unless the servlet has not been destroyed. After initialization, the thread will be created separately for each request by the server, and request and response objects will be passed to the servlet thread. The server will call the service() function. The service() function will generate a dynamic page and bind it to the HttpResponse object. Once the response is sent back to the user, the thread will be deallocated. From the preceding steps, it is pretty clear that the servlet is responsible for: Reading the user input Manipulating the received input Generating the response A good developer always keeps a rule of thumb in mind that a module should not have more than one responsibility, but here the servlet is doing much more. So this has addressed the first problem in testing the code, maybe we will find a solution for this. But the second issue is about response generation. We cannot neglect a very significant problem in writing well-designed code to have a nice look and feel for the page from the servlet. That means a programmer has to know or adapt designing skills as well, but, why should a servlet be responsible for presentation? The basic thought of taking presentation out of the servlet leads to Java Server Page (JSP). JSP solves the issue of using highly designed HTML pages. JSP provides the facility of using all HTML tags as well as writing logical code using Java. The designers can create well-designed pages using HTML, where programmers can add code using scriptlet, expression, declaration, or directives. Even standard actions like useBean can be used to take advantage of Java Beans. These JSP's now get transformed, compiled into the servlet by the servers. Now we have three components: Controller, which handles request and response Model, which holds data acquired from handling business logic View, which does the presentation Combining these three we have come across a design pattern—Model-View-Controller (MVC). Using MVC design patterns, we are trying to write modules which have a clear separation of work. These modules can be upgradable for future enhancement. These modules can be easily tested as they are less dependent on other modules. The discussion of MVC is incomplete without knowing two architectural flavors of it: MVC I architecture MVC II architecture MVC I architecture In this model, the web application development is page-centric around JSP pages. In MVC I, JSP performs the functionalities of handling a request and response and manipulating the input, as well as producing the output alone. In such web applications, we find a number of JSP pages, each one of them performing different functionalities. MVC I architecture is good for small web applications where less complexity and maintaining the flow is easy. The JSP performs the dual task of business logic and presentation together, which makes it unsuitable for enterprise applications. MVC I architecture MVC II architecture In MVC II, a more powerful model has been put forward to give a solution to enterprise applications with a clear separation of work. It comprises two components: one is the controller and other the view, as compared to MVC I where view and controller is JSP (view). The servlets are responsible for maintaining the flow (the controller) and JSP to present the data (the view). In MVC II, it's easy for developers to develop business logic- the modules which are reusable. MVC II is more flexible due to responsibility separation. MVC II architecture The practical aspect We have traveled a long way. So, instead of moving ahead, let's first develop a web application to accept data from the user and display that using MVC II architecture. We need to perform the following steps: Create a dynamic web application using the name Ch02_HelloJavaEE. Find the servlet-api.jar file from your tomcat/lib folder. Add servlet-api.jar to the lib folder. Create index.jsp containing the form which will accept data from the user. Create a servlet with the name HelloWorldServlet in the com.packt.ch02.servlets package. Declare the method doGet(HttpServletRequestreq,HttpServletResponsers) to perform the following task: Read the request data using the HttpServletRequest object. Set the MIME type. Get an object of PrintWriter. Perform the business logic. Bind the result to the session, application or request scope. Create the view with name hello.jsp under the folder jsps. Configure the servlet in deployment descriptor (DD) for the URL pattern. Use expression language or Java Tag Library to display the model in the JSP page. Let's develop the code. The filesystem for the project is shown in the following screenshot: We have created a web application and added the JARs. Let's now add index.jsp to accept the data from the user: <form action="HelloWorldServlet"> <tr> <td>NAME:</td> <td><input type="text" name="name"></td> </tr> <tr> <td></td> <td><input type="submit" value="ENTER"></td> </tr> </form> When the user submits the form, the request will be sent to the URL HelloWorldServlet. Let's create the HelloWorldServlet which will get invoked for the above URL, which will have doGet(). Create a model with the name message, which we will display in the view. It is time to forward the request with the help of the RequestDispatcher object. It will be done as follows: protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {     // TODO Auto-generated method stub     //read the request parameter     String name=request.getParameter("name");     //get the writer PrintWriter writer=response.getWriter();       //set the MIME type response.setContentType("text/html");       // create a model and set it to the scope of request request.setAttribute("message","Hello "+name +" From JAVA Enterprise"); RequestDispatcher dispatcher=request.getRequestDispatcher("jsps/hello.jsp"); dispatcher.forward(request, response);     } Now create the page hello.jsp under the folder jsps to display the model message as follows: <h2>${message }</h2> The final step is to configure the servlet which we just have created in DD. The configuration is made for the URL HelloWorldServlet as follows: <servlet> <servlet-name>HelloWorldServlet</servlet-name> <servlet-class>com.packt.ch02.servlets.HelloWorldServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorldServlet</servlet-name> <url-pattern>/HelloWorldServlet</url-pattern></servlet-mapping> Let's deploy the application to check the output: Displaying the home page for a J2EE application The following screenshot shows the output when a name is entered by the user: Showing the output when a name is entered by the user After developing the above application, we now have a sound knowledge of how web development happens, how to manage the flow, and how navigation happens. We can observe one more thing: that whether it's searching data, adding data, or any other kind of operation, there are certain steps which are common, as follows: Reading the request data Binding this data to a domain object in terms of model data Sending the response We need to perform one or more of the above steps as per the business requirement. Obviously, by only performing the above steps, we will not be able to achieve the end effect but there is no alternative. Let's discuss an example. We want to manage our contact list. We want to have the facilities for adding a new contact, updating a contact, searching one or many contacts, and deleting a contact. The required data will be taken from the user by asking them to fill in a form. Then the data will be persisted in the database. Here, for example, we just want to insert the record in the database. We have to start the coding from reading request data, binding it to an object and then our business operation. The programmers have to unnecessarily repeat these steps. Can't they get rid of them? Is it possible to automate this process?? This is the perfect time to discuss frameworks. What is a framework? A framework is software which gives generalized solutions to common tasks which occur in application development. It provides a platform which can be used by the developers to build up their application elegantly. Advantages of frameworks The advantages of using frameworks are as follows: Faster development Easy binding of request data to a domain object Predefined solutions Validations framework In December 1996, Sun Microsystems published a specification for JavaBean. This specification was about the rules, using which developers can develop reusable, less complex Java components. These POJO classes are now going to be used as a basis for developing a lightweight, less complex, flexible framework: the Spring framework. This framework is from the thoughts of Rod Johnson in February 2003. The Spring framework consists of seven modules: Spring modules Though Spring consists of several modules, the developer doesn't have to be always dependent on the framework. They can use any module as per the requirement. It's not even compulsory to develop the code which has been dependent upon Spring API. It is called a non-intrusive framework. Spring works on the basis of dependency injection (DI), which makes it easy for integration. Each class which the developer develops has some dependencies. Take the example of JDBC: to obtain a connection, the developer needs to provide URL, username, and password values. Obtaining the connection is dependent on these values so we can call them dependencies, and injection of these dependencies in objects is called DI. This makes the emerging spring framework the top choice for the middle tier or business tier in enterprise applications. Spring MVC The spring MVC module is a choice when we look forward for developing web applications. The spring MVC helps to simplify development to develop a robust application. This module can also be used to leave common concerns such as reading request data, data binding to domain object, server-side validation and page rendering to the framework and will concentrate on business logic processes. That's what, as a developer we were looking for. The spring MVC can be integrated with technologies such as Velocity, Freemarker, Excel, and PDF. They can even take advantage of other services such as aspect-oriented programming for cross-cutting technologies, transaction management, and security provided by the framework. The components Let's first try to understand the flow of normal web applications in view of the Spring framework so that it will be easy to discuss the component and all other details: On hitting the URL, the web page will be displayed in the browser. The user will fill in the form and submit it. The front controller intercepts the request. The front controller tries to find the Spring MVC controller and pass the request to it. Business logic will be executed and the generated result is bound to the ModelAndView. The ModelAndView will be sent back to the front controller. The front controller, with the help of ViewResolver, will discover the view, bind the data and send it to the browser. Spring MVC The front controller As already seen in servlet JSP to maintain each flow of the application the developer will develop the servlet and data model from servlet will be forwarded to JSP using attributes. There is no single servlet to maintain the application flow completely. This drawback has been overcome in Spring MVC as it depends on the front controller design pattern. In the front controller design pattern, there will be a single entry point to the application. Whatever URLs are hit by the client, it will be handled by a single piece of the code and then it will delegate the request to the other objects in the application. In Spring MVC, the DispatcherServlet acts as front controller. DispatcherServlet takes the decision about which Spring MVC controller the request will be delegated to. In the case of a single Spring MVC controller in the application, the decision is quite easy. But we know in enterprise applications, there are going to be multiple Spring MVC controllers. Here, the front controller needs help to find the correct Spring MVC controller. The helping hand is the configuration file, where the information to discover the Spring MVC controller is configured using handler mapping. Once the Spring MVC controller is found, the front controller will delegate the request to it. Spring MVC controller All processes, such as the actual business logic, decision making or manipulation of data, happen in the Spring MVC controller. Once this module completes the operation, it will send the view and the model encapsulated in the object normally in the form of ModelAndView to the front controller. The front controller will further resolve the location of the view. The module which helps front controller to obtain the view information is ViewResolver. ModelAndView The object which holds information about the model and view is called as ModelAndView. The model represents the piece of information used by the view for display in the browser of different formats. ViewResolver The Spring MVC controller returns ModelAndView to the front controller. The ViewResolver interface helps to map the logical view name to the actual view. In web applications, data can be displayed in a number of formats, from as simple as JSP to complicated formats like JasperReport. Spring provides InternalResourceViewResolver, JspViewResolver, JasperReportsViewResolver, VelocityLayoutViewResolver, and so on, to support different view formats. The configuration file DispatcherServlet needs to discover information about the Spring MVC controller, ViewResolver, and many more. All this information is centrally configured in a file named XXX-servlet.xml where XXX is the name of the front controller. Sometimes the beans will be distributed across multiple configuration files. In this case, extra configuration has to be made, which we will see later in this article. The basic configuration file will be: <beans xsi_schemaLocation="    http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!—mapping of the controller --> <!—bean to be configured here for view resolver  - -> </beans> The controller configuration file will be named name_of_servlet-servlet.xml. In our project, we will name this HelloWeb-servlet.xml. Let's do the basics of a web application using Spring MVC to accept the data and display it. We need to perform the following steps: Create a web application named Ch02_HelloWorld. Add the required JAR files for Spring (as shown in the following screenshot) and servlets in the lib folder. Create an index page from where the data can be collected from the user and a request sent to the controller. Configure the front controller in DD. Create a SpringMVCcontroller as HelloWorldController. Add a method for accepting requests in the controller which performs business logic, and sends the view name and model name along with its value to the front controller. Create an XML file in WEB-INF as Front_Controller_name-servlet.xml and configure SpringMVCcontroller and ViewResolver. Create a JSP which acts as a view to display the data with the help of Expression Language (EL) and Java Standard Tag Library (JSTL). Let's create the application. The filesystem for the project is as follows: We have already created the dynamic web project Ch02_HelloSpring and added the required JAR files in lib folder. Let's start by creating index.jsp page as: <form action="hello.htm"> <tr> <td>NAME:</td> <td><input type="text" name="name"></td> </tr> <tr> <td></td> <td><input type="submit" value="ENTER"></td> </tr> </form>   When we submit the form, the request is sent to the resource which is mapped for the URL hello.htm. Spring MVC follows the front controller design pattern. So all the requests hitting the application will be first attended by the front controller and then it will send it to the respective Spring controllers. The front controller is mapped in DD as: <servlet> <servlet-name>HelloSpring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloSpring</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> Now the controller needs help to find the Spring MVC controller. This will be taken care of by the configuration file. This file will have the name XXX-servlet.xml where XXX is replaced by the name of the front controller from DD. Here, in this case HelloSpring-servlet.xml will have the configuration. This file we need to keep in the WEB-INF folder. In the Configuration files section, we saw the structure of the file. In this file, the mapping will be done to find out how the package in which the controllers are kept will be configured. This is done as follows: <context:component-scan base-package="com.packt.ch02.controllers" /> Now the front controller will find the controller from the package specified as a value of base-package attribute. The front controller will now visit HelloController. This class has to be annotated by @Controller: @Controller public class HelloController { //code here } Once the front controller knows what the controller class is, the task of finding the appropriate method starts. This will be done by matching the values of @RequestMapping annotation applied either on the class or on the methods present in the class. In our case, the URL mapping is hello.htm. So the method will be developed as: @RequestMapping(value="/hello.htm") publicModelAndViewsayHello(HttpServletRequest request)   {     String name=request.getParameter("name"); ModelAndView mv=new ModelAndView(); mv.setViewName("hello");     String message="Hello "+name +" From Spring"; mv.addObject("message",message); return mv;   } This method will return a ModelAndView object which contains a view name, model name and value for the model. In our code the view name is hello and the model is presented by message. The Front Controller now again uses HelloSpring-servlet.xml for finding the ViewResolver to get the actual name and location of the view. ViewResolver will provide the directory name (location) where the view is placed with a property prefix. The format of the view is given by the property suffix. Using the view name, prefix and suffix, the front controller gets the page. The ViewResolver will bind the model to be used in the view: <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsps/" /> <property name="suffix" value=".jsp" /> </bean> In our case, it will be /WEB-INF/jsps/ as prefix, hello as the name of page, and .jsp is the suffix value. Combining them, we will get /WEB-INF/jsps/hello.jsp, which acts as our view. The Actual view is written as prefix+view_name from ModelAndView+suffix, for instance: /WEB-INF/jsps/+hello+.jsp The data is bounded by the front controller and the view will be able to use it: <h2>${message}</h2>. This page is now ready to be rendered by the browser, which will give output in the browser as: Displaying the home page for a Spring application Entering the name in the text field (for example, Bob) and submitting the form gives the following output: Showing an output when a name is entered by the user Now we understand the working of spring MVC, let's discuss a few more things required in order to develop the Spring MVC controller. Each class which we want to discover as the controller should be annotated with the @Controller annotation. In this class, there may be number of methods which can be invoked on request. The method which we want to map for URL has to be annotated with the annotation @RequestMapping. There can be more than one method mapped for the same URL but it will be invoked for different HTTP methods. This can be done as follows: @RequestMapping(value="/hello.htm",method= RequestMethod.GET) publicModelAndViewsayHello(HttpServletRequest request)   {       } @RequestMapping(value="/hello.htm",method= RequestMethod.POST) publicModelAndViewsayHello(HttpServletRequest request)   {      } These methods normally accept Request as parameter and will return ModelAndView. But the following return types and parameters are also supported. The following are some of the supported method argument types: HttpServletRequest HttpSession Java.util.Map/ org.springframework.ui.Model/ org.springframework.ui.ModelMap @PathVariable @RequestParam org.springframework.validation.Errors/ org.springframework.validation.BindingResult The following are some of the supported method return types: ModelAndView Model Map View String void Sometimes the bean configuration is scattered in more than one file. For example, we can have controller configuration in one file and database, security-related configuration in a separate file. In that case, we have to add extra configuration in DD to load multiple configuration files, as follows: <servlet> <servlet-name>HelloSpring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/beans.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>HelloSpring</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> Summary In this article, we learned how the application will be single-handedly controlled by the front controller, the dispatcher servlet. The actual work of performing business logic and giving the name of the view, data model back will be done by the Spring MVC controller. The view will be resolved by the front controller with the help of the respective ViewResolver. The view will display the data got from the Spring MVC controller. To understand and explore Spring MVC, we need to understand the web layer, business logic layer and data layer in depth using the basics of Spring MVC discussed in this article. Resources for Article:   Further resources on this subject: Working with Spring Tag Libraries [article] Working with JIRA [article] A capability model for microservices [article]
Read more
  • 0
  • 0
  • 2232

article-image-asking-permission-getting-your-head-around-marshmallows-runtime-permissions
Packt
17 Feb 2016
8 min read
Save for later

Asking Permission: Getting your head around Marshmallow's Runtime Permissions

Packt
17 Feb 2016
8 min read
In Android, each application runs with distinct system IDs known as Linux user ID and Group ID. The system parts are also separated into distinct IDs, forming isolated zones for applications—from each other and from the system. As part of this isolated life cycle scheme, accessing services or other applications' data requires that you declare this desire in advance by requesting a permission. This is done by adding the uses-permission element to your AndroidManifest.xml file. Your manifest may have zero or more uses-permission elements, and all of them must be the direct children of the root <manifest> element. Trying to access data or features without proper permission should give out a security exception (using a SecurityException class), informing you about the missing permission in most cases. The sendBroadcast(Intent) method is exceptional as it checks permissions after the method call has returned, so you will not receive an exception if there are permission failures. A permission failure should be printed to the system log. Note that in Android versions prior to Marshmallow, missing permissions were due to missing declarations in the manifest. Hence, it is important that you keep permissions in mind when you come up with the feature list for your app. (For more resources related to this topic, see here.) Understanding Android Marshmallow permissions Android Marshmallow introduces a new application permissions model, allowing a simpler process for users when installing and/or upgrading applications. Applications running on Marshmallow should work according to a new permissions model, where the user can grant or revoke permissions after the installation—permissions are not given until there is user acceptance. Supporting the new permissions model is backward-compatible, which means your apps can still An overview With the Android Marshmallow version, a new application permissions model has been introduced. Let's review it a bit more thoroughly: Declaring permissions: All permissions an app needs are declared in the manifest, which is done to preserve backward compatibility in a manner similar to earlier Android platform versions. Permission groups: As discussed previously, permissions are divided into permission groups based on their functionalities: PROTECTION_NORMAL permissions: Some of the permissions are granted when users install the app. Upon the installation, the system checks your app's manifest and automatically grants permissions that match the PROTECTION_NORMAL group. INTERNET permission: One important permission is the INTERNET permission, which will be granted upon the installation, and the user can't revoke it. App signature permissions granted: The user is not prompted to grant any permissions at the time of installation. Permissions granted by users at runtime: You as an app developer need to request a permission in your app; a system dialog is shown to the user, and the user response is passed back to your app, notifying whether the permission is granted. Permissions can be revoked: Users can revoke permissions that were granted previously. We must learn how to handle these cases, as we'll learn later on. If an app targets an Android Marshmallow version, it must use the new permissions model. Permission groups When working with permissions, we divide them into groups. This division is done for fast user interaction when reviewing and approving permissions. Granting is done only once per permission group. If you add a new permission or request a new permission from the same permission group and the user has already approved that group, the system will grant you the added permission without bothering the user about the approval. For more information on this, visit https://developer.android.com/reference/android/content/pm/PermissionInfo.html#constants[GS1] . When the user installs an app, the app is granted only those permissions that are listed in the manifest that belongs to the PROTECTION_NORMAL group. Requesting permissions from the PROTECTION_SIGNATURE group will be granted only if the application is signed with the same certificate as the app with the declared permission. Apps cannot request signature permissions at runtime. System components automatically receive all the permissions listed in their manifests. Runtime permissions Android Marshmallow showcased a new permissions model where users were able to directly manage app permissions at application runtime. Google has altered the old permissions model, mostly to enable easier and frictionless installations and auto-updates for users as well as for app developers. This allows users to install the app without the need to preapprove each permission the application needs. The user can install the app without going through the phase of checking each permission and declining the installation due to a single permission. Users can grant or revoke permissions for installed apps, leaving the tweaking and the freedom of choice in the users' hands. Most of the applications will need to address these issues when updating the target API to 23. Taking coding permissions into account Well, after all the explanations, we've reached the coding part, and this is where we will get our coding hands dirty. The following are the methods used for coding permissions: Context.checkSelfPermission(): This checks whether your app has been granted a permission Activity.requestPermission(): This requests a permission at runtime Even if your app is not yet targeting Android Marshmallow, you should test your app and prepare to support it. Testing permissions In the Android Marshmallow permissions model, your app must ask the user for individual permissions at runtime. There is limited compatibility support for legacy apps, and you should test your app and also test a version to make sure it's supported. You can use the following test guide and conduct app testing with the new behavior: Map your app's permissions Test flows with permissions granted and revoked The adb command shell can be quite helpful to check for permissions: Listing application permissions and status by group can be done using the following adb command: adb shell pm list permissions -g You can grant or revoke permissions using the following adb syntax: adb shell pm [grant|revoke] <permission.name> You can grant permissions and install apk using the following adb command: adb install -g <path_to_apk> Coding for runtime permissions When we want to adjust our application to the new model, we need to make sure that we organize our steps and leave no permission stranded: Check what platform the app is running on: When running a piece of code that is sensitive at the API level, we start by checking the version/API level that we are running on. By now, you should be familiar with Build.VERSION.SDK_INT. Check whether the app has the required permission: Here, we get ourselves a brand new API call: Context.checkSelfPermission(String permission_name) With this, we silently check whether permissions are granted or not. This method returns immediately, so any permission-related controls/flows should be dealt with by checking this first. Prompting for permissions: We have a new API call, Activity.requestPermissions (String[] permissions, int requestCode). This call triggers the system to show the dialog requesting a permission. This method functions asynchronously. You can request more than one permission at once. The second argument is a simple request code returned in the callback so that you can recognize the calls. This is just like how we've been dealing with startActivityForResult() and onActivityResult() for years. Another new API is Activity.shouldShowRequestPermissionRationale(String permission). This method returns true when you have requested a permission and the user denied the request. It's considered a good practice after verifying that you explain to the user why you need that exact permission. The user can decide to turn down the permission request and select the Don't ask again option; then, this method will return false. The following sample code checks whether the app has permission to read the user's contacts. It requests the permission if required, and the result callback returns to onRequestPermissionsResult: if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, SAMPLE_MATRIXY_READ_CONTACTS); } //Now this is our callback @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case SAMPLE_MATRIXY_READ_CONTACTS: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission granted - we can continue the feature flow. } else { // permission denied! - we should disable the functionality that depends on this permission. } } } Just to make sure we all know the constants used, here's the explanation: public static final int PERMISSION_DENIED=-1: Since it's API level 1, permission has not been granted to the given package public static final int PERMISSION_GRANTED=0: Since it's API level 1. permission has been granted to the given package. If the user denies your permission request, your app should take the appropriate action, such as notifying the user why this permission is required or explaining that the feature can't work without it. Your app cannot assume user interaction has taken place because the user can choose to reject granting a permission along with the do not show again option; your permission request is automatically rejected and onRequestPermissionsResult gets the result back. Summary To learn more about Android 6 Essentials, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended: Android User Interface Development: Beginner's Guide (https://www.packtpub.com/application-development/android-user-interface-development-beginners-guide) Android Native Development Kit Cookbook (https://www.packtpub.com/application-development/android-native-development-kit-cookbook) Resources for Article: Further resources on this subject: Practical How-To Recipes for Android [article] Working with Xamarin.Android [article] Detecting Shapes Employing Hough Transform [article]
Read more
  • 0
  • 0
  • 2227

article-image-process-driven-soa-development
Packt
13 Sep 2010
9 min read
Save for later

Process Driven SOA Development

Packt
13 Sep 2010
9 min read
(For more resources on Oracle, see here.) Business Process Management and SOA One of the major benefits of a Service-Oriented Architecture is its ability to align IT with business processes. Business processes are important because they define the way business activities are performed. Business processes change as the company evolves and improves its operations. They also change in order to make the company more competitive. Today, IT is an essential part of business operations. Companies are simply unable to do business without IT support. However, this places a high level of responsibility on IT. An important part of this responsibility is the ability of IT to react to changes in a quick and efficient manner. Ideally, IT must instantly respond to business process changes. In most cases, however, IT is not flexible enough to adapt application architecture to the changes in business processes quickly. Software developers require time to modify application behavior. In the meantime, the company is stuck with old processes. In a highly competitive marketplace such delays are dangerous, and the threat is exacerbated by a reliance on traditional software development to make quick changes within an increasingly complex IT architecture. The major problem with traditional approaches to software development is the huge semantic gap between IT and the process models. The traditional approach to software development has been focused on functionalities rather than on end-to-end support for business processes. It usually requires the definition of use cases, sequence diagrams, class diagrams, and other artifacts, which bring us to the actual code in a programming language such as Java, C#, C++, and so on. SOA reduces the semantic gap by introducing a development model that aligns the IT development cycle with the business process lifecycle. In SOA, business processes can be executed directly and integrated with existing applications through services. To understand this better, let's look at the four phases of the SOA lifecycle: Process modeling: This is the phase in which process analysts work with process owners to analyze the business process and define the process model. They define the activity flow, information flow, roles, and business documents. They also define business policies and constraints, business rules, and performance measures. Performance measures are often called Key Performance Indicators (KPIs). Examples of KPIs include activity turnaround time, activity cost, and so on. Usually Business Process Modeling Notation (BPMN) is used in this phase. Process implementation: This is the phase in which developers work with process analysts to implement the business process, with the objective of providing end-to-end support for the process. In an SOA approach, the process implementation phase includes process implementation with the Business Process Execution Language (BPEL) and process decomposition to the services, implementation or reuse of services, and integration. Process execution and control: This is the actual execution phase, in which the process participants execute various activities of the process. In the end-to-end support for business processes, it is very important that IT drives the process and directs process participants to execute activities, and not vice versa, where the actual process drivers are employees. In SOA, processes execute on a process server. Process control is an important part of this phase, during which process supervisors or process managers control whether the process is executing optimally. If delays occur, exceptions arise, resources are unavailable, or other problems develop, process supervisors or managers can take corrective actions. Process monitoring and optimization: This is the phase in which process owners monitor the KPIs of the process using Business Activity Monitoring (BAM). Process analysts, process owners, process supervisors, and key users examine the process and analyze the KPIs while taking into account changing business conditions. They examine business issues and make optimizations to the business process. The following figure shows how a process enters this cycle, and goes through the various stages: Once optimizations have been identified and selected, the process returns to the modeling phase, where optimizations are applied. Then the process is re-implemented and the whole lifecycle is repeated. This is referred to as an iterative-incremental lifecycle, because the process is improved at each stage. Organizational aspects of SOA development SOA development, as described in the previous section, differs considerably from traditional development. SOA development is process-centric and keeps the modeler and the developer focused on the business process and on end-to-end support for the process, thereby efficiently reducing the gap between business and IT. The success of the SOA development cycle relies on correct process modeling. Only when processes are modeled in detail can we develop end-to-end support that will work. Exceptional process fl ows also have to be considered. This can be a difficult task, one that is beyond the scope of the IT department (particularly when viewed from the traditional perspective). To make process-centric SOA projects successful, some organizational changes are required. Business users with a good understanding of the process must be motivated to actively participate in the process modeling. Their active participation must not be taken for granted, lest they find other work "more useful," particularly if they do not see the added value of process modeling. Therefore, a concise explanation as to why process modeling makes sense can be a very valuable time investment. A good strategy is to gain top management support. It makes enormous sense to explain two key factors to top management—first, why a process centric approach and end-to-end support for processes makes sense, and second, why the IT department cannot successfully complete the task without the participation of business users. Usually top management will understand the situation rather quickly and will instruct business users to participate. Obviously, the proposed process-centric development approach must become an ongoing activity. This will require the formalization of certain organizational structures. Otherwise, it will be necessary to seek approval for each and every project. We have already seen that the proposed approach outgrows the organizational limits of the IT department. Many organizations establish a BPM/SOA Competency Center, which includes business users and all the other profiles required for SOA development. This also includes the process analyst, process implementation, service development, and presentation layer groups, as well as SOA governance. Perhaps the greatest responsibility of SOA development is to orchestrate the aforementioned groups so that they work towards a common goal. This is the responsibility of the project manager, who must work in close connection with the governance group. Only in this way can SOA development be successful, both in the short term (developing end-to-end applications for business processes), and in the long term (developing a fl exible, agile IT architecture that is aligned with business needs). Technology aspects of SOA development SOA introduces technologies and languages that enable the SOA development approach. Particularly important is BPMN, which is used for business process modeling, and BPEL, which is used for business process execution. BPMN is the key technology for process modeling. The process analyst group must have in-depth knowledge of BPMN and process modeling concepts. When modeling processes for SOA, they must be modeled in detail. Using SOA, we model business processes with the objective of implementing them in BPEL and executing them on the process server. Process models can be made executable only if all the relevant information is captured that is needed for the actual execution. We must identify individual activities that are atomic from the perspective of the execution. We must model exceptional scenarios too. Exceptional scenarios define how the process behaves when something goes wrong—and in the real world, business processes can and do go wrong. We must model how to react to exceptional situations and how to recover appropriately. Next, we automate the process. This requires mapping of the BPMN process model into the executable representation in BPEL. This is the responsibility of the process implementation group. BPMN can be converted to BPEL almost automatically and vice versa, which guarantees that the process map is always in sync with the executable code. However, the executable BPEL process also has to be connected with the business services. Each process activity is connected with the corresponding business service. Business services are responsible for fulfilling the individual process activities. SOA development is most efficient if you have a portfolio of business services that can be reused, and which includes lower-level and intermediate technical services. Business services can be developed from scratch, exposed from existing systems, or outsourced. This task is the responsibility of the service development group. In theory, it makes sense for the service development group to first develop all business services. Only then would the process implementation group start to compose those services into the process. However, in the real world this is often not the case, because you will probably not have the luxury of time to develop the services first and only then start the processes. And even if you do have enough time, it would be difficult to know which business services will be required by processes. Therefore, both groups usually work in parallel, which is a great challenge. It requires interaction between them and strict, concise supervision of the SOA governance group and the project manager; otherwise, the results of both groups (the process implementation group and the service development group) will be incompatible. Once you have successfully implemented the process, it can be deployed on the process server. In addition to executing processes, a process server provides other valuable information, including a process audit trail, lists of successfully completed processes, and a list of terminated or failed processes. This information is helpful in controlling the process execution and in taking any necessary corrective measures. The services and processes communicate using the Enterprise Service Bus (ESB). The services and processes are registered in the UDDI-compliant service registry. Another part of the architecture is the rule engine, which serves as a central place for business rules. For processes with human tasks, user interaction is obviously important, and is connected to identity management. The SOA platform also provides BAM. BAM helps to measure the key performance indicators of the process, and provides valuable data that can be used to optimize processes. The ultimate goal of each BAM user is to optimize process execution, to improve process efficiency, and to sense and react to important events. BAM ensures that we start optimizing processes where it makes most sense. Traditionally, process optimization has been based on simulation results, or even worse, by guessing where bottlenecks might be. BAM, on the other hand, gives more reliable and accurate data, which leads to better decisions about where to start with optimizations. The following figure illustrates the SOA layers:
Read more
  • 0
  • 0
  • 2222
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-testing-agile-development-and-state-agile-adoption
Packt
15 Mar 2017
6 min read
Save for later

Testing in Agile Development and the State of Agile Adoption

Packt
15 Mar 2017
6 min read
In this article written by Renu Rajani, author of the book Testing Practitioner Handbook, we will discuss agile development. Organizations are increasingly struggling to reach the right level of quality versus speed. Some key issues with traditional development and testing include the following: Excessively long time to market for products and applications Inadequate customer orientation and regular interaction Over-engineered products--most of the features on a product or application may not be used High project failure rate ROI below expectation Inability to respond quickly to change Inadequate software quality (For more resources related to this topic, see here.) To address this, QA and testing should be blended with agile development. Agile engagements should take a business-centric approach to select the right test focus areas, such as behavior-driven development (BDD), to define acceptance criteria. This requires skills not only in testing but also in business and software development. The latest World Quality Report reveals an increase in the adoption of agile testing methodologies, which helps expedite time to market for products and services. The need for agile development (and testing) is primarily driven by digital transformation. Let's take a look at the major trends in digital transformation: More continual integration fueled by digital transformation Complex integration using multi-channel, omnipresent commerce, making it necessary to integrate multiple channels, devices, and wearable technology Unlike yesterday's nomenclature, when agile meant colocation, today's advanced telepresence infrastructure makes it possible to work in distributed agile models and has removed colocation dependency. Agile is not just a concept. It is a manner of working, made possible with multiple tools to enable development and testing in agile environments. What do agile projects promise compared to traditional waterfall? The next diagram summarizes the value an agile approach offers compared to traditional waterfall. Waterfall engagements are characterized as plan driven. One should know the software requirements and estimate the time and effort needed to accomplish the task at hand. In the case of agile engagements, one knows the time and resources available and needs to estimate the features that can go into a release. Flavors of agile There are various flavors of agile, including the following: Scrum: This prioritizes the highest-value features and incremental delivery once every 2-4 weeks Kanban: This pinpoints bottlenecks to avoid holdups Lean: This eliminates waste and unnecessary documentation and provides future flexibility XP: This reconfigures and ensures the simplest design to deliver iteration features. Let's look at their features. Scrum Reacts quickly in volatile markets Focuses on customer benefits and avoids both unnecessary outlays and time investments Utilizes organized development teams within a structured framework in order to coordinate activities and work together for quick decision-making Involves customers directly in the development process Kanban Works with existing roles and processes and may be introduced either step by step or by establishing pioneer teams. Scrum and Kanban complement one another. While Scrum ensures adaptability and agile, Kanban improves efficiency and throughput. Both techniques increase overall transparency. How is testing done in agile sprints? I have often heard that agile projects do not require testers. Is this true? Would you compromise on quality in the name of agile? Like any other development life cycle, agile also needs quality and testing. Agile engagements involve testers from the start of the sprint, that is, from the requirement analysis stage, in a process known as user story grooming. In sprint planning, the team selects the story points depending on various factors, including availability of resources and user story complexity. All the members of the sprint team (cross-functional teams) are involved in this process (developers, business analysts, testers, configuration teams, build teams, the scrum master, and the production owner). Once the user stories destined for the sprint are finalized, they are analyzed. Then, developers work on the design while testers write the test cases and share these with business analysts for review. At the end of each sprint, the team discloses the user stories selected during the sprint to the product owner and gets a go or no-go ruling. Once the demo is complete, the team gathers for the retrospective. Take a look at the following diagram: The benefits of this approach include: Productive, collaborative, and high-performing teams Predictability and project control featuring transparency and flexibility Superior prioritization and risk management for business success High-value revenue with low upfront and ongoing costs High-quality products delivered with minimum time to market Increased possibility of stakeholder engagement and high customer satisfaction Agile in distributed environments Often, people assume agile means colocation. Today's technology infrastructure and maturity of distributed teams have enabled agile to be practiced in a distributed mode. As per the World Quality Report 2016-2017, more than 42% of the organizations that adopt an agile delivery model use distributed agile. Distributed agile allows the organizations to achieve higher cost savings with the global delivery model. Take a look at the following figure: Key challenges in distributed agile model include: Communication challenges across the distributed team Increasing product backlogs An ever-growing regression pack Poor knowledge management and handover for new people due to less documentation and high-level placeholder tests Little time overlap with isolated regional developers for distributed teams These challenges can be addressed through the following: Communication: Live meetings, video conference calls, and common chat rooms Product backlogs: Better prioritization within the iteration scope Regression scope: Better impact analysis and targeted regression only Knowledge management: Efficient tools and processes along with audio and video recordings of important tests, virtual scrum boards, and the latest communication and tracking tools Distributed teams: Optimal overlap timings through working shifts (40–50 %) State of agile adoption – findings from the World Quality Report 2016-2017 As per the latest World Quality Report, there are various challenges in applying testing to agile environments. Colocation and a lack of required skills are the two biggest challenges that are considered major risks associated with agile adoption. That said, organizations have been able to find solutions to these challenges. Approaches to testing in agile development environments Organizations use different ways to speed up cycle times and utilize agile. Some of these tactics include predictive analytics, BDD/TDD, continuous monitoring, automated test data generation, and test environment virtualization. The following diagram provides a snapshot of the practices used to convert to agile: Skills needed from QA and testing professions for agile The following diagram from WQR2016 depicts the state of skills relating to agile testing as organizations strive to adopt agile methodologies: Conclusion An ideal agile engagement needs a test ecosystem that is flexible and supports both continual testing and quality monitoring. Given the complexity in agile engagements, there would be value from automated decision-making to achieve both speed and quality. Agile development has attained critical mass and is now being widely adopted; the initial hesitation no longer prevails. The QA function is a key enabler in this journey. The coexistence of traditional IT along with agile delivery principles is giving rise to a new methodology based on bimodal development. Resources for Article: Further resources on this subject: Unit Testing and End-To-End Testing [article] Storing Records and Interface customization [article] Overview of Certificate Management [article]
Read more
  • 0
  • 0
  • 2221

article-image-package-management
Packt
14 Nov 2013
12 min read
Save for later

Package Management

Packt
14 Nov 2013
12 min read
(For more resources related to this topic, see here.) Using NuGet with source control Source control systems are an integral part of software development. As soon as there is more than one person working on the project, it becomes an invaluable tool for sharing source code. Even when we are on the project on our own, there is no better way for tracking versions and source code changes. The question arises: how should we put the installed packages into source control? The first impulse would be to simply add the packages folder to the repository. Though this will work, it isn't the best possible approach. Packages can grow quite large and they can be obtained from elsewhere; therefore, we would only "pollute" the repository with redundant files. Many source control systems don't handle large binary files well. Even for those that don't have such problems, having packages in the repository doesn't add much value; it does noticeably increase the repository size, though. Fortunately, NuGet offers a feature called Package Restore, which can be used to avoid adding packages to source control. Let's see how it works. The following sample will use Team Foundation Service (TFS) for source control. If you don't have an account yet, you can sign up for free at http://tfs.visualstudio.com. You need a Microsoft account for authentication. If you decide to use a different source control system instead, just skip all the steps dealing with TFS, replacing them with equivalent actions in your source control system of choice. We'll start by creating a sample project: Create a new Console Application project in Visual Studio. Install the Json.NET NuGet package into the project. Add the following code to the Main method so that the project won't compile without a valid reference to the Newtonsoft.Json.dll assembly: var jsonString = @"{ ""title"": ""NuGet 2 Essentials"", ""authors"":""Damir Arh & Dejan Dakic"", ""publisher"": ""Packt Publishing"" }"; var parsedJson = Newtonsoft.Json.JsonConvert .DeserializeObject(jsonString); Compile and run the project to make sure the code works. It's time to create a source code repository. If you already have a repository, you can skip the following steps. Just make sure you have a repository ready and know how to connect to it before moving on. You will need Visual Studio 2012 or Visual Studio 2010 with Service Pack 1 and KB2662296 installed to connect to TFS. In a browser, navigate to https://<accountname>.visualstudio.com/ (replacing <accountname> with the name you used when signing up for TFS). Click on New team project. In the CREATE NEW TEAM PROJECT dialog box, enter the project name (for example, PackageRestore) and click on Create project, leaving the rest of the fields unchanged. Click on Navigate to project once the creation process is complete. On the project page, click on Open new instance of Visual Studio in the Activities menu on the right to connect Visual Studio to your TFS account. You can close this Visual Studio instance once the connection is established. Now we're ready to add the project to the repository. Return to Visual Studio, right-click on the solution node in the Solution Explorer window and click on the Add Solution to Source Control… menu item. Make sure you select Team Foundation Version Control as the source control system if a dialog box pops up and asks you to make a selection. In the Connect to Team Foundation Server dialog box which opens next, select your TFS account (for example, accountname.visualstudio.com) from the drop-down list and check the created repository in the Team Projects list box. Click on Connect to move to the next step and confirm the default settings by clicking on OK in the dialog box that follows. We still need to select the right set of files to add to source control and check them in so that they will be available for others. Open the Team Explorer window and click on the Source Control Explorer link inside it. Look in the tree view on the left side of the Source Control Explorer window. You will notice that apart from your project, the packages folder is also included. We need to exclude it since we don't want to add packages to source control. Right-click on the packages folder and select Undo Pending Changes… from the context menu. Click on the Undo Changes button in the Undo Pending Changes dialog box that pops up. Click on the Check In button in the toolbar and click on Check In again in the Pending Changes pane inside the Team Explorer window. Close the confirmation dialog box if it pops up. The packages folder should now be removed from the tree view. Navigate to https://<accountname>.visualstudio.com/DefaultCollection/<PackageRestore>/_versionControl from your browser to check which files have been successfully checked in. Replace <accountname> and <PackageRestore> with appropriate values as necessary for your case. Let's retrieve the code and place it in a different location and see how the packages are going to get restored: With TFS, a new workspace needs to be created for that purpose in the Manage Workspaces dialog box, which can be accessed by clicking on Workspaces… from the Workspace drop-down list in the Source Control Explorer toolbar. Click on Add… to add a new workspace. You need to specify both Source Control Folder (solution folder, that is, $/<PackageRestore>/<SolutionName>) and Local Folder where you want to put the files. After adding the workspace, confirm the next dialog box to get the files from the repository to your selected local folder. Check the contents of that folder after Visual Studio is done to see that there is no packages folder inside it. Open the solution from the new folder in Visual Studio and build it. You should notice a NuGet Package Manager dialog box popping up displaying the package restore progress and closing again once it is done. The application should build successfully. You can run it to see that it works as expected. If you check the contents of the solution folder once again, you will see that the packages folder has been restored with all the required packages inside it. Automatic Package Restore, which was described earlier has been available only since NuGet 2.7. In earlier versions, only MSBuild-Integrated Package Restore was supported. In case your repository will be accessed by users still using NuGet 2.6 or older, it might be a better idea to use this instead; otherwise, package restore won't work for them. You can enable it by following these steps (if you do this in NuGet 2.7, the Automatic Package Restore will get disabled): Right-click on the solution node in the Solution Explorer window and click on the Enable NuGet Package Restore menu item. Confirm the confirmation dialog box that pops up briefly explaining what is going to happen. Another dialog box will pop up once the process is complete. Notice that a .nuget folder containing three files has been added to the solution shown as follows: When adding a solution configured like this to the source control, don't forget to include the .nuget folder as well. The packages folder of course still remains outside source control. If you encounter a repository with MSBuild-Integrated Package Restore, which was enabled with NuGet 2.6 or older, the restoring of packages before build might fail with the following error: Package restore is disabled by default. To give consent, open the VisualStudio Options dialog, click on Package Manager node and check 'AllowNuGet to download missing packages during build.' You can also giveconsent by setting the environment variable 'EnableNuGetPackageRestore'to 'true'. This happens because the Allow NuGet to download missing packages during build setting was disabled by default in NuGet versions before 2.7. To fix the problem navigate to Tools | Library | Package Manager | Package Manager Settings to open the option dialog box on the right node; then uncheck and recheck the mentioned setting and click on OK to explicitly set it. A more permanent solution is to either update NuGet.exe in the .nuget folder to the latest version or to switch to Automatic Package Restore instead as described at http://bit.ly/NuGetAutoRestore. Using NuGet on a build server Automatic Package Restore only works within Visual Studio. If you try to build such a solution on a build server by using MSBuild only, it will fail if the packages are missing. To solve this problem, you should use the Command-Line Package Restore approach by executing the following command as a separate step before building the solution file: C:> NuGet.exe restore pathtoSolutionFile.sln This will restore all of the packages in the solution, making sure that the build won't fail because of missing packages. Even if the solution is using MSBuild-Integrated Package Restore, this approach will still work because all of the packages will already be available when it is invoked; and this will just silently be skipped. The exact procedure for adding the extra step will depend on your existing build server configuration. You should either call it from within your build script or add it as an additional step to your build server configuration. In any case, you need to make sure you have installed NuGet 2.7 on your build server. The NuGet Package Restore feature can be optimized even more on a build server by defining a common package repository for all solutions. This way each package will be downloaded only once even if it is used in multiple solutions; saving both the download time and the storage space. To achieve this, save a NuGet.config file with the following content at the root folder containing all your solutions in its subfolders: <?xml version="1.0" encoding="utf-8"?> <configuration> <config> <add key="repositorypath" value="C:pathtorepository" /> </config> </configuration> You can even have more control of your repository location and other NuGet settings by taking advantage of the hierarchical or machine-wide NuGet.config file as explained at http://bit.ly/NuGetConfig. Using Package Manager Console We have already used Package Manager Console twice to achieve something that couldn't have been done using the graphical user interface. It's time to take a closer look at it and the commands that are available. The Package Manager Console window is accessible by either navigating to Tools | Library Package Manager | Package Manager Console or by navigating to View | Other Windows | Package Manager Console. The most important commands are used to install, update, and uninstall packages on a project. By default, they operate on Default project selected from a drop-down list in the window's toolbar. The target project name can be specified using the -ProjectName parameter. To get a list of all commands, type Get-Help NuGet in the console. To get more information about a command, type Get-Help CommandName in the console, replacing CommandName with the actual name of the command. You can also check the online PowerShell command reference at http://bit.ly/NuGetPsRef. Let's take a look at few of the examples: To install the latest version of the Newtonsoft.Json package to the default project, type: PM> Install-Package Newtonsoft.Json To install Version 5.0.1 of the Newtonsoft.Json package to the default project, type: PM> Install-Package Newtonsoft.Json –Version 5.0.1 To install the latest version of the Newtonsoft.Json package to the Net40 project, type: PM> Install-Package Newtonsoft.Json –ProjectName Net40 To update the Newtonsoft.Json package in all projects to its latest version, type: PM> Update-Package Newtonsoft.Json To update the Newtonsoft.Json package in all projects to Version 5.0.3 (this will fail for projects with a newer version already installed), type: PM> Update-Package Newtonsoft.Json –Version 5.0.3 To update the Newtonsoft.Json package in the Net40 project to the latest version, type: PM> Update-Package Newtonsoft.Json –ProjectName Net40 To update all packages in all projects to the latest available version with the same major and minor version component, type: PM> Update-Package –Safe To uninstall the Newtonsoft.Json package from the default project, type: PM> Uninstall-Package Newtonsoft.Json To uninstall the Newtonsoft.Json package from the Net40 project, type: PM> Uninstall-Package Newtonsoft.Json –ProjectName Net40 To list all packages in the online package source matching the Newtonsoft.Json search filter, type: PM> Get-Package –ListAvailable –Filter Newtonsoft.Json To list all installed packages having an update in the online package source, type: PM> Get-Package –Updates Installed packages can add their own commands. An example of such a package is EntityFramework. To get a list of all commands for a package, type Get-Help PackageName, replacing PackageName with the actual name of the package after it is installed, for example: PM> Get-Help EntityFramework Summary This article has covered various NuGet features in detail. We started out with package versioning support and the package update process. We then moved on to built-in support for different target platforms. A large part of the article was dedicated to the usage of NuGet in conjunction with source control systems. We have seen how to avoid adding packages to source control and still have them automatically restored when they are required during build. We concluded the article with a quick overview of the console and the commands that give access to features not available using the graphical user interface. This concludes our tour of NuGet from the package consumer point of view. In the following article, we will take on the role of a package creator and look at the basics of creating and publishing our own NuGet package. Resources for Article: Further resources on this subject: Lucene.NET: Optimizing and merging index segments [Article] Creating your first collection (Simple) [Article] Material nodes in Cycles [Article]
Read more
  • 0
  • 0
  • 2205

article-image-article-top-features-you-need-know-about
Packt
03 Jun 2013
3 min read
Save for later

Top features you need to know about

Packt
03 Jun 2013
3 min read
(For more resources related to this topic, see here.) 1 – Minimap The minimap is an innovative feature of Sublime Text 2 that gives you a bird's-eye view of the document you are editing. Always present at the right-hand side of the editor, it allows you to quickly look at a live, updated, zoomed out version of your current document. While the text will rarely be distinguishable, it allows for a topographical view of your document structure. Image The minimap feature is also very useful for navigating a large document as it can behave similar to a scroll bar. When clicked on, the minimap can be used to scroll the document to a different portion. However, should you find yourself not needing the minimap, or need the screen real estate it inhabits, it can easily be hidden by using the Menu bar to select View | Hide Minimap. 2 – Multiple cursors Another way Sublime Text 2 differentiates itself from the crowded text editor market is by way of including the functionality that allows the user to edit a document in multiple places at the same time. This can be very useful when making an identical change in multiple places. It is especially useful when the change that needs to occur cannot be easily accomplished with find and replace. By pressing command + left-click on OS X, or Ctrl + left-click on other platforms, an additional cursor will be placed at the location of the click. Each additional cursor will mirror the original cursor. The following screenshot shows a demo of this functionality. First, I created cursors on each of my three lines of text. Then I proceeded to type test without quotes: Image Now, as shown in the following screenshot, anything typed will be typed identically on the three lines where the cursors are placed. In this case I typed a space followed by the word test. This addition was simultaneous and I only had to make the change once, after creating the additional cursors. Image To return to a single cursor, simply press Esc or left-click anywhere on the document. Summary This article covered a few few features of Sublime Text 2 including multiple cursors, a plugin system, and a few others which will be covered in this article. Resources for Article : Further resources on this subject: Building a Flex Type-Ahead Text Input [Article] Introduction to Data Binding [Article] Working with Binding data and UI elements in Silverlight 4 [Article]
Read more
  • 0
  • 0
  • 2205

article-image-data-modeling-and-scalability-google-app
Packt
30 Nov 2010
12 min read
Save for later

Data Modeling and Scalability in Google App

Packt
30 Nov 2010
12 min read
Google App Engine Java and GWT Application Development Build powerful, scalable, and interactive web applications in the cloud Comprehensive coverage of building scalable, modular, and maintainable applications with GWT and GAE using Java Leverage the Google App Engine services and enhance your app functionality and performance Integrate your application with Google Accounts, Facebook, and Twitter Safely deploy, monitor, and maintain your GAE applications A practical guide with a step-by-step approach that helps you build an application in stages         Read more about this book       In deciding how to design your application's data models, there are a number of ways in which your approach can increase the app's scalability and responsiveness. Here, we discuss several such approaches and how they are applied in the Connectr app. In particular, we describe how the Datastore access latency can sometimes be reduced; ways to split data models across entities to increase the efficiency of data object access and use; and how property lists can be used to support "join-like" behavior with Datastore entities. Reducing latency—read consistency and Datastore access deadlines By default, when an entity is updated in the Datastore, all subsequent reads of that entity will see the update at the same time; this is called strong consistency . To achieve it, each entity has a primary storage location, and with a strongly consistent read, the read waits for a machine at that location to become available. Strong consistency is the default in App Engine. However, App Engine allows you to change this default and use eventual consistency for a given Datastore read. With eventual consistency, the query may access a copy of the data from a secondary location if the primary location is temporarily unavailable. Changes to data will propagate to the secondary locations fairly quickly, but it is possible that an "eventually consistent" read may access a secondary location before the changes have been incorporated. However, eventually consistent reads are faster on average, so they trade consistency for availability. In many contexts, for example, with web apps such as Connectr that display "activity stream" information, this is an acceptable tradeoff—completely up-to-date freshness of information is not required. See http://googleappengine.blogspot.com/2010/03/ read-consistency-deadlines-more-control.html, http://googleappengine.blogspot.com/2009/09/migrationto- better-datastore.html, and http://code.google.com/ events/io/2009/sessions/TransactionsAcrossDatacenters. html for more background on this and related topics. In Connectr, we will add the use of eventual consistency to some of our feed object reads; specifically, those for feed content updates. We are willing to take the small chance that a feed object is slightly out-of-date in order to have the advantage of quicker reads on these objects. The following code shows how to set eventual read consistency for a query, using server.servlets.FeedUpdateFriendServlet as an example. Query q = pm.newQuery("select from " + FeedInfo.class.getName() + "where urlstring == :keys");//Use eventual read consistency for this queryq.addExtension("datanucleus.appengine.datastoreReadConsistency", "EVENTUAL"); App Engine also allows you to change the default Datastore access deadline. By default, the Datastore will retry access automatically for up to about 30 seconds. You can set this deadline to a smaller amount of time. It can often be appropriate to set a shorter deadline if you are concerned with response latency, and are willing to use a cached version of the data for which you got the timeout, or are willing to do without it. The following code shows how to set an access timeout interval (in milliseconds) for a given JDO query. Query q = pm.newQuery("...");// Set a Datastore access timeoutq.setTimeoutMillis(10000); Splitting big data models into multiple entities to make access more efficient Often, the fields in a data model can be divided into two groups: main and/or summary information that you need often/first, and details—the data that you might not need or tend not to need immediately. If this is the case, then it can be productive to split the data model into multiple entities and set the details entity to be a child of the summary entity, for instance, by using JDO owned relationships. The child field will be fetched lazily, and so the child entity won't be pulled in from the Datastore unless needed. In our app, the Friend model can be viewed like this: initially, only a certain amount of summary information about each Friend is sent over RPC to the app's frontend (the Friend's name). Only if there is a request to view details of or edit a particular Friend, is more information needed. So, we can make retrieval more efficient by defining a parent summary entity, and a child details entity. We do this by keeping the "summary" information in Friend, and placing "details" in a FriendDetails object , which is set as a child of Friend via a JDO bidirectional, one-to-one owned relationship, as shown in Figure 1. We store the Friend's e-mail address and its list of associated URLs in FriendDetails. We'll keep the name information in Friend. That way, when we construct the initial 'FriendSummaries' list displayed on application load, and send it over RPC, we only need to access the summary object. Splitting Friend data between a "main" Friend persistent class and a FriendDetails child class. A details field of Friend points to the FriendDetails child, which we create when we create a Friend. In this way, the details will always be transparently available when we need them, but they will be lazily fetched—the details child object won't be initially retrieved from the database when we query Friend, and won't be fetched unless we need that information. As you may have noticed, the Friend model is already set up in this manner—this is the rationale for that design. Discussion When splitting a data model like this, consider the queries your app will perform and how the design of the data objects will support those queries. For example, if your app often needs to query for property1 == x and property2 == y, and especially if both individual filters can produce large result sets, you are probably better off keeping both those properties on the same entity (for example, retaining both fields on the "main" entity, rather than moving one to a "details" entity). For persistent classes (that is, "data classes") that you often access and update, it is also worth considering whether any of its fields do not require indexes. This would be the case if you never perform a query which includes that field. The fewer the indexed fields of a persistent class, the quicker are the writes of objects of that cl ass. Splitting a model by creating an "index" and a "data" entity You can also consider splitting a model if you identify fields that you access only when performing queries, but don't require once you've actually retrieved the object. Often, this is the case with multi-valued properties. For example, in the Connectr app, this is the case with the friendKeys list of the server.domain.FeedIndex class. This multi-valued property is used to find relevant feed objects but is not used when displaying feed content information. With App Engine, there is no way for a query to retrieve only the fields that you need, so the full object must always be pulled in. If the multi-valued property lists are long, this is inefficient. To avoid this inefficiency, we can split up such a model into two parts, and put each one in a different entity—an index entity and a data entity. The index entity holds only the multi-valued properties (or other data) used only for querying, and the data entity holds the information that we actually want to use once we've identified the relevant objects. The trick to this new design is that the data entity key is defined to be the parent of the index entity key. More specifically, when an entity is created, its key can be defined as a "child" of another entity's key, which becomes its parent. The child is then in the same entity group as the parent. Because such a child key is based on the path of its parent key, it is possible to derive the parent key given only the child key, using the getParent() method of Key, without requiring the child to be instantiated. So with this design, we can first do a keys-only query on the index kind (which is faster than full object retrieval) to get a list of the keys of the relevant index entities. With that list, even though we've not actually retrieved the index objects themselves, we can derive the parent data entity keys from the index entity keys. We can then do a batch fetch with the list of relevant parent keys to grab all the data entities at once. This lets us retrieve the information we're interested in, without having to retrieve the properties that we do not need. See Brett Slatkin's presentation, Building scalable, complex apps on App Engine (http://code.google.com/events/ io/2009/sessions/BuildingScalableComplexApps. html) for more on this index/data design. Splitting the feed model into an "index" part (server.domain.FeedIndex) and a "data" part (server.domain.FeedInfo) Our feed model maps well to this design—we filter on the FeedIndex.friendKeys multi-valued property (which contains the list of keys of Friends that point to this feed) when we query for the feeds associated with a given Friend. But, once we have retrieved those feeds, we don't need the friendKeys list further. So, we would like to avoid retrieving them along with the feed content. With our app's sample data, these property lists will not comprise a lot of data, but they would be likely to do so if the app was scaled up. For example, many users might have the same friends, or many different contacts might include the same company blog in their associated feeds. So, we split up the feed model into an index part and a parent data part, as shown in Figure 2. The index class is server.domain.FeedIndex; it contains the friendKeys list for a feed. The data part, containing the actual feed content, is server.domain. FeedInfo. When a new FeedIndex object is created, its key will be constructed so that its corresponding FeedInfo object 's key is its parent key. This construction must of course take place at object creation, as Datastore entity keys cannot be changed. For a small-scale app, the payoff from this split model would perhaps not be worth it. But for the sake of example, let's assume that we expect our app to grow significantly. The FeedInfo persistent class —the parent class—simply uses an app-assigned String primary key, urlstring (the feed URL string). The server.domain. FeedIndex constructor, shown in the code below, uses the key of its FeedInfo parent—the URL string—to construct its key. This places the two entities into the same entity group and allows the parent FeedInfo key to be derived from the FeedIndex entity's key. @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")public class FeedIndex implements Serializable { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; ... public FeedIndex(String fkey, String url) { this.friendKeys = new HashSet<String>(); this.friendKeys.add(fkey); KeyFactory.Builder keyBuilder = new KeyFactory.Builder(FeedInfo.class.getSimpleName(), url); keyBuilder.addChild(FeedIndex.class.getSimpleName(), url); Key ckey = keyBuilder.getKey(); this.key= ckey; } The following code, from server.servlets.FeedUpdateFriendServlet, shows how this model is used to efficiently retrieve the FeedInfo objects associated with a given Friend. Given a Friend key, a query is performed for the keys of the FeedIndex entities that contain this Friend key in their friendKeys list. Because this is a keys-only query, it is much more efficient than returning the actual objects. Then, each FeedIndex key is used to derive the parent (FeedInfo) key. Using that list of parent keys, a batch fetch is performed to fetch the FeedInfo objects associated with the given Friend. We did this without needing to actually fetch the FeedIndex objects. ... imports...@SuppressWarnings("serial")public class FeedUpdateFriendServlet extends HttpServlet{ private static Logger logger = Logger.getLogger(FeedUpdateFriendServlet.class.getName()); public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { PersistenceManager pm = PMF.get().getPersistenceManager(); Query q = null; try { String fkey = req.getParameter("fkey"); if (fkey != null) { logger.info("in FeedUpdateFriendServlet, updating feeds for:" +fkey); // query for matching FeedIndex keys q = pm.newQuery("select key from "+FeedIndex.class.getName()+" where friendKeys == :id"); List ids=(List)q.execute(fkey); if (ids.size()==0) { return; } // else, get the parent keys of the ids Key k = null; List<Key>parent list = new ArrayList<Key>(); for (Object id : ids) { // cast to key k = (Key)id; parentlist.add(k.getParent()); } // fetch the parents using the keys Query q2 = pm.newQuery("select from +FeedInfo.class.getName()+ "where urlstring == :keys"); // allow eventual consistency on read q2.addExtension( "datanucleus.appengine.datastoreReadConsistency", "EVENTUAL"); List<FeedInfo>results = (List<FeedInfo>)q2.execute(parentlist); if(results.iterator().hasNext()){ for(FeedInfo fi : results){ fi.updateRequestedFeed(pm); } } } } catch (Exception e) { logger.warning(e.getMessage()); } finally { if q!=null) { q.closeAll(); } pm.close(); } }}//end class
Read more
  • 0
  • 0
  • 2201
article-image-flex-multi-list-selector-using-list-control-datagrid-and-accordion
Packt
02 Mar 2010
3 min read
Save for later

Flex Multi-List Selector using List Control, DataGrid, and the Accordion

Packt
02 Mar 2010
3 min read
Instead of files and directories, I'm going to use States, Counties and Cities. Essentially this application will be used to give the user an easy way to select a city. Flex offers many components that can help us build this application. The controls I immediately consider for the job are the List Control, DataGrid, and the Accordion (in combination with the List). The List is the obvious control to start with because it represents the data in the right way - a list of states, counties, and cities. The reason I also considered the DataGrid and the Accordion (with the List) is because the they both have a header. I want an easy way to label the three columns/list 'States','Counties' and 'Cities'. With that said, I selected the Accordion with the List option. Using this option also allows for future expansion of the tool. For instance, one could adapt the tool to add country, then state, county, and city. The Accordion naturally has this grouping capability. With that said, our first code block contains our basic UI. The structure is pretty simple. The layout of the application is vertical. I've added an HBox which contains the main components of the application. The basic structure of each list is a List Control inside a Canvas Container which is inside of an Accordian Control. The Canvas is there because Accordians must have a container as a child and a List is not a part of the container package. We repeat this 3 times, one for each column and give the appropriate name. <?xml version="1.0" encoding="utf-8"?><mx:Application horizontalGap="0" layout="vertical"> <mx:HBox width="100%" height="100%"> <!-- States --> <mx:Accordion id="statesAccoridon" width="100%" height="100%"> <mx:Canvas width="100%" height="100%" label="States"> <mx:List id="statesList" width="100%" height="100%" dataProvider="{locations.state.@name}" click="{selectCounties()}"/> </mx:Canvas> </mx:Accordion> <!-- Counties --> <mx:Accordion id="countiesAccoridon" width="100%" height="100%"> <mx:Canvas width="100%" height="100%" label="Counties"> <mx:List id="countiesList" width="100%" height="100%" click="selectCities()"/> </mx:Canvas> </mx:Accordion> <!-- Cities --> <mx:Accordion id="citiesAccoridon" width="100%" height="100%"> <mx:Canvas width="100%" height="100%" label="Cities"> <mx:List id="citiesList" width="100%" height="100%"/> </mx:Canvas> </mx:Accordion> </mx:HBox> <!-- Selected City --> <mx:Label text="{citiesList.selectedItem}"/> <mx:Script> <![CDATA[ public function selectCounties():void{ countiesList.dataProvider = locations.state.(@name==statesList.selectedItem).counties.county.@name } public function selectCities():void{ citiesList.dataProvider = locations.state.(@name==statesList.selectedItem).counties.county.(@name==countiesList.selectedItem).cities.city.@name; } ]]> </mx:Script> </mx:Application> I've set the width and height to all containers to 100%. This will make it easy to later embed this application into a web page or other Flex application as a module. Also notice how the dataProvider attribute is only set for the statesList. This is because the countiesList and the citiesList are not populated until a state is selected. These dataProviders are set using ActionScript and are triggered by the click event listeners for both objects. Here is what the start of our selector looks like:
Read more
  • 0
  • 0
  • 2201

article-image-collaborative-work-svn-and-git
Packt
19 Mar 2013
11 min read
Save for later

Collaborative Work with SVN and Git

Packt
19 Mar 2013
11 min read
(For more resources related to this topic, see here.) Working with SVN At first we will take a look at the SVN perspective.The SVN perspective provides a group of views that help us to work with a Subversion server. You can open this perspective by using the Perspective menu in the top-right of the Aptana Studio window. The important and most frequently used views related to SVN, which we will take a look at, are the SVN Repositories view, the Team | History view, and the SVN | Console view. These views are categorized as the views selection into the SVN and Team folder, as shown in the following screenshot:     The SVN Repositories view allows you to add new repositories and manage all available repositories. Additionally, you have the option to create new tags or branches of the Repository. These views belong to the SVN views, as shown in the following screenshot: The History view allows you to get an overview about the project and revisions history. This view is used by SVN and Git projects; for this reason the view is stored in the Team views group. The History view can be opened by the menu under Window | Show View | History. Here you can see all the revisions with their comments and data creation. Furthermore, you can get a view into all revisions of a file and you also have, the ability to compare all revisions. The following screenshot shows the History view: Within the SVN Console view, you will find the output from all the SVN actions that are executed by Aptana Studio. Therefore, if you have an SVN conflict or something else, you can take a look at this Console view's output and you might locate the problem a bit faster. The SVN Console view was automatically integrated in the Aptana Studio Console, while the SVN plugin was installed. So if you need the SVN Console view, just open the general Console view from Window | Show view | Console. If the Console view is open, just use the View menu to select the Console type, which in this case is the SVN Console entry. The following screenshot shows the Console view and how you can select SVN Console: However, before we can start work with SVN, we have to add the related SVN Repository. Time for action – adding an SVN Repository Open the SVN perspective by using the Perspective menu in the top-right corner of the Aptana Studio window. Now, you should see the SVN Repositories view on the left-hand side of the Aptana Studio window. If it does not open automatically, open it by selecting the view from the navigation Window | Show view | SVN Repositories. In order to add a new SVN Repository, click on the small SVN icon with the plus sign at the top of the SVN Repositories view. You will now have to enter the address of the Subversion server in the pop up that appears, for example, svn://219.199.99.99/svn_codeSnippets. After you have clicked on the Finish button, Aptana Studio tries to reach the Subversion server in order to complete the process of adding a new Repository. If the Subversion server was reached and the SVN Repository is password protected, you will have to enter the access data for reading the SVN data. If you don't have the required access data available currently, you can abort the process and Aptana Studio will ask you whether you want to keep the location. If you click on NO, the newly added SVN Repository will be deleted, but if you click on YES, the location will remain. This allows you to retrieve the required access data later, enter them, and begin to work with the SVN Repository. Regardless of whether you keep the location or enter the required access data, the new SVN Repository will be listed in the SVN Repository view. What just happened? We have added a new SVN Repository into Aptana Studio. The new Repository is now listed in our SVN Repositories view and we can check this out from there, or create new tags or branches. Checking out an SVN Repository After we have seen how to add a new SVN Repository to Aptana Studio, we also want to know how we can check this Repository in order to work with the contained source code. You can do this, like many other things are done in Aptana Studio, in different ways. We will take a look at how we can do this directly from the SVN Repositories view, because every time we add a new Repository to Aptana Studio, we will also want to check it and use it as a project. Time for action – checking out an SVN Repository Open the SVN Repositories view. Expand the SVN Repository that you wish to check out. We do this because we want to check out the trunk directory from the Repository, not the tags and branches directory. Now, right-click on the trunk directory and select the Check Out... entry. Aptana Studio will now read the properties of the SVN Repository directly from the Subversion server. When all the required properties are received, the following window will appear on your screen: First of all, we select the Check out as a project in the workspace option and enter the name of the new SVN project. After this, we select the revision that we want to check out. This is usually the head revision. This means that you want to check out the last committed one—called the head revision. But you can check out any revision number you want from the past. If this is so, just deselect the Check out HEAD revision checkbox and enter the number of the revision that you want to check out. In the last section, we select the Fully recursive option within the Depth drop-down list and uncheck the Ignore externals checkbox, but select the Allow unversioned obstructions checkbox. After you have selected these settings, click on the Next button. Finally, you can select the location where the project should be created. Normally, this is the current workspace, but sometimes the location is different from the workspace. Maybe you have a web server installed and want to place the source code directly into the web root, in order to run the web application directly on your local machine. Finally, whether you select a different location for the project or not, you have to click on the Finish button to finalize the "Check out" into a new project. What just happened? We have checked out an SVN Repository from the SVN Repositories view. In addition to that, we have seen how we can also check out the Repository source code into another location other than the workspace. Finally, you should now have a ready SVN project where you can start working. File states If you're now changing some lines within a source code file, the Project Explorer view and the App Explorer view change the files' icon, so that you see a small white star on the black background. This means the file has changed since the last commit/update. There are some more small icons, which give you information about the related files and directories. Let's take a closer look at the Label Decorations tab as shown in the following screenshot: Now, we will discuss the symbols in the order shown in the previous screenshot: The small rising arrow shows you that the file or directory is an external one. The small yellow cylinder shows you that the file or directory is already under version control. The red X shows you that this file or directory is marked for deletion. The next time you commit your changes, the file will be deleted. The small blue cylinder shows you that the file or directory is switched. These are files or directories that belong to a different working copy other than their local parent directory. The small blue plus symbol shows you that this already versioned file or directory needs to be added to the repository. These could be files or directories you may have renamed or moved to a different directory. The small cornered square shows you that these files have a conflict with the repository. The small white star on the black background shows you that these files or directories have been changed since the last commit. If the file's or directory's icon has no small symbol, it means the file is ignored by the SVN Repository. The small white hook on the black background shows you that this file or directory is locked. The small red stop sign shows you that this file or directory is read-only. The small yellow cylinder shows you that this file or directory is already under version control and unchanged since the last commit. The small question mark shows you that this new file or directory isn't currently under version control. If you didn't find your icons in this list, or your icons look different, no problem. Just navigate to Window | Preferences and select the Label Decorations entry under Team | SVN within the tree. Here you will find all of the icons which are used. Committing an SVN Repository If you have finished extending your web application with some new features, you can now commit these changes so that the changes are stored in the Repository, and other developers can also update their working copies and get the new features. But how can you simply commit the changed files? Unlike a Git Repository, SVN allows you to commit changes in a tree from the Repository. By using Git, you can only commit changes in the complete Repository at once. But for now, we want to commit our SVN Repository changes, therefore just follow the steps mentioned in the following Time for action – updating and committing an SVN Repository section. Time for action – updating and committing an SVN Repository The first step, before performing a commit, is to perform an update on your working copy. Therefore, we will start by doing this, Aptana Studio reads all new revisions from the Subversion server and merges them with your local working copy. In order to do this update, right-click on your project root and select Team | Update to HEAD. When your working copy is up to date, navigate to the App Explorer view or the Project Explorer view and right-click on the files or directories that you want to commit, and then select the Commit... entry in the Team option. If you select a few directories or the whole project, the Commit window lists only those files within the selection that have changed since the last commit. So, you are able to select just the files and directories that you want to commit. Compose the selected files and directories as you need, and enter a comment in the top of the window. Why do you have to enter a comment while committing a change? Because, by committing the SVN Repository, it automatically saves the date, time, and your username; with this data the revision history stores information about who has changed which file at what time. In addition to that comes the commenting part. The comment should describe what kind of changes were made and what is their purpose. To finalize the commit, you just have to click on the OK button and the commit process will start. As described previously, you can see the output from all your SVN processes within the SVN Console view. In the following screenshot you can see the result of our commit process: What just happened? We have updated our working copy in order to commit our changes. Now the other developers can update their working copies too and can then work with your extensions. It should be noted again that it's recommended to perform an update before every commit. You can perform an update in a single file tree node. You don't have to update your whole project every time, a single node can also be committed. Updating an SVN Repository Additionally, similar to the SVN check out, you have the option to update your working copy not only to the Head revision, but also to a special revision number. In order to do this, right-click on the project root within the Project Explorer view and select the Update to Head... option or the Update to Version... option under the Team tab. After selecting one of these entries, Aptana Studio determines all the new files and files to be updated, downloads them from the Repository, and merges them with your local working copy. Now you should have all the source code from your current project. But, how can you identify which parts of a file are new or have been changed? No problem! Aptana Studio allows you not only to compare two different local files, you can also compare files from different revisions in your Repository. Refer to the following Time for action section to understand how this works:
Read more
  • 0
  • 0
  • 2195

article-image-exploring-advanced-interactions-webdriver
Packt
21 Jan 2014
9 min read
Save for later

Exploring Advanced Interactions of WebDriver

Packt
21 Jan 2014
9 min read
(For more resources related to this topic, see here.) Understanding actions, build, and perform We know how to take some basic actions, such as clicking on a button and typing text into a textbox; however, there are many scenarios where we have to perform multiple actions at the same time. For example, keeping the Shift button pressed and typing text for uppercase letters, and the dragging and dropping mouse actions. Let's see a simple scenario here. Open the selectable.html file that is attached with this book. You will see tiles of numbers from 1 to 12. If you inspect the elements with Firebug, you will see an ordered list tag (<ol>) and 12 list items (<li>) under it, as shown in the following code: <ol id="selectable" class="ui-selectable"> <li class="ui-state-default ui-selectee" name="one">1</li> <li class="ui-state-default ui-selectee" name="two">2</li> <li class="ui-state-default ui-selectee" name="three">3</li> <li class="ui-state-default ui-selectee" name="four">4</li> <li class="ui-state-default ui-selectee" name="five">5</li> <li class="ui-state-default ui-selectee" name="six">6</li> <li class="ui-state-default ui-selectee" name="seven">7</li> <li class="ui-state-default ui-selectee" name="eight">8</li> <li class="ui-state-default ui-selectee" name="nine">9</li> <li class="ui-state-default ui-selectee" name="ten">10</li> <li class="ui-state-default ui-selectee" name="eleven">11</li> <li class="ui-state-default ui-selectee" name="twelve">12</li> </ol> If you click a number, it's background color changes to orange. Try selecting the 1, 3, and 5 numbered tiles. You do that by holding the Ctrl key + 1 numbered tile + 3 numbered tile + 5 numbered tile. So, this involves performing multiple actions, that is, holding the Ctrl key continuously and clicking on 1, 3, and 5 tiles. How do we perform these multiple actions using WebDriver? The following code demonstrates that: public class ActionBuildPerform {     public static void main(String... args) {       WebDriver driver = new FirefoxDriver();       driver.get("file://C:/selectable.html");       WebElement one = driver.findElement(By.name("one"));       WebElement three = driver.findElement(By.name("three"));      WebElement five = driver.findElement(By.name("five"));       // Add all the actions into the Actions builder.      Actions builder = new Actions(driver);         builder.keyDown( Keys.CONTROL )               .click(one)              .click(three)              .click(five)              .keyUp(Keys.CONTROL);        // Generate the composite action.        Action compositeAction = builder.build();        // Perform the composite action.        compositeAction.perform( );       }    } Now, if you see the code, line number 9 is where we are getting introduced to a new class named Actions. This Actions class is the one that is used to emulate all the complex user events. Using this, the developer of the test script could combine all the necessary user gestures into one composite action. From line 9 to line 14, we have declared all the actions that are to be executed to achieve the functionality of clicking on the numbers 1, 3, and 5. Once all the actions are grouped together, we build that into a composite action. This is contained on line 16. Action is an interface that has only the perform() method, which executes the composite action. Line 18 is where we are actually executing the action using the perform() method. So, to make WebDriver perform multiple actions at the same time, you need to follow a three-step process of using the user-facing API of the Actions class to group all the actions, then build the composite action, and then the perform the action. This process can be made into a two-step process as the perform() method internally calls the build() method. So the previous code will look as follows: public class ActionBuildPerform {     public static void main(String... args) {       WebDriver driver = new FirefoxDriver();       driver.get("file://C:/selectable.html");       WebElement one = driver.findElement(By.name("one"));       WebElement three = driver.findElement(By.name("three"));      WebElement five = driver.findElement(By.name("five"));       // Add all the actions into the Actions builder.     Actions builder = new Actions(driver);         builder.keyDown( Keys.CONTROL )               .click(one)              .click(three)              .click(five)              .keyUp(Keys.CONTROL);        // Perform the action.        builder.perform( );   } } In the preceding code, we have directly invoked the perform() method on the Actions instance, which internally calls the build() method to create a composite action before executing it. In the subsequent sections of this article, we will take a closer look at the Actions class. All the actions are basically divided into two categories: mouse-based actions and keyboard-based actions. In the following sections, we will discuss all the actions that are specific to the mouse and keyboard available in the Actions class. Learning mouse-based interactions There are around eight different mouse actions that can be performed using the Actions class. We will see each of their syntax and a working example. The moveByOffset action The moveByOffset method is used to move the mouse from its current position to another point on the web page. Developers can specify the X distance and Y distance the mouse has to be moved. When the page is loaded, generally the initial position of a mouse would be (0, 0), unless there is an explicit focus declared by the page. The API syntax for the moveByOffset method is as follows: public Actions moveByOffset(int xOffSet, int yOffSet) In the preceding code, xOffSet is the input parameter providing the WebDriver the amount of offset to be moved along the x axis. A positive value is used to move the cursor to the right, and a negative value is used to move the cursor to the left. yOffSet is the input parameter providing the WebDriver the amount of offset to be moved along the y axis. A positive value is used to move the cursor down along the y axis and a negative value is used to move the cursor toward the top. When the xOffSet and yOffSet values result in moving the cursor out of the document, a MoveTargetOutOfBoundsException is raised. Let's see a working example of it. The objective of the following code is to move the cursor on to the number 3 tile on the web page:  public class MoveByOffSet{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement three = driver.findElement(By.name("three"));     System.out.println("X coordinate: "+three.getLocation().getX()+" Y coordinate: "+three.getLocation().getY());     Actions builder = new Actions(driver);     builder.moveByOffset(three.getLocation().getX()+1, three.getLocation().getY()+1);     builder.perform();   }  } We have added +1 to the coordinates, because if you observe the element in Firebug, we have a style border of 1 px. Border is a CSS-style attribute, which when applied to an element, will add a border of the specified color around the element with the specified amount of thickness. Though the previous code does move your mouse over tile 3, we don't realize it because we are not doing any action there. We will see that when we use this moveByOffset() method in combination with the click method shortly. The moveByOffset() method may not work in Mac OSX and may raise a JavaScript error when used independently like the previous code. The click at current location action The click method is used to simulate the left-click of your mouse at its current point of location. This method doesn't really realize where or on which element it is clicking. It just blindly clicks wherever it is at that point of time. Hence, this method is used in combination with some other action rather than independently, to create a composite action. The API syntax for the click method is as follows: public Actions click() The click method doesn't really have any context about where it is performing its action; hence, it doesn't take any input parameter. Let's see a code example of the click method: public class MoveByOffsetAndClick{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement seven = driver.findElement(By.name("seven"));     System.out.println("X coordinate: "+seven.getLocation().getX()+" Y coordinate: "+seven.getLocation().getY());     Actions builder = new Actions(driver);     builder.moveByOffset( seven.getLocation ().getX()+1, seven.getLocation().getY()+1).click();     builder.perform();   } } Line 8 is where we have used a combination of the moveByOffset() and click() methods to move the cursor from point (0, 0) to the point of tile 7. Because the initial position of the mouse is (0, 0), the X, Y offset provided for the moveByOffset() method is nothing but the location of the tile 7 element. Now, lets try to move the cursor from tile 1 to tile 11 and from there to tile 5 and see how the code looks. Before we get into the code, let's inspect the selectable.html page using Firebug. The following is the style of each tile: #selectable li {     float: left;     font-size: 4em;     height : 80px;     text-align: center;     width : 100px; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {     background: url("images/ui-bg_glass_75_e6e6e6_1x400.png") repeat-x scroll 50% 50% #E6E6E6;     border : 1px solid #D3D3D3;     color: #555555;     font-weight: normal; } The three elements with which we are concerned for our offset movement in the preceding style code are: height, width, and the border thickness. Here, the height value is 80px, width value is 100px, and border value is 1px. Use these three factors to calculate the offset to navigate from one tile to the other. Note that the border thickness between any two tiles will result in 2 px; that is, 1 px from each tile. The following is the code that uses the moveByOffset and click() methods to navigate from tile 1 to tile 11, and from there to tile 5: public class MoveByOffsetAndClick{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement one = driver.findElement(By.name("one"));     WebElement eleven = driver.findElement(By.name("eleven"));     WebElement five = driver.findElement(By.name("five"));     int border = 1;     int tileWidth = 100;     int tileHeight = 80;     Actions builder = new Actions(driver);     //Click on One     builder.moveByOffset( one.getLocation ().getX()+border, one.getLocation().getY()+border).click();     builder.build().perform();     // Click on Eleven     builder.moveByOffset( 2*tileWidth+4*border, 2*tileHeight+4*border).click();     builder.build().perform();    //Click on Five     builder.moveByOffset( -2*tileWidth-4*border, -tileHeight-2*border).click();     builder.build().perform();    }  }
Read more
  • 0
  • 0
  • 2194
article-image-listening-out
Packt
17 Aug 2015
14 min read
Save for later

Listening Out

Packt
17 Aug 2015
14 min read
In this article by Mat Johns, author of the book Getting Started with Hazelcast - Second Edition, we will learn the following topics: Creating and using collection listeners Instance, lifecycle, and cluster membership listeners The partition migration listener Quorum functions and listeners (For more resources related to this topic, see here.) Listening to the goings-on One great feature of Hazelcast is its ability to notify us of the goings-on of our persisted data and the cluster as a whole, allowing us to register an interest in events. The listener concept is borrowed from Java. So, you should feel pretty familiar with it. To provide this, there are a number of listener interfaces that we can implement to receive, process, and handle different types of events—one of which we previously encountered. The following are the listener interfaces: Collection listeners: EntryListener is used for map-based (IMap and MultiMap) events ItemListener is used for flat collection-based (IList, ISet, and IQueue) events MessageListener is used to receive topic events, but as we've seen before, it is used as a part of the standard operation of topics QuorumListener is used for quorum state change events Cluster listeners: DistributedObjectListener is used for the collection, creation, and destruction of events MembershipListener is used for cluster membership events LifecycleListener is used for local node state events MigrationListener is used for partition migration state events The sound of our own data Being notified about data changes can be rather useful as we can make an application-level decision regarding whether the change is important or not and react accordingly. The first interface that we are going to look at is EntryListener. This class will notify us when changes are made to the entries stored in a map collection. If we take a look at the interface, we can see four entry event types and two map-wide events that we will be notified about. EntryListener has also being broken up into a number of individual super MapListener interfaces. So, should we be interested in only a subset of event types, we can implement the appropriate super interfaces as required. Let's take a look at the following code: void entryAdded(EntryEvent<K, V> event);void entryRemoved(EntryEvent<K, V> event);void entryUpdated(EntryEvent<K, V> event);void entryEvicted(EntryEvent<K, V> event);void mapCleared(MapEvent event);void mapEvicted(MapEvent event); Hopefully, the first three are pretty self-explanatory. However, the fourth is a little less clear and in fact, one of the most useful. The entryEvicted method is invoked when an entry is removed from a map non-programmatically (that is, Hazelcast has done it all by itself). This instance will occur in one of the following two scenarios: An entry's TTL has been reached and the entry has been expired The map size, according to the configured policy, has been reached, and the appropriate eviction policy has kicked in to clear out space in the map The first scenario allows us a capability that is very rarely found in data sources—to have our application be told when a time-bound record has expired and the ability to trigger some behavior based on it. For example, we can use it to automatically trigger a teardown operation if an entry is not correctly maintained by a user's interactions. This will allow us to generate an event based on the absence of activity, which is rather useful! Let's create an example MapEntryListener class to illustrate the various events firing off: public class MapEntryListenerimplements EntryListener<String, String> {@Overridepublic void entryAdded(EntryEvent<String, String> event) {System.err.println("Added: " + event);}@Overridepublic void entryRemoved(EntryEvent<String, String> event) {System.err.println("Removed: " + event);}@Overridepublic void entryUpdated(EntryEvent<String, String> event) {System.err.println("Updated: " + event);}@Overridepublic void entryEvicted(EntryEvent<String, String> event) {System.err.println("Evicted: " + event);}@Overridepublic void mapCleared(MapEvent event) {System.err.println("Map Cleared: " + event);}@Overridepublic void mapEvicted(MapEvent event) {System.err.println("Map Evicted: " + event);}} We shall see the various events firing off as expected, with a short 10-second wait for the Berlin entry to expire, which will trigger the eviction event, as follows: Added: EntryEvent {c:capitals} key=GB, oldValue=null, value=Winchester,event=ADDED, by Member [127.0.0.1]:5701 thisUpdated: EntryEvent {c:capitals} key=GB, oldValue=Winchester,value=London, event=UPDATED, by Member [127.0.0.1]:5701 thisAdded: EntryEvent {c:capitals} key=DE, oldValue=null, value=Berlin,event=ADDED, by Member [127.0.0.1]:5701 thisRemoved: EntryEvent {c:capitals} key=GB, oldValue=null, value=London,event=REMOVED, by Member [127.0.0.1]:5701 thisEvicted: EntryEvent {c:capitals} key=DE, oldValue=null, value=Berlin,event=EVICTED, by Member [127.0.0.1]:5701 this We can obviously implement the interface as extensively as possible to service our application, potentially creating no-op stubs should we wish not to handle a particular type of event. Continuously querying The previous example focuses on notifying us of all the entry events. However, what if we were only interested in some particular data? We can obviously filter out our listener to only handle entries that we are interested in. However, it is potentially expensive to have all the events flying around the cluster, especially if our interest lies only in a minority of the potential data. To address this, we can combine capabilities from the map-searching features that we looked at a while back. As and when we register the entry listener to a collection, we can optionally provide a search Predicate that can be used as a filter within Hazelcast itself. We can whittle events down to relevant data before they even reach our listener, as follows: IMap<String, String> capitals = hz.getMap("capitals");capitals.addEntryListener(new MapEntryListener(),new SqlPredicate("name = 'London'"), true); Listeners racing into action One issue with the previous example is that we retrospectively reconfigured the map to feature the listener after it was already in service. To avoid this race condition, we should wire up the listener before the node-entering service. We can do this by registering the listener within the map configuration, as follows: <hazelcast><map name="default"><entry-listeners><entry-listener include-value="true">com.packtpub.hazelcast.listeners.MapEntryListener</entry-listener></entry-listeners></map></hazelcast> However, in both the methods of configuration, we have provided a Boolean flag when registering the listener to the map. This include-value flag allows us to configure the listener when it is invoked, as if we are interested in just the key of the event entry or the entries value as well. The default behavior (true) is to include the value, but in case the use case does not require it, there is a performance benefit of not having to provide it to the listener. So, if the use case does not require this extra data, it will be beneficial to set this flag to false. Keyless collections Though the keyless collections (set, list, and queue) are very similar to map collections, they feature their own interface to define the available events, in this case, ItemListener. It is not as extensive as its map counterpart, featuring just the itemAdded and itemRemoved events, and can be used in the same way, though it only offers visibility of these two event types. Programmatic configuration ahead of time So far, most of the extra configurations that we applied have been done either by customizing the hazelcast.xml file, or retrospectively modifying a collection in the code. However, what if we want to programmatically configure Hazelcast without the race condition that we discovered earlier? Fortunately, there is a way. By creating an instance of the Config class, we can configure the appropriate behavior on it by using a hierarchy that is similar to the XML configuration, but in code. Before passing this configuration object over to the instance creation method, the previous example can be reconfigured to do so, as follows: public static void main(String[] args) {Config conf = new Config();conf.addListenerConfig(new EntryListenerConfig(new MapEntryListener(), false, true));HazelcastInstance hz = Hazelcast.newHazelcastInstance(conf); Events unfolding in the wider world Now that we can determine what is going on with our data within the cluster, we may wish to have a higher degree of visibility of the state of the cluster itself. We can use this either to trigger application-level responses to cluster instability, or provide mechanisms to enable graceful scaling. We are provided with a number of interfaces for different types of cluster activity. All of these listeners can be configured retrospectively, as we have seen in the previous examples. However, in production, it is better to configure them in advance for the same reasons regarding the race condition as the collection listeners. We can do this either by using the hazelcast.xml configuration, or by using the Config class, as follows: <hazelcast><listeners><listener>com.packtpub.hazelcast.MyClusterListener</listener></listeners></hazelcast> The first of these, DistributedObjectListener, simply notifies all the nodes in the cluster as to the new collection objects that are being created or destroyed. Again, let's create a new example listener, ClusterObjectListener, to receive events, as follows: public class ClusterObjectListenerimplements DistributedObjectListener {@Overridepublic void distributedObjectCreated(DistributedObjectEvent event) {System.err.println("Created: " + event);}@Overridepublic void distributedObjectDestroyed(DistributedObjectEvent event) {System.err.println("Destroyed: " + event);}} As these listeners are for cluster-wide events, the example usage of this listener is rather simple. It mainly creates an instance with the appropriate listener registered, as follows: public class ClusterListeningExample {public static void main(String[] args) {Config config = new Config();config.addListenerConfig(new ListenerConfig(new ClusterObjectListener()));HazelcastInstance hz = Hazelcast.newHazelcastInstance(config);}} When using the TestApp console, we can create and destroy some collections, as follows: hazelcast[default] > ns testnamespace: testhazelcast[test] > m.put foo barnullhazelcast[test] > m.destroyDestroyed! The preceding code will produce the following, logging on ALL the nodes that feature the listener: Created: DistributedObjectEvent{eventType=CREATED, serviceName='hz:impl:mapService', distributedObject=IMap{name='test'}} Destroyed: DistributedObjectEvent{eventType=DESTROYED, serviceName='hz:impl:mapService', distributedObject=IMap{name='test'}} The next type of cluster listener is MembershipListener, which notifies all the nodes as to the joining or leaving of a node from the cluster. Let's create another example class, this time ClusterMembershipListener, as follows: public class ClusterMembershipListenerimplements MembershipListener {@Overridepublic void memberAdded(MembershipEvent membershipEvent) {System.err.println("Added: " + membershipEvent);}@Overridepublic void memberRemoved(MembershipEvent membershipEvent) {System.err.println("Removed: " + membershipEvent);}@Overridepublic void memberAttributeChanged(MemberAttributeEventmemberAttributeEvent) {System.err.println("Changed: " + memberAttributeEvent);}} Let's add the following code to the previous example application: conf.addListenerConfig(new ListenerConfig(new   ClusterMembershipListener())); Lastly, we have LifecycleListener, which is local to an individual node and allows the application built on top of Hazelcast to understand its particular node state by being notified as it changes when starting, pausing, resuming, or even shutting down, as follows: public class NodeLifecycleListener implements LifecycleListener {@Overridepublic void stateChanged(LifecycleEvent event) {System.err.println(event);}} Moving data around the place The final listener is very useful as it lets an application know when Hazelcast is rebalancing the data within the cluster. This gives us an opportunity to prevent or even block the shutdown of a node, as we might be in a period of increased data resilience risk because we may be actively moving data around at the time. The interface used in this case is MigrationListener. It will notify the application when the partitions migrate from one node to another and when they complete: public class ClusterMigrationListener implements MigrationListener {@Overridepublic void migrationStarted(MigrationEvent migrationEvent) {System.err.println("Started: " + migrationEvent);}@Overridepublic void migrationCompleted(MigrationEvent migrationEvent) {System.err.println("Completed: " + migrationEvent);}@Overridepublic void migrationFailed(MigrationEvent migrationEvent) {System.err.println("Failed: " + migrationEvent);}} When you are registering this cluster listener in your example application and creating and destroying various nodes, you will see a deluge of events that show the ongoing migrations. The more astute among you may have previously spotted a repartitioning task logging when spinning up the multiple nodes: INFO: [127.0.0.1]:5701 [dev] [3.5] Re-partitioning cluster data... Migration queue size: 271 The previous code indicated that 271 tasks (one migration task for each partition being migrated) have been scheduled to rebalance the cluster. The new listener will now give us significantly more visibility on these events as they occur and hopefully, they will be completed successfully: Started: MigrationEvent{partitionId=98, oldOwner=Member [127.0.0.1]:5701, newOwner=Member [127.0.0.1]:5702 this} Completed: MigrationEvent{partitionId=98, oldOwner=Member [127.0.0.1]:5701, newOwner=Member [127.0.0.1]:5702 this} Started: MigrationEvent{partitionId=99, oldOwner=Member [127.0.0.1]:5701, newOwner=Member [127.0.0.1]:5702 this} Completed: MigrationEvent{partitionId=99, oldOwner=Member [127.0.0.1]:5701, newOwner=Member [127.0.0.1]:5702 this} However, this logging information is overwhelming and actually not all that useful to us. So, let's expand on the listener to try and provide the application with the ability to check whether the cluster is currently migrating data partitions or has recently done so. Let's create a new static class, MigrationStatus, to hold information about cluster migration and help us interrogate it as regards its current status: public abstract class MigrationStatus {private static final Map<Integer, Boolean> MIGRATION_STATE =new ConcurrentHashMap<Integer, Boolean>();private static final AtomicLong LAST_MIGRATION_TIME =new AtomicLong(System.currentTimeMillis());public static void migrationEvent(int partitionId, boolean state) {MIGRATION_STATE.put(partitionId, state);if (!state) {LAST_MIGRATION_TIME.set(System.currentTimeMillis());}}public static boolean isMigrating() {Collection<Boolean> migrationStates= MIGRATION_STATE.values();Long lastMigrationTime = LAST_MIGRATION_TIME.get();// did we recently (< 10 seconds ago) complete a migrationif (System.currentTimeMillis() < lastMigrationTime + 10000) {return true;}// are any partitions currently migratingfor (Boolean partition : migrationStates) {if (partition) return true;}// otherwise we're not migratingreturn false;}} Then, we will update the listener to pass through the appropriate calls in response to the events coming into it, as follows: @Overridepublic void migrationStarted(MigrationEvent migrationEvent) {MigrationStatus.migrationEvent(migrationEvent.getPartitionId(), true);}@Overridepublic void migrationCompleted(MigrationEvent migrationEvent) {MigrationStatus.migrationEvent(migrationEvent.getPartitionId(), false);}@Overridepublic void migrationFailed(MigrationEvent migrationEvent) {System.err.println("Failed: " + migrationEvent);MigrationStatus.migrationEvent(migrationEvent.getPartitionId(), false);} Finally, let's add a loop to the example application to print out the migration state over time, as follows: public static void main(String[] args) throws Exception {Config conf = new Config();conf.addListenerConfig(new ListenerConfig(new ClusterMembershipListener()));conf.addListenerConfig(new ListenerConfig(new MigrationStatusListener()));HazelcastInstance hz = Hazelcast.newHazelcastInstance(conf);while(true) {System.err.println("Is Migrating?: " + MigrationStatus.isMigrating());Thread.sleep(5000);}} When starting and stopping various nodes, we should see each node detect the presence of the rebalance occurring, but it passes by quite quickly. It is in these small, critical periods of time when data is being moved around that resilience is mostly at risk, albeit depending on the configured numbers of backup, the risk could potentially be quite small. Added: MembershipEvent {member=Member [127.0.0.1]:5703,type=added}Is Migrating?: trueIs Migrating?: trueIs Migrating?: false Extending quorum We previously saw how we can configure a simple cluster health check to ensure that a given number of nodes were present to support the application. However, should we need more detailed control over the quorum definition beyond a simple node count check, we can create our own quorum function that will allow us to programmatically define what it means to be healthy. This can be as simple or as complex as what the application requires. In the following example, we sourced an expected cluster size (probably from a suitable location than a hard-coded) and dynamically checked whether a majority of the nodes are present: public class QuorumExample {public static void main(String[] args) throws Exception {QuorumConfig quorumConf = new QuorumConfig();quorumConf.setName("atLeastTwoNodesWithMajority");quorumConf.setEnabled(true);quorumConf.setType(QuorumType.WRITE);final int expectedClusterSize = 5;quorumConf.setQuorumFunctionImplementation(new QuorumFunction() {@Overridepublic boolean apply(Collection<Member> members) {return members.size() >= 2&& members.size() > expectedClusterSize / 2;}});MapConfig mapConf = new MapConfig();mapConf.setName("default");mapConf.setQuorumName("atLeastTwoNodesWithMajority");Config conf = new Config();conf.addQuorumConfig(quorumConf);conf.addMapConfig(mapConf);HazelcastInstance hz = Hazelcast.newHazelcastInstance(conf);new ConsoleApp(hz).start(args);}} We can also create a listener for the quorum health check so that we can be notified when the state of the quorum changes, as follows: public class ClusterQuorumListener implements QuorumListener {@Overridepublic void onChange(QuorumEvent quorumEvent) {System.err.println("Changed: " + quorumEvent);}} Let's attach the new listener to the appropriate configuration, as follows: quorumConf.addListenerConfig(new QuorumListenerConfig(new   ClusterQuorumListener())); Summary Hazelcast allows us to be a first-hand witness to a lot of internal state information. By registering the listeners so that they can be notified as the events occur, we can further enhance an application not only in terms of its functionality, but also with respect to its resilience. By allowing the application to know when and what events are unfolding underneath it, we can add defensiveness to it, embracing the dynamic and destroyable nature of the ephemeral approaches towards applications and infrastructure. Resources for Article: Further resources on this subject: What is Hazelcast? [Article] Apache Solr and Big Data – integration with MongoDB [Article] Introduction to Apache ZooKeeper [Article]
Read more
  • 0
  • 0
  • 2191

article-image-posting-reviews-ratings-and-photos
Packt
17 Nov 2014
15 min read
Save for later

Posting Reviews, Ratings, and Photos

Packt
17 Nov 2014
15 min read
In this article, by Hussein Nasser, the author of the book Building Web Applications with ArcGIS, we will learn how to perform editing on services by adding three features, posting reviews, ratings, and uploading pictures for the restaurant. (For more resources related to this topic, see here.) Configuring enterprise Geodatabase Unfortunately, editing process requires some more configurations to be done, and the current service, wouldn't do the trick. The reason is that the service is using a local database file; however, editing GIS data on the Web requires either an enterprise database running on a database management server such as the SQL server, or Oracle, or an ArcGIS Online feature service. Setting up the enterprise geodatabase server is out of the scope of this book. However, you can grab my book Learning ArcGIS Geodatabase, Packt Publishing, and walk through the step-by-step full guide to set up your own enterprise geodatabase with Microsoft SQL Server Express. If you have an existing enterprise geodatabase server, you can use it. I will be using SQL Server Express 2012 SP1. Connecting to the Geodatabase First, we need to establish a connection to the enterprise server. For that we will use a username that has full editing capabilities. I will be using the system administrator (SA) user sa for the SQL server. Note that the SA user has full access to the database; we have used it in this book for simplicity to avoid assigning privileges. In an ideal situation, you would create a user and assign him the correct permissions to read or write into the subject tables. My book, Learning ArcGIS Geodatabase, Packt Publishing, addresses all these issues thoroughly. Follow these steps to establish a connection to your enterprise geodatabase: Open ArcCatalog and expand Database Connections in the Catalog Tree panel. Double-click on Add Database Connection. In the Database Platform option select SQL Server (or your database provider). Type the name of the server hosting the database; in my case, it is the same server arcgismachine. Select Database authentication in Authentication Type and provide the database credentials for the sa user or any user who has administrator privileges on the database. You can use the SDE user as well. Select your Database from the drop-down list and click on OK as shown in the following screenshot: Rename the connection to sa@arcgismachine.sde. We are going to reference this later in the article. Don't close ArcCatalog yet, we will be needing it. You can learn more about ArcGIS database connections and how to create them against different databases from the link http://qr.net/arcgisdb. Copying Bestaurants' data to the server Now that we have our connection ready, we need to copy the Bestaurants data into our new database. Follow these steps: From Catalog Tree, right-click on the Folder connection and select Connect to Folder. Browse to C:2955OT, the folder we created in the book Building Web Application with ArcGIS, and click on OK. This will allow us to access our Bestaurants data. From Folder Connection, expand C:2955OT and browse to 2955OT_01_FilesBestaurants.gdb. Click on Bestaurants.gdb, use the Shift key to select Belize_Landbase and Food_and_Drinks. Then right-click and select Copy as shown in the following screenshot: Double-click on the ags@arcgismachine.sde connection to open it. Right-click on the connection and select Paste. You will be prompted with the following dialog box that will show you what will be copied. Note that related data was also imported. This will paste the data to our new database. After the copying is completed, close ArcCatalog. Publishing feature service Our old service won't work in this article; the reason is that it was pointing to a local database which does not support editing on ArcGIS for Server. That is why we migrated our Bestaurants data to the enterprise geodatabase. It is time to publish a brand new service; it will look the same but will just behave differently. First, we need to open our Belize.mxd map document and point our new database. Second, we will register the database with ArcGIS for Server; finally, we will publish the service. Setting the Source to the Enterprise Geodatabase In order to publish the new service, we have to first create a map document which points to the enterprise geodatabase. Follow these steps to do so: Browse to and open 2955OT_05_FilesBelize.mxd with ArcMap. You can simply double-click on the file. Next, we set the source of our layers from the Table of Contents in ArcMap. Click on List by Source as shown in this screenshot: Double-click on the Food_and_Drinks layer to open the Layer properties. In the Layer Properties window, click on Set Data Source. From the Data Source dialog, browse to the sa@arcgismachine.sde connection and select the sdedb.DBO.Food_and_Drinks object, and then click on Add as illustrated in this screenshot: Click OK to apply the changes. Do the same for the rest of the objects, Landbase and VENUES_REVIEW, in your map selecting the matching objects in the destination connection. The final source list should look like the following, nothing pointing to the local data. Keep ArcMap open for the next step. You can also modify the data sources in an ArcMap document using ArcCatalog. In ArcCatalog, navigate to the map document in Catalog Tree, right-click on the map document, and choose the Set Data Sources option from the pop-up menu. Using this allows you to set the data source for individual and/or all layers at one time. Publishing the map document Now that we have our map document ready, it is time for us to publish it. However, we still need to perform one more step, which is database registration. This step will cause the data to persist in the server, which makes it ready for editing. Follow these steps to publish the map document: From the File menu, point to Share As and click on Service. Select Overwrite an existing service, because we want to replace our old Bestaurants service. Click on Next. Select the Bestaurants service and click on Continue. From the Service Editor window, click on Capabilities. Check the Feature Access capability to enable editing on this service as shown in the following screenshot: Click on Analyze. This will show an error that we have to fix. The error is Feature service requires a registered database. This error can be solved by right-clicking on it and selecting Show Data Store Registration Page, as shown in the following screenshot: In the Data Store window, click on the plus sign to add a new database. In the Register Database window, enter in Bestaurants in the Name textbox. Click on Import and select the sa@arcgismachine connection. Make sure the Same as publisher database connection option is checked as shown in the following screenshot: Click on OK in the Register Database window and the Data Store window. Click on Analyse again; this time you shouldn't get any errors. Go ahead and Publish your service. Close ArcMap. You can read more about registering databases at: http://qr.net/registerdb. Testing the web application with the new service We have updated our Bestaurants service, but it should work fine so far. Hence, just make sure that we run your application under http://arcgismachine/mybestaurants.html. You can find the latest code at 2955OT_05_FilesCodebestaurants01_beforeediting.html, copy it to c:inetpubwwwroot and rename it accordingly. Adding ArcGIS's editing capabilities Currently, the food and drinks layer is being fetched as a read-only map service located at the URL: http://arcgismachine:6080/arcgis/rest/services/Bestaurants/MapServer/0. The only difference is that it points to the enterprise geodatabase. You can see the following code in mybestaurants.html which confirms that: //load the food and drinks layer into an objectlyr_foodanddrinks = new esri.layers.FeatureLayer("http://arcgismachine:6080/arcgis/rest/services/Bestaurants/MapServer/0", { outFields: ["*"] }); We won't be able to edit MapServerlayer, we have to use FeatureServer. We will show how to change this in the next section. Adding or updating records in a service with ArcGIS JavaScript API is simple. We only need to use the applyEdits method on the FeatureLayer object. This method accepts a record and some parameters for the response; what we are interested in is to insert a record. The following code shows how to prepare a record with three fields for this function: varnewrecord = {attributes:{   FIELD1: VALUE1,   FIELD2: VALUE2,   FIELD3: VALUE3}}; For instance, if I want to create a new record that has rating and review, I populate them as follows: varnewrecord = {attributes:{   REVIEW: "This is a sample review",   RATING: 2,   USER: "Hussein"}}; And to add this record, we simply call applyEdits on the corresponding layer and pass the newrecord object as shown in the following code snippet: var layer = new esri.layers.FeatureLayer("URL");layer.applyEdits([newrecord], null, null, null, null); Posting reviews and ratings The first thing we have to add is to point our food and drinks layer to its feature server instead of the map server to allow editing. This can be achieved by using the following URL instead, simply replace MapServer with FeatureServer: http://arcgismachine:6080/arcgis/rest/services/Bestaurants/FeatureServer/0 Follow these steps to perform the first change towards editing our service: Edit mybestaurants.html. Find the food and drinks layer initialization and point it to the feature service instead using the following code snippet: //load the food and drinks layer into an objectlyr_foodanddrinks = new esri.layers.FeatureLayer ("http://arcgismachine:6080/arcgis/rest/services /Bestaurants/FeatureServer/0", { outFields: ["*"] }); The review and rating fields can be found in the VENUES_REVIEW table. So we can add a single record that has a review and a rating, and send it to the service. However, we need to prepare the necessary controls that will eventually populate and add a record to the reviews table. Let's modify the ShowResults function of our query so that each restaurant shows two textboxes: one for review and one for the rating. We will also add a button so that we can call the addnewreview()function that will add the review. Each control will be identified with the object ID of the restaurant as shown in the following code: //display the reatingresulthtml = resulthtml + "<b>Rating:</b> " + record.attributes["RATING"];//create a place holder for each review to be populated laterresulthtml = resulthtml + "<div id = 'review" + record.attributes["OBJECTID"] + "'></div>";//create a place holder for each attachment picture to be populated laterresulthtml = resulthtml + "<div id = 'picture" + record.attributes["OBJECTID"] + "'></div>";//create text box for the review marked with the objectidresulthtml = resulthtml + "<br>Review: <input type = 'text' id = 'txtreview" + record.attributes["OBJECTID"] + "'>";//another one for the rating.resulthtml = resulthtml + "<br>Rating: <input type = 'text' id = 'txtrating" + record.attributes["OBJECTID"] + "'>"; //and a button to call the function addnewreviewresulthtml = resulthtml + "<br><input type = 'button' value = 'Add' onclick = 'addnewreview(" + record.attributes["OBJECTID"] + ")'>"; Now, we need to write the addnewreview function. This function accepts an object ID and adds a record matching that object to the reviews table. I have placed the three empty variables: object ID, review, and rating, and prepared the template to write a new record. I also created a feature layer of our VENUES_REVIEW table: functionaddnewreview(oid){varobjectid;var review;var rating;varnewReview ={   attributes:   {     VENUE_OBJECTID: objectid,     REVIEW: review,     RATING: rating   }};//open the review tablevarreviewtable = new esri.layers.FeatureLayer("http://arcgismachine:6080/arcgis/rest/services/Bestaurants/FeatureServer/2");//apply edits and pass the review recordreviewtable.applyEdits([newReview], null, null, null, null);} You might have guessed how to obtain the review, rating, and object ID. The object ID is passed, so that is easy. The review can be obtained by searching for txtreview + objectid. A similar search can be used for rating. Let's also add a message to see if things went fine: functionaddnewreview(oid){varobjectid = oid;var review =document.getElementById('txtreview' +    oid).value;var rating = document.getElementById('txtrating' +    oid).value;varnewReview ={   attributes:   {     VENUE_OBJECTID: objectid,     REVIEW: review,     RATING: rating   }};//open the review tablevarreviewtable = new esri.layers.FeatureLayer   ("http://arcgismachine:6080/arcgis/rest/services   /Bestaurants/FeatureServer/2");//apply edits and pass the review recordreviewtable.applyEdits([newReview], null, null,   null, null);alert("Review has been added");} You can also add the user to your record in a similar way: varnewReview ={attributes:   OBJECTID: objectid,   REVIEW: review,   USER_: "Hussein"   RATING: rating}}; It is time for us to save and run our new application. Do a search on Fern, then write a review, add a rating, and then click on Add. This should add a record to Fern Diner. You can always check if your record is added or not from ArcCatalog. This can be seen in the following screenshot: You can find the latest code at 2955OT_05_FilesCodebestaurants02_addreviews.html. Uploading pictures Uploading attachments to a service can be achieved by calling the addAttachment method on the feature layer object. However, we have to make some changes in our ShowResults function to ask the user to browse for a file. For that, we will need to use the file's HTML object, but we have to encapsulate it in a form tagged by the object ID of the restaurant we want to upload the pictures for. The file object should be named attachment so that the addAttachment method can find it. Follow these steps to add the upload pictures' logic: Edit the mybestaurants.html file and add the following code to your ShowResults function: //browse for a picture for this restaurantresulthtml = resulthtml + "<form id = 'frm" + record.attributes["OBJECTID"] + "'><input type = 'file' name = 'attachment'/></form>";//and a button to call the function addnewreviewresulthtml = resulthtml + "<br><input type = 'button' value = 'Add' onclick = 'addnewreview(" + record.attributes["OBJECTID"] + ")'>";    //new lineresulthtml = resulthtml + "<br><br>"; We will make it so that when the user clicks on Add, the attachment is also added along with the review for simplicity. The AddAttachment function takes the object ID of the restaurant which you want to upload the picture to, and a form HTML element which contains the file element named attachment: functionaddnewreview(oid){varobjectid = oid;var review = document.getElementById('txtreview' +    oid).value;var rating = document.getElementById('txtrating' +    oid).value;varnewReview ={   attributes:   {     VENUE_OBJECTID: objectid,     USER_: "Hussein",     REVIEW: review,     RATING: rating   }};//open the review tablevarreviewtable = new esri.layers.FeatureLayer("http://arcgismachine:6080/arcgis/rest/services   /Bestaurants/FeatureServer/2");//apply edits and pass the review recordreviewtable.applyEdits   ([newReview], null, null, null, null);//add attachmentlyr_foodanddrinks.addAttachment(oid,    document.getElementById("frm" + oid) , null, null);alert("Review and picture has been added");} Save and run the code. Search for Haulze Restaurant. This one doesn't have an attachment, so go ahead, write a review, and upload a picture. Run the query again and you should see your picture. This is shown in the following screenshot: The final code can be found at 2955OT_05_FilesCodebestaurants03_uploadpicture.html. The final touches This is where we add some web enhancements to the application, things that you as a web developer can do. We will update the status bar, make part of the page scrollable, change the rating into star icons, and do some fine-tuning of the interface. I have already implemented these changes in the final version of the application, which can be found at 2955OT_05_FilesCodebestaurantsfinal.html. These changes don't have anything to do with ArcGIS development; it is pure HTML and JavaScript. The final application should look as shown in the following screenshot: Summary In this article, we have put the final touches to the Bestaurants ArcGIS web application by adding rating, reviews, and uploading pictures to the ArcGIS service. We have learned that editing can only be done for the feature services on the data hosted on enterprise geodatabases that is why we had to set up our own. We have copied the data to a new server, and modified the source document to point to that server. Then we republished the service with feature-access capability to enable editing. We finally added the necessary JavaScript API code to write reviews and upload pictures to the website. With these features, we have completed the Bestaurants project requirements. This is the end of this book but it is only the beginning of great potential applications that you will be developing using the skill set you acquired in the course of this journey. You can now be confident in pursuing more advanced ArcGIS JavaScript APIs from the Esri website (resources.arcgis.com) which is a good place to start. There are hundreds of methods and functions in the API. However, keep in mind that you only need to learn what you really need and require to. We have managed to complete an entire website with a handful of APIs. Take the next project, analyze the requirements, see what APIs you need, and learn them. That is my advice. My inbox is always ready for suggestions and thoughts, and of course, questions. Resources for Article: Further resources on this subject: Enterprise Geodatabase [article] Server Logs [article] Adding Graphics to the Map [article]
Read more
  • 0
  • 0
  • 2168
Modal Close icon
Modal Close icon