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

How-To Tutorials

7018 Articles
article-image-publishing-applications
Packt
02 Aug 2013
6 min read
Save for later

Publishing applications

Packt
02 Aug 2013
6 min read
(For more resources related to this topic, see here.) Step 1 – connecting with AppCenter AppCenter is installed along with the XenApp server; however, if required, it can be installed onto a client machine. Often AppCenter is run remotely by administrators who connect to the XenApp server's desktop. Use the following path to run AppCenter: Start|Administrative Tools | Citrix | Management Consoles | Citix AppCenter The first time the console is run, it is necessary to discover the farm. We can do this by selecting to add the local computer (this is usual if we are running AppCenter on the XenApp Server). Ensure that we only discover XenApp, and not Single Sign-on (SSO) servers. If connecting remotely from AppCenter to XenApp, instead of discovering the local computer, we would add the IP address of any XenApp Server in the farm and ensure we have connectivity on TCP port 2513. Step 2 – publishing an application using AppCenter When users connect to the Web Interface server, they are presented with a list of applications that they may access. To create published applications with AppCenter: If you want an application to appear in the list, it must be "published". Navigating to the Application node of AppCenter, we can use the right-click menu and select the option Publish Application. As we run through the wizard, for our example, we will choose to publish notepad.exe. Set the application name. Set the application type by selecting Application | Accessed from a Server | Installed application . Applications can be installed or streamed to servers. We can see from the following screenshot the application type page from the wizard: As the wizard continues, we choose the remaining options as follows: Set the executable's name and location. Set the servers that will host the application. This could be a list of server names from the farm, or the assignment could be to a group of servers known as a worker group . Assign user access to the application by selecting, most usually, domain groups on the users page of the wizard. Finally, we can choose to add the application to folders either on the web page or start menu depending on the type of access. The properties that we set here are the basic properties, and once set, the application can be published immediately. Step 3 – publishing applications using PowerShell Besides using the GUI AppCenter, it is also possible to add and configure published applications with PowerShell. The following steps will guide you to do the same: The PowerShell modules are installed along with the XenApp Server, but as with AppCenter, it can be added to client machines if required. If it is required to install the snap-ins independently to XenApp, we would navigate the installation DVD to the :AdministrationDelivery Services Consolesetup folder. From the Citrix.XenApp.Commands.Client.Install_x86 folder we can install the snap-ins for a 32-bit platform and from Citrix.XenApp.Commands.Client.Install_x64 for the 64-bit architecture. Once we have a PowerShell prompt open, we will need to load the required snap-in: Add-PSSnapin Citrix.XenApp.Commands With the snap-in loaded, we create the new application: New-XAApplication -BrowserName Notepad -ApplicationTypeServerInstalled -DisplayName Notepad -CommandLineExecutable"notepad.exe" -ServerNames XA1 The application can be associated with users with the following PowerShell command: Add-XAApplicationAccount Notepad "ExampleDomain Users" Finally, the application will need to be enabled with this last line of code: Set-XAApplication Notepad -Enabled $true Step 4 – publishing server desktops If required, users can access a server desktop. For this, the application type would be set to Server Desktop. By default, only administrators are allowed access to published desktops in XenApp. For other users, this can be enabled using Citrix Group Policies as shown in the following screenshot from a Citrix User Policy (Group Policies are covered in more detail later): Step 5 – publishing content The published content can be web URL or files on network shares accessible by the client from the XenApp Server. The content may be in the form of PDF documentation or in the form of access to intranet sites that the users will need access to. We can see from the following screenshot that we can provide shortcuts to web resources such as the licensing server web console: Step 6 – prelaunching applications You will soon note that launching an application for the first time takes a little time as the client device has to establish a session on the server. This involves running login scripts, evaluating policies, and loading the user's profile. Once the session is established, other applications launch more quickly on the same server as they share the existing session. The session exists until the user logs out from all applications. When accessing applications using the Web Interface Services Site with the Citrix Receiver, it is possible to configure session prelaunch. This is achieved by creating a prelaunch application from one of our published applications. When a user logs onto the receiver, a session is then created for him/her immediately or at a scheduled time. This gives faster access to the applications as the session pre-exists. A user license is used as soon as the user logs on onto the Receiver, not just when they launch apps. To create a prelaunch application, right-click on an existing application and from the context menu select Other Tasks | Create pre-launch application, as shown in the following screenshot: Step 7 – accessing published applications We are now ready to test the connection and we will connect to the Web Interface Web Site. The Web Interface Services Site is for direct connections from the Citrix Receiver; the Web Interface Web Site is used by the web browser and online plugins. The default Web Site will be http://<yourwebinterfaceserver>/Citrix/XenApp. You will be prompted for your username and password, and possibly your domain name. Once authenticated, you can see a list of your applications associated with your login, content, and desktops. From the following screenshot, we can see the published application, that is, Notepad: Summary We saw you how to perform one of the core tasks of XenApp: making applications available to remote users. We will do this by using the consoles and the command line using PowerShell. Resources for Article : Further resources on this subject: Getting Started with the Citrix Access Gateway Product Family [Article] Designing a XenApp 6 Farm [Article] Creating a sample C#.NET application [Article]
Read more
  • 0
  • 0
  • 6039

article-image-so-what-mongodb
Packt
02 Aug 2013
6 min read
Save for later

So, what is MongoDB?

Packt
02 Aug 2013
6 min read
(For more resources related to this topic, see here.) What is a document? While it may vary for various implementations of different Document Oriented Databases available, as far as MongoDB is concerned it is a BSON document, which stands for Binary JSON. JSON (JavaScript Object Notation) is an open standard developed for human readable data exchange. Though a thorough knowledge of JSON is not really important to understand MongoDB, for keen readers the URL to its RFC is http://tools.ietf.org/html/rfc4627. Also, the BSON specification can be found at http://bsonspec.org/. Since MongoDB stores the data as BSON documents, it is a Document Oriented Database. What does a document look like? Consider the following example where we represent a person using JSON: {"firstName":"Jack","secondName":"Jones","age":30,"phoneNumbers":[{fixedLine:"1234"},{mobile:"5678"}],"residentialAddress":{lineOne:"…",lineTwo:"…",city:"…",state:"…",zip:"…",country:"…"}} As we can see, a JSON document always starts and ends with curly braces and has all the content within these braces. Multiple fields and values are separated by commas, with a field name always being a string value and the value being of any type ranging from string, numbers, date, array, another JSON document, and so on. For example in "firstName":"Jack", the firstName is the name of the field whereas Jack is the value of the field. Need for MongoDB Many of you would probably be wondering why we need another database when we already have good old relational databases. We will try to see a few drivers from its introduction back in 2009. Relational databases are extremely rich in features. But these features don't come for free; there is a price to pay and it is done by compromising on the scalability and flexibility. Let us see these one by one. Scalability It is a factor used to measure the ease with which a system can accommodate the growing amount of work or data. There are two ways in which you can scale your system: scale up, also known as scale vertically or scale out, also known as scale horizontally. Vertical scalability can simply be put up as an approach where we say "Need more processing capabilities? Upgrade to a bigger machine with more cores and memory". Unfortunately, with this approach we hit a wall as it is expensive and technically we cannot upgrade the hardware beyond a certain level. You are then left with an option to optimize your application, which might not be a very feasible approach for some systems which are running in production for years. On the other hand, Horizontal scalability can be described as an approach where we say "Need more processing capabilities? Simple, just add more servers and multiply the processing capabilities". Theoretically this approach gives us unlimited processing power but we have more challenges in practice. For many machines to work together, there would be a communication overhead between them and the probability of any one of these machines being down at a given point of time is much higher. MongoDB enables us to scale horizontally easily, and at the same time addresses the problems related to scaling horizontally to a great extent. The end result is that it is very easy to scale MongoDB with increasing data as compared to relational databases. Ease of development MongoDB doesn't have the concept of creation of schema as we have in relational databases. The document that we just saw can have an arbitrary structure when we store them in the database. This feature makes it very easy for us to model and store relatively unstructured/ complex data, which becomes difficult to model in a relational database. For example, product catalogues of an e-commerce application containing various items and each having different attributes. Also, it is more natural to use JSON in application development than tables from relational world. Ok, it looks good, but what is the catch? Where not to use MongoDB? To achieve the goal of letting MongoDB scale out easily, it had to do away with features like joins and multi document/distributed transactions. Now, you must be wondering it is pretty useless as we have taken away two of the most important features of the relational database. However, to mitigate the problems of joins is one of the reasons why MongoDB is document oriented. If you look at the preceding JSON document for the person, we have the address and the phone number as a part of the document. In relational database, these would have been in separate tables and retrieved by joining these tables together. Distributed/Multi document transactions inhibit MongoDB to scale out and hence are not supported and nor there is a way to mitigate it. MongoDB still is atomic but the atomicity for inserts and updates is guaranteed at document level and not across multiple documents. Hence, MongoDB is not a good fit for scenarios where complex transactions are needed, such as in an OLTP banking applications. This is an area where good old relational database still rules. To conclude, let us take a look at the following image. This graph is pretty interesting and was presented by Dwight Merriman, Founder and CEO of 10gen, the MongoDB company in one of his online courses. As we can see, we have on one side some products like Memcached which is very low on functionality but high on scalability and performance. On the other end we have RDBMS (Relational Database Management System) which is very rich in features but not that scalable. According to the research done while developing MongoDB, this graph is not linear and there is a point in it after which the scalability and performance fall steeply on adding more features to the product. MongoDB sits on this point where it gives maximum possible features without compromising too much on the scalability and performance. Summary In this article, we saw the features displayed by MongoDB, how a document looks like, and how it is better than relational databases. Resources for Article : Further resources on this subject: Building a Chat Application [Article] Ruby with MongoDB for Web Development [Article] Comparative Study of NoSQL Products [Article]
Read more
  • 0
  • 0
  • 3355

article-image-configuring-alerts
Packt
02 Aug 2013
8 min read
Save for later

Configuring the alerts

Packt
02 Aug 2013
8 min read
(For more resources related to this topic, see here.) Getting ready Armed with knowledge on how to write rules, we could just toggle alerting levels for all rules individually. This would be tedious, unless we used a generic catchall. However, that would destroy the granularity and precision of OSSEC analysis. It would be better to combine the two to maintain granularity and get e-mail alerting down to reasonable levels. Every rule must set a level. The higher the level, the more severe the alert is considered. Alert levels are integers from 0 (ignore) to 15 (certain high-level security event). The official documentation has the definitive list of levels and their meanings and can be found via the following link: http://www.ossec.net/doc/manual/rules-decoders/rule-levels.html. Rules can also append groups to the alert metadata. OSSEC ships with a number of defaults, and you're able to create your own. Here are a few interesting groups from the default rule set: invalid_login, authentication_success, authentication_failed, connection_attempt, and attacks. Using just the level and group of an alert, you can configure a vast amount of alerts in a few lines of configuration. How to do it... Perform the following steps to configure alerts: To do this, start with configuring the default log and the e-mail level for the alerts as follows: <alerts> <log_alert_level>1</log_alert_level> <email_alert_level>7</email_alert_level></alerts> To increase the default level to 9, change a single character in the ossec.conf file as follows: <alerts> <log_alert_level>1</log_alert_level> <email_alert_level>9</email_alert_level></alerts> OSSEC reports feature provides a flexible way to send condensed reports to give you daily insight into alerts that are interesting, though not actionable as individual events. To configure a report of successful logins, add this to your ossec.conf file: <reports> <category>authentication_success</category> <user type="relation">srcip</user> <title>OSSEC: Authentication Report</title> <email_to>security.alerts@example.com</email_to></reports> How it works... The e-mail alerting defaults on large networks may inundate administrators in the alerts for the log lines containing the word error. Log level 8 is reserved for first-time events, and you may not want to know the first time every administrator logs into every server in the network. Given that, we can reasonably adjust the level of the e-mail alerts to level 9 that is reserved for Errors from Invalid Sources. This single-digit change may dramatically improve the volume of the alerts. You may wish to still receive periodic reports on the events not generating e-mails. The use of reports, alerts matching the source IDs, groups, or levels that are specified is summed up and broken down by key elements in the events: usernames, source IPs, event source hosts, levels, and groups. Our sample report generates a daily report of authentication history for all installed and active OSSEC agents. This happens to be a common requirement for PCI-DSS, SOX, FISMA, or FERPA. The report will contain an aggregation of various categories; here's a sampling of some interesting data: Report 'OSSEC: Authentication Report' completed.------------------------------------------------->Processed alerts: 1293->Post-filtering alerts: 120->First alert: 2013 May 10 02:00:02->Last alert: 2013 May 10 22:05:25Top entries for 'Source ip':------------------------------------------------192.168.0.1 |100127.0.0.1 |191.2.3.4 |1Top entries for 'Username':------------------------------------------------compliance_scanner |100root |19mallory |1Related entries for 'Username':------------------------------------------------compliance_scanner |120 srcip: '192.168.0.1'root |19 srcip: '127.0.0.1'mallory |1 srcip: '1.2.3.4' This report uses the relation attribute to aggregate users by source IP to generate the last stanza of the report. It provides some clarity on the Username and Source ip sections to let us know where particular users originated. Each report requires an email_to attribute to be set to valid. Another option that is often useful for very specific reports referencing a particular rule, or set of rules, is the showlogs option. Using this option, you can include a complete history of every log message that generated the alerts in the report. This option may generate large e-mails. To use it, add this to your report declaration: <showlogs>yes</showlogs> There's more... These basic tweaks provide a lot of value, but there are a few additional tweaks we can use to clear up a few noisy alerts and integrate OSSEC with existing security workflows. What is rule 1002 and why is it spamming me? Even when toggling the default alert level, you will notice that they occasionally receive alerts below the threshold set in the ossec.conf file. This is because some rules override this setting by explicitly setting the e-mail alert flag. The "bad words" rule, ID 1002, is another example that overrides the default e-mail behavior. The rule is defined as follows: <!-- Slightly modified for simplicity --><rule id="1002" level="2"> <match>failure|error|attack|bad |illegal|denied|refused|unauthorized</match> <options>alert_by_email</options> <description>Unknown problem somewhere in the system.</description></rule> This rule uses the alert_by_email option, which always alerts you regardless of the settings of the alert levels. Another set of rules that uses this override detects a restart of the OSSEC process. Rules that detect the start or stop of the OSSEC daemon also use this option to ensure that an e-mail alert is always sent. If you're not interested in these alerts, you can overwrite the rule and change its behavior using the overwrite attribute. This rule should be created in the local_rules.xml file as follows: <rule id="1002" level="2" overwrite="yes"> <match>failure|error|attack|bad |illegal|denied|refused|unauthorized</match> <options>no_email_alerts</options> <description>Unknown problem somewhere on the system (no_email_alert)</description></rule> We need to redefine the rule with our modifications because the overwrite flag replaces the existing rule of that source ID entirely. The purpose of this method in creating a new source ID is so other rules dependent on this rule will not need to also be rewritten to accommodate the change. The downside is that if an improvement to the default rule is made in an OSSEC release, you Playing nice with others Once at a larger scale, it may become more useful to integrate OSSEC's alert logs into a larger Security Information and Event Manager (SIEM) such as Splunk or ArcSight. Luckily, OSSEC also supports the logging of events via syslog. Any event that OSSEC logs, which is level 1 and above by default, is also written to syslog. OSSEC supports multiple logging formats, including the following: default: This is the default full syslog output that can be used in hybrid mode CEF: This refers to ArcSight's Common Event Format splunk: This is the key-value output json: This refers to JSON-encoded events; it is most useful for LogStash or Graylog2 To enable one or more syslog outputs, you just need to declare the server and port values. OSSEC uses UDP for all syslog events as follows: <syslog_output> <server>logserver.example.com</server> <port>514</port> <format>json</format></syslog_output> This is plain syslog traffic and will not be encrypted. You can change the level for which a certain syslog server receives events by setting the log level in the syslog definition: <syslog_output> <level>10</level> <server>critical-events.example.com</server> <port>514</port> <format>json</format></syslog_output> You can also route certain events by rule group as follows: <syslog_output> <group>authentication_success</group> <server>authenticationlogs.example.com</server> <port>514</port> <format>json</format></syslog_output> Or, you can also route specific events by the source ID directly: <syslog_output> <rule_id>1002</rule_id> <server>errors.example.com</server> <port>514</port> <format>json</format></syslog_output> You may choose to completely disable e-mail alerting from OSSEC and use this syslog mechanism to work within your existing SIEM workflow. Summary In this article we looked at various options for adjusting the alert volume for OSSEC HIDS. We started with some broad, sweeping approaches to decrease e-mails and gradually increased our granularity. We also explored the different channels for alerting. Resources for Article: Further resources on this subject: BackTrack Forensics [Article] Analyzing network forensic data (Become an expert) [Article] Digging into Windows Azure Diagnostics [Article]
Read more
  • 0
  • 0
  • 2344

