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-support-developers-spring-web-flow-2
Packt
12 Oct 2009
9 min read
Save for later

Support for Developers of Spring Web Flow 2

Packt
12 Oct 2009
9 min read
Build systems Build systems are not necessary for building web applications with Spring Web Flow, but they greatly assist a developer by resolving dependencies between packages and automating the build process. In this article, we will show you how to build your projects with Apache Ant and Apache Maven. Ant Ant is a powerful and very flexible build tool. You can write Extensible Markup Language (XML) files, which tell Ant how to build your application, where to find your dependencies, and where to copy the compiled files. Often, you won't find the need to download Ant, as it is already built-in into popular IDEs such as Eclipse and NetBeans. Ant does not provide you with an automatic dependency resolving mechanism. So you will have to manually download all the libraries your application needs. Alternatively, you can use a third-party dependency resolving system such as Apache Ivy, which we will describe later in this article. When you have obtained a copy of Ant, you can write a build.xml file as shown in the following code. <?xml version="1.0" encoding="UTF-8"?> <project name="login.flow" default="compile"> <description> login.flow </description> <property file="loginflow.properties"/> <path id="classpath"> <fileset dir="lib/"> <include name="*.jar" /> </fileset> </path> <target name="init"> <mkdir dir="${build}" /> <mkdir dir="${build}/WEB-INF/classes" /> </target> <target name="assemble-webapp" depends="init"> <copy todir="${build}" overwrite="y"> <fileset dir="${webapp-src}"> <include name="**/*/" /> </fileset> </copy> </target> <target name="compile" depends="assemble-webapp"> <javac srcdir="${src}" destdir="${build}/WEB-INF/classes"> <classpath refid="classpath" /> </javac> <echo>Copying resources</echo> <copy todir="${build}/WEB-INF/classes" overwrite="y"> <fileset dir="${resources}"> <include name="**/*/" /> </fileset> </copy> <echo>Copying libs</echo> <copy todir="${build}/WEB-INF/lib" overwrite="y"> <fileset dir="lib/"> <include name="*.jar" /> </fileset> </copy> </target> </project> First of all, we will specify that we have defined a few required folders in an external PROPERTIES file. The loginflow.properties, stored in your project's root folder, looks like this: src = src/main/java webapp-src = src/main/webapp resources = src/main/resources build = target/chapter02 These define the folders where your source code lies, where your libraries are located, and where to copy the compiled files and your resources. You do not have to declare them in a PROPERTIES file, but it makes re-using easier. Otherwise, you will have to write the folder names everywhere. This would make the build script hard to maintain if the folder layout changes. In the init target, we create the folders for the finished web application. The next is the assemble-webapp target, which depends on the init target. This means that if you execute the assemble-webapp target, the init target gets executed as well. This target will copy all the files belonging to your web application (such as the flow definition file and your JSP files) to the output folder. If you want to build your application, you will have to execute the compile target. It will initialize the output folder, copy everything your application needs to it, compile your Java source code, and copy the compiled files, along with the dependent libraries. If you want to use Apache Ivy for automatic dependency resolution, first, you have to download the distribution from http://ant.apache.org/ivy. This article refers to Version 2.0.0 Release Candidate 1 of Ivy. Unpack the ZIP file and put the ivy-2.0.0-rc1.jar file in your %ANT_HOME%lib folder. If you are using the Eclipse IDE, Ant is already built into the IDE. You can add the JAR file to its classpath by right-clicking on the task you want to execute and choosing Run As | Ant Build… In the appearing dialog, you can add the JAR file on the Classpath tab, either by clicking on Add JARs… and selecting a file from your workspace, or by selecting Add External JARs…, and looking for the file in your file system. Afterwards, you just have to tell Ant to load the required libraries automatically by modifying your build script. We have highlighted the important changes (to be made in the XML file) in the following source code: <project name="login.flow" default="compile"> ... <target name="resolve" description="--> retrieve dependencies with ivy"> <ivy:retrieve /> </target> ... </project> The last step, before we can actually build the project, involves specifying which libraries you want Ivy to download automatically. Therefore, we will now have to compose an ivy.xml file, stored in your project's root folder, which looks like this: <ivy-module version="2.0"> <info organisation="com.webflow2book" module="login.flow"/> <dependencies> <dependency org="org.springframework.webflow" name="org.springframework.binding" rev="2.0.5.RELEASE" /> <dependency org="org.springframework.webflow" name="org.springframework.js" rev="2.0.5.RELEASE" /> <dependency org="org.springframework.webflow" name="org.springframework.webflow" rev="2.0.5.RELEASE" /> </dependencies> ... </ivy-module> To keep the example simple, we only showed the Spring Web Flow entries of the file we just mentioned. In order to be able to build your whole project with Apache Ivy, you will have to add all other required libraries to the file. The org attribute corresponds to the groupId tag from Maven, as does the name attribute with the artifactId tag. The rev attribute matches the version tag in your pom.xml. Maven Maven is a popular application build system published by the Apache Software Foundation. You can get a binary distribution and plenty of information from the project's web site at http://maven.apache.org. After you have downloaded and unpacked the binary distribution, you have to set the M2_HOME environment variable to point to the folder where you unpacked the files. Additionally, we recommend adding the folder %M2_HOME%bin (on Microsoft® Windows system) or $M2_HOME/bin (on Unix or Linux systems) to your PATH variable. Maven has a configuration file called settings.xml, which lies in the M2_HOMEconf folder. Usually, you do not edit this file, unless you want to define proxy settings (for example, when you are in a corporate network where you have to specify a proxy server to access the Internet), or want to add additional package repositories. There are several plug-ins for the most popular IDEs around, which make working with Maven a lot easier than just using the command line. If you do not want to use a plug-in, you have to at least know that Maven requires your projects to have a specific folder layout. The default folder layout looks like this: The root folder, directly below your projects folder, is the src folder. In the main folder, you have all your source files (src/main/java), additional configuration files, and other resources you need (src/main/resources), and all JSP and other files you need for your web application (src/main/webapp). The test folder can have the same layout, but is used for all your test cases. Please see the project's website for more information on the folder layout. To actually build a project with Maven, you need a configuration file for your project. This file is always saved as pom.xml, and lies in the root folder of your project. The pom.xml for our example is too long to be included in this article. Nevertheless, we want to show you the basic layout. You can get the complete file from the code bundle uploaded on http://www.packtpub.com/files/code/5425_Code.zip. <project xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.webflow2book</groupId> <artifactId>chapter02</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>chapter02 Maven Webapp</name> <url>http://maven.apache.org</url> This is a standard file header where you can define the name and version of your project. Further, you can also specify how your project is supposed to be packaged. As we wanted to build a web application, we used the war option. Next, we can de?ne all the dependencies our project has to the external libraries: <dependencies> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.binding</artifactId> <version>2.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.js</artifactId> <version>2.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.webflow</artifactId> <version>2.0.5.RELEASE</version> </dependency> ... </dependencies> As you can see, defining a dependency is pretty straightforward. If you are using an IDE plug-in, the IDE can do most of this for you. To build the application, you can either use an IDE or open a command-line window and type commands that trigger the build. To build our example, we can enter the projects folder and type: mvn clean compile war:exploded This cleans up the target folder, compiles the source files, and compiles all necessary files for our web application in the target folder. If you use Tomcat, you can point your context docBase to the target folder. The application will be automatically deployed on the startup of Tomcat, and you can test your application.
Read more
  • 0
  • 0
  • 3351

article-image-introduction-soa-testing
Packt
09 Aug 2016
13 min read
Save for later

Introduction to SOA Testing

Packt
09 Aug 2016
13 min read
In this article by Pranai Nandan, the author of Mastering SoapUI, we will see how the increase in implementation of service-oriented architecture (SOA) and architecture across applications leads to various technological and business advantages to the organizations implementing it. But as it's said; There are two sides to every coin, with SOA architecture came advantages like: Reusability Better scalability Platform independency Business agility Enhanced security But there are also disadvantages like: Increased response time Service management effort is high Implementation cost is high (For more resources related to this topic, see here.) In this article we will study the following topics: Introduction to SOA SoapUI architecture Test levels in SOA testing SOA testing approach Introduction to functional, performance & security testing using SoapUI Is SOA really advantageous? Well, let's talk about a few of the advantages of SOA architecture. Reusability: If we want to reuse the same piece of functionality exposed via a web service we should be absolutely sure that the functionality of the service is working as expected; security of the service is reliable and has no performance bottlenecks. Business Agility: With more functional changes being easily adopted in a web service, we make the web service prone to functional Bugs. Enhanced Security: Web services are usually wrapped around systems that are being protected by several layers of security like SSL and usage of Security tokens. Use of the business layer to protect the technical services to be directly exposed is usually handled by these layers. If the security of these layers is removed, the web service is highly vulnerable. Also the use of XML as a communication protocol opens the service to XML based attacks. So to mitigate risks we have SOA Testing, and to help you test SOA architecture we have multiple testing tools on the market for example; SOAP UI, SoapUI Pro, HP Service Test, ITKO LISA and SOA Parasoft. But the most widely used and open source tool in the SOA testing arena is SOAP UI. Following is a comparative analysis of the most famous tools in the Web service testing & test automation arena. Comparative Analysis: S.No Factors SoapUI SaopUI PRO ITKO LISA SOA Parasoft 1 Cost Open source 400 $/License Highly Costly Highly Costly 2 Multilayer testing Yes Yes Yes Yes 3 Scripting support Yes Yes Yes Yes 4 Protocol support Yes Yes Yes Yes 5 CI support Yes Yes Yes Yes 6 Ease Of Use 8/10 9/10 9/10 9/10 7 Learning curve 8/10 8/10 6/10 6/10 As we can see by the preceding comparison metrics, Ease of Use, Learning curve, and Cost play a major role in selection of a tool for any project. So to learn ITKO LISA or SOA Parasoft there is very limited, or no, material available on the Internet. To get resources trained you need to go to the owners of these tools and pay extra and then pay more if you need the training a second time. This gives additional advantages to SaopUI and SoapUI Pro to be the first choice for Test Architects and Test Managers for their projects. Now let's talk about the closely related brothers in this subset; SoapUI & SoapUI pro both are from the same family, Eviware, which is now SmartBear. However, SoapUI Pro has an enriched functionality and GUI which have additional functionalities to help reduce the time for testing, justifying its cost as compared to SoapUI open source. Following is a quick comparison Criteria SoapUI SoapUI Pro Reporting Very limited, no rich reporting Reports are available in different formats XPath Builder Not Available Available Data source Not Available Multiple options for data sources available Data sink Not Available Available XQuery Builder Not Available Available The additional functionality that is available in SoapUI pro can be achieved by SoapUI using Groovy script. To sum up everything that is given as UI functionality in SoapUI PRO is achievable with little effort in SoapUI which finally makes SoapUI open source the preferred choice for tool pickers. SoapUI architecture Before we move onto the architecture let's take a look the capabilities of SOAP UI and how can we use it for the benefit of our projects. SoapUI provides the following testing features to the test team: Functional testing [manual] Function test automation Performance testing Security testing Web service interoperability testing Apart from these, SOAP UI is also capable of integration with the following: LoadUI for advanced performance testing Selenium for multilayer testing Jenkins for continuous integration. HP QC for end-to-end test Automation management and execution. Soap UI has a comparatively simple architecture as compared to other tools in the SOA Testing world. The following image, shows the architecture of SoapUI at an overview level: Let's talk about the architecture in detail: Test config files: Files which require power to test this includes test data, expected results, database connections variables and any other environmental or test specific details. 3rd party API: Third-party API helps create an optimized test automation framework example. JExcel API to help integrate with Microsoft Excel to create a data driven framework. Selenium:Selenium JARs to be used for UI Automation. SOAP UI Runner: This is used to run the soap UI project and is a very useful utility for test automation as it allows you to run the test from the command line and acts as a trigger for test automation. Groovy: This library is used to enable SoapUI to provide its users with groovy as a scripting language. Properties: Test request properties to hold any dynamically generated data. We also have Test properties to configure SSL and other security configurations for test requests. Test Report: SoapUI provides a Junit style report and user Jasper reporting utility for reporting of test results. Test architecture in detail Soap UI Architecture is composed of many key components which help provide the users of SOAP UI with advanced functionality like virtualization, XPath, invoking services with JMS endpoints, logging, and debugging. Let's discuss these key components in detail: Jetty: Service virtualization / mock Service We can create replicas of services in cases where the service is not ready or buggy to test. In the meantime, we want to create our test cases, for that we can use service virtualization or mocking and use that service. Jetty is used for hosting virtual services. Provided by Eclipse, Java based web server. Works for both Soap and Rest. Jasper: Is used to generate reports Open source reporting tool Saxon XSLT and XQuery processor: We can use Path and XQuery to process service results The Saxon platform provides us with the option to process results using Path and XQuery Log4J: Used for logging Provides SoapUI, error, HTTP, Jetty, and memory logs JDBC driver: To interact with different databases we would need the respective drivers Hermes MS: Is used in applications where high volume of transactions take place It is used to send messages to the JMS Queue Receiver results from the JMS Queue We can incorporate Java JMS using Hermes JMS Scripting Language: We can choose with groovy or JavaScript We can select language for each project We can set language at project property level Monitoring To check what is sent to the service and what is received from the service Runners Execution can be run without using SoapUI Run from the command line Execution can be run without using SoapUI Test runner LoadTestRunner SecurityTestRunner MockServiceRunner Can also be executed from build tools like Jenkins Test approaches in SOA testing Approaches to test SOA architecture are usually based on the scope of the project and requirements to test. Let's look at an example: Following is a diagram of a three-tier architecture based on SOA architecture: Validation1 or V1: Validation of integration between Presentation Layer to the Services Layer Validation2 or V2: Validation of integration between Services Layer to the Service Catalogue Layer Validation3 or V3: Validation of integration between Product catalogue layer and the database or backend Layer So we have three integration points which makes us understand that we need integration testing also with functional, performance and security testing. So let's sum up the types of testing that are required to test end-to-end Greenfield projects. Functional testing Integration testing Performance testing Security testing Automation testing Functional testing A web service may expose single or multiple functionalities via operations and sometimes we need to test a business flow which requires calling multiple services in sequence which is known as orchestration testing in which we validate that a particular business flow meets the requirement. Let's see how to configure a SOAP service in SoapUI for functional Testing Open SoapUI by clicking on the launch icon. Click on File in upper-left corner of the top navigation bar. Click on New SOAP Project heading in the File menu. Verify that a popup opens up which asks for the WSDL or WADL details. There are two ways you can pass a URL to the web location of the WSDL, or you can pass a link to the downloaded WSDL on your local system. Enter the project name details and the WSDL location which can either be on your local machine or be called from a URL, then click on OK. You may verify that the WSDL is successfully loaded in SOAP UI with all the operations. Now you can see that service is successfully loaded in the workspace of SoapUI. Now, the first step toward an organized test suite is to create a test suite and relevant test cases. To achieve this, click on the operation request: When you click on Add to TestCase you are asked for the test suite name and then a test case name and finally you will be presented with the following popup: Here you can create a TestCase and add validations to it at run time. After clicking OK you are ready to start your functional and integration testing: Let's take an example of how to test a simple web service functionally. Test case: Validate that Search Customer searches for the customer from the system database using an MSISDN (Telecom Service). Please note MSISDN is a unique identifier for a user to be searched in the database and is a mandatory parameter. API to be tested, Search Customer: Request body: <v11:SearchCustomerRequest> <v11:username>TEST_Agent1</v11:username> <v11:orgID>COM01</v11:orgID> <v11:MSISDN>447830735969</v11:MSISDN> So to test it we pass the mandatory parameters and verify the response which should get us the response parameters expected to be fetched. By this we validate that searching for the customer using some Search criteria is successful or not, similarly, in order to test this service from a business point of view we need to validate this service with multiple scenarios. Following is a list of a few of them. Considering it's a telecom application search customer service: Verify that a prepay customer is successfully searched for using Search customer Verify that a post-pay customer is successfully searched for using Search customer Verify that agents are successfully searched for using search customer Verify that the results retrieved in response have the right data Verify that all the mandatory parameters are presenting the response of the service Here is how the response looks: Response Search Customer <TBD> Performance testing So is it really possible to perform performance testing in SoapUI? The answer is yes, if you just want to do a very simple test on your service itself, not on the orchestration. Soap UI does have limitations when it comes to performance testing but it does provide you a functionality to generate load on your web service with different strategies. So to start with, once you have created your SoapUI project for a service operation, you can just convert the same to a simple load test. Here is how: Right-click on the Load Test option available: Now select the name of the load test; a more relevant one will help you in future runs. You will now see that the load test popup appears and the load test is created: There are several strategies to generate load in SoapUI. The strategies are given below:    Simple    Burst    Thread    Variance Security testing API and web services are highly vulnerable to security attacks and we need to be absolutely sure about the security of the exposed web service depending on the architecture of the web service and the nature of its use. Some of the common attacks types include: Boundary attack Cross-site scripting XPath injection SQL injection Malformed XML XML bomb Malicious attachment Soap UI security Testing functionality provides scans for every attack type and also, if you want to try a custom attack on the service by writing a custom Script. So the scans provided by SOAP UI are: Boundary scan Cross-site scripting scan XPath injection scan SQL injection scan Malformed XML scan XML bomb scan Malicious attachment scan Fuzzing scan Custom script Following are the steps for how we configure a security test in SoapUI: You can see an option for security test just below load test in SoapUI. To add a test, right-click on the Security Test and select New Security Test: Now select New Security Test and verify that a popup asking the name of the security test opens: Select the name of the security test and click on OK. After that, you should see the security test configuration window opened on the screen. For the Service operation of your test case, in case of multiple operation in the same test case, you can configure for multiple operations in a single security test as well. For this pane you can select and configure scans on your service operations. To add a scan, click on the selected icon in the following screenshot: After selecting the icon, you can now select the scan you want to generate on your operation: After that you can configure your scan for the relevant parameter by configuring the XPath of the parameter in the request. After that you can select Assertions and Strategy tabs from the below options: You are now ready to run you security test with Boundary Scan: Summary So now we have been introduced to the key features of SoapUI and by the end of this article the readers of this article will now be familiar with SOA and SOA Testing. They now will have basic understanding of functional, load, and security testing in SOA using SoapUI. Resources for Article: Further resources on this subject: Methodology for Modeling Business Processes in SOA [article] Additional SOA Patterns – Supporting Composition Controllers [article] Web Services Testing and soapUI [article]
Read more
  • 0
  • 0
  • 3339