article-image-classification-and-regression-trees
Packt
02 Aug 2013
23 min read
Save for later

Classification and Regression Trees

Packt
02 Aug 2013
23 min read
(For more resources related to this topic, see here.) Recursive partitions The name of the library package rpart, shipped along with R, stands for Recursive Partitioning . The package was first created by Terry M Therneau and Beth Atkinson , and is currently maintained by Brian Ripley . We will first have a peek at means recursive partitions are. A complex and contrived relationship is generally not identifiable by linear models. In the previous chapter, we saw the extensions of the linear models in piecewise, polynomial, and spline regression models. It is also well known that if the order of a model is larger than 4, then interpretation and usability of the model becomes more difficult. We consider a hypothetical dataset, where we have two classes for the output Y and two explanatory variables in X1 and X2. The two classes are indicated by filled-in green circles and red squares. First, we will focus only on the left display of Figure 1: A complex classification dataset with partitions , as it is the actual depiction of the data. At the outset, it is clear that a linear model is not appropriate, as there is quite an overlap of the green and red indicators. Now, there is a clear demarcation of the classification problem accordingly, as X1 is greater than 6 or not. In the area on the left side of X1=6, the mid-third region contains a majority of green circles and the rest are red squares. The red squares are predominantly identifiable accordingly, as the X2 values are either lesser than or equal to 3 or greater than 6. The green circles are the majority values in the region of X2 being greater than 3 and lesser than 6. A similar story can be built for the points on the right side of X1 greater than 6. Here, we first partitioned the data according to X1 values first, and then in each of the partitioned region, we obtained partitions according to X2 values. This is the act of recursive partitioning. Figure 1: A complex classification dataset with partitions Let us obtain the preceding plot in R. Time for action – partitioning the display plot We first visualize the CART_Dummy dataset and then look in the next subsection at how CART gets the patterns, which are believed to exist in the data. Obtain the dataset CART_Dummy from the RSADBE package by using data( CART_Dummy). Convert the binary output Y as a factor variable, and attach the data frame with CART_Dummy$Y <- as.factor(CART_Dummy$Y). attach(CART_Dummy) In Figure 1: A complex classification dataset with partitions , the red squares refer to 0 and the green circles to 1. Initialize the graphics windows for the three samples by using par(mfrow= c(1,2)). Create a blank scatter plot: plot(c(0,12),c(0,10),type="n",xlab="X1",ylab="X2"). Plot the green circles and red squares: points(X1[Y==0],X2[Y==0],pch=15,col="red") points(X1[Y==1],X2[Y==1],pch=19,col="green") title(main="A Difficult Classification Problem") Repeat the previous two steps to obtain the identical plot on the right side of the graphics window. First, partition according to X1 values by using abline(v=6,lwd=2). Add segments on the graph with the segment function: segments(x0=c(0,0,6,6),y0=c(3.75,6.25,2.25,5),x1=c(6,6,12,12),y1=c(3.75,6.25,2.25,5),lwd=2) title(main="Looks a Solvable Problem Under Partitions") What just happened? A complex problem is simplified through partitioning! A more generic function, segments, has nicely slipped in our program, which you may use for many other scenarios. Now, this approach of recursive partitioning is not feasible all the time! Why? We seldom deal with two or three explanatory variables and data points as low as in the preceding hypothetical example. The question is how one creates recursive partitioning of the dataset. Breiman, et. al. (1984) and Quinlan (1988) have invented tree building algorithms, and we will follow the Breiman, et. al. approach in the rest of book. The CART discussion in this book is heavily influenced by Berk (2008). Splitting the data In the earlier discussion, we saw that partitioning the dataset can benefit a lot in reducing the noise in the data. The question is how does one begin with it? The explanatory variables can be discrete or continuous. We will begin with the continuous (numeric objects in R) variables. For a continuous variable, the task is a bit simpler. First, identify the unique distinct values of the numeric object. Let us say, for example, that the distinct values of a numeric object, say height in cms, are 160, 165, 170, 175, and 180. The data partitions are then obtained as follows: data[Height<=160,], data[Height>160,] data[Height<=165,], data[Height>165,] data[Height<=170,], data[Height>170,] data[Height<=175,], data[Height>175,] The reader should try to understand the rationale behind the code, and certainly this is just an indicative one. Now, we consider the discrete variables. Here, we have two types of variables, namely categorical and ordinal . In the case of ordinal variables, we have an order among the distinct values. For example, in the case of the economic status variable, the order may be among the classes Very Poor, Poor, Average, Rich, and Very Rich. Here, the splits are similar to the case of continuous variable, and if there are m distinct orders, we consider m -1 distinct splits of the overall data. In the case of a categorical variable with m categories, for example the departments A to F of the UCBAdmissions dataset, the number of possible splits becomes 2m-1-1. However, the benefit of using software like R is that we do not have to worry about these issues. The first tree In the CART_Dummy dataset, we can easily visualize the partitions for Y as a function of the inputs X1 and X2. Obviously, we have a classification problem, and hence we will build the classification tree. Time for action – building our first tree The rpart function from the library rpart will be used to obtain the first classification tree. The tree will be visualized by using the plot options of rpart, and we will follow this up with extracting the rules of a tree by using the asRules function from the rattle package. Load the rpart package by using library(rpart). Create the classification tree with CART_Dummy_rpart <- rpart(Y~ X1+X2,data=CART_Dummy). Visualize the tree with appropriate text labels by using plot(CART_Dummy_rpart); text(CART_Dummy_rpart). Figure 2: A classification tree for the dummy dataset Now, the classification tree flows as follows. Obviously, the tree using the rpart function does not partition as simply as we did in Figure 1: A complex classification dataset with partitions , the working of which will be dealt within the third section of this chapter. First, we check if the value of the second variable X2 is less than 4.875. If the answer is an affirmation, we move to the left side of the tree; the right side in the other case. Let us move to the right side. A second question asked is whether X1 is lesser than 4.5 or not, and then if the answer is yes it is identified as a red square, and otherwise a green circle. You are now asked to interpret the left side of the first node. Let us look at the summary of CART_Dummy_rpart. Apply the summary, an S3 method, for the classification tree with summary( CART_Dummy_rpart). That one is a lot of output! Figure 3: Summary of a classification tree Our interests are in the nodes numbered 5 to 9! Why? The terminal nodes, of course! A terminal node is one in which we can't split the data any further, and for the classification problem, we arrive at a class assignment as the class that has a majority count at the node. The summary shows that there are indeed some misclassifications too. Now, wouldn't it be great if R gave the terminal nodes asRules. The function asRules from the rattle package extracts the rules from an rpart object. Let's do it! Invoke the rattle package library(rattle) and using the asRules function, extract the rules from the terminal nodes with asRules(CART_Dummy_rpart). The result is the following set of rules: Figure 4: Extracting "rules" from a tree! We can see that the classification tree is not according to our "eye-bird" partitioning. However, as a final aspect of our initial understanding, let us plot the segments using the naïve way. That is, we will partition the data display according to the terminal nodes of the CART_Dummy_rpart tree. The R code is given right away, though you should make an effort to find the logic behind it. Of course, it is very likely that by now you need to run some of the earlier code that was given previously. abline(h=4.875,lwd=2) segments(x0=4.5,y0=4.875,x1=4.5,y1=10,lwd=2) abline(h=1.75,lwd=2) segments(x0=3.5,y0=1.75,x1=3.5,y1=4.875,lwd=2) title(main="Classification Tree on the Data Display") It can be easily seen from the following that rpart works really well: Figure 5: The terminal nodes on the original display of the data What just happened? We obtained our first classification tree, which is a good thing. Given the actual data display, the classification tree gives satisfactory answers. We have understood the "how" part of a classification tree. The "why" aspect is very vital in science, and the next section explains the science behind the construction of a regression tree, and it will be followed later by a detailed explanation of the working of a classification tree. The construction of a regression tree In the CART_Dummy dataset, the output is a categorical variable, and we built a classification tree for it. The same distinction is required in CART, and we thus build classification trees for binary random variables, where regression trees are for continuous random variables. Recall the rationale behind the estimation of regression coefficients for the linear regression model. The main goal was to find the estimates of the regression coefficients, which minimize the error sum of squares between the actual regressand values and the fitted values. A similar approach is followed here, in the sense that we need to split the data at the points that keep the residual sum of squares to a minimum. That is, for each unique value of a predictor, which is a candidate for the node value, we find the sum of squares of y's within each partition of the data, and then add them up. This step is performed for each unique value of the predictor, and the value, which leads to the least sum of squares among all the candidates, is selected as the best split point for that predictor. In the next step, we find the best split points for each of the predictors, and then the best split is selected across the best split points across the predictors. Easy! Now, the data is partitioned into two parts according to the best split. The process of finding the best split within each partition is repeated in the same spirit as for the first split. This process is carried out in a recursive fashion until the data can't be partitioned any further. What is happening here? The residual sum of squares at each child node will be lesser than that in the parent node. At the outset, we record that the rpart function does the exact same thing. However, as a part of cleaner understanding of the regression tree, we will write raw R codes and ensure that there is no ambiguity in the process of understanding CART. We will begin with a simple example of a regression tree, and use the rpart function to plot the regression function. Then, we will first define a function, which will extract the best split given by the covariate and dependent variable. This action will be repeated for all the available covariates, and then we find the best overall split. This will be verified with the regression tree. The data will then be partitioned by using the best overall split, and then the best split will be identified for each of the partitioned data. The process will be repeated until we reach the end of the complete regression tree given by the rpart. First, the experiment! The cpus dataset available in the MASS package contains the relative performance measure of 209 CPUs in the perf variable. It is known that the performance of a CPU depends on factors such as the cycle time in nanoseconds (syct), minimum and maximum main memory in kilobytes (mmin and mmax), cache size in kilobytes (cach), and minimum and maximum number of channels (chmin and chmax). The task in hand is to model the perf as a function of syct, mmin, mmax, cach, chmin, and chmax. The histogram of perf—try hist(cpus$perf)—will show a highly skewed distribution, and hence we will build a regression tree for the logarithm transformation log10(perf). Time for action – the construction of a regression tree A regression tree is first built by using the rpart function. The getNode function is introduced, which helps in identifying the split node at each stage, and using it we build a regression tree and verify that we had the same tree as returned by the rpart function. Load the MASS library by using library(MASS). Create the regression tree for the logarithm (to the base 10) of perf as a function of the covariates explained earlier, and display the regression tree: cpus.ltrpart <- rpart(log10(perf)~syct+mmin+mmax+cach+chmin+chmax, data=cpus) plot(cpus.ltrpart); text(cpus.ltrpart) The regression tree will be indicated as follows: Figure 6: Regression tree for the "perf" of a CPU We will now define the getNode function. Given the regressand and the covariate, we need to find the best split in the sense of the sum of squares criterion. The evaluation needs to be done for every distinct value of the covariate. If there are m distinct points, we need m -1 evaluations. At each distinct point, the regressand needs to be partitioned accordingly, and the sum of squares should be obtained for each partition. The two sums of squares (in each part) are then added to obtain the reduced sum of squares. Thus, we create the required function to meet all these requirements. Create the getNode function in R by running the following code: getNode <- function(x,y) { xu <- sort(unique(x),decreasing=TRUE) ss <- numeric(length(xu)-1) for(i in 1:length(ss)) { partR <- y[x>xu[i]] partL <- y[x<=xu[i]] partRSS <- sum((partR-mean(partR))^2) partLSS <- sum((partL-mean(partL))^2) ss[i]<-partRSS + partLSS } return(list(xnode=xu[which(ss==min(ss,na.rm=TRUE))], minss = min(ss,na.rm=TRUE),ss,xu)) } The getNode function gives the best split for a given covariate. It returns a list consisting of four objects: xnode, which is a datum of the covariate x that gives the minimum residual sum of squares for the regressand y The value of the minimum residual sum of squares The vector of the residual sum of squares for the distinct points of the vector x The vector of the distinct x values We will run this function for each of the six covariates, and find the best overall split. The argument na.rm=TRUE is required, as at the maximum value of x we won't get a numeric value. We will first execute the getNode function on the syct covariate, and look at the output we get as a result: > getNode(cpus$syct,log10(cpus$perf))$xnode [1] 48 > getNode(cpus$syct,log10(cpus$perf))$minss [1] 24.72 > getNode(cpus$syct,log10(cpus$perf))[[3]] [1] 43.12 42.42 41.23 39.93 39.44 37.54 37.23 36.87 36.51 36.52 35.92 34.91 [13] 34.96 35.10 35.03 33.65 33.28 33.49 33.23 32.75 32.96 31.59 31.26 30.86 [25] 30.83 30.62 29.85 30.90 31.15 31.51 31.40 31.50 31.23 30.41 30.55 28.98 [37] 27.68 27.55 27.44 26.80 25.98 27.45 28.05 28.11 28.66 29.11 29.81 30.67 [49] 28.22 28.50 24.72 25.22 26.37 28.28 29.10 33.02 34.39 39.05 39.29 > getNode(cpus$syct,log10(cpus$perf))[[4]] [1] 1500 1100 900 810 800 700 600 480 400 350 330 320 300 250 240 [16] 225 220 203 200 185 180 175 167 160 150 143 140 133 125 124 [31] 116 115 112 110 105 100 98 92 90 84 75 72 70 64 60 [46] 59 57 56 52 50 48 40 38 35 30 29 26 25 23 17 The least sum of squares at a split for the best split value of the syct variable is 24.72, and it occurs at a value of syct greater than 48. The third and fourth list objects given by getNode, respectively, contain the details of the sum of squares for the potential candidates and the unique values of syct. The values of interest are highlighted. Thus, we will first look at the second object from the list output for all the six covariates to find the best split among the best split of each of the variables, by the residual sum of squares criteria. Now, run the getNode function for the remaining five covariates: getNode(cpus$syct,log10(cpus$perf))[[2]] getNode(cpus$mmin,log10(cpus$perf))[[2]] getNode(cpus$mmax,log10(cpus$perf))[[2]] getNode(cpus$cach,log10(cpus$perf))[[2]] getNode(cpus$chmin,log10(cpus$perf))[[2]] getNode(cpus$chmax,log10(cpus$perf))[[2]] getNode(cpus$cach,log10(cpus$perf))[[1]] sort(getNode(cpus$cach,log10(cpus$perf))[[4]],decreasing=FALSE) The output is as follows: Figure 7: Obtaining the best "first split" of regression tree The sum of squares for cach is the lowest, and hence we need to find the best split associated with it, which is 24. However, the regression tree shows that the best split is for the cach value of 27. The getNode function says that the best split occurs at a point greater than 24, and hence we take the average of 24 and the next unique point at 30. Having obtained the best overall split, we next obtain the first partition of the dataset. Partition the data by using the best overall split point: cpus_FS_R <- cpus[cpus$cach>=27,] cpus_FS_L <- cpus[cpus$cach<27,] The new names of the data objects are clear with _FS_R indicating the dataset obtained on the right side for the first split, and _FS_L indicating the left side. In the rest of the section, the nomenclature won't be further explained. Identify the best split in each of the partitioned datasets: getNode(cpus_FS_R$syct,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$mmin,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$mmax,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$cach,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$chmin,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$chmax,log10(cpus_FS_R$perf))[[2]] getNode(cpus_FS_R$mmax,log10(cpus_FS_R$perf))[[1]] sort(getNode(cpus_FS_R$mmax,log10(cpus_FS_R$perf))[[4]], decreasing=FALSE) getNode(cpus_FS_L$syct,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$mmin,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$mmax,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$cach,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$chmin,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$chmax,log10(cpus_FS_L$perf))[[2]] getNode(cpus_FS_L$mmax,log10(cpus_FS_L$perf))[[1]] sort(getNode(cpus_FS_L$mmax,log10(cpus_FS_L$perf))[[4]], decreasing=FALSE) The following screenshot gives the results of running the preceding R code: Figure 8: Obtaining the next two splits Thus, for the first right partitioned data, the best split is for the mmax value as the mid-point between 24000 and 32000; that is, at mmax = 28000. Similarly, for the first left-partitioned data, the best split is the average value of 6000 and 6200, which is 6100, for the same mmax covariate. Note the important step here. Even though we used cach as the criteria for the first partition, it is still used with the two partitioned data. The results are consistent with the display given by the regression tree, Figure 6: Regression tree for the "perf" of a CPU . The next R program will take care of the entire first split's right side's future partitions. Partition the first right part cpus_FS_R as follows: cpus_FS_R_SS_R <- cpus_FS_R[cpus_FS_R$mmax>=28000,] cpus_FS_R_SS_L <- cpus_FS_R[cpus_FS_R$mmax<28000,] Obtain the best split for cpus_FS_R_SS_R and cpus_FS_R_SS_L by running the following code: cpus_FS_R_SS_R <- cpus_FS_R[cpus_FS_R$mmax>=28000,] cpus_FS_R_SS_L <- cpus_FS_R[cpus_FS_R$mmax<28000,] getNode(cpus_FS_R_SS_R$syct,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$mmin,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$mmax,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$cach,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$chmin,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$chmax,log10(cpus_FS_R_SS_R$perf))[[2]] getNode(cpus_FS_R_SS_R$cach,log10(cpus_FS_R_SS_R$perf))[[1]] sort(getNode(cpus_FS_R_SS_R$cach,log10(cpus_FS_R_SS_R$perf))[[4]], decreasing=FALSE) getNode(cpus_FS_R_SS_L$syct,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$mmin,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$mmax,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$cach,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$chmin,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$chmax,log10(cpus_FS_R_SS_L$perf))[[2]] getNode(cpus_FS_R_SS_L$cach,log10(cpus_FS_R_SS_L$perf))[[1]] sort(getNode(cpus_FS_R_SS_L$cach,log10(cpus_FS_R_SS_L$perf))[[4]],decreasing=FALSE) For the cpus_FS_R_SS_R part, the final division is according to cach being greater than 56 or not (average of 48 and 64). If the cach value in this partition is greater than 56, then perf (actually log10(perf)) ends in the terminal leaf 3, else 2. However, for the region cpus_FS_R_SS_L, we partition the data further by the cach value being greater than 96.5 (average of 65 and 128). In the right side of the region, log10(perf) is found as 2, and a third level split is required for cpus_FS_R_SS_L with cpus_FS_R_SS_L_TS_L. Note that though the final terminal leaves of the cpus_FS_R_SS_L_TS_L region shows the same 2 as the final log10(perf), this may actually result in a significant variability reduction of the difference between the predicted and the actual log10(perf) values. We will now focus on the first main split's left side. Figure 9: Partitioning the right partition after the first main split Partition cpus_FS_L accordingly, as the mmax value being greater than 6100 or otherwise: cpus_FS_L_SS_R <- cpus_FS_L[cpus_FS_L$mmax>=6100,] cpus_FS_L_SS_L <- cpus_FS_L[cpus_FS_L$mmax<6100,] The rest of the partition for cpus_FS_L is completely given next. The details will be skipped and the R program is given right away: cpus_FS_L_SS_R <- cpus_FS_L[cpus_FS_L$mmax>=6100,] cpus_FS_L_SS_L <- cpus_FS_L[cpus_FS_L$mmax<6100,] getNode(cpus_FS_L_SS_R$syct,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$mmin,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$mmax,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$cach,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$chmin,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$chmax,log10(cpus_FS_L_SS_R$perf))[[2]] getNode(cpus_FS_L_SS_R$syct,log10(cpus_FS_L_SS_R$perf))[[1]] sort(getNode(cpus_FS_L_SS_R$syct,log10(cpus_FS_L_SS_R$perf))[[4]], decreasing=FALSE) getNode(cpus_FS_L_SS_L$syct,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$mmin,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$mmax,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$cach,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$chmin,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$chmax,log10(cpus_FS_L_SS_L$perf))[[2]] getNode(cpus_FS_L_SS_L$mmax,log10(cpus_FS_L_SS_L$perf))[[1]] sort(getNode(cpus_FS_L_SS_L$mmax,log10(cpus_FS_L_SS_L$perf))[[4]],decreasing=FALSE) cpus_FS_L_SS_R_TS_R <- cpus_FS_L_SS_R[cpus_FS_L_SS_R$syct<360,] getNode(cpus_FS_L_SS_R_TS_R$syct,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$mmin,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$mmax,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$cach,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$chmin,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$chmax,log10(cpus_FS_L_SS_R_TS_R$ perf))[[2]] getNode(cpus_FS_L_SS_R_TS_R$chmin,log10(cpus_FS_L_SS_R_TS_R$ perf))[[1]] sort(getNode(cpus_FS_L_SS_R_TS_R$chmin,log10(cpus_FS_L_SS_R_TS_R$perf))[[4]],decreasing=FALSE) We will now see how the : Figure 10: Partitioning the left partition after the first main split We leave it to you to interpret the output arising from the previous action. What just happened? Using the rpart function from the rpart library we first built the regression tree for log10(perf). Then, we explored the basic definitions underlying the construction of a regression tree and defined the getNode function to obtain the best split for a pair of regressands and a covariate. This function is then applied for all the covariates, and the best overall split is obtained; using this we get our first partition of the data, which will be in agreement with the tree given by the rpart function. We then recursively partitioned the data by using the getNode function and verified that all the best splits in each partitioned data are in agreement with the one provided by the rpart function. The reader may wonder if the preceding tedious task was really essential. However, it has been the experience of the author that users/readers seldom remember the rationale behind using direct code/functions for any software after some time. Moreover, CART is a difficult concept and it is imperative that we clearly understand our first tree, and return to the preceding program whenever the understanding of a science behind CART is forgotten. Summary We began with the idea of recursive partitioning and gave a legitimate reason as to why such an approach is practical. The CART technique is completely demystified by using the getNode function, which has been defined appropriately depending upon whether we require a regression or a classification tree. Resources for Article : Further resources on this subject: Organizing, Clarifying and Communicating the R Data Analyses [Article] Graphical Capabilities of R [Article] Customizing Graphics and Creating a Bar Chart and Scatterplot in R [Article]
Read more
  • 0
  • 0
  • 3675