article-image-coldfusion-9-power-cfcs-and-web-forms
Packt
05 Aug 2010
13 min read
Save for later

ColdFusion 9: Power CFCs and Web Forms

Packt
05 Aug 2010
13 min read
(For more resources on ColdFusion, see here.) There used to be long pages of what we called "spaghetti code" because the page would go on and on. You had to follow the conditional logic by going through the page up and down, and then had to understand how things worked. This made writing, updating, and debugging a diffcult task even for highly-skilled developers CFCs allow you to encapsulate some part of the logic of a page inside an object. Encapsulation simply means packaged for reuse inside something. CFCs are the object-packaging method used in ColdFusion. The practice of protecting access In CFC methods, there is an attribute called "access".Some methods within a CFC are more examples of reuse. The sample code for _product.cfc is shown here. It is an example of a power CFC. There is a method inside the CFC called setDefaults(). The variable variables.field.names comes from another location in our CFC: <cffunction name="setDefaults" access="private" output="false"> <cfset var iAttr = 0> <cfloop list="#listLen(variables.field.names)#" index="iAttr"> <cfscript> variables.attribute[#listGetAt(variables.field.names,iAttr)#] = setDefault(variables.field.names,iAttr); </cfscript> </cfloop></cffunction> The logic for this would actually be used in more than one place inside the object. When the object is created during the first run, it would call the setDefaults() method and set the defaults. When you use the load method to insert another record inside the CFC, it will run this method. This will become simpler as you use CFCs and methods more often. This is a concept called refactoring, where we take common features and wrap them for reuse. This takes place even inside a CFC. Again, the setDefaults() function is just another method inside the same CFC. Now, we look at the access attribute in the code example and note that it is set to private. This means that only this object can call the method. One of the benefits to CFCs is making code simpler. The interface to the outside world of the CFC is its methods. We can hide a method from the outside world, and also protect access to the method by setting the access attribute to private. If you want to make sure that only CFCs in the same directory can access these CFC's methods, then you will have to set the attribute to package. This is a value that is rarely used. The default value for the access attribute is public. This means that any code running on the web server can access the CFC. (Shared hosting companies block one account from being able to see the other accounts on the same server. If you are concerned about your hosting company, then you should either ask them about this issue or move to a dedicated or virtual hosting server.) The last value for the access attribute is remote. This is actually how you create a number of "cool power" uses of the CFC. There is a technology on the Web called web services. Setting the CFC to remote allows access to the CFC as a web service. You can also connect to this CFC through Flash applications, Flex, or AIR, using the remote access value. This method also allows the CFC to respond to AJAX calls. Now, we will learn to use more of the local power features. Web forms introduction Here, we will discuss web forms along with CFCs. Let us view our web form page. Web forms are the same in ColdFusion as they are in any other HTML scenario. You might even note that there is very little use for web forms until you have a server-side technology such as ColdFusion. This is because when the form is posted, you need some sort of program to handle the data posted back to the server. <!--- Example: 3_1.cfm ---><!--- Processing ---><!--- Content ---><form action="3_1.cfm" method="post"> <table> <tr> <td>Name:</td> <td><input type="text" name="name" id="idName" value="" /></td> </tr> <tr> <td>Description:</td> <td><input type="text" name="description" id="idDescription" value="" /></td> </tr> <tr> <td>Price:</td> <td><input type="text" name="price" id="idPrice" value="" /></td> </tr> <tr> <td>&nbsp;</td> <td><input type="submit" name="submit" value="submit" /></td> </tr> </table></form> First, notice that all of the information on the page is in the content section. Anything that goes from the server to the browser is considered as content. You can fll in and submit the form, and you will observe that all of the form fields get cleared out. This is because this form posts back to the same page. Self-posting forms are a valid method of handling page fow on websites. The reason why nothing seems to be happening is because the server is not doing anything with the data being sent back from the browser. Let us now add <cfdump var="#form#"/> to the bottom of the content, below the form tag, and observe what we get when we post the form: Now we see another common structure in ColdFusion. It is known as the form structure. There are two types of common structures that send data to the server. The first one is called get and the second one is called post. If you see the code, you will notice that the method of the form is post. The form post setting is the same as coding with the form variable in ColdFusion. You should also observe that there is one extra field in the form structure that is not shown in the URL structure variable. It is the FIELDNAMES variable. It returns a simple list of the field names that were returned with the form. Let us edit the code and change the form tag attribute to get. Then, refresh the page and click on the submit button: From the previous screenshot, it is evident that the browser looks at the get or post value of the form, and sends a get or post back to the server. Post is a "form method" belonging to the past and this is why ColdFusion translates posted variables to the form structure. Now change the dump tag to "URL" and observe the results. Fill out the form and submit it again with the new change. This displays the values in our structure as we would expect. This means you can either send URL-type data back to the server, or form-type data with forms. The advantage of sending form data is that form data can handle a larger volume of data being sent back to the server as compared to a get or URL request. Also, it is worth noting that this style of return prevents the form field values from being exposed in the URL. They can still be accessed, but are just not visible in the URL any more. So the method of choice for forms is post. Change both the method of the form attribute and the value of the cfdump var to form again. The Description box is not ideal for entering product descriptions. So, we are going to use a text area in its place. Use the following code to accommodate a text area box. You can change the size of form's objects using attributes and styles: <tr> <td>Description:</td> <td> <textArea name="description" id="idDescription"></textArea> </td></tr> Here, we see our form looking different. If you fill up the description with more content than the box can hold, it shows the scroll bars appropriately. Managing our product data Currently, we have a form that can be used for two purposes. It can be used to enter a new product as well as to edit existing ones. We are going to reuse this form. Reuse is the fastest path to make things easier. However, we must not think that it is the only way to do things. What we should think is that not reusing something requires a reason for doing it differently. In order to edit an existing product, we will have to create a page that shows the existing product records. Let us create the page: <!--- Example: product_list.cfm ---><!--- Processing ---><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); rsProducts = objProduct.getRecordset();</cfscript><!--- Content ---><h3>Select a product to edit.</h3><ul> <cfoutput query="rsProducts"> <li> <a href="product_edit.cfm?id=#rsProducts.id#">#rsProducts.name# </li> </cfoutput></ul> There is no new code here. This is the browser view that we get when we run this page. Here, we will post our edit page. Before you run the code, take the code from 3_1.cfm that we wrote at the beginning of the article and save a copy as product_edit.cfm to make the page work correctly when someone clicks on any of the products: Now, we will click on a product. Let us manage the Watermelon Plant for now and observe what happens on the next page: This is our edit page, and we will modify it so that it can get the data when we click through from our list page. Getting data to our edit page The current page looks similar to the page where we put the form. To get the data from our database onto the page, we need to do a few things here. First, let us change the action of the form tag to product_edit.cfm. We can modify the processing section of the page frst, which will make things simpler. Add the following code to your product_edit.cfm page: <!--- Processing ---><cfparam name="url.id" default="0"><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); objProduct.load(url.id);</cfscript> We need the default value set so that we do not receive an error message if the page is called without an id. After we set our default, we will see that we have created an object from our CFC object class. This time, we are passing the Data Source Name dsn into the object through the constructor method. This makes our code more portable, and ready for reuse. Once we have an instance, we set the current record using the load method and passing the id of the data record to the method. Let us look at the minor changes that we will make to the content section. We will add the values of the object's protected attributes. <!--- Content ---><cfoutput> <form action="product_edit.cfm" method="post"> <table> <tr> <td>Name:</td> <td> <input type="text" name="name" id="idName" value="#objProduct.get('name')#" /> </td> </tr> <tr> <td>Description:</td> <td> <textArea name="description" id="idDescription"> #objProduct.get('description')#</textArea> </td> </tr> <tr> <td>Price:</td> <td> <input type="text" name="price" id="idPrice" value="#objProduct.get('price')#" /> </td> </tr> <tr> <td>&nbsp;</td> <td> <input type="submit" name="submit" value="submit" /> </td> </tr> </table> </form></cfoutput> Now, we will refresh the form and see how the results differ: Doesn't this look better? We can go back to the list page and retrieve an existing product from the edit form. If we submit back the same form, browsers tend to empty out the form. It should not do that, but the form is not posting the ID of the record back to the server. This can lead to a problem because, if we do not send the ID of the record back, the database will have no idea as to which record's details should be changed. Let us solve these issues first, and then we will learn to use a new tag called the <cfinclude> tag along the way. The first problem that we are going to solve is where we are calling the page with the ID value in the URL structure; then, if we post the page we will be calling the page with the ID in the form structure. We are going to use a technique that has been widely used for years in the ColdFusion community. We are going to combine the two scopes into a new common structure. We will create a structure called attributes. First we will check if it exists. If it does not, then we will create the structure. After that, we will merge the URL structure, and then the FORM structure into the attributes structure. We will put that code in a common page called request_attributes.cfm, so we can include it on any page we want, reusing the code. Do remember that the form and URL scope always exist. <!--- request_attributes.cfm ---><cfscript> if(NOT isDefined("attributes")) { attributes = structNew(); } structAppend(attributes,url); structAppend(attributes,form);</cfscript> Let us modify our edit page in order to take care of a couple of issues. We need to include the script that we have just created. We will modify the processing section of our edit page as highlighted here: <!--- Processing ---><cfinclude template="request_attributes.cfm"><cfparam name="attributes.id" default="0"><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); objProduct.load(attributes.id);</cfscript> There is only one more thing we need now: We need our form to store the id value of the record that is being managed. We could just put it in a textbox like the other fields, but the user does not need to know that information. Let us use a hidden input field and add it after our form tag: <!--- Content ---><cfoutput> <form action="product_edit.cfm" method="post"> <input type="hidden" name="id" value="#objProduct.get('id')#"> Refresh the screen, and it will work when we use the form, or when we choose an item from the product list page. We have now created our edit/add page.
Read more
  • 0
  • 0
  • 3331

article-image-fixing-bottlenecks-better-database-access-aspnet
Packt
18 Oct 2010
15 min read
Save for later

Fixing Bottlenecks for Better Database Access in ASP.Net

Packt
18 Oct 2010
15 min read
  ASP.NET Site Performance Secrets Simple and proven techniques to quickly speed up your ASP.NET website Speed up your ASP.NET website by identifying performance bottlenecks that hold back your site's performance and fixing them Tips and tricks for writing faster code and pinpointing those areas in the code that matter most, thus saving time and energy Drastically reduce page load times Configure and improve compression – the single most important way to improve your site's performance Written in a simple problem-solving manner – with a practical hands-on approach and just the right amount of theory you need to make sense of it all           Read more about this book       (For more resources on ASP.Net, see here.) The reader can benefit from the previous article on Pinpointing bottlenecks for better Database Access in ASP.Net. Now that you have pinpointed the bottlenecks to prioritize, skip to the appropriate subsection to find out how to fix those bottlenecks. Missing indexes Just as using an index in a book to find a particular bit of information is often much faster than reading all pages, SQL Server indexes can make finding a particular row in a table dramatically faster by cutting down the number of read operations. This section first discusses the two types of indexes supported by SQL Server: clustered and non-clustered. It also goes into included columns, a feature of nonclustered indexes. After that, we'll look at when to use each type of index. Clustered index Take the following table (missingindexes.sql in the downloaded code bundle): CREATE TABLE [dbo].[Book]( [BookId] [int] IDENTITY(1,1) NOT NULL, [Title] [nvarchar](50) NULL, [Author] [nvarchar](50) NULL, [Price] [decimal](4, 2) NULL) Because this table has no clustered index, it is called a heap table. Its records are unordered, and to get all books with a given title, you have to read all the records. It has a very simple structure: Let's see how long it takes to locate a record in this table. That way, we can compare against the performance of a table with an index. To do that in a meaningful way, first insert a million records into the table (code to do this is in missingindexes.sql in the downloaded code bundle). Tell SQL Server to show I/O and timing details of each query we run: SET STATISTICS IO ONSET STATISTICS TIME ON Also, before each query, flush the SQL Server memory cache: CHECKPOINTDBCC DROPCLEANBUFFERS Now, run the query below with a million records in the Book table: SELECT Title, Author, Price FROM dbo.Book WHERE BookId = 5000 The results on my machine are: reads: 9564, CPU time: 109 ms, elapsed time: 808 ms. SQL Server stores all data in 8-KB pages. This shows that it read 9564 pages, that is, the entire table. Now, add a clustered index: ALTER TABLE BookADD CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED ([BookId] ASC) This puts the index on column BookId, making WHERE and JOIN statements on BookId faster. It sorts the table by BookId and adds a structure called a B-tree to speed up access: BookId is now used the same way as a page number in a book. Because the pages in a book are sorted by page number, finding a page by page number is very fast. Now, run the same query again to see the difference: SELECT Title, Author, Price FROM dbo.Book WHERE BookId = 5000 The results are: reads: 2, CPU time: 0 ms, elapsed time: 32 ms. The number of reads of 8-KB pages has gone from 9564 to 2, CPU time from 109ms to less than 1 ms, and elapsed time from 808 ms to 32 ms. That's a dramatic improvement. Non-clustered index Now let's select by Title instead of BookId: SELECT Title, Author FROM dbo.Book WHERE Title = 'Don Quixote' These results are pretty similar to what we got with the heap table, which is no wonder, seeing that there is no index on Title. The solution obviously is to put an index on Title. However, because a clustered index involves sorting the table records on the index field, there can be only one clustered index. We've already sorted on BookId, and the table can't be sorted on Title at the same time. The solution is to create a non-clustered index. This is essentially a duplicate of the table records, this time sorted by Title. To save space, SQL Server leaves out the other columns, such as Author and Price. You can have up to 249 non-clustered indexes on a table. Because we still want to access those other columns in queries though, we need a way to get from the non-clustered index records to the actual table records. The solution is to add the BookId to the non-clustered records. Because BookId has the clustered index, once we have found a BookId via the non-clustered index, we can use the clustered index to get to the actual table record. This second step is called a key lookup. Why go through the clustered index? Why not put the physical address of the table record in the non-clustered index record? The answer is that when you update a table record, it may get bigger, causing SQL Server to move subsequent records to make space. If non-clustered indexes contained physical addresses, they would all have to be updated when this happens. It's a tradeoff between slightly slower reads and much slower updates. If there is no clustered index or if it is not unique, then non-clustered index records do have the physical address. To see what a non-clustered index will do for us, first create it as follows: CREATE NONCLUSTERED INDEX [IX_Title] ON [dbo].[Book]([Title] ASC) Now, run the same query again: SELECT Title, Author FROM dbo.Book WHERE Title = 'Don Quixote' The results are: reads: 4, CPU time: 0 ms, elapsed time: 46 ms. The number of reads has gone from 9146 to 4, CPU time from 156 ms to less than 1 ms, and elapsed time from 1653 ms to 46 ms. This means that having a non-clustered index is not quite as good as having a clustered index, but still dramatically better than having no index at all. Included columns You can squeeze a bit more performance out of a non-clustered index by cutting out the key lookup—the second step where SQL Server uses the clustered index to find the actual record. Have another look at the test query—it simply returns Title and Author. Title is already present in the non-clustered index record. If you were to add Author to the non-clustered index record as well, there would be no longer any need for SQL Server to access the table record, enabling it to skip the key lookup. It would look similar to the following: This can be done by including Author in the non-clustered index: CREATE NONCLUSTERED INDEX [IX_Title] ON [dbo].[Book]([Title] ASC)INCLUDE(Author)WITH drop_existing Now, run the query again: SELECT Title, Author FROM dbo.Book WHERE Title = 'Don Quixote' The results are: reads: 2, CPU time: 0 ms, elapsed time: 26 ms. The number of reads has gone from 4 to 2, and elapsed time from 46 ms to 26 ms; that's almost 50 percent improvement. In absolute terms, the gain isn't all that great, but for a query that is executed very frequently, this may be worthwhile. Don't overdo this—the bigger you make the non-clustered index records, the fewer fit on an 8KB page, forcing SQL Server to read more pages. Selecting columns to give an index Because indexes do create overhead, you want to carefully select the columns to give indexes. Before starting the selection process, keep the following in mind: Putting a Primary Key on a column by default gives it a clustered index (unless you override the default). So, you may already have many columns in your database with an index. As you'll see later in the When to use a clustered index section, putting the clustered index on the ID column of a record is almost always a good idea. Putting an index on a table column affects all queries that use that table. Don't focus on just one query. Before introducing an index on your live database, test the index in development to make sure it really does improve performance. Let's look at when and when not to use an index, and when to use a clustered index. When to use an index You can follow this decision process when selecting columns to give an index: Start by looking at the most expensive queries. Look at putting an index on at least one column involved in every JOIN. Consider columns used in ORDER BY and GROUP BY clauses. If there is an index on such a column, than SQL Server doesn't have to sort the column again because the index already keeps the column values in sorted order. Consider columns used in WHERE clauses, especially if the WHERE will select a small number of records. However, keep in mind the following: A WHERE clause that applies a function to the column value can't use an index on that column, because the output of the function is not in the index. Take for example the following: SELECT Title, Author FROM dbo.Book WHERE LEFT(Title, 3) = 'Don' Putting an index on the Title column won't make this query any faster. Likewise, SQL Server can't use an index if you use LIKE in a WHERE clause with a wild card at the start of the search string, as in the following: SELECT Title, Author FROM dbo.Book WHERE Title LIKE '%Quixote' However, if the search string starts with constant text instead of a wild card, an index can be used: SELECT Title, Author FROM dbo.Book WHERE Title LIKE 'Don%' Consider columns that have a UNIQUE constraint. Having an index on the column makes it easier for SQL Server to check whether a new value would not be unique. The MIN and MAX functions benefit from working on a column with an index. Because the values are sorted, there is no need to go through the entire table to find the minimum or maximum. Think twice before putting an index on a column that takes a lot of space. If you use a non-clustered index, the column values will be duplicated in the index. If you use a clustered index, the column values will be used in all nonclustered indexes. The increased sizes of the index records means fewer fit in each 8-KB page, forcing SQL Server to read more pages. The same applies to including columns in non-clustered indexes. When not to use an index Having too many indexes can actually hurt performance. Here are the main reasons not to use an index on a column: The column gets updated often The column has low specificity, meaning it has lots of duplicate values Let's look at each reason in turn. Column updated often When you update a column without an index, SQL Server needs to write one 8KB page to disk, provided there are no page splits. However, if the column has a non-clustered index, or if it is included in a nonclustered index, SQL Server needs to update the index as well, so it has to write at least one additional page to disk. It also has to update the B-tree structure used in the index, potentially leading to more page writes. If you update a column with a clustered index, the non-clustered index records that use the old value need to be updated too, because the clustered index key is used in the non-clustered indexes to navigate to the actual table records. Secondly, remember that the table records themselves are sorted based on the clustered index. If the update causes the sort order of a record to change, that may mean more writes. Finally, the clustered index needs to keep its B-tree up-to-date. This doesn't mean you cannot have indexes on columns that get updated; just be aware that indexes slow down updates. Test the effect of any indexes you add. If an index is critical but rarely used, for example only for overnight report generation, consider dropping the index and recreating it when it is needed. Low specificity Even if there is an index on a column, the query optimizer won't always use it. Remember, each time SQL Server accesses a record via an index, it has to go through the index structure. In the case of a non-clustered index, it may have to do a key lookup as well. If you're selecting all books with price $20, and lots of books happen to have that price, than it might be quicker to simply read all book records rather than going through an index over and over again. In that case, it is said that the $20 price has low specificity. You can use a simple query to determine the average selectivity of the values in a column. For example, to find the average selectivity of the Price column in the Book table, use (missingindexes.sql in downloaded code bundle): SELECT COUNT(DISTINCT Price) AS 'Unique prices', COUNT(*) AS 'Number of rows', CAST((100 * COUNT(DISTINCT Price) / CAST(COUNT(*) AS REAL)) AS nvarchar(10)) + '%' AS 'Selectivity'FROM Book If every book has a unique price, selectivity will be 100 percent. However, if half the books cost $20 and the other half $30, then average selectivity will be only 50 percent. If the selectivity is 85 percent or less, an index is likely to incur more overhead than it would save. Some prices may occur a lot more often than other prices. To see the specificity of each individual price, you would run (missingindexes.sql in downloaded code bundle): DECLARE @c realSELECT @c = CAST(COUNT(*) AS real) FROM BookSELECT Price, COUNT(BookId) AS 'Number of rows', CAST((1 - (100 * COUNT(BookId) / @c)) AS nvarchar(20)) + '%' AS 'Selectivity'FROM BookGROUP BY PriceORDER BY COUNT(BookId) The query optimizer is unlikely to use a non-clustered index for a price whose specificity is below 85 percent. It figures out the specificity of each price by keeping statistics on the values in the table. When to use a clustered index You saw that there are two types of indexes, clustered and non-clustered, and that you can have only one clustered index. How do you determine the lucky column that will have the clustered index? To work this out, let's first look at the characteristics of a clustered index against a non-clustered index: Characteristic Clustered index compared to a non-clustered index Reading Faster: Because there is no need for key lookups. No difference if all the required columns are included in the non-clustered index. Updating Slower: Not only the table record, but also all non-clustered index records potentially need to be updated. Inserting/Deleting Faster: With a non-clustered index, inserting a new record in the table means inserting a new record in the non-clustered index as well. With a clustered index, the table is effectively part of the index, so there is no need for the second insert. The same goes for deleting a record. On the other hand, when the record is inserted at any place in the table but the very end, the insert may cause a page split where half the content of the 8-KB page is moved to another page. Having a page split in a non-clustered index is less likely, because its records are smaller (they normally don't have all columns that a table record has), so more records fit on a page. When the record is inserted at the end of the table, there won't be a page split. Column Size Needs to be kept short and fast - Every non-clustered index contains a clustered index value, to do the key lookup. Every access via a non-clustered index has to use that value, so you want it to be fast for the server to process. That makes a column of type int a lot better to put a clustered index on than a column of type nvarchar(50).   If only one column requires an index, this comparison shows that you'll probably want to give it the clustered index rather than a non-clustered index. If multiple columns need indexes, you'll probably want to put the clustered index on the primary key column: Reading: The primary key tends to be involved in a lot of JOIN clauses, making read performance important. Updating: The primary key should never or rarely get updated, because that would mean changing referring foreign keys as well. Inserting/Deleting: Most often you'll make the primary key an IDENTITY column, so each new record is assigned a unique, ever increasing number. This means that if you put the clustered index on the primary key, new records are always added at the end of the table. When a record is added at the end of a table with a clustered index and there is no space in the current page, the new record goes into a new page but the rest of the data in the current page stays in the page. In other words, there is no expensive page split. Size: Most often, the primary key is of type int, which is short and fast. Indeed, when you set the primary key on a column in the SSMS table designer, SSMS gives that column the clustered index by default, unless another column already has the clustered index.
Read more
  • 0
  • 0
  • 3328

article-image-jboss-jbpm-concepts-and-jbpm-process-definition-language-jpdl
Packt
22 Oct 2009
6 min read
Save for later

JBoss jBPM Concepts and jBPM Process Definition Language (jPDL)

Packt
22 Oct 2009
6 min read
JBoss jBPM Concepts JBoss jBPM is built around the concept of waiting. That may sound strange given that software is usually about getting things done, but in this case there is a very good reason for waiting. Real-life business processes cut across an organization, involve numerous humans and multiple systems, and happen over a period of time. In regular software, the code that makes up the system is normally built to "do all these tasks as soon as possible". This wouldn't work for a business process, as the people who need to take part in the process won't always want or be able to "do their task now". The software needs some way of waiting, until the process actor is ready to do their activity. Then once they have done their activity, the software needs to know what is the next activity in the chain and then wait for the next process actor to get round to doing their bit. The orchestration of this sequence of "wait, work, wait, work" is handled by the JBoss jBPM engine. The jBPM engine looks up our process definition and works out which way it should direct us through the process. We know the "process definition" better as our graphical process map. jBPM Process Definition Language—jPDL We will introduce the key terms and concepts here to get the ball rolling. We won't linger too long over the definitions, as the best way to fix the terminology in the brain is to see it used in context. At this point, we will introduce some core terminologies for a better understanding. The visual process map in the Designer is an example of what the JBoss jBPM project calls "Graph Oriented Programming". Instead of programming our software in code, we are programming our software using a visual process map: referred to as a "directed graph". This directed graph is also defined in the XML representation of the process we saw in the Source view. The graph plus the XML is a notation set, which is properly called jPDL, the "jBPM Process Definition Language". A process definition specified in jPDL is composed of "nodes", "transitions", and "actions", which together describe how an "instance" of the process should traverse the directed graph. During execution of the process, as the instance moves through the directed graph, it carries through a "token", which is a pointer to the node of the graph at which the instance is currently waiting. A "signal" tells the token which "transition" it should take from the node: signals specify which path to take through the process. Let's break this down a little bit with some more detail. Nodes A node in jPDL is modeled visually as a box, and hence looks very similar to the activity box we are used to from our workflow and activity flow diagrams. The concept of "nodes" does subtly differ from that of activities, however. In designing jPDL, the jBPM team have logically separated the idea of waiting for the result of an action from that of doing an action. They believe that the term "activity" blurs the line between these two ideas, which causes problems when trying to implement the logic behind a business process management system. For example, both "Seek approval" and "Record approval" would be modeled as activities on an activity flow diagram, but the former would be described as a "state" and the latter as an "action" in jPDL: the state element represents the concept of waiting for the action to happen, moving the graph to the next state. "Node" is therefore synonymous with "state" in jPDL. "Actions" are bits of code that can be added by a developer to tell the business process management system to perform an action that needs to be done by the system: for example, recording the approval of a holiday request in a database. Actions aren't mapped visually, but are recorded in the XML view of the process definition. We'll cover actions a bit later. There are different types of node, and they are used to accomplish different things. Let's quickly go through them so we know how they are used. Tasks A task node represents a task that is to be performed by humans. If we model a task node on our graph, it will result in a task being added to the task list of the person assigned to that task, when the process is executed. The process instance will wait for the person to complete that task and hand back the outcome of the task to the node. State A state node simply tells the process instance to wait, and in contrast to a task node, it doesn't create a task in anybody's task list. A state node would normally be used to model the behavior of waiting for an external system to provide a response. This would typically be done in combination with an Action, which we'll talk about soon. The process instance will resume execution when a signal comes back from the external system. Forks and Joins We can model concurrent paths of execution in jPDL using forks and joins. For example, the changes we made to our model to design our To Be process can be modeled using forks and joins to represent the parallel running of activities. We use a Fork to split the path of execution up, and then join it back together using a Join: the process instance will wait at the Join until the parallel tasks on both sides are completed. The instance can't move on until both chains of activities are finished. jBPM creates multiple child tokens related to the parent token for each path of execution. Decision In modeling our process in jBPM, there are two distinct types of decision with which we need to concern ourselves. Firstly, there is the case where the process definition itself needs to make a decision, based on data at its disposal, and secondly, where a decision made by a human or an external system is an input to the process definition. Where the process definition itself will make the decision, we can use a decision node in the model. Where the outcome of the decision is simply input into the process definition at run time, we should use a state node with multiple exiting transitions representing the possible outcomes of the decision.
Read more
  • 0
  • 1
  • 3308

article-image-python-unit-testing-doctest
Packt
15 Sep 2010
12 min read
Save for later

Python: Unit Testing with Doctest

Packt
15 Sep 2010
12 min read
What is Unit testing and what it is not? The title of this section, begs another question: "Why do I care?" One answer is that Unit testing is a best practice that has been evolving toward its current form over most of the time that programming has existed. Another answer is that the core principles of Unit testing are just good sense; it might actually be a little embarrassing to our community as a whole that it took us so long to recognize them. Alright, so what is Unit testing? In its most fundamental form, Unit testing can be defined as testing the smallest meaningful pieces of code (such pieces are called units), in such a way that each piece's success or failure depends only on itself. For the most part, we've been following this principle already. There's a reason for each part of this definition: we test the smallest meaningful pieces of code because, when a test fails, we want that failure to tell where the problem is us as specifically as possible. We make each test independent because we don't want a test to make any other test succeed, when it should have failed; or fail when it should have succeeded. When tests aren't independent, you can't trust them to tell you what you need to know. Traditionally, automated testing is associated with Unit testing. Automated testing makes it fast and easy to run unit tests, which tend to be amenable to automation. We'll certainly make heavy use of automated testing with doctest and later with tools such as unittest and Nose as well. Any test that involves more than one unit is automatically not a unit test. That matters because the results of such tests tend to be confusing. The effects of the different units get tangled together, with the end result that not only do you not know where the problem is (is the mistake in this piece of code, or is it just responding correctly to bad input from some other piece of code?), you're also often unsure exactly what the problem is this output is wrong, but how does each unit contribute to the error? Empirical scientists must perform experiments that check only one hypothesis at a time, whether the subject at hand is chemistry, physics, or the behavior of a body of program code. Time for action – identifying units Imagine that you're responsible for testing the following code: class testable: def method1(self, number): number += 4 number **= 0.5 number *= 7 return number def method2(self, number): return ((number * 2) ** 1.27) * 0.3 def method3(self, number): return self.method1(number) + self.method2(number) def method4(self): return 1.713 * self.method3(id(self)) In this example, what are the units? Is the whole class a single unit, or is each method a separate unit. How about each statement, or each expression? Keep in mind that the definition of a unit is somewhat subjective (although never bigger than a single class), and make your own decision. Think about what you chose. What would the consequences have been if you chose otherwise? For example, if you chose to think of each method as a unit, what would be different if you chose to treat the whole class as a unit? Consider method4. Its result depends on all of the other methods working correctly. On top of that, it depends on something that changes from one test run to another, the unique ID of the self object. Is it even possible to treat method4 as a unit in a self-contained test? If we could change anything except method4, what would we have to change to enable method4 to run in a self-contained test and produce a predictable result? What just happened? By answering those three questions, you thought about some of the deeper aspects of unit testing. The question of what constitutes a unit, is fundamental to how you organize your tests. The capabilities of the language affects this choice. C++ and Java make it difficult or impossible to treat methods as units, for example, so in those languages each class is usually treated as a single unit. C, on the other hand, doesn't support classes as language features at all, so the obvious choice of unit is the function. Python is flexible enough that either classes or methods could be considered units, and of course it has stand-alone functions as well, which are also natural to think of as units. Python can't easily handle individual statements within a function or method as units, because they don't exist as separate objects when the test runs. They're all lumped together into a single code object that's part of the function. The consequences of your choice of unit are far-reaching. The smaller the units are, the more useful the tests tend to be, because they narrow down the location and nature of bugs more quickly. For example, one of the consequences of choosing to treat the testable class as a single unit is that tests of the class will fail if there is a mistake in any of the methods. That tells you that there's a mistake in testable, but not (for example) that it's in method2. On the other hand, there is a certain amount of rigmarole involved in treating method4 and its like as units. Even so, I recommend using methods and functions as units most of the time, because it pays off in the long run. In answering the third question, you probably discovered that the functions id and self.method3 would need to have different definitions, definitions that produced a predictable result, and did so without invoking code in any of the other units. In Python, replacing the real function with such stand-ins is fairly easy to do in an ad hoc manner. Unit testing throughout the development process We'll walk through the development of a single class, treating it with all the dignity of a real project. We'll be strictly careful to integrate unit testing into every phase of the project. This may seem silly at times, but just play along. There's a lot to learn from the experience. The example we'll be working with is a PID controller. The basic idea is that a PID controller is a feedback loop for controlling some piece of real-world hardware. It takes input from a sensor that can measure some property of the hardware, and generates a control signal that adjusts that property toward some desired state. The position of a robot arm in a factory might be controlled by a PID controller. If you want to know more about PID controllers, the Internet is rife with information. The Wikipedia entry is a good place to start: http://en.wikipedia.org/wiki/PID_controller. Design phase Our notional client comes to us with the following (rather sparse) specification: We want a class that implements a PID controller for a single variable. The measurement, setpoint, and output should all be real numbers. We need to be able to adjust the setpoint at runtime, but we want it to have a memory, so that we can easily return to the previous setpoint. Time for action - unit testing during design Time to make that specification a bit more formal—and complete—by writing unit tests that describe the desired behavior. We need to write a test that describes the PID constructor. After checking our references, we determine that a PID controller is defined by three gains, and a setpoint. The controller has three components: proportional, integral and derivative (hence the name PID). Each gain is a number that determines how much one of the three parts of the controller has on the final result. The setpoint determines what the goal of the controller is; in other words, to where it's trying to move the controlled variable. Looking at all that, we decide that the constructor should just store the gains and the setpoint, along with initializing some internal state that we know we'll need due to reading up on the workings of a PID controller: >>> import pid>>> controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0)>>> controller.gains(0.5, 0.5, 0.5)>>> controller.setpoint[0.0]>>> controller.previous_time is NoneTrue>>> controller.previous_error0.0>>> controller.integrated_error0.0 We need to write tests that describe measurement processing. This is the controller in action, taking a measured value as its input and producing a control signal that should smoothly move the measured variable to the setpoint. For this to work correctly, we need to be able to control what the controller sees as the current time. After that, we plug our test input values into the math that defines a PID controller, along with the gains, to figure out what the correct outputs would be: >>> import time>>> real_time = time.time>>> time.time = (float(x) for x in xrange(1, 1000)).next>>> pid = reload(pid)>>> controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0)>>> controller.measure(12)-6.0>>> controller.measure(6)-3.0>>> controller.measure(3)-4.5>>> controller.measure(-1.5)-0.75>>> controller.measure(-2.25)-1.125>>> time.time = real_time We need to write tests that describe setpoint handling. Our client asked for a setpoint stack, so we write tests that check such stack behavior. Writing code that uses this stack behavior brings to our attention that fact that a PID controller with no setpoint is not a meaningful entity, so we add a test that checks that the PID class rejects that situation by raising an exception. >>> pid = reload(pid)>>> controller = pid.PID(P = 0.5, I = 0.5, D = 0.5, setpoint = 0)>>> controller.push_setpoint(7)>>> controller.setpoint[0.0, 7.0]>>> controller.push_setpoint(8.5)>>> controller.setpoint[0.0, 7.0, 8.5]>>> controller.pop_setpoint()8.5>>> controller.setpoint[0.0, 7.0]>>> controller.pop_setpoint()7.0>>> controller.setpoint[0.0]>>> controller.pop_setpoint()Traceback (most recent call last):ValueError: PID controller must have a setpoint What just happened? Our clients gave us a pretty good initial specification, but it left a lot of details to assumption. By writing these tests, we've codified exactly what our goal is. Writing the tests forced us to make our assumptions explicit. Additionally, we've gotten a chance to use the object, which gives us an understanding of it that would otherwise be hard to get at this stage. Normally we'd place the doctests in the same file as the specification, and in fact that's what you'll find in the book's code archive. In the book format, we used the specification text as the description for each step of the example. You could ask how many tests we should write for each piece of the specification. After all, each test is for certain specific input values, so when code passes it, all it proves is that the code produces the right results for that specific input. The code could conceivably do something entirely wrong, and still pass the test. The fact is that it's usually a safe assumption that the code you'll be testing was supposed to do the right thing, and so a single test for each specified property fairly well distinguishes between working and non-working code. Add to that tests for any boundaries specified—for "The X input may be between the values 1 and 7, inclusive" you might add tests for X values of 0.9 and 7.1 to make sure they weren't accepted—and you're doing fine. There were a couple of tricks we pulled to make the tests repeatable and independent. In every test after the first, we called the reload function on the pid module, to reload it from the disk. That has the effect of resetting anything that might have changed in the module, and causes it to re-import any modules that it depends on. That latter effect is particularly important, since in the tests of measure, we replaced time.time with a dummy function. We want to be sure that the pid module uses the dummy time function, so we reload the pid module. If the real time function is used instead of the dummy, the test won't be useful, because there will be only one time in all of history at which it would succeed. Tests need to be repeatable. The dummy time function is created by making an iterator that counts through the integers from 1 to 999 (as floating point values), and binding time.time to that iterator's next method. Once we were done with the time-dependent tests, we replaced the original time.time. Right now, we have tests for a module that doesn't exist. That's good! Writing the tests was easier than writing the module will be, and it gives us a stepping stone toward getting the module right, quickly and easily. As a general rule, you always want to have tests ready before the code that they test is written. Have a go hero Try this a few times on your own: Describe some program or module that you'd enjoy having access to in real life, using normal language. Then go back through it and try writing tests, describing the program or module. Keep an eye out for places where writing the test makes you aware of ambiguities in your prior description, or makes you realize that there's a better way to do something.
Read more
  • 0
  • 0
  • 3305
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-games-fortune-scratch-14
Packt
15 Oct 2009
4 min read
Save for later

Games of Fortune with Scratch 1.4

Packt
15 Oct 2009
4 min read
Fortune-teller Most of us enjoy a good circus, carnival, or county fair. There's fun, food, and fortunes. Aah, yes, what would a fair be without the fortune-teller's tent? By the end of this article, you'll know everything you need to spin your fortunes and amaze your friends with your wisdom. Before we start the first exercise, create a new project and add two sprites. The first sprite will be the seeker. The second sprite will be the teller. Choose any sprites you want. My seeker will be a clam and my teller will be a snowman. If you want to add a background, go ahead. Time for action – create a list of questions In order to have a successful fortune-telling, we need two things: a question and an answer. Let's start by defining some questions and answers: Select the seeker from the list of sprites. From the Variables palette, click the Make a list button. In the list name dialog box, type questions and select For this sprite only. Click OK to create the list. Several new blocks display in the Variables palette, and an empty block titled seeker questions displays on the stage. Let's think about a couple of questions we may be tempted to ask, such as the following: Will my hair fall out? How many children will I have? Let's add our proposed questions to the questions list. Click the plus sign located in the bottom-left corner of the seeker questions box (on the stage) to display a text input field. Type Will my hair fall out? Press the plus sign again and enter the second question: How many children will I have? We now have two questions in our list. To automatically add the next item in the list, press enter. Let's add a say for 2 secs block to the scripts area of the seeker sprite so that we can start the dialog. From the Variables palette, drag the item of questions block to the input value of the say for 2 secs block. Double-click on the block and the seeker asks, "Will my hair fall out?" Change the value on the item block to last and double-click the block again. This time the seeker asks, "How many children will I have?" What just happened? I'm certain you could come up with a hundred different questions to ask a fortune-teller. Don't worry, you'll get your chance to ask more questions later. Did you notice that the new list we created behaved a lot like a variable? We were able to make the questions list private; we don't want our teller to peek at our questions, after all. Also, the list became visible on the screen allowing us to edit the contents. The most notable difference is that we added more than one item, and each item corresponds to a number. We essentially created a numbered list. If you work with other programming languages, then you might refer to lists as arrays. Because the seeker's questions were contained in a list, we used the item block to provide special instructions to the     say block in order to ask the question. The first value of the item block was position, which defaulted to one. The second value was the name of the list, which defaulted to questions. In contrast, if we used a variable to store a question, we would only need to supply the name of the variable to the say block. Have a go hero Create an answers list for the teller sprite, and add several items to the list. Remember, there are no wrong answers in this exercise. Work with an item in a list We can use lists to group related items, but accessing the items in the list requires an extra level of specificity. We need to know the name of the list and the position of the item within the list before we can do anything with the values. The following table shows the available ways to access a specific item in a list.
Read more
  • 0
  • 0
  • 3302

article-image-introducing-coldfusion-components
Packt
12 Oct 2010
15 min read
Save for later

Introducing ColdFusion Components

Packt
12 Oct 2010
15 min read
Object-Oriented Programming in ColdFusion Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns Fast-paced easy-to-follow guide introducing object-oriented programming for ColdFusion developers Enhance your applications by building structured applications utilizing basic design patterns and object-oriented principles Streamline your code base with reusable, modular objects Packed with example code and useful snippets        For those with any experience with ColdFusion, components should be relatively commonplace. Object-Oriented Programming (OOP) relies heavily on the use of ColdFusion components, so before proceeding onto the ins and outs of OOP, let's re-familiarize ourselves with components within ColdFusion. ColdFusion Components use the same ColdFusion Markup Language (CFML) as 'standard' ColdFusion pages. The core difference is the file extension—components must be saved with a .cfc file extension as opposed to the .cfm file extensions for template pages. The basic structure of a ColdFusion Component is: The component (the page within which you create the code to hold data or perform functions) The methods available to run within the CFC, also known as functions In simple terms, CFCs themselves form a framework within ColdFusion, allowing you to write structured, clear, and organized code. They make application development easier to manage, control, and maintain. ColdFusion Components use the same CFML as 'standard' ColdFusion pages. The core difference is the file extension. Why use CFCs? It is not unusual for applications to grow and seem overly complex. Pages containing detailed information, such as business logic, data access and manipulation, data validation, and layout/presentation logic, can become untidy and hard to manage. Creating and developing applications using CFCs enables you to separate the code logic from the design and presentation, and build an application based around, if not using, traditional Model View Controller (MVC) framework methodologies. Utilizing CFCs and creating a clear structured format for your code will help reduce the complexity of logic within your pages and improve the application speed. Having a clearly structured, well organized code base will make it easier to develop as an individual and share resources within a team. This is the instant benefit of CFC development. A well-written CFC will allow you to reuse your functions, or methods, across your entire application, helping to reduce the risk of code duplication. It will keep your component libraries and code base to a more easily manageable size, preventing it from becoming convoluted and difficult to follow. ColdFusion components are an incredibly powerful and valuable means of creating efficient code. They allow you to: Share properties and variables between other methods and functions Share and interact with functions contained within other CFCs Inherit the properties and methods of a base component Overwrite methods and functions within other components CFCs also give you the ability to clearly document and comment your code, letting you and other developers know what each function and property should do, what it should be expecting to receive to do the job and what output it will give you. ColdFusion components are able to read themselves and display this data to you, using a form of introspection. Although CFCs are an effective tool for code reuse, this is not to say they should be used for every reusable function within your application. They are not a complete replacement for custom tags and user-defined functions. When you load a CFC (instantiate the component), this uses up more processing time than it would to call a custom tag or a User-Defined Function (UDF) into use. Once a CFC has been instantiated, however, calling a method or function within the component will take approximately the same time as it would to call a UDF. It is important, therefore, that CFCs should not necessarily be used as a complete replacement for any UDFs or custom tags that you have in your application. Any code you write can, of course, be optimized, and changes can be made as you learn new things, but UDFs and custom tags perform perfectly well. Using them as they are will help to keep any processing overheads on your application to a minimum. Grouping your functions You may have already written custom tags and user-defined functions that allow similar functionality and reusability, for example, a series of UDFs that interact with a shopping cart. By grouping your functions within specific components according to their use and purpose, you can successfully keep your code library organized and more efficient. You can also further clean your code library by compiling or grouping multiple related components into a package, clearly named and stored in a directory within your application. Organizing your components A typical method for organizing your CFC library is to create a directory structure based on your company or domain name, followed by a directory whose name references the purpose of the included components, for example, 'com.coldfumonkeh.projecttracker' in the webroot of your application. Within this directory, you would then create a directory for each group (or package), of components, with a name reflecting or matching the component name and purpose. Use your ColdFusion Components to create a component structure, or a library, that contains grouped methods and functions, particularly if the methods share properties or data. The ColdFusion component tags You can use these following tags to create a ColdFusion Component. TagPurposecfcomponentThe core CFC tag that defines the component structure. All other content in the component is wrapped within this tag.cffunctionCreates a method (function) within the component.cfargumentCreates a parameter, otherwise known as an argument, to be sent to the function.cfpropertyCan be used to define and document the properties within your component. Can also be used to define variables within a CFC that is used as a web service. These previously mentioned tags are written within the .cfc file that defines the ColdFusion component. In the world of object-oriented programming, you will commonly hear or see reference to the word 'Class'. A class is essentially a blueprint that is used to instantiate an object, and typically contains methods and instance variables. When discussing a Class in the context of ColdFusion development, we are basically referencing a ColdFusion component, so when you see or read about classes, remember it is essentially an alias for a CFC. Our first component To get started, in this example, we will create a component and functions to output the message "Hello world". Create a new file called greetings.cfc and save it within your ColdFusion webroot. The following is a component base tag; add this code into the new CFC to define the component: <cfcomponent displayName="greetings"> </cfcomponent> Listing 1.1 – component base tags As you can see, the name attribute within the CFC matches the name of the file. The cfcomponent tags form the base structure of our ColdFusion Component. No other code can be placed outside of these tags, as it will simply display an error. It may be helpful to think of the cfcomponent tag as the wrapping paper on a parcel. It forms the outer shell of the package, holding everything else nicely in place. Defining a method We have now created the component, but at the moment it does not actually do anything. It has no function to run. We need to add a method into the CFC to create a function to call and use within our application. The following code is a basic function definition; place it between the opening and closing cfcomponent tags: <cffunction name="sayHello"> <!--- the CFML code for the method will go here ---> </cffunction> Listing 1.2 – basic function definition You have now added a method to the CFC. The cffunction tags are nested within the cfcomponent tags. We now need to add some CFML code within the cffunction tags to create our method and perform the operation. Let's create a variable within the function that will be our display message. The following code is for declaring a string variable; place it inside the cffunction tags: <cffunction name="sayHello"> <cfset var strHelloMessage = 'Hello World!' /> </cffunction> Listing 1.3 – declaring a string variable We have created a string variable containing the text to display to the browser. Returning the data To return the data we need to add an extra tag into the method. This is possible by using the cfreturn tag, which returns results from a component method. The cfreturn tag has one required attribute that is the expression or value you wish to return. Add the following code to your CFC so our method will return the welcome message and the completed component will look like this: <cfcomponent displayName="greetings"> <cffunction name="sayHello"> <cfset var strHelloMessage = 'Hello World!' /> <cfreturn strHelloMessage /> </cffunction> </cfcomponent> Listing 1.4 – returning data from the function ColdFusion 9 scripted components Since the release of ColdFusion 9, developers now have the ability to also write ColdFusion components in complete script syntax instead of pure tag form. To write the previous component in this format, the code would look as follows: component displayname="greetings" { function sayHello(){ // the CFML code for the method will go here var strHelloMessage='Hello World'; return strHelloMessage; } } Listing 1.5 – component declaration in the script syntax Although written using cfscript syntax, there is no requirement to wrap the code within <cfscript> tags, instead we can write it directly within the .cfc page. We do not even need to contain the code within cfcomponent tags, as the entire content of the component will be compiled as cfscript if left as plain text without tags. Creating your object There it is, a simple ColdFusion Component. The method is created using the cffunction tags, wrapped up nicely within the cfcomponent tags, and the value returned using the cfreturn tag. Now that we have written the function, how do we call it? In this example, we will call the component and run the method by using the createObject() function. Create a new file called hello.cfm and add the following code to the template: <cfset objGreeting = createObject('component', 'greetings') /> <cfoutput>#objGreeting.sayHello()#</cfoutput> Listing 1.6 – creating the component object In the previous code, we have created an instance of the greetings CFC, which we can reference by using the objGreeting variable. We have then accessed the sayHello() method within the component, surrounded by cfoutput tags, to display the returned data. Save the file and view it within your browser. You should now see the welcome message that we created within the method. Restricting your functions to scopes Imagine we are sending some data through to a login page in our application within the URL scope; the first and last name of a particular person. On the page, we want to join the two values and combine them into one string to form the individual's full name. We could write the code directly on the page, as follows: <cfoutput> Hello, #URL.firstName# #URL.lastName# </cfoutput> Listing 1.7 – displaying URL variables as a string Although this works, you can revise the code and transform it into a ColdFusion function to concatenate the two values into the required single string and return that value: <cffunction name="getName"> <cfset var strFullName = URL.firstName & ' ' & URL.lastName /> <cfreturn strFullName /> </cffunction> Listing 1.8 – concatenate variables into string You can then call this function within your .cfm page to output the resulting string from the function: <cfoutput> #getName()# </cfoutput> However, within this code you have restricted yourself to using only the specific URL scope. What if the first name and last name values were in the FORM scope, or pulled from a query? This block of code is useful only for values within the form scope. Using arguments within your methods To allow us to be able to pass in any parameters into the getName() function, we need to use the cfargument tag to send data into the method. By changing the function in the following code example, the method will create the concatenated string and produce the same results from two parameters or arguments that you choose to pass in. <cffunction name="getName"> <cfargument name="firstName" type="string" /> <cfargument name="lastName" type="string" /> <cfset var strFullName = arguments.firstName & ' ' & arguments.lastName /> <cfreturn strFullName /> </cffunction> Listing 1.10 – using arguments within your function The cfargument tag creates a parameter definition within the component method, and allows you to send in arguments for inclusion into the functions. The Arguments scope The Arguments scope only exists in a method. The scope contains any variables that you have passed into that method, and you can access the variables within the Arguments scope in the following ways: using structure notation - Arguments.variablename or Arguments["variablename"] using array notation - Arguments[1] The Arguments scope does not persist between calls to available CFC methods, meaning that you cannot access a value within the Arguments scope in one function from inside a different function. Redefine the function parameters By defining two arguments and sending in the values for the first and last names, you have created an unrestricted function that is not tied to a specific scope or set of hardcoded values. You can instead choose what values to pass into it on your calling page: <cfoutput> #getName('Gary', 'Brown')# </cfoutput> Listing 1.11a – sending parameters into our function Now that we have removed any restrictions to the values we pass in, and taken away any references to hardcoded variables, we can reuse this function, sending in whichever values or variables we choose to. For example, we could use variables from the FORM scope, URL scope, or query items to concatenate the string: <cfoutput> #getName(form.firstName, form.lastName)# </cfoutput> Listing 1.11b – sending parameters into our function Let's take our getName() method and add it into the greeting.cfc file. By doing so, we are grouping two methods that have a similarity in purpose into one component. This is good programming practice and will aid in creating manageable and clearly organized code. Our greeting.cfc should now look like this: <cfcomponent name="greetings"> <cffunction name="sayHello"> <cfset var strHelloMessage = 'Hello World!' /> <cfreturn strHelloMessage /> </cffunction> <cffunction name="getName"> <cfargument name="firstName" type="string" /> <cfargument name="lastName" type="string" /> <cfset var strFullName = arguments.firstName & ' ' & arguments.lastName /> <cfreturn strFullName /> </cffunction> </cfcomponent> Listing 1.12 – revised greeting.cfc Combining your methods As we have seen, you can easily access the methods within a defined CFC and output the data in a .cfm template page. You can also easily access the functionality of one method in a CFC from another method. This is particularly useful when your component definition contains grouped functions that may have a relationship based upon their common purpose. To show this, let's create a new method that will use the results from both of our existing functions within the greetings.cfc file. Instead of displaying a generic "Hello World" message, we will incorporate the returned data from the getName() method and display a personalized greeting. Create a new method within the CFC, called personalGreeting. <cffunction name="personalGreeting"> <cfargument name="firstName" type="string" /> <cfargument name="lastName" type="string" /> <cfscript> strHello = sayHello(); strFullName = getName(firstName=arguments.firstName, lastName=arguments.lastName); strHelloMessage = strHello & ' My name is ' & strFullName; </cfscript> <cfreturn strHelloMessage /> </cffunction> Listing 1.13 – personalGreeting method Within this method, we are calling our two previously defined methods. The returned value from the sayHello() method is being stored as a string variable, "strHello". We then retrieve the returned value from the getName() method and store this in a string variable "strFullName". As we have written the getName() function to accept two arguments to form the concatenated name string, we also need to add the same two arguments to the personalGreeting() method , as done in the previous code. They will then be passed through to the getName() method in exactly the same way as if we were calling that function directly. Using the two variables that now hold the returned data, we create our strHelloMessage variable, which joins the two values, and is then returned from the method using the cfreturn tag. In this method, we used CFScript instead of CFML and cfset tags, which were used in our previous functions. There is no hard and fast rule for this. You can use whichever coding method you find the most comfortable. Let's call this method on our hello.cfm template page, using the following code: <!--- instatiate the component ---> <cfset objGreeting = createObject('component', 'greetings') /> <!--- access the method and assign results to a string ---> <cfset strPersonalGreeting = objGreeting.personalGreeting( firstName="Gary", lastName="Brown") /> <cfoutput>#strPersonalGreeting#</cfoutput> Listing 1.14 – calling the personalGreeting method We are sending in the same arguments that we were passing through to the original getName() method, in the same way. This time we are passing these through using the newly created personalGreeting() method. You should now see a personalized greeting message displayed in your browser:
Read more
  • 0
  • 0
  • 3288

article-image-introduction-performance-testing-and-jmeter
Packt
20 Feb 2018
11 min read
Save for later

Introduction to Performance Testing and JMeter

Packt
20 Feb 2018
11 min read
In this article by Bayo Erinle, the author of the book Performance Testing with JMeter 3, will explore some of the options that make JMeter a great tool of choice for performance testing.  (For more resources related to this topic, see here.) Performance testing and tuning There is a strong relationship between performance testing and tuning, in the sense that one often leads to the other. Often, end-to-end testing unveils system or application bottlenecks that are regarded unacceptable with project target goals. Once those bottlenecks are discovered, the next step for most teams is a series of tuning efforts to make the application perform adequately. Such efforts normally include, but are not limited to, the following: Configuring changes in system resources Optimizing database queries Reducing round trips in application calls, sometimes leading to redesigning and re-architecting problematic modules Scaling out application and database server capacity Reducing application resource footprint Optimizing and refactoring code, including eliminating redundancy and reducing execution time Tuning efforts may also commence if the application has reached acceptable performance but the team wants to reduce the amount of system resources being used, decrease the volume of hardware needed, or further increase system performance. After each change (or series of changes), the test is re-executed to see whether the performance has improved or declined due to the changes. The process will be continued with the performance results having reached acceptable goals. The outcome of these test-tuning circles normally produces a baseline. Baselines Baseline is a process of capturing performance metric data for the sole purpose of evaluating the efficacy of successive changes to the system or application. It is important that all characteristics and configurations, except those specifically being varied for comparison, remain the same in order to make effective comparisons as to which change (or series of changes) is driving results toward the targeted goal. Armed with such baseline results, subsequent changes can be made to the system configuration or application and testing results can be compared to see whether such changes were relevant or not. Some considerations when generating baselines include the following: They are application-specific They can be created for system, application, or modules They are metrics/results They should not be over generalized They evolve and may need to be redefined from time to time They act as a shared frame of reference They are reusable They help identify changes in performance Load and stress testing Load testing is the process of putting demand on a system and measuring its response, that is, determining how much volume the system can handle. Stress testing is the process of subjecting the system to unusually high loads far beyond its normal usage pattern to determine its responsiveness. These are different from performance testing, whose sole purpose is to determine the response and effectiveness of a system, that is, how fast the system is. Since load ultimately affects how a system responds, performance testing is always done in conjunction with stress testing. JMeter to the rescue One of the areas performance testing covers is testing tools. Which testing tool do you use to put the system and application under load? There are numerous testing tools available to perform this operation, from free to commercial solutions. However, our focus will be on Apache JMeter, a free, open source, cross-platform desktop application from the Apache Software foundation. JMeter has been around since 1998 according to historic change logs on its official site, making it a mature, robust, and reliable testing tool. Cost may also have played a role in its wide adoption. Small companies usually may not want to foot the bill for commercial end testing tools, which often place restrictions, for example, on how many concurrent users one can spin off. My first encounter with JMeter was exactly a result of this. I worked in a small shop that had paid for a commercial testing tool, but during the course of testing, we had outrun the licensing limits of how many concurrent users we needed to simulate for realistic test plans. Since JMeter was free, we explored it and were quite delighted with the offerings and the share amount of features we got for free. Here are some of its features: Performance tests of different server types, including web (HTTP and HTTPS), SOAP, database, LDAP, JMS, mail, and native commands or shell scripts Complete portability across various operating systems Full multithreading framework allowing concurrent sampling by many threads and simultaneous sampling of different functions by separate thread groups Full featured Test IDE that allows fast Test Plan recording, building, and debugging Dashboard Report for detailed analysis of application performance indexes and key transactions In-built integration with real-time reporting and analysis tools, such as Graphite, InfluxDB, and Grafana, to name a few Complete dynamic HTML reports Graphical User Interface (GUI) HTTP proxy recording server Caching and offline analysis/replaying of test results High extensibility Live view of results as testing is being conducted JMeter allows multiple concurrent users to be simulated on the application, allowing you to work toward most of the target goals obtained earlier, such as attaining baseline and identifying bottlenecks. It will help answer questions, such as the following: Will the application still be responsive if 50 users are accessing it concurrently? How reliable will it be under a load of 200 users? How much of the system resources will be consumed under a load of 250 users? What will the throughput look like with 1000 users active in the system? What will be the response time for the various components in the application under load? JMeter, however, should not be confused with a browser. It doesn't perform all the operations supported by browsers; in particular, JMeter does not execute JavaScript found in HTML pages, nor does it render HTML pages the way a browser does. However, it does give you the ability to view request responses as HTML through many of its listeners, but the timings are not included in any samples. Furthermore, there are limitations to how many users can be spun on a single machine. These vary depending on the machine specifications (for example, memory, processor speed, and so on) and the test scenarios being executed. In our experience, we have mostly been able to successfully spin off 250-450 users on a single machine with a 2.2 GHz processor and 8 GB of RAM. Up and running with JMeter Now, let's get up and running with JMeter, beginning with its installation. Installation JMeter comes as a bundled archive, so it is super easy to get started with it. Those working in corporate environments behind a firewall or machines with non-admin privileges appreciate this more. To get started, grab the latest binary release by pointing your browser to http://jmeter.apache.org/download_jmeter.cgi. At the time of writing this, the current release version is 3.1. The download site offers the bundle as both a .zip file and a .tgz file. We go with the .zip file option, but feel free to download the .tgz file if that's your preferred way of grabbing archives. Once downloaded, extract the archive to a location of your choice. The location you extracted the archive to will be referred to as JMETER_HOME. Provided you have a JDK/JRE correctly installed and a JAVA_HOME environment variable set, you are all set and ready to run! The following screenshot shows a trimmed down directory structure of a vanilla JMeter install: JMETER_HOME folder structure The following are some of the folders in Apache-JMeter-3.2, as shown in the preceding screenshot: bin: This folder contains executable scripts to run and perform other operations in JMeter docs: This folder contains a well-documented user guide extras: This folder contains miscellaneous items, including samples illustrating the usage of the Apache Ant build tool (http://ant.apache.org/) with JMeter, and bean shell scripting lib: This folder contains utility JAR files needed by JMeter (you may add additional JARs here to use from within JMeter; we will cover this in detail later) printable_docs: This is the printable documentation Installing Java JDK Follow these steps to install Java JDK: Go to http://www.oracle.com/technetwork/java/javase/downloads/index.html. Download Java JDK (not JRE) compatible with the system that you will use to test. At the time of writing, JDK 1.8 (update 131) was the latest. Double-click on the executable and follow the onscreen instructions. On Windows systems, the default location for the JDK is under Program Files. While there is nothing wrong with this, the issue is that the folder name contains a space, which can sometimes be problematic when attempting to set PATH and run programs, such as JMeter, depending on the JDK from the command line. With this in mind, it is advisable to change the default location to something like C:toolsjdk. Setting up JAVA_HOME Here are the steps to set up the JAVA_HOME environment variable on Windows and Unix operating systems. On Windows For illustrative purposes, assume that you have installed Java JDK at C:toolsjdk: Go to Control Panel. Click on System. Click on Advance System settings. Add Environment to the following variables:     Value: JAVA_HOME     Path: C:toolsjdk Locate Path (under system variables, bottom half of the screen). Click on Edit. Append %JAVA_HOME%/bin to the end of the existing path value (if any). On Unix For illustrative purposes, assume that you have installed Java JDK at /opt/tools/jdk: Open up a Terminal window. Export JAVA_HOME=/opt/tools/jdk. Export PATH=$PATH:$JAVA_HOME. It is advisable to set this in your shell profile settings, such as .bash_profile (for bash users) or .zshrc (for zsh users), so that you won't have to set it for each new Terminal window you open. Running JMeter Once installed, the bin folder under the JMETER_HOME folder contains all the executable scripts that can be run. Based on the operating system that you installed JMeter on, you either execute the shell scripts (.sh file) for operating systems that are Unix/Linux flavored, or their batch (.bat file) counterparts on operating systems that are Windows flavored. JMeter files are saved as XML files with a .jmx extension. We refer to them as test scripts or JMX files. These scripts include the following: jmeter.sh: This script launches JMeter GUI (the default) jmeter-n.sh: This script launches JMeter in non-GUI mode (takes a JMX file as input) jmeter-n-r.sh: This script launches JMeter in non-GUI mode remotely jmeter-t.sh: This opens a JMX file in the GUI jmeter-server.sh: This script starts JMeter in server mode (this will be kicked off on the master node when testing with multiple machines remotely) mirror-server.sh: This script runs the mirror server for JMeter shutdown.sh: This script gracefully shuts down a running non-GUI instance stoptest.sh: This script abruptly shuts down a running non-GUI instance   To start JMeter, open a Terminal shell, change to the JMETER_HOME/bin folder, and run the following command on Unix/Linux: ./jmeter.sh Alternatively, run the following command on Windows: jmeter.bat Take a moment to explore the GUI. Hover over each icon to see a short description of what it does. The Apache JMeter team has done an excellent job with the GUI. Most icons are very similar to what you are used to, which helps ease the learning curve for new adapters. Some of the icons, for example, stop and shutdown, are disabled for now till a scenario/test is being conducted. The JVM_ARGS environment variable can be used to override JVM settings in the jmeter.bat or jmeter.sh script. Consider the following example: export JVM_ARGS="-Xms1024m -Xmx1024m -Dpropname=propvalue". Command-line options To see all the options available to start JMeter, run the JMeter executable with the -? command. The options provided are as follows: . ./jmeter.sh -? -? print command line options and exit -h, --help print usage information and exit -v, --version print the version information and exit -p, --propfile <argument> the jmeter property file to use -q, --addprop <argument> additional JMeter property file(s) -t, --testfile <argument> the jmeter test(.jmx) file to run -l, --logfile <argument> the file to log samples to -j, --jmeterlogfile <argument> jmeter run log file (jmeter.log) -n, --nongui run JMeter in nongui mode ... -J, --jmeterproperty <argument>=<value> Define additional JMeter properties -G, --globalproperty <argument>=<value> Define Global properties (sent to servers) e.g. -Gport=123 or -Gglobal.properties -D, --systemproperty <argument>=<value> Define additional system properties -S, --systemPropertyFile <argument> additional system property file(s) This is a snippet (non-exhaustive list) of what you might see if you did the same. Summary In this article we have learnt relationship between performance testing and tuning, and how to install and run JMeter.   Resources for Article: Further resources on this subject: Functional Testing with JMeter [article] Creating an Apache JMeter™ test workbench [article] Getting Started with Apache Spark DataFrames [article]
Read more
  • 0
  • 0
  • 3287

article-image-getting-started-codeception
Packt
04 May 2015
17 min read
Save for later

Getting started with Codeception

Packt
04 May 2015
17 min read
In this article by Matteo Pescarin, the author of Learning Yii Testing, we will get introduced to Codeception. Not everyone has been exposed to testing. The ones who actually have are aware of the quirks and limitations of the testing tools they've used. Some might be more efficient than others, and in either case, you had to rely on the situation that was presented to you: legacy code, hard to test architectures, no automation, no support whatsoever on the tools, and other setup problems, just to name a few. Only certain companies, because they have either the right skillsets or the budget, invest in testing, but most of them don't have the capacity to see beyond the point that quality assurance is important. Getting the testing infrastructure and tools in place is the immediate step following getting developers to be responsible for their own code and to test it. (For more resources related to this topic, see here.) Even if testing is something not particularly new in the programming world, PHP always had a weak point regarding it. Its history is not the one of a pure-bred programming language done with all the nice little details, and only just recently has PHP found itself in a better position and started to become more appreciated. Because of this, the only and most important tool that came out has been PHPUnit, which was released just 10 years ago, in 2004, thanks to the efforts of Sebastian Bergmann. PHPUnit was and sometimes is still difficult to master and understand. It requires time and dedication, particularly if you are coming from a non-testing experience. PHPUnit simply provided a low-level framework to implement unit tests and, up to a certain point, integration tests, with the ability to create mocks and fakes when needed. Although it still is the quickest way to discover bugs, it didn't cover everything and using it to create large integration tests will end up being an almost impossible task. On top of this, PHPUnit since version 3.7, when it switched to a different autoloading mechanism and moved away from PEAR, caused several headaches rendering most of the installations unusable. Other tools developed since mostly come from other environments and requirements, programming languages, and frameworks. Some of these tools were incredibly strong and well-built, but they came with their own way of declaring tests and interacting with the application, set of rules, and configuration specifics. A modular framework rather than just another tool Clearly, mastering all these tools required a bit of understanding, and the learning curve wasn't promised to be the same among all of them. So, if this is the current panorama, why create another tool if you will end up in the same situation we were in before? Well, one of the most important things to be understood about Codeception is that it's not just a tool, rather a full stack, as noted on the Codeception site, a suite of frameworks, or if you want to go meta, a framework for frameworks. Codeception provides a uniform way to design different types of test by using as much as possible the same semantic and logic, a way to make the whole testing infrastructure more coherent and approachable. Outlining concepts behind Codeception Codeception has been created with the following basic concepts in mind: Easy to read: By using a declarative syntax close to the natural language, tests can be read and interpreted quite easily, making them an ideal candidate to be used as documentation for the application. Any stakeholder and engineer close to the project can ensure that tests are written correctly and cover the required scenarios without knowing any special lingo. It can also generate BDD-style test scenarios from code test cases. Easy to write: As we already underlined, every testing framework uses its own syntax or language to write tests, resulting in some degree of difficulty when switching from one suite to the other, without taking into account the learning curve each one has. Codeception tries to bridge this gap of knowledge by using a common declarative language. Further, abstractions provide a comfortable environment that makes maintenance simple. Easy to debug: Codeception is born with the ability to see what's behind the scenes without messing around with the configuration files or doing random print_r around your code. On top of this all, Codeception has also been written with modularity and extensibility in mind, so that organizing your code is simple while also promoting code reuse throughout your tests. But let's see what's provided by Codeception in more detail. Types of tests As we've seen, Codeception provides three basic types of test: Unit tests Functional tests Acceptance tests Each one of them is self-contained in its own folder where you can find anything needed, from the configuration and the actual tests to any additional piece of information that is valuable, such as the fixtures, database snapshots, or specific data to be fed to your tests. In order to start writing tests, you need to initialize all the required classes that will allow you to run your tests, and you can do this by invoking codecept with the build argument: $ cd tests $ ../vendor/bin/codecept build Building Actor classes for suites: functional, acceptance, unit FunctionalTester includes modules: Filesystem, Yii2 FunctionalTester.php generated successfully. 61 methods added AcceptanceTester includes modules: PhpBrowser AcceptanceTester.php generated successfully. 47 methods added UnitTester includes modules: UnitTester.php generated successfully. 0 methods added $ The codecept build command needs to be run every time you modify any configuration file owned by Codeception when adding or removing any module, in other words, whenever you modify any of the .suite.yml files available in the /tests folder. What you have probably already noticed in the preceding output is the presence of a very peculiar naming system for the test classes. Codeception introduces the Guys that have been renamed in Yii terminology as Testers, and are as follows: AcceptanceTester: This is used for acceptance tests FunctionalTester: This is used for functional tests UnitTester: This is used for unit tests These will become your main interaction points with (most of) the tests and we will see why. By using such nomenclature, Codeception shifts the point of attention from the code itself to the person that is meant to be acting the tests you will be writing. This way we will become more fluent in thinking in a more BDD-like mindset rather than trying to figure out all the possible solutions that could be covered, while losing the focus of what we're trying to achieve. Once again, BDD is an improvement over TDD, because it declares in a more detailed way what needs to be tested and what doesn't. AcceptanceTester AcceptanceTester can be seen as a person who does not have any knowledge of the technologies used and tries to verify the acceptance criteria that have been defined at the beginning. If we want to re-write our previously defined acceptance tests in a more standardized BDD way, we need to remember the structure of a so-called user story. The story should have a clear title, a short introduction that specifies the role that is involved in obtaining a certain result or effect, and the value that this will reflect. Following this, we will then need to specify the various scenarios or acceptance criteria, which are defined by outlining the initial scenario, the trigger event, and the expected outcome in one or more clauses. Let's discuss login using a modal window, which is one of the two features we are going to implement in our application. Story title – successful user login I, as an acceptance tester, want to log in into the application from any page. Scenario 1: Log in from the homepage      I am on the homepage.      I click on the login link.      I enter my username.      I enter my password.      I press submit.      The login link now reads "logout (<username>)" and I'm still on the homepage. Scenario 2: Log in from a secondary page      I am on a secondary page.     I click on the login link.     I enter my username.     I enter my password.     I press Submit.     The login link now reads "logout (<username>)" and I'm still on the secondary page. As you might have noticed I am limiting the preceding example to successful cases. The preceding story can be immediately translated into something along the lines of the following code: // SuccessfulLoginAcceptanceTest.php   $I = new AcceptanceTester($scenario); $I->wantTo("login into the application from any page");   // scenario 1 $I->amOnPage("/"); $I->click("login"); $I->fillField("username", $username); $I->fillField("password", $password); $I->click("submit"); $I->canSee("logout (".$username.")"); $I->seeInCurrentUrl("/");   // scenario 2 $I->amOnPage("/"); $I->click("about"); $I->seeLink("login"); $I->click("login"); $I->fillField("username", $username); $I->fillField("password", $password); $I->click("submit"); $I->canSee("logout (".$username.")"); $I->amOnPage("about"); As you can see this is totally straightforward and easy to read, to the point that anyone in the business should be able to write any case scenario (this is an overstatement, but you get the idea). Clearly, the only thing that is needed to understand is what the AcceptanceTester is able to do: The class generated by the codecept build command can be found in tests/codeception/acceptance/AcceptanceTester.php, which contains all the available methods. You might want to skim through it if you need to understand how to assert a particular condition or perform an action on the page. The online documentation available at http://codeception.com/docs/04-AcceptanceTests will also give you a more readable way to get this information. Don't forget that at the end AcceptanceTester is just a name of a class, which is defined in the YAML file for the specific test type: $ grep class tests/codeception/acceptance.suite.yml class_name: AcceptanceTester Acceptance tests are the topmost level of tests, as some sort of high-level user-oriented integration tests. Because of this, acceptance tests end up using an almost real environment, where no mocks or fakes are required. Clearly, we would need some sort of initial state that we can revert to, particularly if we're causing actions that modify the state of the database. As per Codeception documentation, we could have used a snapshot of the database to be loaded at the beginning of each test. Unfortunately, I didn't have much luck in finding this feature working. So later on, we'll be forced to use the fixtures. Everything will then make more sense. When we will write our acceptance tests, we will also explore the various modules that you can also use with it, such as PHPBrowser and Selenium WebDriver and their related configuration options. FunctionalTester As we said earlier, FunctionalTester represents our character when dealing with functional tests. You might think of functional tests as a way to leverage on the correctness of the implementation from a higher standpoint. The way to implement functional tests bears the same structure as that of acceptance tests, to the point that most of the time the code we've written for an acceptance test in Codeception can be easily swapped with that for a functional test, so you might ask yourself: "where are the differences?" It must be noted that the concept of functional tests is something specific to Codeception and can be considered almost the same as that of integration tests for the mid-layer of your application. The most important thing is that functional tests do not require a web server to run, and they're called headless: For this reason, they are not only quicker than acceptance tests, but also less "real" with all the implications of running on a specific environment. And it's not the case that the acceptance tests provided by default by the basic application are, almost, the same as the functional tests. Because of this, we will end up having more functional tests that will cover more use cases for specific parts of our application. FunctionalTester is somehow setting the $_GET, $_POST and $_REQUEST variables and running the application from within a test. For this reason, Codeception ships with modules that let it interact with the underlying framework, be it Symfony2, Laravel4, Zend, or, in our case, Yii 2. In the configuration file, you will notice the module for Yii 2 already enabled: # tests/functional.suite.yml   class_name: FunctionalTester modules:    enabled:      - Filesystem      - Yii2 # ... FunctionalTester has got a better understanding of the technologies used although he might not have the faintest idea of how the various features he's going to test have been implemented in detail; he just knows the specifications. This makes a perfect case for the functional tests to be owned or written by the developers or anyone that is close to the knowledge of how the various features have been exposed for general consumption. The base functionality of the REST application, exposed through the API, will also be heavily tested, and in this case, we will have the following scenarios: I can use POST to send correct authentication data and will receive a JSON containing the successful authentication I can use POST to send bad authentication data and will receive a JSON containing the unsuccessful authentication After a correct authentication, I can use GET to retrieve the user data After a correct authentication, I will receive an error when doing a GET for a user stating that it's me I can use POST to send my updated hashed password Without a correct authentication, I cannot perform any of the preceding actions The most important thing to remember is that at the end of each test, it's your responsibility to keep the memory clean: The PHP application will not terminate after processing a request. All requests happening in the same memory container are not isolated. If you see your tests failing for some unknown reason when they shouldn't, try to execute a single test separately. UnitTester I've left UnitTester for the end as it's a very special guy. For all we know, until now, Codeception must have used some other framework to cover unit tests, and we're pretty much sure that PHPUnit is the only candidate to achieve this. If any of you have already worked with PHPUnit, you will remember the learning curve together with the initial problem of understanding its syntax and performing even the simplest of tasks. I found that most developers have a love-and-hate relationship with PHPUnit: either you learn its syntax or you spend half of the time looking at the manual to get to a single point. And I won't blame you. We will see that Codeception will come to our aid once again if we're struggling with tests: remember that these unit tests are the simplest and most atomic part of the work we're going to test. Together with them come the integration tests that cover the interaction of different components, most likely with the use of fake data and fixtures. If you're used to working with PHPUnit, you won't find any particular problems writing tests; otherwise, you can make use of UnitTester and implement the same tests by using the Verify and Specify syntax. UnitTester assumes a deep understanding of the signature and how the infrastructure and framework work, so these tests can be considered the cornerstone of testing. They are super fast to run, compared to any other type of test, and they should also be relatively easy to write. You can start with adequately simple assertions and move to data providers before needing to deal with fixtures. Other features provided by Codeception On top of the types of tests, Codeception provides some more aids to help you organize, modularize, and extend your test code. As we've seen, functional and acceptance tests have a very plain and declarative structure, and all the code and the scenarios related to specific acceptance criteria are kept in the same file at the same level and these are executed linearly. In most of the situations, as it is in our case, this is good enough, but when your code starts growing and the number of components and features become more and more complex, the list of scenarios and steps to perform an acceptance or functional test can be quite lengthy. Further, some tests might end up depending on others, so you might want to start considering writing more compact scenarios and promote code reuse throughout your tests or split your test into two or more tests. If you feel your code needs a better organization and structure, you might want to start generating CEST classes instead of normal tests, which are called CEPT instead. A CEST class groups the scenarios all together as methods as highlighted in the following snippet: <?php // SuccessfulLoginCest.php   class SuccessfulLoginCest {    public function _before(CodeceptionEventTestEvent $event) {}      CodeceptionEventTestEvent $event        public function _fail(CodeceptionEventTestEvent $event) {}      // tests    public function loginIntoTheApplicationTest(AcceptanceTester $I)    {        $I->wantTo("login into the application from any page");        $I->amOnPage("/");        $I->click("login");        $I->fillField("username", $username);        $I->fillField("password", $password);        $I->click("submit");        $I->canSee("logout (".$username.")");        $I->seeInCurrentUrl("/");        // ...    } } ?> Any method that is not preceded by the underscore is considered a test, and the reserved methods _before and _after are executed at the beginning and at the end of the list of tests contained in the test class, while the _fail method is used as a cleanup method in case of failure. This alone might not be enough, and you can use document annotations to create reusable code to be run before and after the tests with the use of @before <methodName> and @after <methodName>. You can also be stricter and require a specific test to pass before any other by using the document annotation @depends <methodName>. We're going to use some of these document annotations, but before we start installing Codeception, I'd like to highlight two more features: PageObjects and StepObjects. The PageObject is a common pattern amongst test automation engineers. It represents a web page as a class, where its DOM elements are properties of the class, and methods instead provide some basic interactions with the page. The main reason for using PageObjects is to avoid hardcoding CSS and XPATH locators in your tests. Yii provides some example implementation of the PageObjects used in /tests/codeception/_pages. StepObject is another way to promote code reuse in your tests: It will define some common actions that can be used in several tests. Together with PageObjects, StepObjects can become quite powerful. StepObject extends the Tester class and can be used to interact with the PageObject. This way your tests will become less dependent on a specific implementation and will save you the cost of refactoring when the markup and the way to interact with each component in the page changes. For future reference, you can find all of these in the Codeception documentation in the section regarding the advanced use at http://codeception.com/docs/07-AdvancedUsage together with other features, like grouping and an interactive console that you can use to test your scenarios at runtime. Summary In this article, we got hands-on with Codeception and looked at the different types of tests available. Resources for Article: Further resources on this subject: Building a Content Management System [article] Creating an Extension in Yii 2 [article] Database, Active Record, and Model Tricks [article]
Read more
  • 0
  • 0
  • 3286
article-image-customization-using-adf-meta-data-services
Packt
15 Jun 2011
8 min read
Save for later

Customization using ADF Meta Data Services

Packt
15 Jun 2011
8 min read
Oracle ADF Enterprise Application Development—Made Simple Successfully plan, develop, test and deploy enterprise applications with Oracle ADF      Why customization? The reason ADF has customization features built-in is because Oracle Fusion Applications need them. Oracle Fusion Applications is a suite of programs capable of handling every aspect of a large organization—personnel, finance, project management, manufacturing, logistics, and much more. Because organizations are different, Oracle has to offer a way for each customer organization to fit Oracle Fusion Applications to their requirements. This customization functionality can also be very useful for organizations that do not use Oracle Fusion Applications. If you have two screens that work with the same data, but one of the screens must show more fields than the other, you can create one screen with all the fields and use customization to create another version of the same screen with fewer fields for other users. For example, the destination management application might have a data entry screen showing all details of a task to a dispatcher, but only the relevant details to an airport transfer guide: Companies such as DMC Solutions that produce software for sale realize additional benefit from the customization features in ADF. DMC Solu a base application, sell it to different customers and customize each in application to that customer without changing the base application. How does an ADF customization work? More and more Oracle products are using something called Meta Data Services to store metadata. Metadata is data that describes other pieces of information—where it came from, what it means, or how it is intended to be used. An image captured by a digital camera might include metadata about where and when the picture was taken, which camera settings were used, and so on. In the case of an ADF application, the metadata describes how the application is intended to be used. There are three kinds of customizations in ADF: Seeded customizations:They are customizations defined in advance (before the user runs the application) by customization developers. User customizations(sometimes called personalizations): They are changes to aspects of the user interface by application end users. The ADF framework offers a few user customization features, but you need additional software such as Oracle WebCenter for most user customizations. User customizations are outside the scope of this article. Design time at runtime:They are advanced customization of the application by application administrators and/or properly authorized end users. This requires that application developers have prepared the possible customizations as part of application development—it is complicated to program using only ADF, but Oracle WebCenter provides advanced components that make this easier. This is outside the scope of this article. Your customization metadata is stored in either files or a database repository. If you are only planning to use seeded customizations, a file-based repository is fine. However, if you plan to allow user customizations or design time at runtime, you should set up your production server to store customizations in a metadata database. Refer to the Fusion Middleware Administrator's Guide for information about setting up a metadata database. Applying the customization layers When an ADF application is customized, the ADF framework applies one or more customization layers on top of the base application. Each layer has a value, and customizations are assigned to a specific customization layer and value. The concept of multiple layers makes it possible to apply, for example: Industry customization (customizing the application for example, the travel industry: industry=travel) Organization customization (customizing the application for a specific travel company: org=xyztravel) Site customization (customizing the application for the Berlin office) Role-based customization (customizing the application for casual, normal, and advanced users) The XDM application that DMC Solution is building could be customized in one way for ABC Travel and in another way for XYZ Travel, and XYZ Travel might decide to further customize the application for different types of users: You can have as many layers as you need—Oracle Fusion Applications is reported to use 12 layers, but your applications are not likely to be that complex. For each customization layer, the developer of the base application must provide a customization class that will be executed at runtime, returning a value for each customization layer. The ADF framework will then apply the customizations that the customization developer has specified for that layer/value combination. This means that the same application can look in many different ways, depending on the values returned by the customization classes and the customizations registered:     Org layer value Role layer value Result qrstravel any Base application, because there are no customizations defined for QRS Travel abctravel any The application customized for ABC Travel, because there are no role layer customizations for ABC Travel, the value of the role layer does not change the application xyztravel normal The application customized for XYZ Travel and further customized for normal users in XYZ Travel xyztravel superuser The application customized for XYZ Travel and further customized for super users in XYZ Travel Making an application customizable To make an application customizable, you need to do three things: Develop a customization class for each layer of customization. Enable seeded customization in the application. Link the customization class to the application. The customization developer, who will be developing the customizations, will additionally have to set up JDeveloper correctly so that all customization levels can be accessed. This setup is described later in the article. Developing the customization classes For each layer of customization, you need to develop a customization class with a specific format—technically, it has to extend the Oracle-supplied abstract class oracle.mds.cust.CustomizationClass. A customization class has a name (returned by the getName() method) and a value (returned by the getValue() method). At runtime, the ADF framework will execute the customization classes for all layers to determine the customization value at each level. Additionally, the customization class has to return a short unique prefix to use for all customized items, and a cache hint telling ADF if this is a static or dynamic customization. Building the classes Your customization classes should go in your Common Code workspace. A customization class is a normal Java class, that is, it is created with File | New | General | Java Class. In the Create Java Class dialog, give your class a name (OrgLayerCC) and place it into a customization package (for example, com.dmcsol. xdm.customization). Choose to extend oracle.mds.cust.CustomizationClass and check the Implement Abstract Methods checkbox: Create a similar class called RoleLayerCC. Implementing the methods Because you asked the JDeveloper to implement the abstract methods, your classes already contain three methods: getCacheHint() getName() getValue(RestrictedSession, MetadataObject) The getCacheHint() method must return an oracle.mds.cust.CacheHint constant that tells ADF if the value of this layer is static (common for all users) or dynamic (depending on the user). The normal values here are ALL_USERS for static customizations or MULTI_USER for customizations that apply to multiple users. In the XDM application, you will use: ALL_USERS for OrgLevelCC, because this customization layer will apply to all users in the organization MULTI_USER for RoleLevelCC, because the role-based customization will apply to multiple users, but not necessarily to all Refer to the chapter on customization with MDS in Fusion Developer's Guide for Oracle Application Development Framework for information on other possible values. The getName() method simply returns the the name of the customization layer. The getValue() method must return an array of String objects. It will normally make most sense to return just one value—the application is running for exactly one organization, you are either a normal user or a super user. For advanced scenarios, it is possible to return multiple values, in such a case multiple customizations will be applied at the same layer. Each customization that a customization developer defines will be tied to a specific layer and value—there might be a customization that happens when org has the value xyztravel. For the OrgLayerCC class, the value is static and is defined when DMC Solutions installs the application for XYZ Travel—for example, in a property file. For the RoleLayerCC class , the value is dynamic, depending on the current user, and can be retrieved from the ADF security context. The OrgLayerCC class could look like the following: package com.dmcsol.xdm.customization; import ... public class RoleLayerCC extends CustomizationClass { public CacheHint getCacheHint() { return CacheHint.MULTI_USER; } public String getName() { return "role"; } public String[] getValue(RestrictedSession restrictedSession, MetadataObject metadataObject) { String[] roleValue = new String[1]; SecurityContext sec = ADFContext.getCurrent(). getSecurityContext(); if (sec.isUserInRole("superuser")) { roleValue[0] = "superuser"; } else { roleValue[0] = "normal"; } return roleValue; } } The GetCacheHint() method returns MULTI_USER because this is a dynamic customization—it will return different values for different users. The GetName() method simply returns the name of the layer. The GetValue() method uses oracle.adf.share.security.SecurityContext to look up if the user has the super user role and returns the value superuser or normal. Deploying the customization classes Because you place your customization class in the Common Code project, you need to deploy the Common Code project to an ADF library and have the build/ configuration manager copy it to your common library directory.
Read more
  • 0
  • 0
  • 3281

article-image-microsoft-enterprise-library-security-application-block
Packt
09 Dec 2010
5 min read
Save for later

Microsoft Enterprise Library: Security Application Block

Packt
09 Dec 2010
5 min read
Microsoft Enterprise Library 5.0 Develop Enterprise applications using reusable software components of Microsoft Enterprise Library 5.0 Develop Enterprise Applications using the Enterprise Library Application Blocks Set up the initial infrastructure configuration of the Application Blocks using the configuration editor A step-by-step tutorial to gradually configure each Application Block and implement its functions to develop the required Enterprise Application The first step is the process of validating an identity against a store (Active Directory, Database, and so on); this is commonly called as Authentication. The second step is the process of verifying whether the validated identity is allowed to perform certain actions; this is commonly known Authorization. These two security mechanisms take care of allowing only known identities to access the application and perform their respective actions. Although, with the advent of new tools and technologies, it is not difficult to safeguard the application, utilizing these authentication and authorization mechanisms and implementing security correctly across different types of applications, or across different layers and in a consistent manner is pretty challenging for developers. Also, while security is an important factor, it's of no use if the application's performance is dismal. So, a good design should also consider performance and cache the outcome of authentication and authorization for repeated use. The Security Application Block provides a very simple and consistent way to implement authorization and credential caching functionality in our applications. Authorization doesn't belong to one particular layer; it is a best practice to authorize user action not only in the UI layer but also in the business logic layer. As Enterprise Library application blocks are layer-agnostic, we can leverage the same authorization rules and expect the same outcome across different layers bringing consistency. Authorization of user actions can be performed using an Authorization Provider; the block provides Authorization Rule Provider or AzMan Authorization Provider; it also provides the flexibility of implementing a custom authorization provider. Caching of security credentials is provided by the SecurityCacheProvider by leveraging the Caching Application Block and a custom caching provider can also be implemented using extension points. Both Authorization and Security cache providers are configured in the configuration file; this allows changing of provider any time without re-compilation. The following are the key features of the Security block: The Security Application Block provides a simple and consistent API to implement authorization. It abstracts the application code from security providers through configuration. It provides the Authorization Rule Provider to store rules in a configuration file and Windows Authorization Manager (AzMan) Authorization Provider to authorize against Active Directory, XML file, or database. Flexibility to implement custom Authorization Providers. It provides token generation and caching of authenticated IIdentity, IPrincipal and Profile objects. It provides User identity cache management, which improves performance while repeatedly authenticating users using cached security credentials. Flexibility to extend and implement custom Security Cache Providers. Developing an application We will explore each individual Security block feature and along the way we will understand the concepts behind the individual elements. This will help us to get up to speed with the basics. To get started, we will do the following: Reference the Validation block assemblies Add the required Namespaces Set up the initial configuration To complement the concepts and allow you to gain quick hands-on experience of different features of the Security Application Block, we have created a sample web application project with three additional projects, DataProvider, BusinessLayer, and BusinessEntities, to demonstrate the features. The application leverages SQL Membership, Role, and Profile provider for authentication, role management, and profiling needs. Before running the web application you will have to run the database generation script provided in the DBScript folder of the solution, and update the connection string in web.config appropriately. You might have to open the solution in "Administrator" mode based on your development environment. Also, create an application pool with an identity that has the required privileges to access the development SQL Server database, and map the application pool to the website. A screenshot of the sample application is shown as follows: (Move the mouse over the image to enlarge.) Referencing required/optional assemblies For the purposes of this demonstration we will be referencing non-strong-named assemblies but based on individual requirements Microsoft strong-named assemblies, or a modified set of custom assemblies can be referenced as well. The list of Enterprise Library assemblies that are required to leverage the Security Application Block functionality is given next. A few assemblies are optional based on the Authorization Provider and cache storage mechanism used. Use the Microsoft strong-named, or the non-strong-named, or a modified set of custom assemblies based on your referencing needs. The following table lists the required/optional assemblies: AssemblyRequired/OptionalMicrosoft.Practices.EnterpriseLibrary.Common.dllRequiredMicrosoft.Practices.ServiceLocation.dllRequiredMicrosoft.Practices.Unity.dllRequiredMicrosoft.Practices.Unity.Interception.dllRequiredMicrosoft.Practices.Unity.Configuration.dll Optional Useful while utilizing Unity configuration classes in our code Microsoft.Practices.EnterpriseLibrary.Security.dllRequiredMicrosoft.Practices.EnterpriseLibrary.Security.AzMan.dll Optional Used for Windows Authorization Manager Provider Microsoft.Practices.EnterpriseLibrary.Security.Cache.CachingStore.dll Optional Used for caching the User identity Microsoft.Practices.EnterpriseLibrary.Data.dll Optional Used for caching in Database Cache Storage Open Visual Studio 2008/2010 and create a new ASP.NET Web Application Project by selecting File | New | Project | ASP.NET Web Application; provide the appropriate name for the solution and the desired project location. Currently, the application will have a default web form and assembly references. In the Solution Explorer, right-click on the References section and click on Add Reference and go to the Browse tab. Next, navigate to the Enterprise Library 5.0 installation location; the default install location is %Program Files%Microsoft Enterprise Library 5.0Bin. Now select all the assemblies listed in the previous table, excluding the AzMan-related assembly (Microsoft.Practices.EnterpriseLibrary.Security.AzMan.dll). The final assembly selection will look similar to the following screenshot:
Read more
  • 0
  • 0
  • 3274

article-image-communicating-dynamics-crm-biztalk-server
Packt
20 Jul 2011
6 min read
Save for later

Communicating from Dynamics CRM to BizTalk Server

Packt
20 Jul 2011
6 min read
Microsoft BizTalk 2010: Line of Business Systems Integration A practical guide to integrating Line of Business systems with BizTalk Server 2010 There are three viable places where Dynamics CRM can communicate with BizTalk Server. First, a Dynamics CRM form is capable of executing client-side JavaScript at various points in the form lifecycle. One can definitely use JavaScript to invoke web services, including web services exposed by BizTalk Server. However, note that JavaScript invocation of web services is typically synchronous and could have a negative impact on the user experience if a form must constantly wait for responses from distributed services. Also, JavaScript that runs within Dynamics CRM is clientside and tied directly to the page on which it resides. If we programmatically interact with a Dynamics CRM entity, then any code existing in the client-side script will not get invoked. For instance, if after an "account" record is created we send a message, via JavaScript, to BizTalk, this logic would not fire if we created an "account" record programmatically. The second place where Dynamics CRM can communicate with BizTalk Server is through workflows. A workflow in Dynamics CRM is an automated process where a set of steps is executed according to rules that we define. For example, when a sales opportunity is closed, we run a workflow that adds a message to the customer record, notifies all parties tied to the opportunity, and sends a polite email to the lost prospect. Workflows are based on Windows Workflow 4.0 technology and can be built either in the Dynamics CRM application itself or within Visual Studio 2010. The Dynamics CRM web application allows us to piece together workflows using previously registered workflow steps. If we need new workflow steps or need to construct something complex, we can jump into Visual Studio 2010 and define the workflow there. Why would we choose to use a workflow to send a message to BizTalk Server? If you have a long-running process that can either be scheduled or executed on demand and want the option for users to modify the process, the workflow may be the right choice. The final strategy for communicating between Dynamics CRM and BizTalk Server is to use plugins. Plugins are server-based application extensions that execute business logic and get tied directly to an entity. This means that they are invoked whether we work in the Dynamics CRM web interface or through the API. I can run a plugin both synchronously and asynchronously, depending on the situation. For instance, if we need to validate the data on a record prior to saving it, we can set a plugin to run before the "save" operation is committed and provide some user feedback on the invalid information. Or, we could choose to asynchronously call a plugin after a record is saved and transmit data to our service bus, BizTalk Server. In the following exercise, we will leverage plugins to send data from Dynamics CRM to BizTalk Server. Integration with BizTalk Server In this first walkthrough, we will build a plugin that communicates from Dynamics CRM to a BizTalk Server located. An event message will be sent to BizTalk whenever a change occurs on an Account record in Dynamics CRM. Setup This exercise leverages a BizTalk Server project already present in your Visual Studio 2010 solution. We are going to publish a web service from BizTalk Server that takes in a message and routes it to a BizTalk send port that writes the message to the file system. If you have not already done so, go to the code package and navigate to C:LOBIntegrationChapter03Chapter3-DynamicsCRM and open the Visual Studio 2010 solution file named Chapter3-DynamicsCRM.sln. Find the BizTalk Server project named Chapter3-DynamicsCRM.AcctRouting and open it. The code package includes a custom schema named AccountEventChange_XML.xsd and notice which elements we want from Dynamics CRM 2011 when an account changes. The first element, EventSource, is used to designate the source of the change event, as there may be multiple systems that share changes in an organization's accounts. This BizTalk project should be set to deploy to a BizTalk application named Chapter3. Build and deploy the project to the designated BizTalk Server. After confirming a successful deployment, launch the BizTalk WCF Service Publishing Wizard. We are going to use this schema to expose a web service entry point into BizTalk Server that Dynamics CRM 2011 can invoke. On the WCF Service Type wizard page, select a WCF-BasicHttp adapter and set the service to expose metadata and have the wizard generate a receive location for us in the Chapter3 application: On the Create WCF Service wizard page, choose to Publish schemas as WCF service. This option gives us fine-grained control over the naming associated with our service. On the next page, delete the two-way operation already present in the service definition. Rename the topmost service definition to AccountChangeService and assign the service the same name. Right-click the service and create a new one-way operation named PublishAccountChange. Right-click the Request message of the operation and choose the AccountChangeEvent message from our BizTalk Project's DLL: On the following wizard page, set the namespace of the service to http://Chapter3/AccountServices. Next, set the location of our service to http://localhost/AccountChangeService and select the option to allow anonymous access to the generated service. Finally, complete the wizard by clicking the Create button on the final wizard page. Confirm that the wizard successfully created both an IIS-hosted web service, and a BizTalk receive port/location. Ensure that the IIS web service is running under an Application Pool that has permission to access the BizTalk databases. In order to test this service, first, go to the BizTalk Server Administration Console and locate the Chapter3 application. Right click the Send Ports folder and create a new, static one-way send port named Chapter3.SendAccountChange.FILE. Set the send port to use the FILE adapter and select the FileDropDropCustomerChangeEvent folder that is present in the code package: This send port should listen for all account change event messages, regardless of which receive location (and system) that they came from. Go to the Filters tab of this send port. Set the filter Property to BTS.MessageType and filter Value to http://Chapter3-DynamicsCRM.AcctRouting.AccountChangeEvent_XML#AccountChangeEvent. All that remains is to test our service. Open the WCF Test Client application and add a new service reference to http://localhost/AccountChangeService/AccountChangeService.svc. Invoke the PublishAccountChange method and, if everything is configured correctly, we will see a message emitted by BizTalk Server that matches our service input parameters: (Move the mouse over the image to enlarge.) We now are sufficiently ready to author the Dynamics CRM plugin, which calls this BizTalk service.  
Read more
  • 0
  • 0
  • 3274
article-image-creating-mobile-dashboards
Packt
06 Jul 2015
13 min read
Save for later

Creating Mobile Dashboards

Packt
06 Jul 2015
13 min read
In this article by Taha M. Mahmoud, author of the book Learning SAP BusinessObjects Dashboards, in the last few decades, the usage of smart devices, such as mobile phones, tablets, and smart watches has increased dramatically. Now, the hardware of smart devices is powerful enough to handle all that we need it to. Indeed, we are now carrying smart devices with us all the time, that act like small, but powerful, computers. Here comes the idea of Mobile BI. We need to select the most important information for the BI end user to track on the go, using their smart devices. According to the Industrial Design Center (IDC: http://www.idc.com/), by 2017, 87 percent of all connected devices sold will be tablets and smartphones. (For more resources related to this topic, see here.) SAP BusinessObjects has different BI tools that handle different user requirements. They have the following BI reporting tools: Web Intelligence (Webi) reports: This tool can be used to help business users to execute their day-to-day reports. The main advantage of Webi reports is that you can schedule them to run and be sent directly to users by e-mail. This is a very powerful tool, because it is very similar to MS Excel, so business users can start using it directly, without a lot of effort and time. Crystal reports: This is one of the most famous report types. We call it a pixel-perfect report because we can control and adjust our report design, up to the pixel level. Normally, we use these reports to create the annual and quarterly reports used and published by an organization's end users. Dashboards: This is the tool that you are learning in this book. Dashboards are a powerful way to deliver information to the top management and executives. Lumira: This tool is a data discovery tool that can help data and business analysts explore data. It is very powerful and can connect to any source data. In minutes, you can come up with neat and wonderful dashboards and charts with this tool. The idea behind this tool is that you don't have initial requirements to implement, but you have data to explore instead. Explorer: This is another powerful data discovery tool, but its main focus is on analyzing data rather than presenting it. You can use it to explore the information you have. Design studio: This is a new dashboard tool. It was released at the end of 2013 for designing and implementing dashboards. It needs coding experience, as it is heavily dependent on JavaScript. Someone with technical skills should use this tool to produce dashboards, and then make them available to the end user. A lay user will not be able to create their own dashboards using this tool, at least at the current stage. SAP is focusing on upgrading this tool to be their main dashboard tool. We can find a matrix that shows the supported content on each device, as follows: BI document* iPad* iPhone* Android tablet* Android phone* Webi Yes Yes Yes Yes Crystal Yes Yes No No Dashboards Yes No Yes No Design studio Yes Yes Yes Yes Explorer Yes Yes No No Lumira Yes No No No * This is as per Q4-2014. SAP BO Dashboard can be viewed only on tablets, and not cell phones (as per the current available release SAP BO BI platform 4.1 SP5). In this article, we will focus on the following topics: Creating dashboards for mobile devices Developing mobile dashboards Publishing mobile dashboards Accessing mobile dashboards Creating dashboards for smart devices Mobility is one of the main enterprise goals for all market leaders. Mobility is a term that refers to providing company services for the customer through smart devices (including mobile devices). So, having a mobile application is one of the factors of an organization's success. Facebook, Google, Twitter, and many other enterprises across the globe are competing with each other to reach people everywhere. You don’t need to use a computer to buy something from Amazon.com. All that you need now is to install the Amazon application on your device and buy anything, at anytime. The fact that we are carrying our smart devices all the time, and using them regularly, makes them a golden place for reaching people. Business Intelligence also found that smart devices are perfect for delivering BI content to the end users, and to achieve the concept of giving the right information to the right person at the right time. We can use SAP BO dashboards to create one of the following dashboard types: Desktop Mobile Desktop and mobile If we are targeting desktop users only, we don’t need to worry about the compatibility of dashboard components, as all components are compatible with desktops; whereas, we need to take care if we are targeting mobile users. We need to avoid unsupported components and find alternatives and workarounds, as we will discuss in this article. Here, we must mention one big difference between desktop and mobile dashboards, which is the technology used in each. The technology used in desktop dashboards is Macromedia Flash, while the technology used in mobile dashboards is HTML5. This is the main reason that all the desktop dashboard components that we discussed throughout this book are not supported in the mobile version. You will learn how to find unsupported components and how to avoid them in the first place, if you are targeting mobile users. The second thing that we need to be aware of is the hardware limitation on mobile devices in comparison with powerful desktop and client tools. We need to consider using lightweight dashboard components and presenting the most important and critical information, which the end user really wants to track and monitor on the go. These types of KPIs need immediate action and can't wait until the user returns to their office. Here are the main steps for creating mobile dashboards: Design phase: We need to consider which KPIs should be displayed in the mobile dashboard version and how they should be displayed Development phase: We need to use supported dashboard components and connections only Publishing phase: We need to publish our dashboard and make it available for end users Accessing dashboard: We need to install the SAP BI application and configure it to connect to our SAP BO system Next, we will discuss each phase. Developing a mobile SAP BO Dashboard We can use SAP BO Dashboards to develop dashboards for desktops as well as mobiles. We just need to consider the following if we are developing for mobile dashboards: Using only supported mobile components Using the recommended canvas size for iPads Using only supported mobile connections Now, we will discuss each of these topics. Using supported mobile components To make sure that we are using only supported mobile dashboard components, we can use the Mobile Only filter from the Components panel. You can see this filter in the following screenshot: You can see a list of all supported Mobile dashboard components and connections in Appendix 3, Supported Mobile Components and Connections. We can also use the Mobile Compatibility panel to highlight unsupported dashboard components. This panel is very useful because it is also used to highlight unsupported functions, such as Entry Effect. Unsupported features will simply be lost when you view the dashboard on a mobile phone. You can see the Mobile Compatibility panel in the following screenshot: Using the recommended canvas size for iPads We need also to take care of the canvas size, as the recommended canvas size is 1024 x 768 pixels if we are developing a dashboard for mobiles. We can change the canvas size from the following places: Document properties Preferences Changing the canvas size from the preferences will make it the default canvas size for all new dashboards, whereas changing it from document properties will change the canvas size for the current dashboard only. If we have selected any canvas size other than the recommended one, we will get the following warning in the Mobile Compatibility panel: Using a supported mobile data connection The next thing we need to take care of is the external data connection type, as only a few of them are supported by mobile dashboards. You can see the Data Manager window, selected via data connections, in the following screenshot: Next, we will see how to preview and publish our mobile dashboard. Publishing mobile dashboards Publishing a dashboard will make it available for end users. After developing our mobile dashboard, we will need to do the following: Preview our dashboard to see what it will look like on a tablet Publish our dashboard on the SAP BO server as a mobile dashboard Add our dashboard to the mobile category to make it available for mobile users Previewing our mobile dashboard There are two modes for previewing mobile dashboards: Mobile (Fit to Screen) Mobile (Original Size) You can see the three available options in the following screenshot. We have already explained how to use the first one. The main difference between the other two options is that Mobile (Fit to Screen) will fit the dashboard to the screen size, and the other will display the original size. We need to note that the previewing option will affect only the preview mode. It will not affect the mobile dashboard after it is published. A mobile preview exactly simulates what we will see on the iPad. You can see a preview of a mobile dashboard in the following screenshot: You may notice that some components, such as a pie chart for example, will create a different user experience on the mobile preview compared to the desktop preview. This is because a desktop preview generates a flash file, whereas a mobile preview generates an HTML5 file. Publishing our mobile dashboard The next step is to publish our dashboard on the SAP BO server. We have the following options: Save to Platform | Mobile Only Save to Platform | Desktop Only Save to Platform | Desktop and Mobile We can access the Save to Platform menu from the File menu and see these options: The options are self-explanatory. The Mobile Only option will publish the dashboard as an HTML5 object only and can be accessed only from mobile devices. The Desktop Only option will generate a flash file and can be accessed only by desktop clients. Finally, the Desktop and Mobile option will generate both HTML5 and desktop, and can be accessed by both clients. Adding our dashboard to the mobile category After publishing our mobile dashboard, we need to make it available for mobile users. By default, any dashboard or report under the Mobile category will be displayed for mobile users. To do this, we should follow the steps: Access the BI Launch Pad (the URL will be <SAP_BO_SERVER_NAME:8080>/BOE/BI). Navigate to the folder that we used to publish our mobile dashboard. Right-click on that dashboard and add it to the Mobile category. You can see these steps in the following screenshot: You can see the last step here: You may need to refer to the SAP BusinessObjects administrator guide to get more information on how to set up and configure a mobile server on the SAP BO server. We used the default configuration settings here. Next, you will learn how to access it from an iPad or an Android tablet. Accessing and using mobile dashboards The first thing we need to do before accessing our mobile dashboard is to download the SAP BusinessObjects BI mobile application from the following links: Android: https://play.google.com/store/apps/details?id=com.sap.mobi&hl=en Mac OS: https://itunes.apple.com/en/app/sap-businessobjects-mobile/id441208302?mt=8 The most strongly recommended mobile device for displaying SAP BO dashboards is the iPad. Starting from SAP BO BI platform 4.1 SP1, we can also view SAP BO dashboards on Android tablets. Then, we need to configure SAP BO mobile application to connect to our server by following these steps: You may need to create a VPN, if you want to access your mobile dashboards from outside your organization. Open the SAP BO Mobile application (SAP BI). Tap on Connect and select Create New Connection. Enter BO Server in the connection name. Enter Mobile Server URL and CMC in the connection details (this information will depend on your SAP BO server information). Fill in Authentication Details (username and password). Establish the connection that you've already created. You should be able to see our eFashion dashboard. Tap it to display it on your tablet. Introducing the main features of the SAP BI application We can use the SAP BI application as a master place to view SAP BI content produced by different SAP BI tools, such as Web Intelligence, dashboards, Lumira, and so on. We can perform the following actions: Viewing document information and adding it to favorites Annotation E-mail For a complete user guide to SAP BI applications, refer to the following links: Mac OS: http://help.sap.com/bomobileios Android: https://help.sap.com/bomobileandroid Viewing document information and adding a document to favorites We can click on the three dots beside any BI document (report or dashboard) to view the document information (metadata), such as who the author is, and what the type of this document is. A small yellow star will appear on top of the document when it's added to favorites. You can see this menu in the following screenshot: Using the Annotation feature We can use this feature to take a screenshot of the current dashboard view and start annotating and adding our comments to it. Then, we can send it to the corresponding person. You can even add voice comments, which make it ideal to communicate results with others. This feature is shown here: E-mailing dashboards We can use this feature to e-mail the BI document to a specific person. It is the same as what we did in the annotation feature, except that it will send a plain image of the current view. Summary In this article, you learned how to create a mobile dashboard using SAP BO Dashboards. Then, we discussed how to find unsupported mobile dashboard components using the mobile compatibility panel. As a best practice, we should use the Mobile Only filter from the Components panel if we are targeting mobile devices for our dashboard. Next, you learned how to preview and publish your dashboard, so that it can be used and accessed by mobile devices. After that, we had an overview of the main features of a SAP BI mobile application, such as annotation and sharing via e-mails. Throughout this article, you learned how to create a dashboard step by step, starting from the analysis phase, right up to design and development. The main challenge that you will face later is how to present your information in a meaningful way, and how to get the maximum value of your information. I hope that you enjoyed reading this article, and I am looking forward to your input and    comments. Resources for Article: Further resources on this subject: Authorizations in SAP HANA [article] SAP HANA integration with Microsoft Excel [article] SAP HANA Architecture [article]
Read more
  • 0
  • 0
  • 3265

article-image-geolocating-photos-map
Packt
25 Mar 2015
7 min read
Save for later

Geolocating photos on the map

Packt
25 Mar 2015
7 min read
In this article by Joel Lawhead, author of the book, QGIS Python Programming Cookbook uses the tags to create locations on a map for some photos and provide links to open them. (For more resources related to this topic, see here.) Getting ready You will need to download some sample geotagged photos from https://github.com/GeospatialPython/qgis/blob/gh-pages/photos.zip?raw=true and place them in a directory named photos in your qgis_data directory. How to do it... QGIS requires the Python Imaging Library (PIL), which should already be included with your installation. PIL can parse EXIF tags. We will gather the filenames of the photos, parse the location information, convert it to decimal degrees, create the point vector layer, add the photo locations, and add an action link to the attributes. To do this, we need to perform the following steps: In the QGIS Python Console, import the libraries that we'll need, including k for parsing image data and the glob module for doing wildcard file searches: import globimport Imagefrom ExifTags import TAGS Next, we'll create a function that can parse the header data: def exif(img):   exif_data = {}   try:         i = Image.open(img)       tags = i._getexif()       for tag, value in tags.items():         decoded = TAGS.get(tag, tag)           exif_data[decoded] = value   except:       passreturn exif_data Now, we'll create a function that can convert degrees-minute-seconds to decimal degrees, which is how coordinates are stored in JPEG images: def dms2dd(d, m, s, i):   sec = float((m * 60) + s)   dec = float(sec / 3600)   deg = float(d + dec)   if i.upper() == 'W':       deg = deg * -1   elif i.upper() == 'S':       deg = deg * -1   return float(deg) Next, we'll define a function to parse the location data from the header data: def gps(exif):   lat = None   lon = None   if exif['GPSInfo']:             # Lat       coords = exif['GPSInfo']       i = coords[1]       d = coords[2][0][0]       m = coords[2][1][0]       s = coords[2][2][0]       lat = dms2dd(d, m ,s, i)       # Lon       i = coords[3]       d = coords[4][0][0]       m = coords[4][1][0]       s = coords[4][2][0]       lon = dms2dd(d, m ,s, i)return lat, lon Next, we'll loop through the photos directory, get the filenames, parse the location information, and build a simple dictionary to store the information, as follows: photos = {}photo_dir = "/Users/joellawhead/qgis_data/photos/"files = glob.glob(photo_dir + "*.jpg")for f in files:   e = exif(f)   lat, lon = gps(e) photos[f] = [lon, lat] Now, we'll set up the vector layer for editing: lyr_info = "Point?crs=epsg:4326&field=photo:string(75)"vectorLyr = QgsVectorLayer(lyr_info, "Geotagged Photos" , "memory")vpr = vectorLyr.dataProvider() We'll add the photo details to the vector layer: features = []for pth, p in photos.items():   lon, lat = p   pnt = QgsGeometry.fromPoint(QgsPoint(lon,lat))   f = QgsFeature()   f.setGeometry(pnt)   f.setAttributes([pth])   features.append(f)vpr.addFeatures(features)vectorLyr.updateExtents() Now, we can add the layer to the map and make the active layer: QgsMapLayerRegistry.instance().addMapLayer(vectorLyr)iface.setActiveLayer(vectorLyr)activeLyr = iface.activeLayer() Finally, we'll add an action that allows you to click on it and open the photo: actions = activeLyr.actions()actions.addAction(QgsAction.OpenUrl, "Photos", '[% "photo" %]') How it works... Using the included PIL EXIF parser, getting location information and adding it to a vector layer is relatively straightforward. This action is a default option for opening a URL. However, you can also use Python expressions as actions to perform a variety of tasks. The following screenshot shows an example of the data visualization and photo popup: There's more... Another plugin called Photo2Shape is available, but it requires you to install an external EXIF tag parser. Image change detection Change detection allows you to automatically highlight the differences between two images in the same area if they are properly orthorectified. We'll do a simple difference change detection on two images, which are several years apart, to see the differences in urban development and the natural environment. Getting ready You can download the two images from https://github.com/GeospatialPython/qgis/blob/gh-pages/change-detection.zip?raw=true and put them in a directory named change-detection in the rasters directory of your qgis_data directory. Note that the file is 55 megabytes, so it may take several minutes to download. How to do it... We'll use the QGIS raster calculator to subtract the images in order to get the difference, which will highlight significant changes. We'll also add a color ramp shader to the output in order to visualize the changes. To do this, we need to perform the following steps: First, we need to import the libraries that we need in to the QGIS console: from PyQt4.QtGui import *from PyQt4.QtCore import *from qgis.analysis import * Now, we'll set up the path names and raster names for our images: before = "/Users/joellawhead/qgis_data/rasters/change-detection/before.tif"|after = "/Users/joellawhead/qgis_data/rasters/change-detection/after.tif"beforeName = "Before"afterName = "After" Next, we'll establish our images as raster layers: beforeRaster = QgsRasterLayer(before, beforeName)afterRaster = QgsRasterLayer(after, afterName) Then, we can build the calculator entries: beforeEntry = QgsRasterCalculatorEntry()afterEntry = QgsRasterCalculatorEntry()beforeEntry.raster = beforeRasterafterEntry.raster = afterRasterbeforeEntry.bandNumber = 1afterEntry.bandNumber = 2beforeEntry.ref = beforeName + "@1"afterEntry.ref = afterName + "@2"entries = [afterEntry, beforeEntry] Now, we'll set up the simple expression that does the math for remote sensing: exp = "%s - %s" % (afterEntry.ref, beforeEntry.ref) Then, we can set up the output file path, the raster extent, and pixel width and height: output = "/Users/joellawhead/qgis_data/rasters/change-detection/change.tif"e = beforeRaster.extent()w = beforeRaster.width()h = beforeRaster.height() Now, we perform the calculation: change = QgsRasterCalculator(exp, output, "GTiff", e, w, h, entries)change.processCalculation() Finally, we'll load the output as a layer, create the color ramp shader, apply it to the layer, and add it to the map, as shown here: lyr = QgsRasterLayer(output, "Change")algorithm = QgsContrastEnhancement.StretchToMinimumMaximumlimits = QgsRaster.ContrastEnhancementMinMaxlyr.setContrastEnhancement(algorithm, limits)s = QgsRasterShader()c = QgsColorRampShader()c.setColorRampType(QgsColorRampShader.INTERPOLATED)i = []qri = QgsColorRampShader.ColorRampItemi.append(qri(0, QColor(0,0,0,0), 'NODATA'))i.append(qri(-101, QColor(123,50,148,255), 'Significant Itensity Decrease'))i.append(qri(-42.2395, QColor(194,165,207,255), 'Minor Itensity Decrease'))i.append(qri(16.649, QColor(247,247,247,0), 'No Change'))i.append(qri(75.5375, QColor(166,219,160,255), 'Minor Itensity Increase'))i.append(qri(135, QColor(0,136,55,255), 'Significant Itensity Increase'))c.setColorRampItemList(i)s.setRasterShaderFunction(c)ps = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, s)lyr.setRenderer(ps)QgsMapLayerRegistry.instance().addMapLayer(lyr) How it works... If a building is added in the new image, it will be brighter than its surroundings. If a building is removed, the new image will be darker in that area. The same holds true for vegetation, to some extent. Summary The concept is simple. We subtract the older image data from the new image data. Concentrating on urban areas tends to be highly reflective and results in higher image pixel values. Resources for Article: Further resources on this subject: Prototyping Arduino Projects using Python [article] Python functions – Avoid repeating code [article] Pentesting Using Python [article]
Read more
  • 0
  • 0
  • 3254
Modal Close icon
Modal Close icon