article-image-securing-data-cell-level-intermediate
Packt
01 Aug 2013
4 min read
Save for later

Securing data at the cell level (Intermediate)

Packt
01 Aug 2013
4 min read
(For more resources related to this topic, see here.) Getting ready The following prerequisite is essential for our recipe to continue the recipe: SQL Server 2012 Management Studio (SSMS). The AdventureWorks2012 database. We can obtain the necessary database files and database product samples from SQL Server Database Product Samples landing page (http://msftdbprodsamples.codeplex.com/releases/view/55330). These sample databases cannot be installed on any version of SQL Server other than SQL Server 2012 RTM or higher. Ensure you install the databases to your specified 2012 version instance. For this article I have created a new OLAP database using the AdventureWorksDM.xmlafile. Also, ensure that the user who is granting permissions is a member of Analysis Services server role or member of Analysis Services database role that has Administrator permissions. How to do it... The following steps are continued from the previous recipe, but I believe it is necessary to reiterate them from the beginning. Hence, this recipe's steps are listed as follows: Start the SQL Server Management Studio and connect to the SQL Server 2012 Analysis Services instance. Expand the Databases folder. Choose the AdventureWorksDM database (created within the Getting ready section as previously mentioned) and expand the Roles folder. If you are reading this recipe directly without the previous recipes, you can create the necessary roles as per the Creating security roles(Intermediate) recipe. Right-click on the role (here I have selected the DBIA_Processor role) to choose Role Properties. Click on Cell Data on the Select a page option to present a relevant permissions list. In some cases, if you have observed that there is no option available in the Cube drop-down list in the Cell Data option, ensure you check that the relevant cube is set with appropriate Access and Local Cube/Drillthrough options by choosing the Cubes option on the left-hand side on Select a page. Refer to the following screenshot: Now let us continue with the Cell Data options: Click on Cell Data in the Select a page option to present a relevant permissions list. Select the appropriate cube from the drop-down list; here I have selected the Adventure Works DW2012 cube. Choose the Enable read permissions option and then click on the Edit MDX button. You will be presented with the MDX Builder screen. Then, choose the presented Metadata measure value to grant this permission. Similarly, for the Enable read-contingent permissions option, follow the previous step. Finally, click on the Enable read/write permissions option. As a final check, either we can click on the Check button or the OK button, which will check whether valid syntax is parsed from the MDX expressions previously mentioned. If there are any syntax errors, you can fix them by choosing the relevant Edit MDX button to correct. This completes the steps to secure the data at the cell level using a defined role in the Analysis Services database. How it works... There are a few guidelines and some contextual information that will help us understand how we can best secure the data in a cell. Nevertheless, whether the database role has read, read-contingent, or read/write permissions to the cell data, we need to ensure that we are granting permissions to derived cells correctly. By default, a derived cell obtains the relevant data from the other cells. So, the appropriate database role has the required permissions to the derived cell but not to the cells from which the derived cell obtain its values. Irrespective of the database role, whether the members have read or write permissions on some or all the cells within a cube, the members of the database role have no permissions to view any cube data. Once the denied permissions on certain dimensions are effective, the cell level security cannot expand the rights of the database role members to include cell members from that dimension. The blank expression within the relevant box will have no effect in spite of clicking on Enable read/write permissions. Summary Many databases insufficiently implement security through row- and column-level restrictions. Column-level security is only sufficient when the data schema is static, well known, and aligned with security concerns. Row-level security breaks down when a single record conveys multiple levels of information. The ability to control access at the cell level based on security labels, intrinsically within the relational engine, is an unprecedented capability. It has the potential to markedly improve the management of sensitive information in many sectors, and to enhance the ability to leverage data quickly and flexibly for operational needs. This article showed us just how to secure the data at the cell level. Resources for Article: Further resources on this subject: Getting Started with Microsoft SQL Server 2008 R2 [Article] Microsoft SQL Server 2008 High Availability: Installing Database Mirroring [Article] SQL Server and PowerShell Basic Tasks [Article]
Read more
  • 0
  • 0
  • 7996

article-image-making-simple-curl-request-simple
Packt
01 Aug 2013
5 min read
Save for later

Making a simple cURL request (Simple)

Packt
01 Aug 2013
5 min read
(For more resources related to this topic, see here.) Getting ready In this article we will use cURL to request and download a web page from a server. How to do it... Enter the following code into a new PHP project: <?php // Function to make GET request using cURL function curlGet($url) { $ch = curl_init(); // Initialising cURL session // Setting cURL options curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_URL, $url); $results = curl_exec($ch); // Executing cURL session curl_close($ch); // Closing cURL session return $results; // Return the results } $packtPage = curlGet('http://www.packtpub.com/oop-php-5/book'); echo $packtPage; ?> Save the project as 2-curl-request.php (ensure you use the .php extension!). Execute the script. Once our script has completed, we will see the source code of http://www.packtpub.com/oop-php-5/book displayed on the screen. How it works... Let's look at how we performed the previously defined steps: The first line, <?php, and the last line,?>, indicate where our PHP code block will begin and end. All the PHP code should appear between these two tags. Next, we create a function called curlGet(), which accepts a single parameter $url, the URL of the resource to be requested. Running through the code inside the curlGet() function, we start off by initializing a new cURL session as follows: $ch = curl_init(); We then set our options for cURL as follows: curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Tells cURL to return the results of the request (the source code of the target page) as a string. curl_setopt($ch, CURLOPT_URL, $url); // Here we tell cURL the URL we wish to request, notice that it is the $url variable that we passed into the function as a parameter. We execute our cURL request, storing the returned string in the $results variable as follows: $results = curl_exec($ch); Now that the cURL request has been made and we have the results, we close the cURL session by using the following code: curl_close($ch); At the end of the function, we return the $results variable containing our requested page, out of the function for using in our script. return $results; After the function is closed we are able to use it throughout the rest of our script. Later, deciding on the URL we wish to request, http://www.packtpub.com/oop-php-5/book , we execute the function, passing the URL as a parameter and storing the returned data from the function in the $packtPage variable as follows: $packtPage = curlGet('http://www.packtpub.com/oop-php-5/book'); Finally, we echo the contents of the $packtPage variable (the page we requested) to the screen by using the following code: echo $packtPage; There's more... There are a number of different HTTP request methods which indicate the server the desired response, or the action to be performed. The request method being used in this article is cURLs default GET request. This tells the server that we would like to retrieve a resource. Depending on the resource we are requesting, a number of parameters may be passed in the URL. For example, when we perform a search on the Packt Publishing website for a query, say, php, we notice that the URL is http://www.packtpub.com/books?keys=php. This is requesting the resource books (the page that displays search results) and passing a value of php to the keys parameter, indicating that the dynamically generated page should show results for the search query php. More cURL Options Of the many cURL options available, only two have been used in our preceding code. They are CURLOPT_RETURNTRANSFER and CURLOPT_URL. Though we will cover many more throughout the course of this article, some other options to be aware of, that you may wish to try out, are listed in the following table: Option Name Value Purpose CURLOPT_FAILONERROR TRUE or FALSE If a response code greater than 400 is returned, cURL will fail silently. CURLOPT_FOLLOWLOCATION TRUE or FALSE If Location: headers are sent by the server, follow the location. CURLOPT_USERAGENT A user agent string, for example: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:15.0) Gecko/20100101 Firefox/15.0.1' Sending the user agent string in your request informs the target server, which client is requesting the resource. Since many servers will only respond to 'legitimate' requests it is advisable to include one. CURLOPT_HTTPHEADER An array containing header information, for example: array('Cache-Control: max-age=0', 'Connection: keep-alive', 'Keep-Alive: 300', 'Accept-Language: en-us,en;q=0.5') This option is used to send header information with  the request and we will come across use cases for this in later recipes. A full listing of cURL options can be found on the PHP website at http://php.net/manual/en/function.curl-setopt.php. The HTTP response code An HTTP response code is the number that is returned, which corresponds with the result of an HTTP request. Some common response code values are as follows: 200: OK 301: Moved Permanently 400: Bad Request 401: Unauthorized 403: Forbidden 404: Not Found 500: Internal Server Error Summary This article covers techniques on making a simple cURL request. It is often useful to have our scrapers responding to different response code values in a different manner, for example, letting us know if a web page has moved, or is no longer accessible, or we are unauthorized to access a particular page. In this case, we can access the response of a request using cURL by adding the following line to our function, which will store the response code in the $httpResponse variable: $httpResponse = curl_getinfo($ch, CURLINFO_HTTP_CODE); Resources for Article: Further resources on this subject: A look into the high-level programming operations for the PHP language [Article] Installing PHP-Nuke [Article] Creating Your Own Theme—A Wordpress Tutorial [Article]
Read more
  • 0
  • 0
  • 3722
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
Packt
01 Aug 2013
12 min read
Save for later

Vaadin – Using Input Components and Forms

Packt
01 Aug 2013
12 min read
(For more resources related to this topic, see here.) The Time It application A couple of years ago I was working with some friends on a personal Java project. We used to meet every Saturday to review what we had done before building the entire system. Let me introduce you to my friends: Susan Obstinate and Mark Nowsitall (weird last names, aren't they?). "I've spent the entire week writing this code, but it's ready now," said Susan with an embittered tone. "Let me see how you handled that," replied Mark suspiciously. Though they didn't seem to be, they were a couple. So Susan proudly showed us her piece of code: // some nasty code was here (censored for respect of the reader) public String getUglyUrl(long total) { String url = "http://localhost/app/someservice?code="; for(long i = 0; i < total; i++) { url += someTrickyMath(i); } return url; } public String someTrickyMath(long i) { // (censored) } "We can use an int object type instead of long for the loop in your getUglyUrl method," instantly affirmed Mark. "I don't think we need that," said Susan. "You could also use a StringBuilder class to..." I started to say, but suddenly got interrupted by Mark. "An int object type would improve performance a lot. The int comparisons and manipulations are faster than long ones," Mark explained. "What if the total gets too big? We'd need a long object type then," Susan argued. "Total has never gone beyond 10,000 and I highly doubt it will in the near future," Mark replied. We (actually it was Mark) finally managed to convince Susan to change her code. There are lots of situations similar to this one, more complicated, and with tons of external factors that make it hard to be 100 percent sure about which of two code strategies will work faster. Let's take advantage of this story and develop a nice Vaadin application for timing code. Introducing: Time It! The application that will show some facts to Susan. Time for action – separating business classes from UI classes Vaadin is mostly about UI. Vaadin's motto thinking of U and I is not in vain. I said mostly because you can additionally find a bunch of useful add-ons to deal with server-side technologies. Even Vaadin itself ships with some data components. Most, if not all, applications have some kind of business logic. That is, something to do with the application's data. If you are an experienced developer you will agree with me that separating business logic from UI logic makes a lot of sense. For the "Time It" application, we will use two Java packages to separate business logic from UI logic: Create a new Vaadin project named time-it using your IDE. Delete the all the generated classes. We will add our own classes in a minute. Create the following package. Don't worry about the classes right now. Just create the Java packages timeit, timeit.biz, timeit.biz.test, and timeit.ui: Browse the book's source code and copy all the classes inside the biz package and paste them into your own biz package. Don't copy TimeItUI.java, we will work on that through the article. Create a new class with the TimeItUI name inside the ui package. Update your web.xml file to use TimeItUI as the starting application: <servlet> <servlet-name>Time It</servlet-name> <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <description> Vaadin UI class to use</description> <param-name>UI</param-name> <param-value>timeit.ui.TimeItUI</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Time It</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> Let's start with an outline of our TimeItUI class. Modify your TimeItUI class to match something like this: public class TimeItUI extends UI { ... some variables ... @Override protected void init(VaadinRequest request) { ... } private void initCombo() { ... } private void initButton() { ... } private void initLayout() { ... } public boolean validate() { ... } public void runSelectedTest() { ... } private void showResults(Collection<String> results) { ... } } What just happened? Of course, the TimeItUI class won't compile. But now you have an outline with the structure of methods we will implement through the article. Just keep reading. Most of the application is about business (the biz package) with only one class handling our UI logic. However, we will focus on the UI part. Business classes are not puzzling at all. We will use them as black boxes in our TimeItUI class (that's the reason we are just copying them). Time for action – adding components as class members To add UI components as class members, edit your TimeItUI class by adding these variables to it: private static final TestSet[] testSets = new TestSet[] { new LongVsInt(), new StringVsStringBuffer(), new ShortCircuitVsNoShortCircuit() }; private VerticalLayout layout = new VerticalLayout(); private ComboBox combo = new ComboBox("Test"); private final TextField textField = new TextField("Number of iterations", "1000"); private CheckBox checkBox = new CheckBox("Keep previous results"); private Button button = new Button("Time it!"); private VerticalLayout resultsLayout = new VerticalLayout(); What just happened? The first thing you see, testSets, is just an array of business objects, specifically, an array containing instances of TestSet (take a look at the TestSet interface in the book's source code). Think of TestSet as a single scenario from which we want to obtain timing results. For example, the LongVsInt class will run two tests: one to time a loop controlled by a long object type and another to time a loop controlled by an int object type. If you want to add some testing scenarios, all you must do is to implement the TestSet interface and add a new instance to the testSets array. Time for action – adding some infrastructure Edit the init method of your TimeItUI class to match the following: @Override protected void init(VaadinRequest request) { initCombo(); initButton(); initLayout(); } What just happened? Here we are breaking up the functionality to initialize our UI components in a more suitable way by implementing smaller methods. Now that we have the required infrastructure, we can start adding input components. Comboboxes A combobox is an input component that allows users to select an option from a drop-down list. It looks like the following screenshot: You must be thinking "yeah right, but how do you put those options in there?" This is easy: ComboBox c = new ComboBox("Select an option"); c.addItem("Option one"); c.addItem("Option two"); c.addItem("Option three"); If you have the options in a Java Collection class, you can pass the Collection instance to the constructor like this: ArrayList<String> options = new ArrayList<>(); options.add("Option 1"); options.add("Option 2"); options.add("Option 3"); ComboBox c = new ComboBox("Select an option", options); The method addItem accepts an Object, so we can pass instances of any class. For example, if we had a User class we could have done this: User user1 = new User("Jurka", "Rahikkala"); User user2 = new User("Joonas", "Lehtinen"); ComboBox c = new ComboBox("Select a user"); c.addItem(user1); c.addItem(user2); Now, how will the ComboBox component know what to print as option captions? First, let's go back to our "Time It" application. Time for action – adding a combobox Implement the initCombo method of your TimeItUI class as shown in the following code snippet: private void initCombo() { for(TestSet testSet : testSets) { combo.addItem(testSet); combo.setitemCaption(testSet, testSet.getTitle()); } combo.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { TestSet testSet = (TestSet) combo.getValue(); textField.setValue("" + testSet.getDefaultTimes()); button.setDescription(testSet.getDescription()); } }); combo.setimmediate(true); } What just happened? It's not that complicated. If we isolate the for portion of the previous code, we'll get this: for(TestSet testSet : testSets) { combo.addItem(testSet); combo.setitemCaption(testSet, testSet.getTitle()); } For each TestSet instance in our array, we add a TestSet instance and then we say, "Okay, Vaadin for this testSet array I just added, please show what testSet.getTitle() returns. Thank you very much". We are adding instances of TestSet and explicitly specifying what we want to be shown for each option inside the ComboBox component. Responding to value changes So, we have our combo ready and showing all available tests. If you have already played with the application, you may have noted that when you select a test, the number of iterations shown in the text field and the button tooltip explaining the test are updated accordingly. Well, the rest of the initCombo method implements this functionality. Here, We are adding a ValueChangeListener instance to execute our code when the user selects an option: combo.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { // your code here } }); Getting and setting the value of input components The user selects one option, the valueChange method of our anonymous listener is called, and now we can update the value in textField. That's one line of code: textField.setValue(theValue); Wait... how do we know what is the selected value in the combobox? If setValue is for setting the value, then getValue is for getting the value! Unbelievable! Let's get the value: TestSet testSet = (TestSet) combo.getValue(); Now that we have the value, we can easily set the text in the textField: textField.setValue("" + testSet.getDefaultTimes()); We've just learned something valuable (it's not wordplay): input components, they all have the getValue and setValue methods. Tooltips A tooltip is boxed text that appears when the user holds the mouse pointer over a UI element. The following screenshot shows a Vaadin tooltip: Adding tooltips is a piece of cake. All we need to do is the following: button.setDescription(testSet.getDescription()); Most UI components include this method. You can put any HTML you want to nicely format your tooltips. Immediate mode There is just one final line that we have not explained yet in the initCombo method: combo.setimmediate(true); This makes the component respond as soon as the user changes its value (and after the component loses focus). If we don't put this line, when the user changes the value, Vaadin could say "Okay, I will wait for some more events before I send that change in combo". This is not only for the ComboBox component, all input components have this method too. Error indicators We must provide feedback to the user when the input is incorrect. Error indicators are a way to provide such feedback. Time for action – validating user input We can run a TestSet instance only if the user selects one. Follow these steps to add a proper validation: Implement your initButton method to match this code: private void initButton() { button.addClickListener(new ClickListener() { @Override public void buttonClick(ClickEvent event) { if(isValid()) { runSelectedTest(); } } }); } Now implement your validate method. Here is how we validate: public boolean isValid() { combo.setComponentError(null); textField.setComponentError(null); boolean isValid = true; if(combo.getValue() == null) { combo.setComponentError( boolean isValid = true; if(combo.getValue() == null) { combo.setComponentError( new UserError("Select a test from the list.")); isValid = false; } if(textField.getValue().toString().isEmpty()) { textField.setComponentError(new UserError( "You must introduce the number of iterations to execute")); isValid = false; } return isValid; } What just happened? We have a button and we want to respond to click events, so we add ClickListener, using an anonymous class. As you can see, if the isValid method returns true, we proceed to run the selected test. First two lines of the method are for clearing any error we may have added to the components in previous executions of the isValid method itself. Then, we declare a flag that will tell us whether the components have valid values or not. If the selected value in combo is null, we add an error message to the component using the following code line: combo.setComponentError(new UserError("Select a test from the list.")); setComponentError expects an instance of ErrorMessage. UserError is an implementation of the ErrorMessage interface that allows us to show an error message on the component. Usually, the component will show an error indicator. If the user places the mouse cursor over the component, a tooltip will appear showing the error text: A similar logic is used to show an error over textField if the users left it empty. Layout spacing We have our components ready. We know how they respond to events (clicks and value changes) and how they communicate. We still have to know how the tests are executed and how the results are shown. But first, let's incorporate all those components into the main layout. Time for action – adding input component into the layout Implement your initLayout method using the following snippet of code: private void initLayout() { layout.setMargin(true); layout.setSpacing(true); layout.addComponent(combo); layout.addComponent(textField); layout.addComponent(checkBox); layout.addComponent(button); layout.addComponent(resultsLayout); setContent(layout); } What just happened? We let the layout to have an appropriate margin and spacing. This last one adds some space between components instead of having them bonded inside the layout. Following that, we add combo, textField, checkBox, button, and a VerticalLayout component to put some labels for showing the results of the test case execution. Finally, the last statement sets layout as content of the page. Checkboxes Everyone knows checkboxes. Have you ever accepted license agreements during software installations? Just in case, this is a checkbox: We have already created our checkbox: private CheckBox checkBox = new CheckBox("Keep previous results"); Removing components from layouts Before explaining how we show the results, let's see how we can execute the selected TestSet instance.
Read more
  • 0
  • 0
  • 2668

article-image-jsf2-composite-component-primefaces
Packt
31 Jul 2013
9 min read
Save for later

JSF2 composite component with PrimeFaces

Packt
31 Jul 2013
9 min read
(For more resources related to this topic, see here.) The Contacts tab is where users can connect with their friends, family, and colleagues and chat online. For this screen let's write a JSF2 composite component that can render any list of User objects for desktop and mobile browsers. In preceding screenshot, we use a JSF2 composite component to render groups of contacts for the user. When a contact has signed in, his or her avatar image is highlighted to show presence. Clicking on a contact opens a live chat dialog that showcases the PrimeFaces Push technology. We enable our JSF2 composite component to be integrated in a mobile UI based on PrimeFaces Mobile. In this mode, our component renders a simpler, mobile-friendly UI with some special CSS and JavaScript to leverage the PrimeFaces Mobile API. Our contactList composite component has three attributes: header: Specifies the text to be displayed above the contacts value: Binds the component to any list of Userobjects mobile: Set to true for mobile display mode We can use our <mycompany:contactList> tag to display a list of friends, family, and colleagues. Notice that we use the PrimeFaces poll component to check every 10 seconds to see if one of our contacts has logged in. <h:form id="contactsForm"><p:poll update="contactsPanel" interval="10" />...<p:accordionPanel id="contactsPanel" multiple="true"><p:tab title="Friends"><mycompany:contactList header="Friends" value="#{contactsController.friends}" /></p:tab>...</p:accordionPanel></h:form> Let's see how we developed this component. First we declared the composite component's interface: <composite:interface><composite:attribute name="value" required="true" /><composite:attribute name="header" required="false" default="People" /><composite:attribute name="mobile" required="false" default="false" /></composite:interface> Next, we implement the composite component using the PrimeFaces carousel component for desktop, and the simpler PrimeFaces dataList component for mobile. Notice that we use the boolean mobile attribute declared in our component interface in our rendering logic by using the #{cc.attrs.mobile} EL expression. If the mobile attribute is true, we render the mobile UI, otherwise we show the desktop UI. <composite:implementation><p:carousel style="width:100%" value="#{cc.attrs.value}" var="person" numVisible="4" rendered="#{not empty cc.attrs.value and not cc.attrs.mobile}" itemStyleClass="person-item"><f:facet name="header"><h:outputText value="#{cc.attrs.header}" /></f:facet><h:panelGrid columns="1" style="width:100%"><p:commandLink value="Chat" onclick="chatDialogWidget.show()" update=":chatForm:chatPanel" actionListener="#{chatController.beginChat}" disabled="#{!userController.isUserPresent(person)}" /><h:outputText value="#{person.firstName}" /><p:graphicImage value="#{resource['images:user-icon.png']}" width="75" rendered="#{userController.isUserPresent(person)}" /><p:graphicImage value="#{resource['images:offline-user- icon.png']}"width="75" rendered="#{!userController.isUserPresent(person)}" /></h:panelGrid><f:facet name="footer"><h:outputText value="Total: #{cc.attrs.value.size()}" /></f:facet></p:carousel><!-- Mobile UI --><p:dataList style="width:110%" value="#{cc.attrs.value}" var="person" id="mobileContactList" rendered="#{not empty cc.attrs.value and cc.attrs.mobile}" itemStyleClass="mobile-person-item"><f:attribute name="filter" value="true" /><h:panelGroup rendered="#{userController.isUserPresent(person)}"><h:outputLink value="#chat" onclick="beginMobileChat()"><p:graphicImage value="#{resource['images:user-icon.png']}" width="50" style="text-align:left; vertical-align:middle; margin-top:15px" /><h:outputText value="#{person.firstName}" style="display:block; margin-top:18px; font-size:0.9em" /></h:outputLink></h:panelGroup><h:panelGroup rendered="#{!userController.isUserPresent(person)}"><p:graphicImage value="#{resource['images:offline-user- icon.png']}" width="50" style="text-align:left; vertical-align:middle; margin-top:15px" /><h:outputText value="#{person.firstName}" style="display:block; margin-top:18px; font-size:0.9em" /></h:panelGroup></p:dataList></composite:implementation> Chat feature with PrimeFaces Push One of the most interesting features of PrimeFaces is the Prime Push API. Designed by Atmosphere Framework creator Jean-François Arcand, the Prime Push API supports asynchronous communication from the web server to the web browser on desktop or mobile using various transports such as WebSocket and Comet. Prime Push technology opens up a whole new set of possibilities for web developers. We will implement a simple chat feature for our web application based on Prime Push. What is WebSocket? WebSocket is a standardized, full-duplex communication protocol based on TCP that can be used to establish a persistent, bidirectional communication channel between a web browser and a web server. WebSocket has better performance than Comet techniques such as long polling and HTTP streaming, and is well supported by modern browsers and application servers. WebSocket support can be enabled in GlassFish 3 with a simple command: $GLASSFISH_HOME/bin/asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-1.http.websockets-support-enabled=true Once WebSocket support is enabled in GlassFish, we are ready to use Prime Push in our web application. Chat room Before we can see the power of Prime Push in action, we need to implement a chat room feature in our application. The PrimeFaces showcase application includes a chat room example, so we have adapted it for our purposes and integrated it into our application. One of the coolest things about PrimeFaces is the ability to push updates to desktop and mobile users at the same time from the server using PrimeFaces Mobile and Prime Push technologies. The previous screenshot shows a live chat session in our web application between a mobile and desktop user. Getting started with Prime Push The first step in using Prime Push is configuring the Prime Push servlet in web.xml: <servlet><servlet-name>PushServlet</servlet-name><servlet-class>org.primefaces.push.PushServlet</servlet-cla<init-param><param-name>org.primefaces.push.rules</param-name><param-value>com.mycompany.websocket.DefaultPushRule</paramvalue></init-param> ...<load-on-startup>1</load-on-startup><async-supported>true</async-supported></servlet><servlet-mapping><servlet-name>PushServlet</servlet-name><url-pattern>/primepush/*</url-pattern></servlet-mapping> An important point about this configuration is the use of a custom push rule implemented in the com.mycompany.websocket.DefaultPushRule class. This class provides some GlassFish-specific support that was necessary to ensure Prime Push worked properly on GlassFish. Opening a WebSocket communication channel The next step in using Prime Push is to establish the WebSocket communication channel between the web page and the web server. In our application, when the user clicks on the Chat link on the contact screen, we call the following method in our ChatController using Ajax to begin the chat: public void beginChat() { User user = userController.getUser(); RequestContext requestContext = RequestContext.getCurrentInstance(); // ... requestContext.execute("socketWidget.connect( '/" + user.getUsername() + "')"); pushContext.push(CHANNEL + "*", user.getUsername() + " joined the channel.");} Notice that we use the very cool PrimeFaces RequestContext API to invoke some JavaScript in the browser when the response is completed. We can do a lot more with the RequestContext API, such as update a DOM element, scroll to a component, and execute arbitrary JavaScript. Definitely check it out. Here we call connect() to tell the browser to listen for messages on the WebSocket communication channel. Use of a PrimeFaces socket component The PrimeFaces socket component establishes a WebSocket connection with the PushServlet running in our web application. Here it uses a communication channel named /chat for sending and receiving Push messages. p:socket onMessage="handleMessage" channel="/chat" autoConnect="false" widgetVar="socketWidget" /><script type="text/javascript"> //<![CDATA[function handleMessage(data) {// append chat messages to output panel var chatContent = $(PrimeFaces.escapeClientId('chatForm:chatPanel'));chatContent.append(data + '<br />');//keep scrollchatContent.scrollTop(chatContent.height()); } //]]></script> When a chat message is received, our handleMessage() JavaScript function is called and the chat message is appended to the chat content panel. Implementation of the chat room dialog for desktop web browsers To provide a chat room user interface for desktop users, we implemented the following modal dialog using the PrimeFaces dialog component. It renders the list of active users on our website. <p:dialog header="Chat" modal="true" showEffect="fade" hideEffect="fade" widgetVar="chatDialogWidget" width="700" position="center" appendToBody="false" height="400" draggable="true" resizable="false"id="chatDialog"> ...<p:outputPanel id="chatPanel" layout="block" styleClass="ui-corner-all ui-widget-content chatlogs"/><p:dataList id="users" var="user" value="#{activeUsers}" styleClass="usersList"><f:facet name="header"> Users</f:facet> #{user.username}</p:dataList> Next, we need to provide an input field for users to enter a chat message. <p:inputText value="#{chatController.globalMessage}" styleClass="messageInput" style="width:300px" /><p:spacer width="5" /><p:commandButton value="Send" actionListener="#{chatController.sendGlobal}" oncomplete="$('.messageInput').val('').focus()"/> ... <p:commandButton value="Close" style="margin-top:20px" actionListener="#{chatController.endChat}" onclick="chatDialogWidget.hide()" global="false" /> When the user clicks on the Send button, the chat message text is submitted using Ajax and our ChatController.sendGlobal() method is invoked to push the message to the WebSocket channel. private static final String CHANNEL = "/chat/";public void sendGlobal() { String username = getLoggedInUser().getUsername(); pushContext.push(CHANNEL + "*", username + ": " + globalMessage);} On the client side, the browser will receive the message over the WebSocket channel and our handleMessage() JavaScript function will append the text to the chat panel. Summary This article helped you understand JSF2 composite component with PrimeFaces and chat feature with PrimeFaces Push. It also helped you understand about opening a WebSocket communication channel, use of PrimeFaces socket component, and implementation of chat rooms for web browsers. Resources for Article: Further resources on this subject: Integrating Images with JSF, CSS with JSF and, JS with JSF [Article] Apache MyFaces Extensions Validator [Article] Getting Started with PrimeFaces [Article]
Read more
  • 0
  • 0
  • 4752

Packt
31 Jul 2013
6 min read
Save for later

Quick start – creating your first grid

Packt
31 Jul 2013
6 min read
(For more resources related to this topic, see here.) So, let's do that right now for this example. Create a copy of the entire jqGrid folder named quickstart; easy as pie. Let's begin by creating the simplest grid possible; open up the index.html file from the newly created quickstart folder, and modify the body section to look like the following code: <body><table id="quickstart_grid"></table><script>var dataArray = [{name: 'Bob', phone: '232-532-6268'},{name: 'Jeff', phone: '365-267-8325'}];$("#quickstart_grid").jqGrid({datatype: 'local',data: dataArray,colModel: [{name: 'name', label: 'Name'},{name: 'phone', label: 'Phone Number'}]});</script></body> The first element in the body tags is a standard table element; this is what will be converted into our grid, and it's literally all the HTML needed to make one. The first four lines are just defining some data. I didn't want to get into AJAX or opening other files, so I decided to just create a simple JavaScript array with two entries. The next line is where the magic happens; this single command is being used to create and populate a grid using the information provided. We select the table element with jQuery, and call the jqGrid function, passing it all the properties needed to make a grid. The first two options set the data along with its type, in our case the data is the array we made and the type is local, which is in contrast to some of the other datatypes which use AJAX to retrieve remote data. After that we set the columns, this is done with the colModel property. Now, there are a lot of options for the colModel property, which we will get to later on, numerous settings for customizing and manipulating the data in the table. But for this simple example, we are just specifying the name and label properties, which tell jqGrid the column's label for the header and the value's key from the data array. Now, open index.html in your browser and you should see something like the following screenshot: Not particularly pretty, but you can see that with just a few short lines, we have created a grid and populated it with data that can be sorted. But we can do better; first off, we are only using two of the four standard layers we talked about: the header layer and the body layer. Let's add a caption layer to provide little context, and let's adjust the size of the grid to fit our data. So, modify the call to jqGrid with the following: $("#grid").jqGrid({datatype: 'local',data: dataArray,colModel: [{name: 'name', label: 'Name'},{name: 'phone', label: 'Phone Number'}],height: 'auto',caption: 'Users Grid',}); And refresh your browser; your grid should now look like the following screenshot: That's looking much better. Now, you may be wondering, we only set the height property to auto, so how come the width seems to have snapped to the content? This is due to the fact that the right margin we saw earlier is actually a column for the scroll bar. By default jqGrid sets your grid's height to 150 pixels, this means, regardless of whether you have only one row, or a thousand rows, the height will remain the same, so that there is a gap to hold the scroll bar in an event when you have more rows than that would fit in the given space. When we set the height to auto, it will stretch the grid vertically to contain all the items, making the scroll bar irrelevant and therefore it knows not to place it. Now this is a pretty good quick start example, but to finish things off, let's take a look at the navigation layer, just so we can say we did. For this next part, although we are going to need more data, I can't really show pagination with just two entries, luckily there is a site http://www.json-generator.com/ created by Vazha Omanashvili for doing exactly this. The way it works is, you specify the format and number of rows you want, and it generates it with random data. We are going to keep the format we have been using, of name and phone number, so in the box on the left, enter the following code: ['{{repeat(50)}}',{name: '{{firstName}} {{lastName}}',phone: '{{phone}}'}] Here we're saying we would like 50 rows with a name field containing both firstname and lastname, and we would also like a phone number. This site is not really in the scope of this book, but if you would like to know about other fields, you can click on the help button at the top. Click on Generate to produce a result object, and then just click on the copy to clipboard button. With that done, open your index.html file and replace the array for dataArray with what you copied. Your code should now look like the following code: var dataArray = {"id": 1,"jsonrpc": "2.0","total": 50,"result": [ /* the 50 rows */ ]}; As you can see, the actual rows are under a property named result, so we will need to change the data key in the call to jqGrid from dataArray to dataArray.result. Refreshing the page now you will see the first 20 rows being displayed (that is the default limit). But how can we get to the rest? Well, jqGrid provides a special navigation layer named "pager", which contains a pagination control. To display it, we will need to create an HTML element for it. So, right underneath the table element add a div like: <table id="grid"></table><div id="pager"></div> Then, we just need to add a key to the jqGrid method for the pager and row limit: caption: 'Users Grid',height: 'auto',rowNum: 10,pager: '#pager'}); And that's all there to it, you can adjust the rowNum property to display more or less entries at once, and the pages will be automatically calculated for you. Summary In this article we learned how to create a simple Grid and customize it. We used different properties and functions for the same. We also used different layers to customize the jqGrid. Resources for Article : Further resources on this subject: jQuery and Ajax Integration in Django [Article] Implementing AJAX Grid using jQuery data grid plugin jqGrid [Article] Django JavaScript Integration: jQuery In-place Editing Using Ajax [Article]
Read more
  • 0
  • 0
  • 9785

article-image-participating-business-process-intermediate
Packt
31 Jul 2013
5 min read
Save for later

Participating in a business process (Intermediate)

Packt
31 Jul 2013
5 min read
(For more resources related to this topic, see here.) The hurdles and bottlenecks for financial services from an IT point of view are: Silos of data Outdated IT system and many applications running on legacy and non-standard based systems Business process and reporting systems not in sync with each other Lack of real-time data visibility Automated decision making Ability to change and manage business processes in accordance with changes in business dynamics Partner management Customer satisfaction This is where BPM plays a key role in bridging the gap between key business requirements and technology or businesses hurdles. In a real-life scenario, a typical home loan use case would be tied up with Know Your Customer (KYC) regulatory requirement. In India for example, the Reserve Bank of India ( RBI) had passed on guidelines that make it mandatory for banks to properly know their customers. RBI mandates that banks collect their customers' proof of identity, recent photographs, and Income Tax PAN. Proof of residence can be a voter card, a driving license, or a passport copy. Getting ready We start with the source code from the previous recipe. We will add a re-usable e-mail or SMS notification process. It is always a best practice to add a new process if it is called multiple times in the same process. This can be a subprocess within the main process itself, or it can be a part of the same composite outside the main process. We will add a new regulatory requirement that allows the customer to add KYC requirements such as photo, proof of address, and Income Tax PAN copy as attachments that will be checked into the WebCenter Content repository. These checks become a part of the customer verification stage before finance approval. We will make KYC as a subprocess with a scope of expansion under a different scenario. We will also save the process data into a filesystem or in a JMS messaging queue at the end of the loan process completion. In a banking scenario, it can also be the integration stage for other applications such as a CRM application or any other application. How to do it… Let's perform the following steps: Launch JDeveloper and open the composite.xml of LoanApplicationProcess in the Design view. Drag-and-drop a new BPMN Process component from the Component Palette. Create the Send Notifications process next to the existing LoanApplicationProcess, and edit the new process. The Send Notifications process will take input parameters as To e-mail ID, From e-mail ID, Subject, CC, and send e-mail to the given e-mail ID. Similarly, we will drag-and-drop a File Adapter component from the Component Palette that saves the customer data into a file. We place this component the end of the LoanApplication process, just before the End activity. We will use this notification service to notify Verification Officers about the arrival of a new eligible application that needs to be verified. In the Application Verification Officer stage, we will add a subprocess, KYC , that will be assigned to the loan initiator—James Cooper in our case. This will be preceded by sending an e-mail notification to the applicant asking for KYC details such as PAN number, scanned photograph, and voter ID as requested by the Verification Officers. Now, let us implement Save Loan Application by invoking the File Adapter service. The Email notification services are also available out of the box. How it works… The outputs of this recipe are re-usable services that can be used across multiple service calls such as notification services. This recipe also demonstrates how to use subprocesses and change the process to meet regulatory requirements. Let's understand the output by taking our use case scenario: When the process is initiated, the e-mail notification gets triggered at appropriate stages of the process. Conan Doyle and John Steinbeck will get the e-mail, requesting them to process the application, with the required information of the applicant, along with the link to BPM Workspace. The KYC task also sends an e-mail to James Cooper, requesting him for the documents required for the KYC check. James Cooper logs in to the James Bank WebCenter Portal and sees there is a task assigned to him to upload his KYC details. James Cooper clicks on the task link and submits the required soft copy documents, and gets them checked into the content repository once the form is submitted.            The start-to-end process flow now looks as follows: Summary BPM Process Spaces, which is an extension template of BPM, allows process and task views to be exposed to WebCenter Portal. The advantage of having Process Spaces made available within the Portal is that the users can collaborate with others using out of the box Portal features such as wikis, discussion forums, blogs, and content management. This improves productivity as the user need not log in to different applications for different purposes, as all the required data and information will be made available within the Portal environment. It is also possible to expose some of the WSRP supported application portlets (for example, HR Portlets from PeopleSoft) into a corporate portal environment. All of this sums up to provide higher visibility of the entire business process, and a nature of working and collaborating together in an enterprise business environment. Resources for Article : Further resources on this subject: Managing Oracle Business Intelligence [Article] Oracle E-Business Suite: Creating Bank Accounts and Cash Forecasts [Article] Getting Started with Oracle Information Integration [Article]
Read more
  • 0
  • 0
  • 1853
article-image-data-sources-charts
Packt
31 Jul 2013
12 min read
Save for later

Data sources for the Charts

Packt
31 Jul 2013
12 min read
(For more resources related to this topic, see here.) Spreadsheets In Spreadsheets, two preparation steps must be addressed in order to use a Spreadsheet as a data source with the Visualization API. The first is to identify the URL location of the Spreadsheet file for the API code. The second step is to set appropriate access to the data held in the Spreadsheet file. Preparation The primary method of access for a Spreadsheet behaving as a data source is through a JavaScript-based URL query. The query itself is constructed with the Google Query Language. If the URL request does not include a query, all data source columns and rows are returned in their default order. To query a Spreadsheet also requires that the Spreadsheet fi le and the API application security settings are con figured appropriately. Proper preparation of a Spreadsheet as a data source involves both setting the appropriate access as well as locating the fi le's query URL. Permissions In order for a Spreadsheet to return data to the Visualization API properly, access settings on the Spreadsheets fi le itself must allow view access to users. For a Spreadsheet that allows for edits, including form-based additions, permissions must be set to Edit . To set permissions on the Spreadsheet, select the Share button to open up the Sharing settings dialog. To be sure the data is accessible to the Visualization API, access levels for both the Visualization application and Spreadsheet must be the same. For instance, if a user has access to the Visualization application and does not have view access to the Spreadsheet, the user will not be able to run the visualization as the data is more restrictive to that user than the application. The opposite scenario is true as well, but less likely to cause confusion as a user unable to access the API application is a fairly self-described problem. All Google applications handle access and permissions similarly. More information on this topic can be found on the Google Apps Support pages. Google Permissions overview is available at  http://support.google. com/drive/bin/answer.py?hl=en&answer=2494886&rd=1. Get the URL path At present, acquiring a query-capable URL for a Spreadsheet is not as straightforward a task as one might think. There are several methods for which a URL is generated for sharing purposes, but the URL format needed for a data source query can only be found by creating a gadget in the Spreadsheet. A Google Gadget is simply dynamic, HTML or JavaScript-based web content that can be embedded in a web page. Google Gadgets also have their own API, and have capabilities beyond Spreadsheets applications. Information on Google Gadget API is available at https://developers.google.com/gadgets/. Initiate gadget creation by selecting the Gadget... option from the Insert item on the menu bar. When the Gadget Settings window appears, select Apply & close from the Gadget Settings dialog. Choose any gadget from the selection window. The purpose of this procedure is simply to retrieve the correct URL for querying. In fact, deleting the gadget as soon as the URL is copied is completely acceptable. In other words, the specific gadget chosen is of no consequence. Once the gadget has been created, select Get query data source url… from the newly created gadget's drop-down menu. Next, determine and select the range of the Spreadsheet to query. Either the previously selected range when the gadget was created, or the entire sheet is acceptable, depending on the needs of the Visualization application being built. The URL listed under Paste this as a gadget data source url in the Table query data source window is the correct URL to use with the API code requiring query capabilities. Be sure to select the desired cell range, as the URL will change with various options. Important note Google Gadgets are to be retired in 2013, but the query URL is still part of the gadget object at the time of publication. Look for the method of finding the query URL to change as Gadgets are retired. Query Use the URL retrieved from the Spreadsheet Gadget to build the query. The following query statement is set to query the entire Spreadsheet of the key indicated: var query =new google.visualization.Query ('https://docs.google.com/spreadsheet/tq?key =0AhnmGz1SteeGdEVsNlNWWkoxU3ZRQjlmbDdTTjF2dHc&headers=-1'); Once the query is built, it can then be sent. Since an external data source is by definition not always under explicit control of the developer, a valid response to a query is not necessarily guaranteed. In order to prevent hard-to-detect data-related issues, it is best to include a method of handling erroneous returns from the data source. The following query.send function also informs the application how to handle information returned from the data source, regardless of quality. query.send(handleQueryResponse); The handleQueryResponse function sent along with the query acts as a filter, catching and handling errors from the data source. If an error was detected, the handleQueryResponse function displays an alert message. If the response from the data source is valid, the function proceeds and draws the visualization. function handleQueryResponse(response) { if (response.isError()) {alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage()); return; } var data = response.getDataTable(); visualization = new google.visualization.Table (documnt.getElementById('visualization')); visualization.draw(data, null);} Best practice Be prepared for potential errors by planning for how to handle them. For reference, the previous example is given in its complete HTML form: <html > <head><meta http-equiv="content-type" content ="text/html; charset=utf-8"/> <title> Google Visualization API Sample </title> <script type="text/javascript" src ="http://www.google.com/jsapi"> </script><script type="text/javascript"> google.load('visualization', '1', {packages: ['table']}); </script> <script type="text/javascript">var visualization;function drawVisualization() {// To see the data that this visualization uses, browse to //https://docs.google.com/spreadsheet/ccc?key=0AhnmGz1SteeGdEVsNlN WWkoxU3ZRQjlmbDdTTjF2dHc&usp=sharing var query = new google.visualization.Query('https://docs.google.com/spreadsheet/tq?key= 0AhnmGz1SteeGdEVsNlNWWkoxU3ZRQjlmbDdTTjF2dHc&headers=-1'); // Send the query with a callback function. query.send(handleQueryResponse); } function handleQueryResponse(response) { if (response.isError()) { alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage()); return; } var data = response.getDataTable(); visualization = new google.visualization.Table(document.getEleme ntById('visualization')); visualization.draw(data, null);} google.setOnLoadCallback(drawVisualization); </script></head><body style="font-family: Arial;border: 0 none;"> <div id="visualization" style ="height: 400px; width: 400px;"> </div> </body></html>  View live examples for Spreadsheets at http://gvisapi-packt. appspot.com/ch6-examples/ch6-datasource.html Apps Script method Just as the Visualization API can be used from within an Apps Script, external data sources can also be requested from the script. In the Apps Script Spreadsheet example presented earlier in this article, the DataTable() creation was performed within the script. In the following example, the create data table element has been removed and a .setDataSourceUrloption has been added to Charts. newAreaChart(). The script otherwise remains the same. functiondoGet() {var chart = Charts.newAreaChart().setDataSourceUrl("https: //docs.google.com/spreadsheet/tq ?key= 0AhnmGz1SteeGdEVsNlNWWkoxU3ZRQjlmbDdTTjF2dHc&headers=-1").setDimensions(600, 400) .setXAxisTitle("Age Groups") .setYAxisTitle("Population") .setTitle("Chicago Population by Age and Gender - 2010 Census") .build();varui = UiApp.createApplication(); ui.add(chart); returnui;} View live examples in Apps Script at https://script. google.com/d/1Q2R72rGBnqPsgtOxUUME5zZy5Kul5 3r_lHIM2qaE45vZcTlFNXhTDqrr/edit. Fusion Tables Fusion Tables are another viable data source ready for use by Visualization API. Fusion Tables offer benefit over Spreadsheets beyond just the Google Map functionality. Tables API also allows for easier data source modification than is available in Spreadsheets. Preparation Preparing a Fusion Table to be used as a source is similar in procedure to preparing a Spreadsheet as a data source. The Fusion Table must be shared to the intended audience, and a unique identifier must be gathered from the Fusion Tables application. Permissions Just as with Spreadsheets, Fusion Tables must allow a user a minimum of view permissions in order for an application using the Visualization API to work properly. From the Sharing settings window in Fusion Tables, give the appropriate users viewaccess as a minimum. Get the URL path Referencing a Fusion Table is very similar in method to Spreadsheets. Luckily, the appropriate URL ID information is slightly easier to find in Fusion Tables than in Spreadsheets. With the Sharing settings window open, there is a field at the top of the page containing the Link to share . At the end portion of the link, following the characters dcid= is the Table's ID. The ID will look something like the following: 1Olo92KwNin8wB4PK_dBDS9eghe80_4kjMzOTSu0 This ID is the unique identifier for the table. Query Google Fusion Tables API includes SQL-like queries for the modification of Fusion Tables data from outside the GUI interface. Queries take the form of HTTP POST and GET requests and are constructed using the Fusion Tables API query capabilities. Data manipulation using Fusion Tables API is beyond the scope of this article, but a simple example is offered here as a basic illustration of functionality. Fusion Table query requests the use of the API SELECT option, formatted as: SELECT Column_name FROM Table_ID Here Column_name is the name of the Fusion Table column and Table_ID is the table's ID extracted from the Sharing settings window. If the SELECT call is successful, the requested information is returned to the application in the JSON format. The Visualization API drawChart() is able to take the SELECT statement and the corresponding data source URL as options for the chart rendering. The male and female data from the Fusion Tables 2010 Chicago Census file have been visualized using the drawChart() technique. function drawVisualization() { google.visualization.drawChart({ containerId: 'visualization', dataSourceUrl: 'http://www.google.com/fusiontables/gvizdata?tq=', query: 'SELECT Age, Male, Female FROM 1Olo92KwNin8wB4PK_ dBDS9eghe80_4kjMzOTSu0', chartType: 'AreaChart', options: { title: 'Chicago Population by Age and Sex - 2010 Census', vAxis: { title: 'Population' }, hAxis: { title: 'Age Groups' } } });} The preceding code results in the following visualization: Live examples are available at http://gvisapi-packt. appspot.com/ch6-examples/ch6-queryfusion.html. Important note Fusion Table query responses are limited to 500 rows. See Fusion Tables API documentation for other resource parameters. API Explorer With so many APIs available to developers using the Google platform, testing individual API functionality can be time consuming. The same issue arises for GUI applications used as a data source. Fortunately, Google provides API methods for its graphical applications as well. The ability to test API requests against Google's infrastructure is a desirable practice for all API programing efforts. To support this need, Google maintains the APIs Explorer service. This service is a console-based, web application that allows queries to be submitted to APIs directly, without an application to frame them. This is helpful functionality when attempting to verify whether a data source is properly configured. To check if the Fusion Tables 2010 U.S. Census data instance is configured properly, a query can be sent to list all columns, which informs which columns are actually exposed to the Visualization API application. Best practice Use the Google API Explorer service to test if API queries work as intended. To use the API Explorer for Fusion Tables, select Fusion Tables API from the list of API services. API functions available for testing are listed on the Fusion Tables API page. Troubleshooting a Chart with a Fusion Tables data source usually involves fi rst verifying all columns are available to the visualization code. If a column is not available, or is not formatted as expected, a visualization issue related to data problems may be difficult to troubleshoot from inside the Visualization API environment. The API call that best performs a simple check on column information is the fusiontables.column.list item. Selecting fusiontables.column.list opens up a form-based interface. The only required information is the Table ID (collected from the Share settings window in the Fusion Tables file). Click on the Execute button to run the query. The API Explorer tool will then show the GET query sent to the Fusion Table in addition to the results it returned. For the fusiontables.column.list query, columns are returned in bracketed sections. Each section contains attributes of that column. The following queried attributes should look familiar, as it is the fusiontables.column.list result of a query to the 2010 Chicago Census data Fusion Table. Best Practice The Column List Tool is helpful when troubleshooting Fusion Table to API code connectivity. If the Table is able to return coherent values through the tool, it can generally be assumed that access settings are appropriate and the code itself may be the source of connection issues. Fusion Tables—row and query reference is available at https:// developers.google.com/fusiontables/docs/v1/sqlreference. Information on API Explorer—column list is available at https:// developers.google.com/fusiontables/docs/v1/ reference/column/list#try-it.
Read more
  • 0
  • 0
  • 2001

article-image-introduction-nginx
Packt
31 Jul 2013
8 min read
Save for later

Introduction to nginx

Packt
31 Jul 2013
8 min read
(For more resources related to this topic, see here.) So, what is nginx? The best way to describe nginx (pronounced engine-x) is as an event-based multi-protocol reverse proxy. This sounds fancy, but it's not just buzz words and actually affects how we approach configuring nginx. It also highlights some of the flexibility that nginx offers. While it is often used as a web server and an HTTP reverse proxy, it can also be used as an IMAP reverse proxy or even a raw TCP reverse proxy. Thanks to the plug-in ready code structure, we can utilize a large number of first and third party modules to implement a diverse amount of features to make nginx an ideal fit for many typical use cases. A more accurate description would be to say that nginx is a reverse proxy first, and a web server second. I say this because it can help us visualize the request flow through the configuration file and rationalize how to achieve the desired configuration of nginx. The core difference this creates is that nginx works with URIs instead of files and directories, and based on that determines how to process the request. This means that when we configure nginx, we tell it what should happen for a certain URI rather than what should happen for a certain file on the disk. A beneficial part of nginx being a reverse proxy is that it fits into a large number of server setups, and can handle many things that other web servers simply aren't designed for. A popular question is "Why even bother with nginx when Apache httpd is available?" The answer lies in the way the two programs are designed. The majority of Apache setups are done using prefork mode, where we spawn a certain amount of processes and then embed our dynamic language in each process. This setup is synchronous, meaning that each process can handle one request at a time, whether that connection is for a PHP script or an image file. In contrast, nginx uses an asynchronous event-based design where each spawned process can handle thousands of concurrent connections. The downside here is that nginx will, for security and technical reasons, not embed programming languages into its own process - this means that to handle those we will need to reverse proxy to a backend, such as Apache, PHP-FPM, and so on. Thankfully, as nginx is a reverse proxy first and foremost, this is extremely easy to do and still allows us major benefits, even when keeping Apache in use. Let's take a look at a use case where Apache is used as an application server described earlier rather than just a web server. We have embedded PHP, Perl, or Python into Apache, which has the primary disadvantage of each request becoming costly. This is because the Apache process is kept busy until the request has been fully served, even if it's a request for a static file. Our online service has gotten popular and we now find that our server cannot keep up with the increased demand. In this scenario introducing nginx as a spoon-feeding layer would be ideal. When an nginx server with a spoon-feeding layer will sit between our end user and Apache and a request comes in, nginx will reverse proxy it to Apache if it is for a dynamic file, while it will handle any static file requests itself. This means that we offload a lot of the request handling from the expensive Apache processes to the more lightweight nginx processes, and increase the number of end users we can serve before having to spend money on more powerful hardware. Another example scenario is where we have an application being used from all over the world. We don't have any static files so we can't easily offload a number of requests from Apache. In this use case, our PHP process is busy from the time the request comes in until the user has finished downloading the response. Sadly, not everyone in the world has fast internet and, as a result, the sending process could be busy for a relatively significant period of time. Let's assume our visitor is on an old 56k modem and has a maximum download speed of 5 KB per second, it will take them five seconds to download a 25 KB gzipped HTML file generated by PHP. That's five seconds where our process cannot handle any other request. When we introduce nginx into this setup, we have PHP spending only microseconds generating the response but have nginx spend five seconds transferring it to the end user. Because nginx is asynchronous it will happily handle other connections in the meantime, and thus, we significantly increase the number of concurrent requests we can handle. In the previous two examples I used scenarios where nginx was used in front of Apache, but naturally this is not a requirement. nginx is capable of reverse proxying via, for instance, FastCGI, UWSGI, SCGI, HTTP, or even TCP (through a plugin) enabling backends, such as PHP-FPM, Gunicorn, Thin, and Passenger. Quick start – Creating your first virtual host It's finally time to get nginx up and running. To start out, let's quickly review the configuration file. If you installed via a system package, the default configuration file location is most likely /etc/nginx/nginx.conf. If you installed via source and didn't change the path pre fix, nginx installs itself into/usr/local/nginx and places nginx.conf in a /conf subdirectory. Keep this file open as a reference to help visualize many of the things described in this article. Step 1 – Directives and contexts To understand what we'll be covering in this section, let me first introduce a bit of terminology that the nginx community at large uses. Two central concepts to the nginx configuration file are those of directives and contexts. A directive is basically just an identifier for the various configuration options. Contexts refer to the different sections of the nginx configuration file. This term is important because the documentation often states which context a directive is allowed to have within. A glance at the standard configuration file should reveal that nginx uses a layered configuration format where blocks are denoted by curly brackets {}. These blocks are what are referred to as contexts. The topmost context is called main, and is not denoted as a block but is rather the configuration file itself. The main context has only a few directives we're really interested in, the two major ones being worker_processes and user. These directives handle how many worker processes nginx should run and which user/group nginx should run these under. Within the main context there are two possible subcontexts, the first one being called events. This block handles directives that deal with the event-polling nature of nginx. Mostly we can ignore every directive in here, as nginx can automatically configure this to be the most optimal; however, there's one directive which is interesting, namely worker_connections. This directive controls the number of connections each worker can handle. It's important to note here that nginx is a terminating proxy, so if you HTTP proxy to a backend, such as Apache httpd, that will use up two connections. The second subcontext is the interesting one called http. This context deals with everything related to HTTP, and this is what we will be working with almost all of the time. While there are directives that are configured in the http context, for now we'll focus on a subcontext within http called server. The server context is the nginx equivalent of a virtual host. This context is used to handle configuration directives based on the host name your sites are under. Within the server context, we have another subcontext called location. The location context is what we use to match the URI. Basically, a request to nginx will flow through each of our contexts, matching first the server block with the hostname provided by the client, and secondly the location context with the URI provided by the client. Depending on the installation method, there might not be any server blocks in the nginx.conf file. Typically, system package managers take advantage of the include directive that allows us to do an in-place inclusion into our configuration file. This allows us to separate out each virtual host and keep our configuration file more organized. If there aren't any server blocks, check the bottom of the file for an includedirective and check the directory from which it includes, it should have a file which contains a server block. Step 2 – Define your first virtual hosts Finally, let us define our first server block! server { listen 80; server_name example.com; root /var/www/website;} That is basically all we need, and strictly speaking, we don't even need to define which port to listen on as port 80 is default. However, it's generally a good practice to keep it in there should we want to search for all virtual hosts on port 80 later on. Summary This article provided the details about the important aspects of nginx. It also briefed about the configuration of our virtual host using nginx by explaining two simple steps, along with a configuration example. Resources for Article : Further resources on this subject: Nginx HTTP Server FAQs [Article] Nginx Web Services: Configuration and Implementation [Article] Using Nginx as a Reverse Proxy [Article]
Read more
  • 0
  • 0
  • 6110

article-image-working-blocks
Packt
31 Jul 2013
20 min read
Save for later

Working with Blocks

Packt
31 Jul 2013
20 min read
(For more resources related to this topic, see here.) Creating a custom block type Creating block types is a great way to add custom functionality to a website. This is the preferred way to add things like calendars, dealer locators, or any other type of content that is visible and repeatable on the frontend of the website. Getting ready The code for this recipe is available to download from the book's website for free. We are going to create a fully functioning block type that will display content on our website. How to do it... The steps for creating a custom block type are as follows: First, you will need to create a directory in your website's root /blocks directory. The name of the directory should be underscored and will be used to refer to the block throughout the code. In this case, we will create a new directory called /hello_world. Once you have created the hello_world directory, you will need to create the following files: controller.php db.xml form.php add.php edit.php view.php view.css Now, we will add code to each of the files. First, we need to set up the controller file. The controller file is what powers the block. Since this is a very basic block, our controller only will contain information to tell concrete5 some details about our block, such as its name and description. Add the following code to controller.php: class HelloWorldBlockController extends BlockController { protected $btTable = "btHelloWorld"; protected $btInterfaceWidth = "300"; protected $btInterfaceHeight = "300"; public function getBlockTypeName() { return t('Hello World'); } public function getBlockTypeDescription() { return t('A basic Hello World block type!'); } } Notice that the class name is HelloWorldBlockController. concrete5 conventions dictate that you should name your block controllers with the same name as the block directory in camel case (for example: CamelCase) form, and followed by BlockController. The btTable class variable is important, as it tells concrete5 what database table should be used for this block. It is important that this table doesn't already exist in the database, so it's a good idea to give it a name of bt (short for "block type") plus the camel cased version of the block name. Now that the controller is set up, we need to set up the db.xml file. This file is based off of the ADOXMLS format, which is documented at http://phplens.com/lens/adodb/docs-datadict.htm#xmlschema. This XML file will tell concrete5 which database tables and fields should be created for this new block type (and which tables and fields should get updated when your block type gets updated). Add the following XML code to your db.xml file: lt;?xml version="1.0"?> <schema version="0.3"> <table name="btHelloWorld"> <field name="bID" type="I"> <key /> <unsigned /> </field> <field name="title" type="C" size="255"> <default value="" /> </field> <field name="content" type="X2"> <default value="" /> </field> </table> </schema> concrete5 blocks typically have both an add.php and edit.php file, both of which often do the same thing: show the form containing the block's settings. Since we don't want to repeat code, we will enter our form HTML in a third file, form.php, and <?php $form = Loader::helper('form'); ?> <div> <label for="title">Title</label> <?php echo $form->text('title', $title); ?> </div> <div> <label for="content">Content</label> <?php echo $form->textarea('content', $content); ?> </div> Once that is all set, add this line of code to both add.php and edit.php to have this HTML code appear when users add and edit the block: <?php include('form.php') ?> Add the following HTML to your view.php file: <h1><?php echo $title ?></h1> <div class="content"> <?php echo $content ?> </div> Finally, for a little visual appeal, add the following code to view.css: content { background: #eee; padding: 20px; margin: 20px 0; border-radius: 10px; } Now all of the files have been filled with the code to make our Hello World block function. Now we need to install this block in concrete5 so we can add it to our pages. To install the new block, you will need to sign into your concrete5 website and navigate to /dashboard/blocks/types/. If you happen to get a PHP fatal error here, clear your concrete5 cache by visiting /dashboard/system/optimization/clear_cache (it is always a good idea to disable the cache while developing in concrete5). At the top of the Block Types screen, you should see your Hello World block, ready to install. Click on the Install button. Now the block is installed and ready to add to your site! How it works... Let's go through the code that we just wrote, step-by-step. In controller.php, there are a few protected variables at the top of the class. The $btTable variable tells concrete5 which table in the database holds the data for this block type. The $btInterfaceWidth and $btInterfaceHeight variables determine the initial size of the dialog window that appears when users add your block to a page on their site. We put the block's description and name in special getter functions for one reason, to potentially support for translations down the road. It's best practice to wrap any strings that appear in concrete5 in the global t() function. The db.xml file tells concrete5 what database tables should be created when this block gets installed. This file uses the ADOXMLS format to generate tables and fields. In this file, we are telling concrete5 to create a table called btHelloWorld. That table should contain three fields, an ID field, the title field, and the content field. The names of these fields should be noted, because concrete5 will require them to match up with the names of the fields in the HTML form. In form.php, we are setting up the settings form that users will fill out to save the block's content. We are using the Form Helper to generate the HTML for the various fields. Notice how we are able to use the $title and $content variables without them being declared yet. concrete5 automatically exposes those variables to the form whenever the block is added or edited. We then include this form in the add.php and edit.php files. The view.php file is a template file that contains the HTML that the end users will see on the website. We are just wrapping the title in an <h1> tag and the content in a <div> with a class of .content. concrete5 will automatically include view.css (and view.js, if it happens to exist) if they are present in your block's directory. Also, if you include an auto.js file, it will automatically be included when the block is in edit mode. We added some basic styling to the .content class and concrete5 takes care of adding this CSS file to your site's <head> tag. Using block controller callback functions The block controller class contains a couple of special functions that get automatically called at different points throughout the page load process. You can look into these callbacks to power different functionalities of your block type. Getting ready To get started, you will need a block type created and installed. See the previous recipe for a lesson on creating a custom block type. We will be adding some methods to controller.php. How to do it... The steps for using block controller callback functions are as follows: Open your block's controller.php file. Add a new function called on_start(): public function on_start() { } Write a die statement that will get fired when the controller is loaded. die('hello world'); Refresh any page containing the block type. The page should stop rendering before it is complete with your debug message. Be sure to remove the die statement, otherwise your block won't work anymore! How it works... concrete5 will call the various callback functions at different points during the page load process. The on_start() function is the first to get called. It is a good place to put things that you want to happen before the block is rendered. The next function that gets called depends on how you are interacting with the block. If you are just viewing it on a page, the view() function gets called. If you are adding or editing the block, then the add() or edit() functions will get called as appropriate. These functions are a good place to send variables to the view, which we will show how to do in the next recipe. The save() and delete() functions also get called automatically at this point, if the block is performing either of those functions. After that, concrete5 will call the on_before_render() function. This is a good time to add items to the page header and footer, since it is before concrete5 renders the HTML for the page. We will be doing this later on in the article. Finally, the on_page_view() function is called. This is actually run once the page is being rendered, so it is the last place where you have the code executed in your block controller. This is helpful when adding HTML items to the page. There's more... The following functions can be added to your controller class and they will get called automatically at different points throughout the block's loading process. on_start on_before_render view add edit on_page_view save delete For a complete list of the callback functions available, check out the source for the block controller library, located in /concrete/core/libraries/block_controller.php. Sending variables from the controller to the view A common task in MVC programming is the concept of setting variables from a controller to a view. In concrete5, blocks follow the same principles. Fortunately, setting variables to the view is quite easy. Getting ready This recipe will use the block type that was created in the first recipe of this article. Feel free to adapt this code to work in any block controller, though. How to do it... In your block's controller, use the set() function of the controller class to send a variable and a value to the view. Note that the view doesn't necessarily have to be the view.php template of your block. You can send variables to add.php and edit.php as well. In this recipe, we will send a variable to view.php. The steps are as follows: Open your block's controller.php file. Add a function called view() if it doesn't already exist: public function view() { } Set a variable called name to the view. $this->set('name', 'John Doe'); Open view.php in your block's directory. Output the value of the name variable. <div class="content"> <?php echo $name ?> </div> Adding items to the page header and footer from the block controller An important part of block development is being able to add JavaScript and CSS files to the page in the appropriate places. Consider a block that is using a jQuery plugin to create a slideshow widget. You will need to include the plugin's JavaScript and CSS files in order for it to work. In this recipe, we will add a CSS <link> tag to the page's <head> element, and a JavaScript <script> tag to bottom of the page (just before the closing </body> tag). Getting ready This recipe will continue working with the block that was created in the first recipe of this article. If you need to download a copy of that block, it is included with the code samples from this book's website. This recipe also makes a reference to a CSS file and a JavaScript file. Those files are available for download in the code on this book's website as well. How to do it... The steps for adding items to the page header and footer from the block controller are as follows: Open your block's controller.php file. Create a CSS file in /css called test.css. Set a rule to change the background color of the site to black. body { background: #000 !important; } Create a JavaScript file in /js called test.js. Create an alert message in the JavaScript file. alert('Hello!'); In controller.php, create a new function called on_page_view(). public function on_page_view() { } Load the HTML helper: $html = Loader::helper('html'); Add a CSS file to the page header: $this->addHeaderItem($html->css('testing.css')); Add a JavaScript file to the page footer: $this->addFooterItem($html->javascript('test.js')); Visit a page on your site that contains this block. You should see your JavaScript alert as well as a black background. How it works... As mentioned in the Using block controller callback function recipe, the ideal place to add items to the header (the page's <head> tag) and footer (just before the closing </body> tag) is the on_before_render() callback function. The addHeaderItem and addFooterItem functions are used to place strings of text in those positions of the web document. Rather than type out <script> and <link> tags in our PHP, we will use the built-in HTML helper to generate those strings. The files should be located in the site's root /css and /js directories. Since it is typically best practice for CSS files to get loaded first and for JavaScript files to get loaded last, we place each of those items in the areas of the page that make the most sense. Creating custom block templates All blocks come with a default view template, view.php. concrete5 also supports alternative templates, which users can enable through the concrete5 interface. You can also enable these alternative templates through your custom PHP code. Getting ready You will need a block type created and installed already. In this recipe, we are going to add a template to the block type that we created at the beginning of the article. How to do it... The steps for creating custom block templates are as follows: Open your block's directory. Create a new directory in your block's directory called templates/. Create a file called no_title.php in templates/. Add the following HTML code to no_title.php: <div class="content"> <?php echo $content ?> </div> Activate the template by visiting a page that contains this block. Enter edit mode on the page and click on the block. Click on "Custom Template".     Choose "No Title" and save your changes. There's more... You can specify alternative templates right from the block controller, so you can automatically render a different template depending on certain settings, conditions, or just about anything you can think of. Simply use the render() function in a callback that gets called before the view is rendered. public function view() { $this->render('templates/no_title'); } This will use the no_title.php file instead of view.php to render the block. Notice that adding the .php file extension is not required. Just like the block's regular view.php file, developers can include view.css and view.js files in their template directories to have those files automatically included on the page. See also The Using block controller callback functions recipe The Creating a custom block type recipe Including JavaScript in block forms When adding or editing blocks, it is often desired to include more advanced functionality in the form of client-side JavaScript. concrete5 makes it extremely easy to automatically add a JavaScript file to a block's editor form. Getting ready We will be working with the block that was created in the first recipe of this article. If you need to catch up, feel free to download the code from this book's website. How to do it... The steps for including JavaScript in block forms are as follows: Open your block's directory. Create a new file called auto.js. Add a basic alert function to auto.js: alert('Hello!'); Visit a page that contains your block. Enter edit mode and edit the block. You should see your alert message appear as shown in the following screenshot: How it works... concrete5 automatically looks for the auto.js file when it enters add or edit mode on a block. Developers can use this to their advantage to contain special client-side functionality for the block's edit mode. Including JavaScript in the block view In addition to being able to include JavaScript in the block's add and edit forms, developers can also automatically include a JavaScript file when the block is viewed on the frontend. In this recipe, we will create a simple JavaScript file that will create an alert whenever the block is viewed. Getting ready We will continue working with the block that was created in the first recipe of this article. How to do it... The steps for including JavaScript in the block view are as follows: Open your block's directory. Create a new file called view.js. Add an alert to view.js: alert('This is the view!'); Visit the page containing your block. You should see the new alert appear. How it works... Much like the auto.js file discussed in the previous recipe, concrete5 will automatically include the view.js file if it exists. This allows developers to easily embed jQuery plugins or other client-side logic into their blocks very easily. Including CSS in the block view Developers and designers working on custom concrete5 block types can have a CSS file automatically included. In this recipe, we will automatically include a CSS file that will change our background to black. Getting ready We are still working with the block that was created earlier in the article. Please make sure that block exists, or adapt this recipe to suit your own concrete5 environment. How to do it... The steps for including CSS in the block view are as follows: Open your block's directory. Create a new file called view.css, if it doesn't exist. Add a rule to change the background color of the site to black: body { background: #000 !important; } Visit the page containing your block. The background should now be black! How it works... Just like it does with JavaScript, concrete5 will automatically include view.css in the page's header if it exists in your block directory. This is a great way to save some time with styles that only apply to your block. Loading a block type by its handle Block types are objects in concrete5 just like most things. This means that they have IDs in the database, as well as human-readable handles. In this recipe, we will load the instance of the block type that we created in the first recipe of this article. Getting ready We will need a place to run some arbitrary code. We will rely on /config/site_post.php once again to execute some random code. This recipe also assumes that a block with a handle of hello_world exists in your concrete5 site. Feel free to adjust that handle as needed. How to do it... The steps for loading a block type by its handle are as follows: Open /config/site_post.php in your preferred code editor. Define the handle of the block to load: $handle = 'hello_world'; Load the block by its handle: $block = BlockType::getByHandle($handle); Dump the contents of the block to make sure it loaded correctly: print_r($block); exit; How it works... concrete5 will simply query the database for you when a handle is provided. It will then return a BlockType object that contains several methods and properties that can be useful in development. Adding a block to a page Users can use the intuitive concrete5 interface to add blocks to the various areas of pages on the website. You can also programmatically add blocks to pages using the concrete5 API. Getting ready The code in this article can be run anywhere that you would like to create a block. To keep things simple, we are going to use the /config/site_post.php file to run some arbitrary code. This example assumes that a page with a path of /about exists on your concrete5 site. Feel free to create that page, or adapt this recipe to suit your needs. Also, this recipe assumes that /about has a content area called content. Again, adapt according to your own website's configuration. We will be using the block that was created at the beginning of this article. How to do it... The steps for adding a block to a page are as follows: Open /config/site_post.php in your code editor. Load the page that you would like to add a block to: $page = Page::getByPath('/about'); Load the block by its handle: $block = BlockType::getByHandle('hello_world'); Define the data that will be sent to the block: $data = array( 'title' => 'An Exciting Title', 'content' => 'This is the content!' ); Add the block to the page's content area: $page->addBlock($block, 'content', $data); How it works... First you need to get the target page. In this recipe, we get it by its path, but you can use this function on any Page object. Next, we need to load the block type that we are adding. In this case, we are using the one that was created earlier in the article. The block type handle is the same as the directory name for the block. We are using the $data variable to pass in the block's configuration options. If there are no options, you will need to pass in an empty array, as concrete5 does not allow that parameter to be blank. Finally, you will need to know the name of the content area; in this case, the content area is called "content". Getting the blocks from an area concrete5 pages can have several different areas where blocks can be added. Developers can programmatically get an array of all of the block objects in an area. In this recipe, we will load a page and get a list of all of the blocks in its main content area. Getting ready We will be using /config/site_post.php to run some arbitrary code here. You can place this code wherever you find appropriate, though. This example assumes the presence of a page with a path of /about, and with a content area called content. Make the necessary adjustments in the code as needed. How to do it... The steps for getting the blocks from an area are as follows: Open /config/site_post.php in your code editor. Load the page by its path: $page = Page::getByPath('/about'); Get the array of blocks in the page's content area. $blocks = $page->getBlocks('content'); Loop through the array, printing each block's handle. foreach ($blocks as $block) { echo $block->getBlockTypeHandle().'<br />'; } Exit the process. exit; How it works... concrete5 will return an array of block objects for every block that is contained within a content area. Developers can then loop through this array to manipulate or read the block objects. Summary This article discussed how to create custom block types and integrate blocks in your own website using concrete5's blocks. Resources for Article : Further resources on this subject: Everything in a Package with concrete5 [Article] Creating Your Own Theme [Article] concrete5: Mastering Auto-Nav for Advanced Navigation [Article]
Read more
  • 0
  • 0
  • 2381
article-image-performance-testing-fundamentals
Packt
31 Jul 2013
12 min read
Save for later

Performance Testing Fundamentals

Packt
31 Jul 2013
12 min read
(For more resources related to this topic, see here.) The incident Up until recently, traffic on TrainBot had been light as it had only been opened to a handful of clients, since it was still in closed beta. Everything was fully operational and the application as a whole was very responsive. Just a few weeks ago, TrainBot was open to the public and all was still good and dandy. To celebrate the launch and promote its online training courses, Baysoft Training Inc. recently offered 75 percent off for all the training courses. However, that promotional offer caused a sudden influx on TrainBot, far beyond what the company had anticipated. Web traffic shot up by 300 percent and suddenly things took a turn for the worse. Network resources weren't holding up well, server CPUs and memory were at 90-95 percent and database servers weren't far behind due to high I/O and contention. As a result, most web requests began to get slower response times, making TrainBot totally unresponsive for most of its first-time clients. It didn't take too long after that for the servers to crash and for the support lines to get flooded. The aftermath It was a long night at BaySoft Training Inc. corporate office. How did this happen? Could this have been avoided? Why was the application and system not able to handle the load? Why weren't adequate performance and stress tests conducted on the system and application? Was it an application problem, a system resource issue or a combination of both? All of these were questions management demanded answers to from the group of engineers, which comprised software developers, network and system engineers, quality assurance (QA) testers, and database administrators gathered in the WAR room. There sure was a lot of finger pointing and blame to go around the room. After a little brainstorming, it wasn't too long for the group to decide what needed to be done. The application and its system resources will need to undergo extensive and rigorous testing. This will include all facets of the application and all supporting system resources, including, but not limited to, infrastructure, network, database, servers, and load balancers. Such a test will help all the involved parties to discover exactly where the bottlenecks are and address them accordingly. Performance testing Performance testing is a type of testing intended to determine the responsiveness, reliability, throughput, interoperability, and scalability of a system and/or application under a given workload. It could also be defined as a process of determining the speed or effectiveness of a computer, network, software application, or device. Testing can be conducted on software applications, system resources, targeted application components, databases, and a whole lot more. It normally involves an automated test suite as this allows for easy, repeatable simulations of a variety of normal, peak, and exceptional load conditions. Such forms of testing help verify whether a system or application meets the specifications claimed by its vendor. The process can compare applications in terms of parameters such as speed, data transfer rate, throughput, bandwidth, efficiency, or reliability. Performance testing can also aid as a diagnostic tool in determining bottlenecks and single points of failure. It is often conducted in a controlled environment and in conjunction with stress testing; a process of determining the ability of a system or application to maintain a certain level of effectiveness under unfavorable conditions. Why bother? Using Baysoft's case study mentioned earlier, it should be obvious why companies bother and go through great lengths to conduct performance testing. Disaster could have been minimized, if not totally eradicated, if effective performance testing had been conducted on TrainBot prior to opening it up to the masses. As we go ahead in this article, we will continue to explore the many benefits of effective performance testing. At a very high level, performance testing is always almost conducted to address one or more risks related to expense, opportunity costs, continuity, and/or corporate reputation. Conducting such tests help give insights to software application release readiness, adequacy of network and system resources, infrastructure stability, and application scalability, just to name a few. Gathering estimated performance characteristics of application and system resources prior to the launch helps to address issues early and provides valuable feedback to stakeholders, helping them make key and strategic decisions. Performance testing covers a whole lot of ground including areas such as: Assessing application and system production readiness Evaluating against performance criteria Comparing performance characteristics of multiple systems or system configurations Identifying source of performance bottlenecks Aiding with performance and system tuning Helping to identify system throughput levels Testing tool Most of these areas are intertwined with each other, each aspect contributing to attaining the overall objectives of stakeholders. However, before jumping right in, let's take a moment to understand the core activities in conducting performance tests: Identify the test environment: Becoming familiar with the physical test and production environments is crucial to a successful test run. Knowing things, such as the hardware, software, and network configurations of the environment help derive an effective test plan and identify testing challenges from the outset. In most cases, these will be revisited and/or revised during the testing cycle. Identify acceptance criteria: What is the acceptable performance of the various modules of the application under load? Specifically, identify the response time, throughput, and resource utilization goals and constraints. How long should the end user wait before rendering a particular page? How long should the user wait to perform an operation? Response time is usually a user concern, throughput a business concern, and resource utilization a system concern. As such, response time, throughput, and resource utilization are key aspects of performance testing. Acceptance criteria is usually driven by stakeholders and it is important to continuously involve them as testing progresses as the criteria may need to be revised. Plan and design tests: Know the usage pattern of the application (if any), and come up with realistic usage scenarios including variability among the various scenarios. For example, if the application in question has a user registration module, how many users typically register for an account in a day? Do those registrations happen all at once, or are they spaced out? How many people frequent the landing page of the application within an hour? Questions such as these help to put things in perspective and design variations in the test plan. Having said that, there may be times where the application under test is new and so no usage pattern has been formed yet. At such times, stakeholders should be consulted to understand their business process and come up with as close to a realistic test plan as possible. Prepare the test environment: Configure the test environment, tools, and resources necessary to conduct the planned test scenarios. It is important to ensure that the test environment is instrumented for resource monitoring to help analyze results more efficiently. Depending on the company, a separate team might be responsible for setting up the test tools, while another may be responsible for configuring other aspects such as resource monitoring. In other organizations, a single team is responsible for setting up all aspects. Record the test plan: Using a testing tool, record the planned test scenarios. There are numerous testing tools available, both free and commercial that do the job quite well, each having their pros and cons. Such tools include HP Load Runner, NeoLoad, LoadUI, Gatling, WebLOAD, WAPT, Loadster, LoadImpact, Rational Performance Tester, Testing Anywhere, OpenSTA, Loadstorm, and so on. Some of these are commercial while others are not as mature or as portable or extendable as JMeter is. HP Load Runner, for example, is a bit pricey and limits the number of simulated threads to 250 without purchasing additional licenses. It does offer a much nicer graphical interface and monitoring capability though. Gatling is the new kid on the block, is free and looks rather promising. It is still in its infancy and aims to address some of the shortcomings of JMeter, including easier testing DSL (domain specific language) versus JMeter's verbose XML, nicer and more meaningful HTML reports, among others. Having said that, it still has only a tiny user base when compared with JMeter, and not everyone may be comfortable with building test plans in Scala, its language of choice. Programmers may find it more appealing. In this book, our tool of choice will be Apache JMeter to perform this step. That shouldn't be a surprise considering the title of the book. Run the tests: Once recorded, execute the test plans under light load and verify the correctness of the test scripts and output results. In cases where test or input data is fed into the scripts to simulate more realistic data , also validate the test data. Another aspect to pay careful attention to during test plan execution is the server logs. This can be achieved through the resource monitoring agents set up to monitor the servers. It is paramount to watch for warnings and errors. A high rate of errors, for example, could be indicative that something is wrong with the test scripts, application under test, system resource, or a combination of these. Analyze results, report, and retest: Examine the results of each successive run and identify areas of bottleneck that need addressing. These could be system, database, or application related. System-related bottlenecks may lead to infrastructure changes such as increasing the memory available to the application, reducing CPU consumption, increasing or decreasing thread pool sizes, revising database pool sizes, and reconfiguring network settings. Database-related bottlenecks may lead to analyzing database I/O operations, top queries from the application under test, profiling SQL queries, introducing additional indexes, running statistics gathering, changing table page sizes and locks, and a lot more. Finally, application-related changes might lead to activities such as refactoring application components, reducing application memory consumption and database round trips. Once the identified bottlenecks are addressed, the test(s) should then be rerun and compared with previous runs. To help better track what change or group of changes resolved a particular bottleneck, it is vital that changes are applied in an orderly fashion, preferably one at a time. In other words, once a change is applied, the same test plan is executed and the results compared with a previous run to see if the change made had any improved or worsened effect on results. This process repeats until the performance goals of the project have been met. Performance testing core activities Performance testing is usually a collaborative effort between all parties involved. Parties include business stakeholders, enterprise architects, developers, testers, DBAs, system admins, and network admins. Such collaboration is necessary to effectively gather accurate and valuable results when conducting testing. Monitoring network utilization, database I/O and waits, top queries, and invocation counts, for example, helps the team find bottlenecks and areas that need further attention in ongoing tuning efforts. 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 as incompatible 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: Configuring changes in system resources Optimizing database queries Reducing round trips in application calls; sometimes leading to re-designing 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 volume of hardware needed, or further increase system performance. After each change (or series of changes), the test is re-executed to see whether performance has increased or declined as a result of the changes. The process will be continued until the performance results reach 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 the driving result towards the targeted goal. Armed with such baseline results, subsequent changes can be made to system configuration or application and testing results compared to see whether such changes were relevant or not. Some considerations when generating baselines include: 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 is the system. Since load ultimately affects how a system responds, performance testing is almost always done in conjunction with stress testing.
Read more
  • 0
  • 0
  • 2354

article-image-setting-environment-cucumber-bdd-rails
Packt
31 Jul 2013
4 min read
Save for later

Setting up environment for Cucumber BDD Rails

Packt
31 Jul 2013
4 min read
(For more resources related to this topic, see here.) Getting ready This article will focus on how to use Cucumber in daily BDD development on the Ruby on Rails platform. Please install the following software to get started: Ruby Version Manager Version 1.9.3 of Ruby Version 3.2 of Rails The latest version of Cucumber A handy text editor; Vim or Sublime Text How to do it... To install RVM, bundler, and Rails we need to complete the following steps: Install RVM (read the latest installation guide from http://rvm.io ). $ curl -L https://get.rvm.io | bash -s stable --ruby Install the latest version of Ruby as follows: $ rvm install ruby-1.9.3 Install bundler as follows: $ gem install bundler Install the latest version of Rails as follows: $ gem install rails Cucumber is a Ruby gem. To install it we can run the following command in the terminal: Cucumber contains two parts: features and step definitions. They are explained in the following section: $ gem install cucumber If you are using bundler in your project, you need to add the following lines into your Gemfile: gem 'cucumber' How it works... We will have to go through the following files to see how this recipe works: Feature files (their extension is .feature): Each feature is captured as a "story", which defines the scope of the feature along with its acceptance criteria. A feature contains a feature title and a description of one or more scenarios. One scenario contains describing steps. Feature: A unique feature title within the project scope with a description. Its format is as follows: Feature: <feature title><feature description> Scenario: This elaborates how the feature ought to behave. Its format is as follows: Scenario: <Scenario short description>Given <some initial context>When <an event occurs>Then <ensure some outcomes> Step definition files: A step definition is essentially a block of code associated with one or more steps by a regular expression (or, in simple cases, an exact equivalent string). Given "I log into system through login page" dovisit login_pagefill_in "User name", :with => "wayne"fill_in "Password", :with => "123456"click_button "Login"end When running a Cucumber feature, each step in the feature file is like a method invocation targeting the related step definition. Each step definition is like a Ruby method which takes one or more arguments (the arguments are interpreted and captured by the Cucumber engine and passed to the step method; this is essentially done by regular expression). The engine reads the feature steps and tries to find the step definition one by one. If all the steps match and are executed without any exceptions thrown, then the result will be passed; otherwise, if one or more exceptions are thrown during the run, the exception can be one of the following: Cucumber::Undefined: Step was an undefined exception Cucumber::Pending: Step was defined but is pending implementation Ruby runtime exception: Any kind of exception thrown during step execution Similar with other unit-testing frameworks, Cucumber runs will either pass or fail depending on whether or not exception(s) are thrown, whereas the difference is that according to different types of exceptions, running a Cucumber could result in the following four kinds: Passed Pending Undefined Failed The following figure demonstrates the flow chart of running a Cucumber feature: There's more... Cucumber is not only for Rails, and the Cucumber feature can be written in many other languages other than English. Cucumber in other languages/platforms Cucumber is now available on many platforms. The following is a list of a number of popular ones: JVM: Cucumber-JVM .NET: SpecFlow Python: RubyPython, Lettuce PHP: Behat Erlang: Cucumberl Cucumber in your mother language We can actually write Gherkin in languages other than English too, which is very important because domain experts might not speak English. Cucumber now supports 37 different languages. There are many great resources online for learning Cucumber: The Cucumber home page: http://cukes.info/ The Cucumber project on Github: https://github.com/cucumber/cucumber The Cucumber entry on Wikipedia: http://en.wikipedia.org/wiki/ Cucumber_(software) The Cucumber backgrounder: https://github.com/cucumber/cucumber/ wiki/Cucumber-Backgrounder Summary: In this article we saw what is Cucumber, how to use Cucumber in daily BDD development on the Ruby on Rails, how to install RVM, bundler, and Rails, running a Cucumber feature, and Cucumber in different language and platform. Resources for Article : Further resources on this subject: Introducing RubyMotion and the Hello World app [Article] Building tiny Web-applications in Ruby using Sinatra [Article] Xen Virtualization: Work with MySQL Server, Ruby on Rails, and Subversion [Article]
Read more
  • 0
  • 0
  • 3094
Modal Close icon
Modal Close icon