Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-apache-ofbiz-service-engine-part-1
Packt
21 Oct 2009
6 min read
Save for later

Apache OFBiz Service Engine: Part 1

Packt
21 Oct 2009
6 min read
Defining a Service We first need to define a service. Our first service will be named learningFirstService. In the folder ${component:learning}, create a new folder called servicedef. In that folder, create a new file called services.xml and enter into it this: <?xml version="1.0" encoding="UTF-8" ?> <services xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/services.xsd"> <description>Learning Component Services</description> <service name="learningFirstService" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="learningFirstService"> <description>Our First Service</description> <attribute name="firstName" type="String" mode="IN" optional="true"/> <attribute name="lastName" type="String" mode="IN" optional="true"/> </service> </services> In the file ${component:learning}ofbiz-component.xml, add after the last <entity-resource> element this: <service-resource type="model" loader="main" location="service def/services.xml"/> That tells our component learning to look for service definitions in the file ${component:learning}servicedefservices.xml. It is important to note that all service definitions are loaded at startup; therefore any changes to any of the service definition files will require a restart! Creating the Java Code for the Service In the package org.ofbiz.learning.learning, create a new class called LearningServices with one static method learningFirstService: package org.ofbiz.learning.learning; import java.util.Map; import org.ofbiz.service.DispatchContext; import org.ofbiz.service.ServiceUtil; public class LearningServices { public static final String module = LearningServices.class.getName(); public static Map learningFirstService(DispatchContext dctx, Map context){ Map resultMap = ServiceUtil.returnSuccess("You have called on service 'learningFirstService' successfully!"); return resultMap; } } Services must return a map. This map must contain at least one entry. This entry must have the key responseMessage (see org.ofbiz.service.ModelService.RESPONSE_MESSAGE), having a value of one of the following: success or ModelService.RESPOND_SUCCESS error or ModelService.RESPOND_ERROR fail or ModelService.RESPOND_FAIL By using ServiceUtil.returnSuccess() to construct the minimal return map, we do not need to bother adding the responseMessage key and value pair. Another entry that is often used is that with the key successMessage (ModelService.SUCCESS_MESSAGE). By doing ServiceUtil.returnSuccess("Some message"), we will get a return map with entry successMessage of value "Some message". Again, ServiceUtil insulates us from having to learn the convention in key names. Testing Our First Service Stop OFBiz, recompile our learning component and restart OFBiz so that the modified ofbiz-component.xml and the new services.xml can be loaded. In ${component:learning}widgetlearningLearningScreens.xml, insert a new Screen Widget: <screen name="TestFirstService"> <section> <widgets> <section> <condition><if-empty field-name="formTarget"/></condition> <actions> <set field="formTarget" value="TestFirstService"/> <set field="title" value="Testing Our First Service"/> </actions> <widgets/> </section> <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}"> <decorator-section name="body"> <include-form name="TestingServices" location="component://learning/widget/learning/LearningForms.xml"/> <label text="Full Name: ${parameters.fullName}"/> </decorator-section> </decorator-screen> </widgets> </section> </screen> In the file ${component:learning}widgetlearningLearningForms.xml, insert a new Form Widget: <form name="TestingServices" type="single" target="${formTarget}"> <field name="firstName"><text/></field> <field name="lastName"><text/></field> <field name="planetId"><text/></field> <field name="submit"><submit/></field> </form> Notice how the formTarget field is being set in the screen and used in the form. For now don't worry about the Full Name label we are setting from the screen. Our service will eventually set that. In the file ${webapp:learning}WEB-INFcontroller.xml, insert a new request map: <request-map uri="TestFirstService"> <event type="service" invoke="learningFirstService"/> <response name="success" type="view" value="TestFirstService"/> </request-map> The control servlet currently has no way of knowing how to handle an event of type service, so in controller.xml we must add a new handler element immediately under the other <handler> elements: <handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/> <handler name="service-multi" type="request" class="org.ofbiz.webapp.event.ServiceMultiEventHandler"/> We will cover service-multi services later. Finally add a new view map: <view-map name="TestFirstService" type="screen" page="component://learning/widget/learning/LearningScreens.xml#TestFirstService"/> Fire to webapp learning an http OFBiz request TestFirstService, and see that we have successfully invoked our first service: Service Parameters Just like Java methods, OFBiz services can have input and output parameters and just like Java methods, the parameter types must be declared. Input Parameters (IN) Our first service is defined with two parameters: <attribute name="firstName" type="String" mode="IN" optional="true"/> <attribute name="lastName" type="String" mode="IN" optional="true"/> Any parameters sent to the service by the end-user as form parameters, but not in the services list of declared input parameters, will be dropped. Other parameters are converted to a Map by the framework and passed into our static method as the second parameter. Add a new method handleInputParamaters to our LearningServices class. public static Map handleParameters(DispatchContext dctx, Map context){ String firstName = (String)context.get("firstName"); String lastName = (String)context.get("lastName"); String planetId= (String)context.get("planetId"); String message = "firstName: " + firstName + "<br/>"; message = message + "lastName: " + lastName + "<br/>"; message = message + "planetId: " + planetId; Map resultMap = ServiceUtil.returnSuccess(message); return resultMap; } We can now make our service definition invoke this method instead of the learningFirstService method by opening our services.xml file and replacing: <service name="learningFirstService" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="learningFirstService"> with: <service name="learningFirstService" engine="java" location="org.ofbiz.learning.learning.LearningServices" invoke="handleParameters"> Once again shutdown, recompile, and restart OFBiz. Enter for fields First Name, Last Name, and Planet Id values Some, Name, and Earth, respectively. Submit and notice that only the first two parameters went through to the service. Parameter planetId was dropped silently as it was not declared in the service definition. Modify the service learningFirstService in the file ${component:learning}servicedefservices.xml, and add below the second parameter a third one like this: <attribute name="planetId" type="String" mode="IN" optional="true"/> Restart OFBiz and submit the same values for the three form fields, and see all three parameters go through to the service.  
Read more
  • 0
  • 0
  • 3399

article-image-access-control-php5-cms-part-2
Packt
21 Oct 2009
17 min read
Save for later

Access Control in PHP5 CMS - Part 2

Packt
21 Oct 2009
17 min read
Framework Solution The implementation of access control falls into three classes. One is the class that is asked questions about who can do what. Closely associated with this is another class that caches general information applicable to all users. It is made a separate class to aid implementation of the split of cache between general and user specific. The third class handles administration operations. Before looking at the classes, though, let's figure out the database design. Database for RBAC All that is required to implement basic RBAC is two tables. A third table is required to extend to a hierarchical model. An optional extra table can be implemented to hold role descriptions. Thinking back to the design considerations, the first need is for a way to record the operations that can be done on the subjects, that is the permissions. They are the targets for our access control system. You'll recall that a permission consists of an action and a subject, where a subject is defined by a type, and an identifier. For ease of handling, a simple auto-increment ID number is added. But we also need a couple of other things. To make our RBAC system general, it is important to be able to control not only the actual permissions, but also who can grant those permissions, and whether they can grant that right to others. So an extra control field is added with one bit for each of those three possibilities. It therefore becomes possible to grant the right to access something with or without the ability to pass on that right. The other extra data item that is useful is a "system" flag. It is used to make some permissions incapable of deletion. Although not being a logical requirement, this is certainly a practical requirement. We want to give administrators a lot of power over the configuration of access rights, but at the same time, we want to avoid any catastrophes. The sort of thing that would be highly undesirable would be for the top level administrator to remove all of their own rights to the system. In practice, most systems will have a critical central structure of rights, which should not be altered even by the highest administrator. So now the permissions table can be seen to be as shown in the following screenshot: Note that the character strings for role, action, and subject_type are given generous lengths of 60, which should be more than adequate. The subject ID will often be quite short, but to avoid constraining generality, it is made a text field, so that the RBAC system can still handle very complex identifiers, if required. Of course, there will be some performance penalties if this field is very long, but it is better to have a design trade-off than a limitation. If we restricted the subject ID to being a number, then more complex identifiers would be a special case. This would destroy the generality of our scheme, and might ultimately reduce overall efficiency. In addition to the auto-increment primary key ID, two indices are created, as shown in the following screenshot. They involve overhead during update operations but are likely to speed access operations. Since far more accesses will typically be made than updates, this makes sense. If for some reason an index does not give a benefit, it is always possible to drop it. Note that the index on the subject ID has to be constrained in length to avoid breaking limits on key size. The value chosen is a compromise between efficiency through short keys, and efficiency through the use of fine grained keys. In a heavily used system, it would be worth reviewing the chosen figure carefully, and perhaps modifying it in the light of studies into actual data. The other main database table is even simpler, and holds information about assignment of accessors to roles. Again, an auto-increment ID is added for convenience. Apart from the ID, the only fields required are the role, the accessor type, and the accessor ID. This time a single index, additional to the primary key, is sufficient. The assignment table is shown in the following screenshot, and its index is shown in the screenshot after that: Adding hierarchy to RBAC requires only a very simple table, where each row contains two fields: a role, and an implied role. Both fields constitute the primary key, neither field on its own being necessarily unique. An index is not required for efficiency, since the volume of hierarchy information is assumed to be small, and whenever it is needed, the whole table is read. But it is still a good principle to have a primary key, and it also guarantees that there will not be redundant entries. For the example given earlier, a typical entry might have consultant as the role, and doctor as the implied role. At present, Aliro implements hierarchy only for backwards compatibility, but it is a relatively easy development to make hierarchical relationships generally available. Optionally, an extra table can be used to hold a description of the roles in use. This has no functional purpose, and is simply an option to aid administrators of the system. The table should have the role as its primary key. As it does not affect the functionality of the RBAC at all, no further detail is given here. With the database design settled, let's look at the classes. The simplest is the administration class, so we'll start there. Administering RBAC The administration of the system could be done by writing directly to the database, since that is what most of the operations involve. There are strong reasons not to do so. Although the operations are simple, it is vital that they be handled correctly. It is generally a poor principle to allow access to the mechanisms of a system rather than providing an interface through class methods. The latter approach ideally allows the creation of a robust interface that changes relatively infrequently, while details of implementation can be modified without affecting the rest of the system. The administration class is kept separate from the classes handling questions about access because for most CMS requests, administration will not be needed, and the administration class will not load at all. As a central service, the class is implemented as a standard singleton, but it is not cached because information generally needs to be written immediately to the database. In fact, the administration class frequently requests the authorization cache class to clear its cache so that the changes in the database can be effective immediately. The class starts off: class aliroAuthorisationAdmin { private static $instance = __CLASS__; private $handler = null; private $authoriser = null; private $database = null; private function __construct() { $this->handler =& aliroAuthoriserCache::getInstance(); $this->authoriser =& aliroAuthoriser::getInstance(); $this->database = aliroCoreDatabase::getInstance(); } private function __clone() { // Enforce singleton } public static function getInstance() { return is_object(self::$instance) ? self::$instance : (self::$instance = new self::$instance()); } private function doSQL($sql, $clear=false) { $this->database->doSQL($sql); if ($clear) $this->clearCache(); } private function clearCache() { $this->handler->clearCache(); } Apart from the instance property that is used to implement the singleton pattern, the other private properties are related objects that are acquired in the constructor to help other methods. Getting an instance operates in the usual fashion for a singleton, with the private constructor, and clone methods enforcing access solely via getInstance. The doSQL method also simplifies other methods by combining a call to the database with an optional clearing of cache through the class's clearCache method. Clearly the latter is simple enough that it could be eliminated. But it is better to have the method in place so that if changes were made to the implementation such that different actions were needed when any relevant cache is to be cleared, the changes would be isolated to the clearCache method. Next we have a couple of useful methods that simply refer to one of the other RBAC classes: public function getAllRoles($addSpecial=false) { return $this->authoriser->getAllRoles($addSpecial); }public function getTranslatedRole($role) { return $this->authoriser->getTranslatedRole($role); } Again, these are provided so as to simplify the future evolution of the code so that implementation details are concentrated in easily identified locations. The general idea of getAllRoles is obvious from the name, and the parameter determines whether the special roles such as visitor, registered, and nobody will be included. Since those roles are built into the system in English, it would be useful to be able to get local translations for them. So the method getTranslatedRole will return a translation for any of the special roles; for other roles it will return the parameter unchanged, since roles are created dynamically as text strings, and will therefore normally be in a local language from the outset. Now we are ready to look at the first meaty method: public function permittedRoles ($action, $subject_type, $subject_id) { $nonspecific = true; foreach ($this->permissionHolders ($subject_type, $subject_id) as $possible) { if ('*' == $possible->action OR $action == $possible->action) { $result[$possible->role] = $this->getTranslatedRole ($possible->role); if ('*' != $possible->subject_type AND '*' != $possible_subject_id) $nonspecific = false; } } if (!isset($result)) { if ($nonspecific) $result = array('Visitor' => $this->getTranslatedRole('Visitor')); else return array(); } return $result; }private function &permissionHolders ($subject_type, $subject_id) { $sql = "SELECT DISTINCT role, action, control, subject_type, subject_id FROM #__permissions"; if ($subject_type != '*') $where[] = "(subject_type='$subject_type' OR subject_type='*')"; if ($subject_id != '*') $where[] = "(subject_id='$subject_id' OR subject_id='*')"; if (isset($where)) $sql .= " WHERE ".implode(' AND ', $where); return $this->database->doSQLget($sql); } Any code that is providing an RBAC administration function for some part of the CMS is likely to want to know what roles already have a particular permission so as to show this to the administrator in preparation for any changes. The private method permissionHolders uses the parameters to create a SQL statement that will obtain the minimum relevant permission entries. This is complicated by the fact that in most contexts, asterisk can be used as a wild card. The public method permittedRoles uses the private method to obtain relevant database rows from the permissions table. These are checked against the action parameter to see which of them are relevant. If there are no results, or if none of the results refer specifically to the subject, without the use of wild cards, then it is assumed that all visitors can access the subject, so the special role of visitor is added to the results. When actual permission is to be granted we need the following methods: public function permit ($role, $control, $action, $subject_type, $subject_id) { $sql = $this->permitSQL($role, $control, $action, $subject_type, $subject_id); $this->doSQL($sql, true); }private function permitSQL ($role, $control, $action, $subject_type, $subject_id) { $this->database->setQuery("SELECT id FROM #__permissions WHERE role='$role' AND action='$action' AND subject_type='$subject_type' AND subject_id='$subject_id'"); $id = $this->database->loadResult(); if ($id) return "UPDATE #__permissions SET control=$control WHERE id=$id"; else return "INSERT INTO #__permissions (role, control, action, subject_type, subject_id) VALUES ('$role', '$control', '$action', '$subject_type', '$subject_id')"; } The public method permit grants permission to a role. The control bits are set in the parameter $control. The action is part of permission, and the subject of the action is identified by the subject type and identity parameters. Most of the work is done by the private method that generates the SQL; it is kept separate so that it can be used by other methods. Once the SQL is obtained, it can be passed to the database, and since it will normally result in changes, the option to clear the cache is set.   The SQL generated depends on whether there is already a permission with the same parameters, in which case only the control bits are updated. Otherwise an insertion occurs. The reason for having to do a SELECT first, and then decide on INSERT or UPDATE is that the index on the relevant fields is not guaranteed to be unique, and also because the subject ID is allowed to be much longer than can be included within an index. It is therefore not possible to use ON DUPLICATE KEY UPDATE. Wherever possible, it aids efficiency to use the MySQL option for ON DUPLICATE KEY UPDATE. This is added to the end of an INSERT statement, and if the INSERT fails by virtue of the key already existing in the table, then the alternative actions that follow ON DUPLICATE KEY UPDATE are carried out. They consist of one or more assignments, separated by commas, just as in an UPDATE statement. No WHERE is permitted since the condition for the assignments is already determined by the duplicate key situation. A simple method allows deletion of all permissions for a particular action and subject: public function dropPermissions ($action, $subject_type, $subject_id) { $sql = "DELETE FROM #__permissions WHERE action='$action' AND subject_type='$subject_type'AND subject_id='$subject_id' AND system=0"; $this->doSQL($sql, true); } The final set of methods relates to assigning accessors to roles. Two of them reflect the obvious need to be able to remove all roles from an accessor (possibly preparatory to assigning new roles) and the granting of a role to an accessor. Where the need is to assign a whole set of roles, it is better to have a method especially for the purpose. Partly this is convenient, but it also provides an extra operation, minimization of the set of roles. The method is: public function assign ($role, $access_type, $access_id, $clear=true) { if ($this->handler->barredRole($role)) return false; $this->database->setQuery("SELECT id FROM #__assignments WHERE role='$role' AND access_type='$access_type' AND access_id='$access_id'"); if ($this->database->loadResult()) return true; $sql = "INSERT INTO #__assignments (role, access_type, access_id) VALUES ('$role', '$access_type', '$access_id')"; $this->doSQL($sql, $clear); return true; }public function assignRoleSet ($roleset, $access_type, $access_id) { $this->dropAccess ($access_type, $access_id); $roleset = $this->authoriser->minimizeRoleSet($roleset); foreach ($roleset as $role) $this->assign ($role, $access_type, $access_id, false); $this->clearCache(); }public function dropAccess ($access_type, $access_id) { $sql = "DELETE FROM #__assignments WHERE access_type='$access_type' AND access_id='$access_id'"; $this->doSQL($sql, true); } The method assign links a role to an accessor. It checks for barred roles first, these are simply the special roles discussed earlier, which cannot be allocated to any accessor. As with the permitSQL method, it is not possible to use ON DUPLICATE KEY UPDATE because the full length of the accessor ID is not part of an index, so again the existence of an assignment is checked first. If the role assignment is already in the database, there is nothing to do. Otherwise a row is inserted, and the cache is cleared. Getting rid of all role assignments for an accessor is a simple database deletion, and is implemented in the dropAccess method. The higher level method assignRoleSet uses dropAccess to clear out any existing assignments. The call to the authorizer object to minimize the role set reflects the implementation of a hierarchical model. Once there is a hierarchy, it is possible for one role to imply another as consultant implied doctor in our earlier example. This means that a role set may contain redundancy. For example, someone who has been allocated the role of consultant does not need to be allocated the role of doctor. The minimizeRoleSet method weeds out any roles that are superfluous. Once that has been done, each role is dealt with using the assign method, with the clearing of the cache saved until the very end. The General RBAC Cache As outlined earlier, the information needed to deal with RBAC questions is cached in two ways. The file system cache is handled by the aliroAuthoriserCache singleton class, which inherits from the cachedSingleton class. This means that the data of the singleton object will be automatically stored in the file system whenever possible, with the usual provisions for timing out an old cache, or clearing the cache when an update has occurred. It is highly desirable to cache the data both to avoid database operations and to avoid repeating the processing needed in the constructor. So the intention is that the constructor method will run only infrequently. It contains this code: protected function __construct() { // Making private enforces singleton $database = aliroCoreDatabase::getInstance(); $database->setQuery("SELECT role, implied FROM #__role_link UNION SELECT DISTINCT role, role AS implied FROM #__assignments UNION SELECT DISTINCT role,role AS implied FROM #__permissions"); $links = $database->loadObjectList(); if ($links) foreach ($links as $link) { $this->all_roles[$link->role] = $link->role; $this->linked_roles[$link->role][$link->implied] = 1; foreach ($this->linked_roles as $role=>$impliedarray) { foreach ($impliedarray as $implied=>$marker) { if ($implied == $link->role OR $implied == $link->implied) { $this->linked_roles[$role][$link->implied] = 1; if (isset($this->linked_roles[$link->implied])) foreach ($this->linked_roles[$link->implied] as $more=>$marker) { $this->linked_roles[$role][$more] = 1; } } } } } $database->setQuery("SELECT role, access_id FROM #__assignments WHERE access_type = 'aUser' AND (access_id = '*' OR access_id = '0')"); $user_roles = $database->loadObjectList(); if ($user_roles) foreach ($user_roles as $role) $this- >user_roles[$role->access_id][$role->role] = 1; if (!isset($this->user_roles['0'])) $this->user_roles['0'] = array(); if (isset($this->user_roles['*'])) $this->user_roles['0'] = array_merge($this->user_roles['0'], $this->user_roles['*']); } All possible roles are derived by a UNION of selections from the permissions, assignments, and linked roles database tables. The union operation has overheads, so that alone is one reason for favoring the use of a cache. The processing of linked roles is also complex, and therefore worth running as infrequently as possible. Rather than working through the code in detail, it is more useful to describe what it is doing. The concept is much simpler than the detail! If we take an example from the backwards compatibility features of Aliro, there is a role hierarchy that includes the role Publisher, which implies membership of the role Editor. The role Editor also implies membership of the role Author. In the general case, it is unreasonable to expect the administrator to figure out the implied relationships. In this case, it is clear that the role Publisher must also imply membership of the role Editor. But these linked relationships can plainly become quite complex. The code in the constructor therefore assumes that only the least number of connections have been entered into the database, and it figures out all the implications. The other operation where the code is less than transparent is the setting of the user_roles property. The Aliro RBAC system permits the use of wild cards for specification of identities within accessor, or subject types. An asterisk indicates any identity. For accessors whose accessor type is user, another wild card available is zero. This means any user who is logged in, and is not an unregistered visitor. Given the relatively small number of role assignments of this kind, it saves a good deal of processing if all of them are cached. Hence the user_roles processing is done in the constructor. Other methods in the cache class are simple enough to be mentioned rather than given in detail. They include the actual implementation of the getTranslatedRole method, which provides local translations for the special roles. Other actual implementations are getAllRoles with the option to include the special roles, getTranslatedRole, which translates a role if it turns out to be one of the special ones and barredRole, which in turn, tests to see if the passed role is in the special group. It may therefore not be assigned to an accessor.
Read more
  • 0
  • 0
  • 2174

article-image-sakai-web-services-connecting-enterprise-part-1
Packt
21 Oct 2009
17 min read
Save for later

Sakai Web Services: Connecting to the Enterprise (Part 1)

Packt
21 Oct 2009
17 min read
Connecting to Sakai is straightforward, and simple tasks, such as automatic course creation, take only a few tens of lines of programming effort. There are significant advantages to having web services in the enterprise. If a developer writes an application that calls a number of web services, then the application does not need to know the hidden details behind the services. It just needs to agree on what data to send. This loosely couples the application to the services. Later, you can replace one web service with another. Programmers do not need to change the code on the application side. SOAP works well with most organizations' firewalls (http://en.wikipedia.org/wiki/Firewall), as SOAP uses the same protocol as web browsers. System administrators have a tendency to protect an organization's network by closing unused ports to the outside world. This means that most of the time there is no extra network configuration effort required to enable web services. Another simplifying factor is that a programmer does not need to know the details of SOAP or REST, as there are libraries and frameworks that hide the underlying magic. For the Sakai implementation of SOAP, to add a new service is as simple as writing a small amount of Java code within a text file, which then is automatically compiled and run the first time the service is called. This is great for rapid application development and deployment, as the system administrator does not need to restart Sakai for each change. Just as importantly, the Sakai services use the well-known libraries from the Apache Axis project (http://ws.apache.org/axis/). SOAP is an XML message passing protocol that, in the case of Sakai sites, sits on top of the Hyper Text Transfer Protocol (HTTP). HTTP is the protocol used by web browsers to obtain web pages from a server. The client sends messages in XML format to a service, including the information that the service needs, and then the service returns a message with the results or an error message. A readable reference to this interchange is the book Pro Apache XML by Poornachandra Sarang, PhD (http://www.freesoftwaremagazine.com/articles/book_review_pro_apache_xml). The full definition of HTTP is given at http://www.w3.org/TR/soap12-part1. The architects introduced SOAP-based web services first to Sakai and later RESTful services. Unlike SOAP, instead of sending XML via HTTP posts to one URL that points to a service, REST sends to a URL that includes information about the entity, such as a user, with which the client wishes to interact. For example, a REST URL for viewing an address book item could look similar to http://host/direct/addressbook_item/15. Applying URLs in this way makes understandable address spaces that are easier for a human to read. This more intuitive approach simplifies coding. Further, SOAP XML passing requires that the client and server parse the XML and at times, the parsing effort is expensive in CPU cycles and response times. The Entity Broker is an internal service that makes life easier for programmers and helps them manipulate entities. Entities in Sakai are managed pieces of data such as representations of courses, users, grade books, and so on. In the newer versions of Sakai, the Entity Broker has the power to expose entities as RESTful services. In contrast, for SOAP services, if you wanted a new service, you would need to write it yourself. Over time, the Entity Broker exposes more and more entities RESTfully, delivering more hooks free to integrate with other enterprise systems. Both SOAP and REST services sit on top of the HTTP protocol, which is explained in the next section of this article. Protocols This section explains how web browsers talk to servers in order to gather web pages. It explains how to use the telnet command and a visual tool called TCPMON (http://ws.apache.org/commons/tcpmon/tcpmontutorial.html) to gain insight into how web services and Web 2.0 technologies work. Playing with Telnet It turns out that message passing occurs via text commands between the browser and the server. Web browsers use HTTP (http://www.w3.org/Protocols/rfc2616/rfc2616.html) to get web pages and the embedded content from the server and to send form information to the server. HTTP talks between the client and server via text (7 bit ASCII) commands. When humans talk with each other, they have a wide vocabulary. However, HTTP uses fewer than twenty words. You can experiment directly with HTTP using a Telnet client to send your commands to a web server. For example, if your demonstration Sakai instance is running on port 8080, the following command will get you the login page: telnet localhost 8080GET /portal/login The GET command does what it sounds like and gets a web page. Forms can use the GET verb to send data at the end of the URL. For example, GET /portal/login?name=alan&age=15 is sending the variables name=alan and age=15 to the server. Installing TCPMON You can use the TCPMON tool to view requests and responses from a web browser such as Firefox. One of TCPMON's abilities is that it can act as an invisible man in the middle, recording the messages between the web browser and the server. Once set up, the requests sent from the browser go to TCPMON and TCPMON passes the request on to the server. The server passes back a response and then TCPMON, a transparent proxy (http://en.wikipedia.org/wiki/Proxy_server), returns the response to the web browser. This allows us to look at all requests and responses graphically. First, you can set TCPMON up to listen on a given port number—by convention, normally, port 8888—and then you can configure your web browser to send its requests through the proxy. Then, you can type the address of a given page into the web browser, but instead of going directly to the relevant server, the browser sends the request to the proxy, which then passes it on and passes the response back. TCPMON displays both the request and responses in a window. You can download TCPMON from http://ws.apache.org/commons/tcpmon/download.cgi. After downloading and unpacking, you can, from within the build directory, run either tcpmon.bat for the Windows environment or tcpmon.sh for Unix/Linux environments. To configure a proxy, you can click the Admin tab and then set the Listen Port to 8888 and select the Proxy radio button. After that, clicking Add will create a new tab, where the requests and responses will later be displayed. Your favorite web browser now has to recognize the newly set up proxy. For Firefox 3, you can do this by selecting the menu option Edit/Preferences and then choosing the advanced tab and the network tab, as shown next. You will need to set the proxy options HTTP proxy to 127.0.0.1 and the port number to 8888. If you do this, you will need to ensure that the No proxies text input is blank. Clicking the OK button enables the new settings. To use the Proxy from within Internet Explorer 7 for a Local Area Network (LAN), you can edit the dialog box found under Tools | Internet Options | Connections | LAN settings. Once the proxy is working, typing http://localhost:8080/portal/login in the address bar will seamlessly return the login page of your local Sakai instance. Otherwise, you will see an error message similar to Proxy Server Refused Connection for Firefox or Internet Explorer cannot display the webpage. To turn the proxy settings off, simply select the No Proxies radio box and click OK for Firefox 3, or unselect the Use the proxy server for the LAN tick box in Internet Explorer 7 and click OK. Requests and returned status codes When TCPMON is running a proxy on port 8888, it allows you to view the requests from the browser and the response in an extra tab, as shown in the following screen grab. Notice the extra information that the browser sends as part of the request. HTTP/1.1 defines the protocol and version level and the lines below the GET are header variables. The User-Agent defines which client sent the request. The Accept headers tell the server what the capabilities of the browser are, and the Cookie header defines the value stored in a cookie. HTTP is stateless, that is, in principle; each response is based only on the current request. However, to get around this, persistent information can be stored in cookies. Web browsers normally store their representation of a cookie as a little text file or in a small database on the end users' computers. Sakai uses the supporting features of a servlet container, such as Tomcat, to maintain state in cookies. A cookie stores a session ID, and when the server sees the session ID, it can look up the request's server-side state. Server-side state contains information such as whether the user is logged in or what he or she has ordered. The web browser deletes the local representation of the cookie each time the browser closes. A cookie that is deleted when a web browser closes is known as a session cookie. The server response starts with the protocol followed by a status number. HTTP/1.1 200 OK tells the web browser that the server is using HTTP version 1.1 and it was able to return the requested web page successfully. 2xx status codes imply success. 3xx status codes imply some form of redirection and tell the web browser where to try to pick up the requested resource. 4xx status codes are for client errors, such as malformed requests or lack of permission to obtain the resource. 4xx states are fertile grounds for security managers to look in log files for attempted hacking. 5xx status codes mostly have to do with a failure of the server itself and are mostly of interest to system administrators and programmers during the debugging cycle. In most cases, 5xx status numbers are about either high server load or a broken piece of code. Sakai is changing rapidly and even with the most vigorous testing, there are bound to be the occasional hiccups. You will find accurate details of the full range of status codes at: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Another important part of the response is the Content-Type, which tells the web browser which type of material the response is returning so the browser knows how to handle it. For example, the web browser may want to run a plug-in for video types and display text natively. The Content-Length in characters is normally also given. After the header information is finished, there is a newline followed by the content. Web browsers interpret any redirects that are returned by sending extra requests. Web browsers also interpret any HTML pages and make multiple requests for resources such as JavaScript files and images. Modern browsers do not wait until the server returns all the requests, but render the HTML page live as the server returns the parts. The GET verb is not very efficient for posting a large amount of data, as the URL has a length limit of around 2000 characters. Further, the end user can see the form data, and the browser may encode entities such as spaces to make the URL unreadable. There is also a security aspect: if you are typing in passwords in forms using GET, others may see your password or other details. This is not a good idea, especially at Internet Cafés where the next user who logs on can see the password in the browsing history. The POST verb is a better choice. Let us take as an example the Sakai demonstration login page http://localhost:8080/portal/login. The login page itself contains a form tag that points with the POST method to the relogin page. <form method="post" action="http://localhost:8080/portal/relogin" enctype="application/x-www-form-urlencoded"> Notice the HTML tag also defines the content type. Key features of the Post request compared to the GET are: the form values are stored as content after the header values, there is a newline between the end of the header and the data, and the request mentions data and the amount of data by the use of the Content-Length header value. The essential POST values for a login form with user admin (eid=admin) and password admin (pw=admin) will look like: POST http://localhost:8080/portal/relogin HTTP/1.1Content-Type: application/x-www-form-urlencodedContent-Length: 31eid=admin&pw=admin&submit=Login POSTs can contain much more information than GETs, and the request hides the values from the Address bar of the web browser. This is not secure. The header is just as visible as the URL, so POST values are also neither hidden nor secure. The only viable solution is for your web browser to encrypt your transactions using SSL/TLS (http://www.ietf.org/rfc/rfc2246.txt) for security, and this occurs every time you connect to a server using an HTTPS URL. SOAP Sakai uses the Apache Axis framework, which the developers have configured to accept SOAP calls via POST. SOAP sends messages in a specific XML format with the Content-Type, otherwise known as MIME type, application/soap+xml. A programmer does not need to know much more than that, as client libraries take care of the majority of the excruciating low-level details. An example SOAP message generated by the Perl module SOAP::Lite (http://www.soaplite.com/) for creating a login session in Sakai will look like the following Post data: <?xml version="1.0" encoding="UTF-8"?><soap:Envelope soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" ><soap:Body><login ><c-gensym3 xsi_type="xsd:string">admin</c-gensym3><c-gensym5 xsi_type="xsd:string">admin</c-gensym5></login></soap:Body></soap:Envelope> There is an envelope with a body containing data for the service to consume. The important point to remember is that both the client and the server have to be able to parse the specific XML schema. SOAP messages can include extra security features, but Sakai does not require these. The architects expect organizations to encrypt web services using SSL/TSL. The last extra SOAP-related complexity is the Web Service Description Language (http://www.w3.org/TR/wsdl). Web services may change location or exist in multiple locations for redundancy. The service writer can define the location of the services and the data types involved with those services in another file, in XML format. JSON Also worth mentioning is JavaScript Object Notation (JSON) (http://tools.ietf.org/html/rfc4627), which is another popular format passed using HTTP. A significant improvement in the quality of the end user experience during web browsing occurred when web developers realized that they could force browsers to load parts of a web page in at a time. This asynchronous loading enables all kinds of whiz-bang features, such as when you type in a search term and can choose from a set of search term completions before pressing submit. Asynchronous loading delivers more responsive and richer web pages that feel more like traditional applications than a plain old web page. JSON is one of the formats of choice for passing asynchronous requests and responses. The asynchronous communication normally occurs through HTTP GET or POST, but with a specific content structure that is designed to be human readable and script language parser-friendly. JSON calls have the file extension .json as part of the URL. As mentioned in RFC 4627, an example image object communicated in JSON looks like: { "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] }} To confuse the boundaries between client and server, a lot of the presentation and business logic is locked on the client side in scripting languages such as JavaScript. The scripting language orchestrates the loading of parts of pages and the generation of widget sets. Frameworks such as jQuery (http://jquery.com/) and MyFaces (http://myfaces.apache.org/) significantly ease the client-side programming burden. REST To understand REST, you need to understand the other verbs in HTTP (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html). The full HTTP set is OPTIONS, GET, HEAD, POST, PUT, DELETE, and TRACE. The HEAD verb returns from the server only the headers of the response without the content, and is useful for clients that want to see if the content has changed since the last request. PUT requests that the content in the request be stored at the particular location mentioned in the request. DELETE is for deleting the entity. REST uses the URL of the request to route to the resource, and the HTTP verb GET is used to get a resource, PUT to update, DELETE to delete, and POST to add a new resource. In general, POST=create an item, PUT=update an item, DELETE=delete an item, and GET=return information on the item. In SOAP, you are pointing directly towards the service the client calls or indirectly via the web service description. However, in REST, part of the URL describes the resource or resources you wish to work with. For example, a hypothetical address book application that lists all email addresses in HTML format would look similar to the following: GET /email To list the addresses in XML format or JSON format: GET /email.xmlGET /email.json To get the first email address in the list: GET /email/1 To create a new email address, of course remembering to add the rest of email details to the end of the GET: POST /email And to delete address 5 in the list: DELETE /email/5 To obtain address 5 in other formats such as JSON or XML, then use file extensions at the end of the URL, for example: GET /email/5.jsonGET /email/5.xml RESTful services are more intuitively descriptive than SOAP services and they enable easy switching of the format from HTML to JSON to fuel dynamic, asynchronously-loaded web sites. Due to the direct use of HTTP verbs by REST, this methodology also fits well with the most common application type: CRUD (Create, Read, Update, Delete) applications, such as the site or user tools within Sakai. Now that we have discussed the theory, in the next section, we shall discuss which Sakai-related SOAP services already exist. Existing web services Sakai has built in, by default, the most community-requested web services, and there are also a few more services in the contributed section of the source code repository. This section describes the currently available services and the next section explains an example use, creating a new user. Recapping terminology In general, developers write web services for other developer's code to connect to (consume). Therefore, terminology can be confusing. In Sakai, a realm is a set of roles and their associated permissions. When you create a site, a copy is made from a specific realm template for that particular site type. The permissions can then be modified for the roles in the site, and members added to the site with one or other of the specific roles. Internally, Sakai uses AuthzGroups to keep track of groups of users. An AuthzGroup is an authorization group (a group of users, each with a role and a set of permissions of functions assigned to each role). A site contains pages; when you click on the tool menu for a given tool, normally, you will see one tool displayed in a page. However, for the home page tool, you will see more tools contained within a page.
Read more
  • 0
  • 0
  • 2015

article-image-managing-pages-liferay-portal-52-systems-development
Packt
21 Oct 2009
14 min read
Save for later

Managing Pages in Liferay Portal 5.2 Systems Development

Packt
21 Oct 2009
14 min read
Each site is represented as a community and each community is made up of a lot of pages, for example, public pages and private pages. In order to build web sites, we need to manage communities and, further, manage pages for each community. The Communities portlet provides the ability to create and manage communities and their users, as well as of the Manage Pages portlet. Extending Communities portlet The Communities portlet provides the ability to create and manage communities and their users. A community is a special group holding a number of users who share common interests. By default, a community is represented by the Group_ table with fields such as groupId, companyId, creatorUserId, name, description, type, typeSettings, friendlyURL, active, and so on. Now let's take an in-depth look at the customization of the community. As shown in the following screenshot, we may want to add one searchable field for each community, which is Keywords. For example, suppose we are creating a new community with the name Book Street, and the description a community for website www.bookpubstreet.com. Now we have a chance to add the new Keywords field with the value, for example, Book; Street; Palm Tree; Publication. Similarly, when editing the properties of a community—for example Name, Description, Type, and Active—we again have a chance to edit Keywords. In addition, we expect to have more fields in the customized communities: Created (when the community was created), ModifierUserId (who modified the community), and Modified (when the community was modified). As shown in the preceding screenshot, when listing communities, not only should the default fields (for example, Name, Type, Members, Online Now, Active, Pending Requests) and Actions icons (for example, Edit, Permissions, Manage Pages, Assign User Roles, Assign Members, Leave, and Delete) be displayed, but also the customized columns (for example, the username and Keywords) should be displayed. How do we implement these features? In this article, we're going to show how to customize the Communities portlet using the above requirements as examples. Obviously, it is open for you to customize this portlet in a number of ways according to your own requirements. In general, the processes for customization of this portlet should be the same. Building Ext Communities portlet The Communities portlet can be used to create and manage new portal communities and their users. As you can see, a community can be regarded as a separate portal instance; each community gets its own set of pages, content management system, shared calendar, and default permissions. Moreover, a user belonging to multiple communities can navigate among them within the same portal session. Generally speaking, we do not want to update the Communities portlet, but keep it as it is. Our goal is to customize and extend it. In general, this can be done by using the following two steps: Build a customized Ext Communities portlet, which has exactly the same functions, look, and feel as that of the original Communities portlet. Extend this customized portlet and let it have an additional model and service, and moreover, its own look and feel. In this part, let's build the Ext Communities portlet, having exactly same functions, look, and feel as that of the Communities portlet. Constructing the portlet Now let's define a Struts portlet with the name "Ext Communities". We first need to configure it in both portlet-ext.xml and liferay-portlet-ext.xml, and then set the title in Language-ext.properties, and then add the Ext Communities portlet to the Book category in liferay-display.xml. Locate the portlet-ext.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it. Add the following lines between </portlet> and </portlet-app> and save the file: <portlet> <portlet-name>extCommunities</portlet-name> <display-name>Ext Communities</display-name> <portlet-class>com.liferay.portlet.StrutsPortlet</portlet-class> <init-param><name>view-action</name> <value>/ext/communities/view</value></init-param> <expiration-cache>0</expiration-cache> <supports><mime-type>text/html</mime-type></supports> <resource-bundle> com.liferay.portlet.StrutsResourceBundle </resource-bundle> <security-role-ref> <role-name>power-user</role-name> </security-role-ref> <security-role-ref> <role-name>user</role-name> </security-role-ref> </portlet> As shown in the code above, the portlet-name element contains the canonical name of the portlet (for example, extCommunities). The display-name element contains a short name that is intended to be displayed in the portal (for example, Ext Communities). The portlet-class element contains the fully qualified class name of the portlet (for example, com.liferay.portlet.StrutsPortlet). The init-param element contains a name-value pair, for example view-action-ext/communities/view, as an initialization parameter of the portlet. Further, the expiration-cache defines expiration-based caching for this portlet. The supports element contains the supported MIME-type. The resource-bundle element contains a resource bundle class, for example com.liferay.portlet. StrutsResourceBundle. Finally, the security-role-ref element contains the declaration of a security role reference in the code of the web application. Secondly, let's register the extCommunities portlet in liferay-portlet-ext.xml as follows: Locate the liferay-portlet-ext.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it. Add the following lines immediately after <!-- Custom Portlets --> and save it: <portlet> <portlet-name>extCommunities</portlet-name> <struts-path>ext/communities</struts-path> <use-default-template>false</use-default-template> <restore-current-view>false</restore-current-view> </portlet> As shown in the code above, the Ext Communities portlet is registered in the portal. The portal will check struts-path to see whether a user has the required permissions to access the portlet or not. As you can see, struts-path has the value ext/communities. It means that all requests to the ext/communities/* path are considered a part of this portlet scope. Only those users whose request paths match ext/communities/* will be granted access. Moreover, the use-default-template element has the value false, so the portlet will not use any user's default template. The restore-current-view element has the value false so the portlet will reset the current view when toggling between maximized and normal states. Thirdly, add a title (for example, Ext Communities), for the Ext Communities portlet at Language-ext.properties as follows: Locate the Language-ext.properties file in the /ext/ext-impl/src/content folder and open it. Add the following line after javax.portlet.title.book_reports=Reports for Books and save it: javax.portlet.title.extCommunities=Ext Communities The code above provides mapping for the title of the portlet. If the mapping is not provided, the portal will show the default title javax.portlet.title.extCommunities. Finally, add the Ext Communities portlet to the Book category in liferay-display.xml as follows: Locate the liferay-display.xml file in the /ext/ext-web/docroot/WEBINF folder and open it. Add the following line immediately after the line <portlet id="book_reports" /> and save it: <portlet id="extCommunities" /> As shown in the code above, it adds the Ext Communities portlet to the category Book. From now on, you are able to select this portlet from the Book category directly when adding portlets to pages. Setting up actions Now, let's set up all actions required for the Ext Communities portlet. We need to prepare an action class, for example, ExtEditGroupAction. So how do we build this action? You can build the actions from scratch, but our purpose is to customize and extend the Communities portlet. In one word, we expect to reuse the out of the box portlet source code as much as possible and to write minimum code. As mentioned earlier, we have the portal project for the portal source code in the Eclipse IDE, which is referred to as the /portal prefix. We also have the ext project for customized code, which is referred to as the /ext prefix. The following is a process flow to build the ExtEditGroupAction action class of the Ext Communities portlet. Create a com.ext.portlet.communities.action package in the /ext/ext-impl/src folder. Create an ExtEditGroupAction class in this package and open it. Add the following lines and save it: public class ExtEditGroupAction extends EditGroupAction { public void processAction( ActionMapping mapping, ActionForm form, PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { String cmd = ParamUtil.getString(actionRequest, Constants.CMD); try { if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) { updateGroup(actionRequest); } else if (cmd.equals(Constants.DELETE)) { deleteGroup(actionRequest); } sendRedirect(actionRequest, actionResponse); } catch (Exception e) { if (e instanceof NoSuchGroupException || e instanceof PrincipalException) { SessionErrors.add(actionRequest, e.getClass().getName()); setForward(actionRequest, "portlet.ext.communities.error"); } else if (e instanceof DuplicateGroupException || e instanceof GroupFriendlyURLException || e instanceof GroupNameException || e instanceof RequiredGroupException) { SessionErrors.add(actionRequest, e.getClass().getName(), e); if (cmd.equals(Constants.DELETE)) { actionResponse.sendRedirect( ParamUtil.getString(actionRequest, "redirect")); } } else { throw e;} } } public ActionForward render(ActionMapping mapping, ActionForm form, PortletConfig portlonfig, RenderRequest renderRequest, RenderResponse renderResponse) throws Exception { try { ActionUtil.getGroup(renderRequest); } catch (Exception e) { if (e instanceof NoSuchGroupException || e instanceof PrincipalException) { SessionErrors.add(renderRequest, e.getClass().getName()); return mapping.findForward ("portlet.ext.communities.error"); } else {throw e;} } return mapping.findForward(getForward(renderRequest, "portlet.ext.communities.edit_community")); } } As shown in the code above, ExtEditGroupAction extends EditGroupAction from the com.liferay.portlet.communities.action package in the /portal/portal-impl/src folder. It overrides two methods (render and processAction) of EditGroupAction. Setting up page flow and page layout We have set up the action. We have also updated the forward path as the portlet.ext.communities.* value. In order to get the page flow working, we need to set up an action path and a page flow. First, let's set up the action path and page flow in struts-config.xml as follows: Locate the struts-config.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it. Add the following lines after <struts-config> <action-mappings> and save it: <!-- Ext Communities --> <action path="/ext/communities/edit_community" type="com.ext.portlet.communities.action. ExtEditGroupAction"> <forward name="portlet.ext.communities.edit_community" path="portlet.ext.communities.edit_community" /> <forward name="portlet.ext.communities.error" path="portlet.ext.communities.error" /> </action> <action path="/ext/communities/view" forward="portlet.ext.communities.view" /> The code above defines a set of action paths associated with the action and forward paths, as well as those mentioned earlier. For example, the action path /ext/communities/edit_community is associated with the com.ext.portlet.communities.action.ExtEditGroupAction action and the forward path names portlet.ext.communities.edit_community and portlet.ext.communities.error. Then based on the page flow and JSP files, let's define the page layout in tiles-defs.xml: Locate the tiles-defs.xml file in the ext/ext-web/docroot/WEB-INF folder and open it. Add the following lines after <struts-config> <action-mappings> and save it: <!-- Ext Communities --> <action path="/ext/communities/edit_community" type="com.ext.portlet.communities.action. ExtEditGroupAction"> <forward name="portlet.ext.communities.edit_community" path="portlet.ext.communities.edit_community" /> <forward name="portlet.ext.communities.error" path="portlet.ext.communities.error" /> </action> <action path="/ext/communities/view" forward="portlet.ext.communities.view" /> The code above defines a set of action paths associated with the action and forward paths, as well as those mentioned earlier. For example, the action path /ext/communities/edit_community is associated with the com.ext.portlet.communities.action.ExtEditGroupAction action and the forward path names portlet.ext.communities.edit_community and portlet.ext.communities.error. Then based on the page flow and JSP files, let's define the page layout in tiles-defs.xml: Locate the tiles-defs.xml file in the ext/ext-web/docroot/WEB-INF folder and open it. Add the following lines after <tiles-definitions> and save it: <!-- Ext Communities --> <definition name="portlet.ext.communities" extends="portlet" /> <definition name="portlet.ext.communities.edit_community" extends="portlet.ext.communities"> <put name="portlet_content" value="/portlet/ext/communities/edit_community.jsp" /> </definition> <definition name="portlet.ext.communities.view" extends="portlet"> <put name="portlet_content" value="/portlet/ext/communities/view.jsp" /> </definition> <definition name="portlet.ext.communities.error" extends="portlet"> <put name="portlet_content" value="/portlet/communities/error.jsp" /> </definition> The code above defines the page layout for the Ext Communities portlet. For example, portlet.ext.communities.edit_community is associated with the JSP file /portlet/ext/communities/edit_community.jsp. In addition, it specifies that the community view page layout (for example, portlet.ext.communities.view) is associated with the JSP page file /portlet/ext/communities/view.jsp. Preparing JSP files We have now set up the actions. We have also set up page flow and page layout. Now let's set up the JSP files that are required for the Ext Communities portlet. We need to prepare JSP files such as view.jsp, edit_community.jsp, group_search.jsp, and so on. So how do we build this? You can build them from scratch. However, here we will copy and modify JSP files of the Communities portlet. In this section we expect to reuse the source code, including JSP files, as much as possible. First, let's create the view.jsp JSP file as follows: Create a communities folder within the /ext/ext-web/docroot/html/portlet/ext/ folder. Locate the view.jsp JSP file in the /portal/portal-web/docroot/html/portlet/communities folder, and copy it to the /ext/ext-web/docroot/html/portlet/ext/communities folder. Open view.jsp in the /ext/ext-web/docroot/html/portlet/ext/communities folder, update /communities/edit_community with /ext/communities/edit_community as shown in the following two lines, and save it: portletURL.setParameter("struts_action", "/ext/communities/view"); <liferay-ui:search-form page="/html/portlet/ext/communities/group_search.jsp" searchContainer="<%= searchContainer %>" showAddButton="<%= showTabs1 %>" /> Next, we need to create the JSP file edit_community.jsp as follows: Locate the JSP file edit_community.jsp in the /portal/portal-web/docroot/html/portlet/communities folder, and copy it to the /ext/extweb/docroot/html/portlet/ext/communities folder. Open edit_community.jsp in the /ext/ext-web/docroot/html/portlet/ext/communities folder, update /communities/edit_community with /ext/communities/edit_community as shown in following line, and save it: <form action="<portlet:actionURL windowState="<%= WindowState.MAXIMIZED. toString() %>"> <portlet:param name="struts_action" value="/ext/communities/edit_community" /> </portlet:actionURL>" method="post" name="<portlet:namespace />fm" onSubmit="<portlet:namespace />saveGroup(); return false;"> In addition, we need to make the button Add Community available, in the following manner: Locate JSP file group_search.jsp in the /portal/portal-web/docroot/html/portlet/enterprise_admin folder. Copy the JSP file group_search.jsp from /portal/portal-web/docroot/html/portlet/enterprise_admin to /ext/ext-web/docroot/html/portlet/ext/communities, and open it. Update /communities/edit_community with /ext/communities/edit_community as shown in the following lines, and save it: submitForm(document.<portlet:namespace />fm, '<portlet:renderURL windowState="<%= WindowState.MAXIMIZED.toString() %>"> <portlet:param name="struts_action" value="/ext/communities/edit_community" /> <portlet:param name="redirect" value="<%= currentURL %>" /> </portlet:renderURL>'); Congratulations! You have cloned the Communities portlet. Finally, we can deploy updates into Tomcat as follows: Stop Tomcat if it is running. Click on the Ant target: deploy at the Ant view ext. Start Tomcat. Open up a new browser with the URL http://localhost:8080. Click on Sign in and enter test@liferay.com / test. Click on Add Application | Book
Read more
  • 0
  • 0
  • 1738

article-image-creating-efficient-reports-visual-studio
Packt
21 Oct 2009
5 min read
Save for later

Creating efficient reports with Visual Studio

Packt
21 Oct 2009
5 min read
Report Services, Analysis Services, and Integration Services are the three pillars of Business Intelligence in Microsoft's vision that continues to evolve. Reporting is a basic activity, albeit one of the most important activities of an organization because it provides a specialized and customized view of the data of various forms (relational, text, xml etc) that live in data stores. The report is useful in making business decisions, scheduling business campaigns, or assessing the competition. The report itself may be required in hard copy in several document formats such as DOC, HTML, PDF, etc. Many times it is also required to be retrieved in an interactive form from the data store and viewed on a suitable interface, including a web browser. The Microsoft SQL Server 2005 Reporting Services, popularly known by its acronym SSRS, provides all that is necessary to create and manage reports and deploy them on a report server with output available in several document formats. The reader will greatly benefit from reading the several articles detailed in the author's Hodentek Blog. The content for the articles were developed using VS 2003, VS 2005, SQL 2000 and SQL 2005. (For more resources on Microsoft, see here.) The content for the present tutorial uses a Visual Studio 2008 Professional and a Microsoft SQL Server Compact 3.5 embeddable database for its data. In Visual Studio a Report Design Wizard guides you through fashioning a report from your choices. Create a Windows Project in VS2008 Create a new project from File | New | Project. Provide a name instead of the default name (WindowsApplicaiton1). This is changed to ReportDesign for this tutorial as shown in the next figure. VS 2008 supports multi-version targeting. In the top right of the New Project window you can see that this report is targeted for the NET 2.0 Framework Version and can be published to a Net 2.0 web site. Slightly enlarge the Form1. Drag and drop the Microsoft Report Viewer control shown in the next figure on to the form from the Toolbox. This has the same functionality as the ReportViewer control in VS 2005 as shown in the next figure. The control will be housed on the form as shown in the next figure. You can display the tasks needed to configure the Report Viewer by clicking on the Smart Task as shown in the same figure. The report will have all the functionalities like print, save to different formats, navigating through pages, etc. Working with the Report Wizard Now click on the Design a new report task. The opens the Report Wizard window as shown in the figure. Read the instructions on this page carefully. Click on the Next Button. This displays the Data Source Configuration Wizard shown in the next figure. Choosing a Data Source The application can obtain data from these different resources. Click on the Database icon and then click on the Next button. This displays the window where you need to select a connection to the data source. If there are existing connections you should be able to see them in the drop-down list box. Making a Connection to Get Data Click on the New Connection button. This brings up the Add Connection window showing a default connection to a Microsoft SQL Server Compact 3.5.NET Framework Data Provider. It also shows the location to be My Computer. This source can be changed by clicking on the Change... button. This will bring up the Change Data Source window where you can choose. As found in this version you have the following options: Microsoft SQL Server option lets you connect to SQL 2000 or 2005 using the .NET Framework Data Provider for SQL Server. Microsoft SQL Server Compact 3.5 lets you connect to a database file. Microsoft SQL Server Database File lets you connect to a Local Microsoft SQL Server Instance including a SQL Express. Although it is not explicitly stated what these versions are. For this tutorial the Compact 3.5 will be used (also uses a .NET Framework Data Provider of Compact 3.5). Click on the OK button in the Change Data Source window. VS 2008 installation also installs a database file on the computer for the SQL Server Compact 3.5. Click on Browse button (you could also create one if you like, herein it will be browsed). This brings up the Select SQL Server Compact 3.5 Database File window with the default location where the database file is parked as shown in the next figure. Click on the Northwind icon in the window and click on the Open button. This updates the Add Connection window with this information as shown in the next figure. You may test the connection by hitting the Test Connection button which should display a successful outcome as shown in the next figure. There is no need for a password as you are the owner. Click OK twice and this will take you back to the Data Source Configuration Wizard updating the connection information which you may review as shown in the next figure. Click on the Next button. This brings up the Microsoft Visual Studio message window giving you the option to bring this data source to your project.    
Read more
  • 0
  • 0
  • 6528

article-image-setting-most-popular-journal-articles-your-personalized-community-liferay-portal
Packt
21 Oct 2009
6 min read
Save for later

Setting up the most Popular Journal Articles in your Personalized Community in Liferay Portal

Packt
21 Oct 2009
6 min read
Personal community is a dynamic feature of Liferay portal. By default, the personal community is a portal-wide setting that will affect all of the users. It would be nice to have more features in the personal community such as showing the most popular journal articles. This article by Jonas Yuan will address how to set up the most popular journal articles in you personalized community and view the counter for other assets. In a web site, we will have a lot of journal articles (that is, web content) for a given article type. For example, for the article type Article Content, we will have articles talking about product family. We may want to know how many times the end users read each article. Meanwhile, it would be nice if we could show the most popular articles (for example, TOP 10 articles) for this given article type. As shown in the following screenshot, a journal article My EDI Product I is shown via a portlet Ext Web Content Display. Rating and comments on this article are also exhibited. At the same time, the medium-size image, polls, and related content of this article are listed, too. A view counter of this article is especially displayed under the ratings. Moreover, the most popular articles are exhibited with article title and number of views under related content. All these articles belong to the article type article-content. That is, the article in the current portlet Ext Web Content Display has the most popular articles only for the article type article-content. Of course, you can customize the portlet Web Content Display directly through changing JSP files. For demo purposes, we will implement the view counter in the portlet Ext Web Content Display. Meanwhile, we will implement the mostly popular articles via VM services and article templates. In addition, we will analyze the view counter for other assets such as Image Gallery images, Document Library documents, Wiki articles, Blog entries, Message Boards threads, and so on. Adding a view counter in the Web Content Display portlet First of all, let's add a view counter in the Ext Web Content Display portlet. As the function of view counter for assets (including journal articles) is provided in the model TagsAssetModel of the com.liferay.portlet.tags.model package in the /portal/portal-service/src folder, we could use this feature in this portlet directly. To do so, use the following steps: Create a folder journal_content in the folder /ext/ext-web/docroot/html/portlet/. Copy the JSP file view.jsp in the folder /portal/portal-web/docroot/html/portlet/ to the folder /ext/ext-web/docroot/html/portlet/journal_content and open it. Add the line <%@ page import="com.liferay.portlet.tags.model.TagsAsset" %> after the line <%@ include file="/html/portlet/journal_content/init.jsp" %>, and check the following lines: JournalArticleDisplay articleDisplay = (JournalArticleDisplay) request.getAttribute( WebKeys.JOURNAL_ARTICLE_DISPLAY); if (articleDisplay != null) { TagsAssetLocalServiceUtil.incrementViewCounter( JournalArticle.class.getName(), articleDisplay.getResourcePrimKey());} Then add the following lines after the line <c:if test="<%=enableComments %>"> and save it: <span class="view-count"> <% TagsAsset asset = TagsAssetLocalServiceUtil.getAsset (JournalArticle.class.getName(), articleDisplay.getResourcePrimKey());%> <c:choose> <c:when test="<%= asset.getViewCount() == 1 %>"> <%= asset.getViewCount() %> <liferay-ui:message key="view" />, </c:when> <c:when test="<%= asset.getViewCount() > 1 %>"> <%= asset.getViewCount() %> <liferay-ui:message key="views" />, </c:when> </c:choose></span> The code above shows a way to increase the view counter via the TagsAssetLocalServiceUtil.incrementViewCounter method. This method takes two parameters className and classPK as inputs. For the current journal article, the two parameters are JournalArticle.class.getName() and articleDisplay.getResourcePrimKey(). Then, this code shows a way to display view counted through the TagsAssetLocalServiceUtil.getAsset method. Similarly, this method also takes two parameters, className and classPK, as inputs. This approach would be useful for other assets, as the className parameter could be Image Gallery, Document Library, Wiki, Blogs, Message Boards, Bookmark, and so on. Setting up VM service We can set up the VM service to exhibit the most popular articles. We can also add the getMostPopularArticles method in the custom velocity tool ExtVelocityToolUtil. To do so, first add the following method in the ExtVelocityToolService interface: public List<TagsAsset> getMostPopularArticles(String companyId, String groupId, String type, int limit); And then add an implementation of the getMostPopularArticles method in the ExtVelocityToolServiceImpl class as follows: public List<TagsAsset> getMostPopularArticles(String companyId, String groupId, String type, int limit) { List<TagsAsset> results = Collections.synchronizedList(new ArrayList<TagsAsset>()); DynamicQuery dq0 = DynamicQueryFactoryUtil.forClass( JournalArticle.class, "journalarticle"). setProjection(ProjectionFactoryUtil.property ("resourcePrimKey")).add(PropertyFactoryUtil. forName("journalarticle.companyId"). eqProperty("tagsasset.companyId")). add(PropertyFactoryUtil.forName( "journalarticle.groupId").eqProperty( "tagsasset.groupId")).add(PropertyFactoryUtil. forName("journalarticle.type").eq( "article-content")); DynamicQuery query = DynamicQueryFactoryUtil.forClass( TagsAsset.class, "tagsasset") .add(PropertyFactoryUtil.forName( "tagsasset.classPK").in(dq0)) .addOrder(OrderFactoryUtil.desc( "tagsasset.viewCount")); try{ List<Object> assets = TagsAssetLocalServiceUtil. dynamicQuery(query); int index = 0; for (Object obj: assets) { TagsAsset asset = (TagsAsset) obj; results.add(asset); index ++; if(index == limit) break; } } catch (Exception e){ return results; } return results; } The preceding code shows a way to get the most popular articles by company ID, group ID, article type, and limited articles to be returned. DynamicQuery API allows us to leverage the existing mapping definitions through access to the Hibernate session. For example, DynamicQuery dq0 selects the journal articles by companyID, groupId, and type; DynamicQuery query selects tagsassets by classPK, which exists in DynamicQuery dq0; and tagsassets are ordered by viewCount as well. Finally, add the following method to register the above method in ExtVelocityToolUtil: public List<TagsAsset> getRelatedArticles(String companyId, String groupId, String articleId, int limit){ return _extVelocityToolService.getRelatedArticles(companyId, groupId, articleId, limit);} The code above shows a generic approach to get TOP 10 articles for any article types. Of course, you can extend this approach to find TOP 10 assets. This can include Image Gallery images, Document Library documents, Wiki articles, Blog entries, Message Boards threads, Bookmark entries, slideshow, videos, games, video queue, video list, playlist, and so on. You may practice these TOP 10 assets feature. Building article template for the most popular journal articles We have added view counter on journal articles. We have already built VM service for the most popular articles too. Now let's build an article template for them. Setting up the default article type As mentioned earlier, there is a set of types of journal articles, for example, announcements, blogs, general, news, press-release, updates, article-tout, article-content, and so on. In real case, only some of these types will require view counter, for example article-content. Let's configure the default article type for mostly popular articles. We can add the following line at the end of portal-ext.properties. ext.most_popular_articles.article_type=article-content The code above shows that the default article type for most_popular_articles is article-content.
Read more
  • 0
  • 0
  • 6716
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-creating-pseudo-3d-imagery-gimp-part-2
Packt
21 Oct 2009
6 min read
Save for later

Creating Pseudo-3D Imagery with GIMP: Part 2

Packt
21 Oct 2009
6 min read
The next step would be to play around with Layer Modes which, I believe, is one of the most exciting aspects of graphic design. Let's leave layer “lower shine” for awhile and let's get back to layer “upper shine”, and change its layer mode to make it look more appealing and following a scheme in accordance to the color of the sphere. To do this, let's select “upper shine” layer on the Layers Window and right above the Opacity Slider is a dropdown menu containing lots of interesting layer modes, each having its own distinct advantages. You can play around and choose whichever suits your vision the best. I chose Overlay for that matter. Ever since I've started GIMPing, this layer mode has been my best friend for a couple of years already, it works like a charm most of the time.  I wonder though why on some applications, applying the overlay layer mode does different results.  As in the case of Photoshop, the closest I could get with GIMP's overlay is the Screen mode.  You've got to play around a bit and see which works best for you. Do the same thing for the “lower shine” layer, choosing Overlay as the layer mode.  Then, whenever you see fit, you can duplicate the layers to achieve a multiplied effect of the mode. I did that because it felt that something was still missing in the luminous aspect of the shine. So I selected each layer, duplicated them both and voila. To duplicate a layer, you can either right click on the layer name and choose Duplicate Layer from the choices or just press the Duplicate Button on the bottom part of the Layers Window. Duplicated Layers Next, we'll add additional highlights to better emulate specular reflections. And again, we're exploiting the Ellipse Select Tool and another new technique called Feathering. I don't know exactly the definition of feathering in CG, but as far as my experience goes, feathering is a technique from sets of tools where you soften the edges of a selection creating a subtle transition and blurred edges. Create a new layer at the top of the layer stack and call it “blurred shine”, then give it a Layer Fill Type of Transparency, just like what we did with the previous layers.  And with layer 'blurred shine” active, let's create an elliptical selection on the upper left hand part of the sphere, just where the sharp shine has been cast. Creating the Specular Selection With the selection active, right click on the Image Window and choose Select > Feather, then input a value for the feather and the unit to be used. I used 50 pixels. You might have noticed now that the selection seemed to have become smaller, and that's alright, that means you've done it right.  And with the marching ants still active, grab the Bucket Fill Tool over at the Toolbox Window or press SHIFT + B to activate it. Change your foreground color to something close to white or simply pure white, then with the Bucket Fill Tool active, click on the active selection. Tadaaaa! You just created a replica of a specular highlight, though not so close enough. What's great about feathering selections as opposed to applying a blur filter is that you only blur the selection border and not the entire selection. So, say, you have a picture of yourself and you wanted your face fade out smoothly on a vast landscape that you have photographed. Simply create a selection around your face, then apply a Feather to that selection, invert the selection and delete the outer parts, thus leaving only your face and the landscape behind (supposing you have your picture on a separate layer above the landscape layer.) Feathering the Selection Applying the Color with the Bucket Fill Whew, that was pretty quick, isn't it? I hope you agree with me on that.  If so, let's create another one, though smaller and placed just on the left of the blurred shine.  Create a new layer for this new blurred shine and name it “small blurred shine”.  Follow the same procedure for the feathering and color-filling. I used the same feather value for the smaller selection (even though it obviously is smaller), just so it almost affects the center of the selection, blurring the whole selection already, which is what I like for this part. And then, just like what we did with the upper and lower shine respectively, we'll change the Layer Modes to Overlay and duplicate the layers as we see fit.  Doing so results in this image: Blurred Shines Overlay Our sphere now looks a lot better than it had been when we first added its color. However, the shading still looks a bit flat and volumeless. To deal with that, we'll simulate the strength with which the light diffused our sphere object, creating deeper shadows on the opposite side of the light source. Duplication of layers is not only a matter of multiplying the effects of layer effects or such, but it can also be a good way to trace your changes, or better yet, as safe backups where working on the duplicate doesn't affect the original one and you can go back each time to the untouched layer anytime you want to see the differences that have been made.  But be careful though, the more layers and contents of each layer you have, the more computing memory will be consumed and will eventually cause a system slow down. Let's select the “sphere” layer and duplicate in once.  Automatically, the duplicate layer which is now named “sphere copy” becomes the active layer.  Right Click on “sphere copy” layer and choose Alpha to Selection to create a selection out of the fully opaque sphere. Next step is to shrink the selection such that we create a smaller elliptical selection inside the sphere.  To do this, right click on the Image Window and choose Select > Shrink.  Then on the pop up window that appears, type in an appropriate value for the shrinking. I chose 50 pixels. Shrinking the Selection Shrinked Selection Remember how we moved the selection last time? I believe you do. To translate/move our selection, grab the Ellipse Select Tool and activate the selection by clicking on it (clicking the middle portion of the selection makes this easier) until you see your cursor change into crossed arrows, this means you have just activated the move tool for the selection. And since the light is coming from the upper left direction, we would want to move the selection over to the location where the specular reflections are and where the lightest shading is.  Thats because later on, we'll be using this same selection to create shadows on the opposite side of the shade.  Now go ahead and drag the selection over to the upper left portion of the sphere.
Read more
  • 0
  • 0
  • 3995

article-image-multiple-templates-django
Packt
21 Oct 2009
13 min read
Save for later

Multiple Templates in Django

Packt
21 Oct 2009
13 min read
Considering the different approaches Though there are different approaches that can be taken to serve content in multiple formats, the best solution will be specific to your circumstances and implementation. Almost any approach you take will have maintenance overhead. You'll have multiple places to update when things change. As copies of your template files proliferate, a simple text change can become a large task. Some of the cases we'll look at don't require much consideration. Serving a printable version of a page, for example, is straightforward and easily accomplished. Putting a pumpkin in your site header at Halloween or using a heart background around Valentine's Day can make your site seem timely and relevant, especially if you are in a seasonal business. Other techniques, such as serving different templates to different browsers, devices, or user-agents might create serious debate among content authors. Since serving content to mobile devices is becoming a new standard of doing business, we'll make it the focus of this article. Serving mobile devices The Mobile Web will remind some old timers (like me!) of the early days of web design where we'd create different sites for Netscape and Internet Explorer. Hopefully, we take lessons from those days as we go forward and don't repeat our mistakes. Though we're not as apt to serve wholly different templates to different desktop browsers as we once were, the mobile device arena creates special challenges that require careful attention. One way to serve both desktop and mobile devices is a one-size-fits-all approach. Through carefully structured and semantically correct XHTML markup and CSS selectors identified to be applied to handheld output, you can do a reasonable job of making your content fit a variety of contexts and devices. However, this method has a couple of serious shortcomings. First, it does not take into account the limitations of devices for rich media presentation with Flash, JavaScript, DHTML, and AJAX as they are largely unsupported on all but the highest-end devices. If your site depends on any of these technologies, your users can get frustrated when trying to experience it on a mobile device. Also, it doesn't address the varying levels of CSS support by different mobile devices. What looks perfect on one device might look passable on another and completely unusable on a third because only some of the CSS rules were applied properly. It also does not take into account the potentially high bandwidth costs for large markup files and CSS for users who pay by the amount of data transferred. For example, putting display: none on an image doesn't stop a mobile device from downloading the file. It only prevents it from being shown. Finally, this approach doesn't tailor the experience to the user's circumstances. Users tend to be goal-oriented and have specific actions in mind when using the mobile web, and content designers should recognize that simply recreating the desktop experience on a smaller screen might not solve their needs. Limiting the information to what a mobile user is looking for and designing a simplified navigation can provide a better user experience. Adapting content You know your users best, and it is up to you to decide the best way to serve them. You may decide to pass on the one-size-fits-all approach and serve a separate mobile experience through content adaptation. The W3C's Mobile Web Initiative best practices guidelines suggest giving users the flexibility and freedom to choose their experience, and provide links between the desktop and mobile templates so that they can navigate between the two. It is generally not recommended to automatically redirect users on mobile devices to a mobile site unless you give them a way to access the full site. The dark side to this kind of content adaptation is that you will have a second set of template files to keep updated when you make site changes. It can also cause your visitors to search through different bookmarks to find the content they have saved. Before we get into multiple sites, let's start with some examples of showing alternative templates on our current site. Setting up our example Since we want to customize the output of our detail page based on the presence of a variable in the URL, we're going to use a view function instead of a generic view. Let us consider a press release application for a company website. The press release object will have a title, body, published date, and author name.In the root directory of your project (in the directory projects/mycompany), create the press application by using the startapp command: $ python manage.py startapp press This will create a press folder in your site. Edit the mycompany/press/models.py file: from django.db import models class PressRelease(models.Model): title = models.CharField(max_length=100) body = models.TextField() pub_date = models.DateTimeField() author = models.CharField(max_length=100) def __unicode__(self): return self.title Create a file called admin.py in the mycompany/press directory, adding these lines: from django.contrib import adminfrom mycompany.press.models import PressRelease admin.site.register(PressRelease) Add the press and admin applications to your INSTALLED_APPS variable in the settings.py file: INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.admin', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'mycompany.press',) In the root directory of your project, run the syncdb command to add the new models to the database: $ python manage.py syncdb We will be prompted to create a superuser, go ahead and create it. We can access the admin site by browsing to http://localhost:8000/admin/ and add data. Create your mycompany/press/urls.py file as shown: urlpatterns = patterns('', (r'detail/(?P<pid>d+)/$', 'mycompany.press.views.detail'), (r'list/$','django.views.generic.list_detail.object_list', press_list_dict), (r'latest/$','mycompany.press.views.latest'), (r'$','django.views.generic.simple.redirect_to', {'url': '/press/list/'})) In your mycompany/press/views.py file, your detail view should look like this: from django.http import HttpResponsefrom django.shortcuts import get_object_or_404from django.template import loader, Contextfrom mycompany.press.models import PressRelease def detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=pid) t = loader.get_template('press/detail.html') c = Context({'press': p}) return HttpResponse(t.render(c)) Let's jazz up our template a little more for the press release detail by adding some CSS to it. In mycompany/templates/press/detail.html, edit the file to look like this: <html><head><title>{{ press.title }}</title><style type="text/css">body { text-align: center;}#container { margin: 0 auto; width: 70%; text-align: left;}.header { background-color: #000; color: #fff;}</style></head><body><div id="container"><div class="header"><h1>MyCompany Press Releases</h1></div><div><h2>{{ press.title }}</h2><p>Author: {{ press.author }}<br/>Date: {{ press.pub_date }}<br/></p><p>{{ press.body }}</p></div></body></html> Start your development server and point your browser to the URL http://localhost:8000/press/detail/1/. You should see something like this, depending on what data you entered before when you created your press release: If your press release detail page is serving correctly, you're ready to continue. Remember that generic views can save us development time, but sometimes you'll need to use a regular view because you're doing something in a way that requires a view function customized to the task at hand. The exercise we're about to do is one of those circumstances, and after going through the exercise, you'll have a better idea of when to use one type of view over another. Serving printable pages One of the easiest approaches we will look at is serving an alternative version of a page based on the presence of a variable in the URL (aka a URL parameter). To serve a printable version of an article, for example, we can add ?printable to the end of the URL. To make it work, we'll add an extra step in our view to check the URL for this variable. If it exists, we'll load up a printer-friendly template file. If it doesn't exist, we'll load the normal template file. Start by adding the highlighted lines to the detail function in the mycompany/press/views.py file: def detail(request, pid): ''' Accepts a press release ID and returns the detail page ''' p = get_object_or_404(PressRelease, id=pid) if request.GET.has_key('printable'): template_file = 'press/detail_printable.html' else: template_file = 'press/detail.html' t = loader.get_template(template_file) c = Context({'press': p}) return HttpResponse(t.render(c)) We're looking at the request.GET object to see if a query string parameter of printable was present in the current request. If it was, we load the press/detail_printable.html file. If not, we load the press/detail.html file. We've also changed the loader.get_template function to look for the template_file variable. To test our changes, we'll need to create a simple version of our template that only has minimal formatting. Create a new file called detail_printable.html in the mycompany/templates/press/ directory and add these lines into it: <html><head><title>{{ press.title }}</title></head><body><h1>{{ press.title }}</h1><p>Author: {{ press.author }}<br/>Date: {{ press.pub_date }}<br/></p><p>{{ press.body }}</p></body></html> Now that we have both regular and printable templates, let's test our view.Point your browser to the URL http://localhost:8000/press/detail/1/, and you should see our original template as it was before. Change the URL to http://localhost:8000/press/detail/1/?printable and you should see our new printable template: Creating site themes Depending on the audience and focus of your site, you may want to temporarily change the look of your site for a season or holiday such as Halloween or Valentine's Day. This is easily accomplished by leveraging the power of the TEMPLATE_DIRS configuration setting. The TEMPLATE_DIRS variable in the settings.py file allows you to specify the location of the templates for your site. Also TEMPLATE_DIRS allows you to specify multiple locations for your template files. When you specify multiple paths for your template files, Django will look for a requested template file in the first path, and if it doesn't find it, it will keep searching through the remaining paths until the file is located. We can use this to our advantage by adding an override directory as the first element of the TEMPLATE_DIRS value. When we want to override a template with a special themed one, we'll add the file to the override directory. The next time the template loader tries to load the template, it will find it in the override directory and serve it. For example, let's say we want to override our press release page from the previous example. Recall that the view loaded the template like this (from mycompany/press/views.py): template_file = 'press/detail.html't = loader.get_template(template_file) When the template engine loads the press/detail.html template file, it gets itfrom the mycompany/templates/ directory as specified in the mycompany/settings.py file: TEMPLATE_DIRS = ( '/projects/mycompany/templates/',) If we add an additional directory to our TEMPLATE_DIRS setting, Django will look in the new directory first: TEMPLATE_DIRS = ( '/projects/mycompany/templates/override/’, '/projects/mycompany/templates/',) Now when the template is loaded, it will first check for the file /projects/mycompany/templates/override/press/detail.html. If that file doesn't exist, it will go on to the next directory and look for the file in /projects/mycompany/templates/press/detail.html. If you're using Windows, use the Windows-style file path c:/projects/mycompany/templates/ for these examples. Therein lies the beauty. If we want to override our press release template, we simply drop an alternative version with the same file name into the override directory. When we're done using it, we just remove it from the override directory and the original version will be served (or rename the file in the override directory to something other than detail.html). If you're concerned about the performance overhead of having a nearly empty override directory that is constantly checked for the existence of template files, we should consider caching techniques as a potential solution for this. Testing the template overrides Let's create a template override to test the concept we just learned. In your mycompany/settings.py file, edit the TEMPLATE_DIRS setting to look like this: TEMPLATE_DIRS = ( '/projects/mycompany/templates/override/', '/projects/mycompany/templates/',) Create a directory called override at mycompany/templates/ and another directory underneath that called press. You should now have these directories: /projects/mycompany/templates/override//projects/mycompany/templates/override/press/ Create a new file called detail.html in mycompany/templates/override/press/ and add these lines to the file: <html><head><title>{{ press.title }}</title></head><body><h1>Happy Holidays</h1><h2>{{ press.title }}</h2><p>Author: {{ press.author }}<br/>Date: {{ press.pub_date }}<br/></p><p>{{ press.body }}</p></body></html> You'll probably notice that this is just our printable detail template with an extra "Happy Holidays" line added to the top of it. Point your browser to the URL http://localhost:8000/press/detail/1/ and you should see something like this: By creating a new press release detail template and dropping it in the override directory, we caused Django to automatically pick up the new template and serve it without us having to change the view. To change it back, you can simply remove the file from the override directory (or rename it). One other thing to notice is that if you add ?printable to the end of the URL, it still serves the printable version of the file we created earlier. Delete the mycompany/templates/override/ directory and any files in it as we won't need them again.
Read more
  • 0
  • 0
  • 15561

article-image-configuring-jdbc-oracle-jdeveloper
Packt
21 Oct 2009
14 min read
Save for later

Configuring JDBC in Oracle JDeveloper

Packt
21 Oct 2009
14 min read
Introduction Unlike Eclipse IDE, which requires a plug-in, JDeveloper has a built-in provision to establish a JDBC connection with a database. JDeveloper is the only Java IDE with an embedded application server, the Oracle Containers for J2EE (OC4J). This database-based web application may run in JDeveloper without requiring a third-party application server. However, JDeveloper also supports third-party application servers. Starting with JDeveloper 11, application developers may point the IDE to an application server instance (or OC4J instance), including third-party application servers that they want to use for testing during development. JDeveloper provides connection pooling for the efficient use of database connections. A database connection may be used in an ADF BC application, or in a JavaEE application. A database connection in JDeveloper may be configured in the Connections Navigator. A Connections Navigator connection is available as a DataSource registered with a JNDI naming service. The database connection in JDeveloper is a reusable named connection that developers configure once and then use in as many of their projects as they want. Depending on the nature of the project and the database connection, the connection is configured in the bc4j.xcfg file or a JavaEE data source. Here, it is necessary to distinguish between data source and DataSource. A data source is a source of data; for example an RDBMS database is a data source. A DataSource is an interface that represents a factory for JDBC Connection objects. JDeveloper uses the term Data Source or data source to refer to a factory for connections. We will also use the term Data Source or data source to refer to a factory for connections, which in the javax.sql package is represented by the DataSource interface. A DataSource object may be created from a data source registered with the JNDI (Java Naming and Directory) naming service using JNDI lookup. A JDBC Connection object may be obtained from a DataSource object using the getConnection method. As an alternative to configuring a connection in the Connections Navigator a data source may also be specified directly in the data source configuration file data-sources.xml. In this article we will discuss the procedure to configure a JDBC connection and a JDBC data source in JDeveloper 10g IDE. We will use the MySQL 5.0 database server and MySQL Connector/J 5.1 JDBC driver, which support the JDBC 4.0 specification. In this article you will learn the following: Creating a database connection in JDeveloper Connections Navigator. Configuring the Data Source and Connection Pool associated with the connection configured in the Connections Navigator. The common JDBC Connection Errors. Before we create a JDBC connection and a data source we will discuss connection pooling and DataSource. Connection Pooling and DataSource The javax.sql package provides the API for server-side database access. The main interfaces in the javax.sql package are DataSource, ConnectionPoolDataSource, and PooledConnection. The DataSource interface represents a factory for connections to a database. DataSource is a preferred method of obtaining a JDBC connection. An object that implements the DataSource interface is typically registered with a Java Naming and Directory API-based naming service. DataSource interface implementation is driver-vendor specific. The DataSource interface has three types of implementations: Basic implementation: In basic implementation there is 1:1 correspondence between a client's Connection object and the connection with the database. This implies that for every Connection object, there is a connection with the database. With the basic implementation, the overhead of opening, initiating, and closing a connection is incurred for each client session. Connection pooling implementation: A pool of Connection objects is available, from which connections are assigned to the different client sessions. A connection pooling manager implements the connection pooling. When a client session does not require a connection, the connection is returned to the connection pool and becomes available to other clients. Thus, the overheads of opening, initiating, and closing connections are reduced. Distributed transaction implementation: Distributed transaction implementation produces a Connection object that is mostly used for distributed transactions and is always connection pooled. A transaction manager implements the distributed transactions. An advantage of using a data source is that code accessing a data source does not have to be modified when an application is migrated to a different application server. Only the data source properties need to be modified. A JDBC driver that is accessed with a DataSource does not register itself with a DriverManager. A DataSource object is created using a JNDI lookup and subsequently a Connection object is created from the DataSource object. For example, if a data source JNDI name is jdbc/OracleDS a DataSource object may be created using JNDI lookup. First, create an InitialContext object and subsequently create a DataSource object using the InitialContext lookup method. From the DataSource object create a Connection object using the getConnection() method: InitialContext ctx=new InitialContext(); DataSource ds=ctx.lookup("jdbc/OracleDS"); Connection conn=ds.getConnection(); The JNDI naming service, which we used to create a DataSource object is provided by J2EE application servers such as the Oracle Application Server Containers for J2EE (OC4J) embedded in the JDeveloper IDE. A connection in a pool of connections is represented by the PooledConnection interface, not the Connection interface. The connection pool manager, typically the application server, maintains a pool of PooledConnection objects. When an application requests a connection using the DataSource.getConnection() method, as we did using the jdbc/OracleDS data source example, the connection pool manager returns a Connection object, which is actually a handle to an object that implements the PooledConnection interface. A ConnectionPoolDataSource object, which is typically registered with a JNDI naming service, represents a collection of PooledConnection objects. The JDBC driver provides an implementation of the ConnectionPoolDataSource, which is used by the application server to build and manage a connection pool. When an application requests a connection, if a suitable PooledConnection object is available in the connection pool, the connection pool manager returns a handle to the PooledConnection object as a Connection object. If a suitable PooledConnection object is not available, the connection pool manager invokes the getPooledConnection() method of the ConnectionPoolDataSource to create a new PooledConnection object. For example, if connectionPoolDataSource is a ConnectionPoolDataSource object a new PooledConnection gets created as follows: PooledConnection pooledConnection=connectionPoolDataSource.getPooledConnection(); The application does not have to invoke the getPooledConnection() method though; the connection pool manager invokes the getPooledConnection() method and the JDBC driver implementing the ConnectionPoolDataSource creates a new PooledConnection, and returns a handle to it. The connection pool manager returns a Connection object, which is a handle to a PooledConnection object, to the application requesting a connection. When an application closes a Connection object using the close() method, as follows, the connection does not actually get closed. conn.close(); The connection handle gets deactivated when an application closes a Connection object with the close() method. The connection pool manager does the deactivation. When an application closes a Connection object with the close() method any client info properties that were set using the setClientInfo method are cleared. The connection pool manager is registered with a PooledConnection object using the addConnectionEventListener() method. When a connection is closed, the connection pool manager is notified and the connection pool manager deactivates the handle to the PooledConnection object, and returns the PooledConnection object to the connection pool to be used by another application. The connection pool manager is also notified if a connection has an error. A PooledConnection object is not closed until the connection pool is being reinitialized, the server is shutdown, or a connection becomes unusable. In addition to connections being pooled, PreparedStatement objects are also pooled by default if the database supports statement pooling. It can be discovered if a database supports statement pooling using the supportsStatementPooling() method of the DatabaseMetaData interface. The PeparedStatement pooling is also managed by the connection pool manager. To be notified of PreparedStatement events such as a PreparedStatement getting closed or a PreparedStatement becoming unusable, a connection pool manager is registered with a PooledConnection manager using the addStatementEventListener() method. A connection pool manager deregisters a PooledConnection object using the removeStatementEventListener() method. Methods addStatementEventListener and removeStatementEventListener are new methods in the PooledConnection interface in JDBC 4.0. Pooling of Statement objects is another new feature in JDBC 4.0. The Statement interface has two new methods in JDBC 4.0 for Statement pooling: isPoolable() and setPoolable(). The isPoolable method checks if a Statement object is poolable and the setPoolable method sets the Statement object to poolable. When an application closes a PreparedStatement object using the close() method the PreparedStatement object is not actually closed. The PreparedStatement object is returned to the pool of PreparedStatements. When the connection pool manager closes a PooledConnection object by invoking the close() method of PooledConnection all the associated statements also get closed. Pooling of PreparedStatements provides significant optimization, but if a large number of statements are left open, it may not be an optimal use of resources. Thus, the following procedure is followed to obtain a connection in an application server using a data source: Create a data source with a JNDI name binding to the JNDI naming service. Create an InitialContext object and look up the JNDI name of the data source using the lookup method to create a DataSource object. If the JDBC driver implements the DataSource as a connection pool, a connection pool becomes available. Request a connection from the connection pool. The connection pool manager checks if a suitable PooledConnection object is available. If a suitable PooledConnection object is available, the connection pool manager returns a handle to the PooledConnection object as a Connection object to the application requesting a connection. If a PooledConnection object is not available the connection pool manager invokes the getPooledConnection() method of the ConnectionPoolDataSource, which is implemented by the JDBC driver. The JDBC driver implementing the ConnectionPoolDataSource creates a PooledConnection object and returns a handle to it. The connection pool manager returns a handle to the PooledConnection object as a Connection object to the application requesting a connection. When an application closes a connection, the connection pool manager deactivates the handle to the PooledConnection object and returns the PooledConnection object to the connection pool. ConnectionPoolDataSource provides some configuration properties to configure a connection pool. The configuration pool properties are not set by the JDBC client, but are implemented or augmented by the connection pool. The properties can be set in a data source configuration. Therefore, it is not for the application itself to change the settings, but for the administrator of the pool, who also happens to be the developer sometimes, to do so. Connection pool properties supported by ConnectionPoolDataSource are discussed in following table: Connection Pool Property Type Description maxStatements int Maximum number of statements the pool should keep open. 0 (zero) indicates that statement caching is not enabled. initialPoolSize int The initial number of connections the pool should have at the time of creation. minPoolSize int The minimum number of connections in the pool. 0 (zero) indicates that connections are created as required. maxPoolSize int The maximum number of connections in the connection pool. 0 indicates that there is no maximum limit. maxIdleTime int Maximum duration (in seconds) a connection can be kept open without being used before the connection is closed. 0 (zero) indicates that there is no limit. propertyCycle int The interval in seconds the pool should wait before implementing the current policy defined by the connection pool properties. maxStatements int The maximum number of statements the pool can keep open. 0 (zero) indicates that statement caching is not enabled.     Setting the Environment Before getting started, we have to install the JDeveloper 10.1.3 IDE and the MySQL 5.0 database. Download JDeveloper from: http://www.oracle.com/technology/software/products/jdev/index.html. Download the MySQL Connector/J 5.1, the MySQL JDBC driver that supports JDBC 4.0 specification. To install JDeveloper extract the JDeveloper ZIP file to a directory. Log in to the MySQL database and set the database to test. Create a database table, Catalog, which we will use in a web application. The SQL script to create the database table is listed below: CREATE TABLE Catalog(CatalogId VARCHAR(25)PRIMARY KEY, Journal VARCHAR(25), Publisher VARCHAR(25),Edition VARCHAR(25), Title Varchar(45), Author Varchar(25));INSERT INTO Catalog VALUES('catalog1', 'Oracle Magazine', 'Oracle Publishing', 'Nov-Dec 2004', 'Database Resource Manager', 'Kimberly Floss');INSERT INTO Catalog VALUES('catalog2', 'Oracle Magazine', 'Oracle Publishing', 'Nov-Dec 2004', 'From ADF UIX to JSF', 'Jonas Jacobi'); MySQL does not support ROWID, for which support has been added in JDBC 4.0. Having installed the JDeveloper IDE, next we will configure a JDBC connection in the Connections Navigator. Select the Connections tab and right-click on the Database node to select New Database Connection. Click on Next in Create Database Connection Wizard. In the Create Database Connection Type window, specify a Connection Name—MySQLConnection for example—and set Connection Type to Third Party JDBC Driver, because we will be using MySQL database, which is a third-party database for Oracle JDeveloper and click on Next. If a connection is to be configured with Oracle database select Oracle (JDBC) as the Connection Type and click on Next. In the Authentication window specify Username as root (Password is not required to be specified for a root user by default), and click on Next. In the Connection window, we will specify the connection parameters, such as the driver name and connection URL; click on New to specify a Driver Class. In the Register JDBC Driver window, specify Driver Class as com.mysql.jdbc.Driver and click on Browse to select a Library for the Driver Class. In the Select Library window, click on New to create a new library for the MySQL Connector/J 5.1 JAR file. In the Create Library window, specify Library Name as MySQL and click on Add Entry to add a JAR file entry for the MySQL library. In the Select Path Entry window select mysql-connector-java-5.1.3-rcmysql-connector-java-5.1.3-rc-bin.jar and click on Select. In the Create Library window, after a Class Path entry gets added to the MySQL library, click on OK. In the Select Library window, select the MySQL library and click on OK. In the Register JDBC Driver window, the MySQL library gets specified in the Library field and the mysql-connector-java-5.1.3-rcmysql-connector-java-5.1.3-rc-bin.jar gets specified in the Classpath field. Now, click on OK. The Driver Class, Library, and Classpath fields get specified in the Connection window. Specify URL as jdbc:mysql://localhost:3306/test, and click on Next. In the Test window click on Test Connection to test the connection that we have configured. A connection is established and a success message gets output in the Status text area. Click on Finish in the Test window. A connection configuration, MySQLConnection, gets added to the Connections navigator. The connection parameters are displayed in the structure view. To modify any of the connection settings, double-click on the Connection node. The Edit Database Connection window gets displayed. The connection Username, Password, Driver Class, and URL may be modified in the Edit window. A database connection configured in the Connections navigator has a JNDI name binding in the JNDI naming service provided by OC4J. Using the JNDI name binding, a DataSource object may be created in a J2EE application. To view, or modify the configuration settings of the JDBC connection select Tools | Embedded OC4J Server Preferences in JDeveloper. In the window displayed, select Global | Data Sources node, and to update the data-sources.xml file with the connection defined in the Connections navigator, click on the Refresh Now button. Checkboxes may be selected to Create data-source elements where not defined, and to Update existing data-source elements. The connection pool and data source associated with the connection configured in the Connections navigator get listed. Select the jdev-connection-pool-MySQLConnection node to list the connection pool properties as Property Set A and Property Set B. The tuning properties of the JDBC connection pool may be set in the Connection Pool window. The different tuning attributes are listed in following table:        
Read more
  • 0
  • 0
  • 10382

article-image-using-jquery-script-creating-dynamic-table-contents
Packt
21 Oct 2009
6 min read
Save for later

Using jQuery Script for Creating Dynamic Table of Contents

Packt
21 Oct 2009
6 min read
  A typical jQuery script uses a wide assortment of the methods that the library offers. Selectors, DOM manipulation, event handling, and so forth come into play as required by the task at hand. In order to make the best use of jQuery, we need to keep in mind the wide range of capabilities it provides. A Dynamic Table of Contents As an example of jQuery in action, we'll build a small script that will dynamically extract the headings from an HTML document and assemble them into a table of contents for that page. Our table of contents will be nestled on the top right corner of the page: We'll have it collapsed initially as shown above, but a click will expand it to full height: At the same time, we'll add a feature to the main body text. The introduction of the text on the page will not be initially loaded, but when the user clicks on the word Introduction, the introductory text will be inserted in place from another file: Before we reveal the script that performs these tasks, we should walk through the environment in which the script resides. Obtaining jQuery The official jQuery website (http://jquery.com/) is always the most up-to-date resource for code and news related to the library. To get started, we need a copy of jQuery, which can be downloaded right from the home page of the site. Several versions of jQuery may be available at any given moment; the latest uncompressed version will be most appropriate for us. No installation is required for jQuery. To use jQuery, we just need to reside it on our site in a public location. Since JavaScript is an interpreted language, there is no compilation or build phase to worry about. Whenever we need a page to have jQuery available, we will simply refer to the file's location from the HTML document. Setting Up the HTML Document There are three sections to most examples of jQuery usage— the HTML document itself, CSS files to style it, and JavaScript files to act on it. For this example, we'll use a page containing the text of a book: <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xml_lang="en" lang="en">  <head>      <meta http-equiv="Content-Type" content="text/html;                                                   charset=utf-8"/>      <title>Doctor Dolittle</title>    <link rel="stylesheet" href="dolittle.css" type="text/css" />      <script src="jquery.js" type="text/javascript"></script>      <script src="dolittle.js" type="text/javascript"></script>  </head>  <body>    <div id="container">      <h1>Doctor Dolittle</h1>      <div class="author">by Hugh Lofting</div>      <div id="introduction">        <h2><a href="introduction.html">Introduction</a></h2>      </div>      <div id="content">        <h2>Puddleby</h2>        <p>ONCE upon a time, many years ago when our grandfathers           were little children--there was a doctor; and his name was           Dolittle-- John Dolittle, M.D.  &quot;M.D.&quot; means            that he was a proper doctor and knew a whole lot.       </p>           <!-- More text follows... -->      </div>    </div>  </body></html> The actual layout of files on the server does not matter. References from one file to another just need to be adjusted to match the organization we choose. In most examples in this book, we will use relative paths to reference files (../images/foo.png) rather than absolute paths (/images/foo.png).This will allow the code to run locally without the need for a web server. The stylesheet is loaded immediately after the standard <head> elements. Here are the portions of the stylesheet that affect our dynamic elements: /* -----------------------------------   Page Table of Contents-------------------------------------- */#page-contents {  position: absolute;  text-align: left;  top: 0;  right: 0;  width: 15em;  border: 1px solid #ccc;  border-top-width: 0;  border-right-width: 0;  background-color: #e3e3e3;}#page-contents h3 {  margin: 0;  padding: .25em .5em .25em 15px;  background: url(arrow-right.gif) no-repeat 0 2px;  font-size: 1.1em;  cursor: pointer;}#page-contents h3.arrow-down {  background-image: url(arrow-down.gif);}#page-contents a {  display: block;  font-size: 1em;  margin: .4em 0;  font-weight: normal;}#page-contents div {  padding: .25em .5em .5em;    display: none;  background-color: #efefef;}/* -----------------------------------   Introduction-------------------------------------- */.dedication {  margin: 1em;  text-align: center;  border: 1px solid #555;  padding: .5em;} After the stylesheet is referenced, the JavaScript files are included. It is important that the script tag for the jQuery library be placed before the tag for our custom scripts; otherwise, the jQuery framework will not be available when our code attempts to reference it.  
Read more
  • 0
  • 0
  • 5707
article-image-getting-grips-facebook-platform
Packt
21 Oct 2009
6 min read
Save for later

Getting to Grips with the Facebook Platform

Packt
21 Oct 2009
6 min read
The Purpose of the Facebook Platform As you develop your Facebook applications, you'll find that the Facebook Platform is essential—in fact you won't really be able to do anything without it. So what does it do? Well, before answering that, let's look at a typical web-based application. The Standard Web Application Model If you've ever designed and built a web application before, then you'd have done it in a fairly standard way. Your application and any associated data would have been placed on a web server, and then your application users will access it from their web browsers via the Internet: The Facebook model is slightly different. The Facebook Web Application Model As far as your application users are concerned, they will just access Facebook.com and your application, by using a web browser and the Internet. But, that's not where the application lives—it's actually on your own server: Once you've looked at the Facebook web application model and realized that your application actually resides on your own server, it becomes obvious what the purpose of the Facebook Platform is—to provide an interface between your application and itself. There is an important matter to be considered here. If the application actually resides on your server, and your application becomes very successful (according to Facebook there are currently 25 million active users), then will your server be able to able to cope with that number of hits? Don't be too alarmed. This doesn't mean that your server will be accessed every time someone looks at his or her profile. Facebook employs a cache to stop that happening: Of course, at this stage, you're probably more concerned with just getting the application working—so let's continue looking at the Platform, but just bear that point in mind. Different components of the Facebook platform There are three elements to the Facebook Platform: The Facebook API (Application Programming Interface) FBML—Facebook Markup Language FQL—Facebook Query Language We'll now spend some time with each of these elements, and you'll see how you can use them individually, and in conjunction to make powerful yet simple applications. The great thing is that if you haven't got your web server set up yet, don't worry, because Facebook supplies you with all of the tools that you would need in order to do a test run with each of the elements. The Facebook API If you've already done some programming, then you'll probably know what an API (or Application Programming Interface) is. It's a set of software libraries that enable you to work with an application (in this case, Facebook) without knowing anything about its internal workings. All you have to do is obtain the libraries, and start making use of them in your own application. Now, before you start downloading files, you can actually learn more about their functionality by making use of the Facebook API Test Console. The Facebook API Test Console If you want to make use of the Facebook Test Console, you'll first need to access the Facebook developers' section—you'll find a link to this at the bottom of every Facebook page: Alternatively, you can use the URL http://developers.facebook.com to go there directly in your browser. When you get to this page, you'll find a link to the Tools page: Or, again, you can go directly to http://developers.facebook.com/tools.php, where you'll find the API Test Console: You'll find that the API Test Console has a number of fields: User ID—A read-only field which (when you're logged on to Facebook) unsurprisingly displays your user ID number. Response Format—With this, you can select the type of response that you want, and this can be: XML JSON Facebook PHP Client Callback—If you are using XML or JSON, then you can encapsulate the response in a function. Method—The actual Facebook method that you want to test. Once you've logged in, you'll see that your User ID is displayed and that all the drop-downs are enabled: You will also notice that a new link, documentation, appears on the screen, which is very useful. All you have to do is to select a method from the drop-down list, and then click on documentation. Once you've done that you'll see: A description of the method The parameters used by the method An example return XML A description of the expected response. The FQL equivalent (we will discuss this later in the chapter.) Error codes For now, let's just change the Response Format to Facebook PHP Client, and then click on Call Method to see what happens: In this case, you can see that the method returns an array of user ids—each one is the ID of one of the friends of the currently logged in user (that is your list of friends because you're the person logged in). You could, of course, go on to use this array in PHP as part of your application, but don't worry about that at the moment. For the time being, we'll just concentrate on working with our prototyping in the test console. However, before we move on, it's worth noting that you can obtain an array of friends only for the currently logged in user. You can't obtain the list of friends for any other user. So, for example, you would not be able to use friends. get on id 286601116 or 705175505. In fact, you wouldn't be able to use friends. get for 614902533 (as shown in the example) because that's my ID and not yours. On the other hand, having obtained a list of valid IDs we can now do something more interesting with them. For example, we can use the users.getinfo method to obtain the first name and birthday for particular users: As you can see, a multidimensional array is returned to your PHP code (if you were actually using this in an application). Therefore, for example, if you were to load the array into a variable $birthdays, then $birthdays[0][birthday] would contain January 27, 1960. Of course, in the above example, the most important piece of information is the first birthday in the array—record that in your diary for future reference. And, if you're thinking that I'm old enough to be your father, well, in some cases this is actually true: Now that you've come to grips with the API Test console, we can turn our attention to FBML and the FBML Test Console.
Read more
  • 0
  • 0
  • 1954

article-image-multimedia-and-assessments-moodle-19-part-1
Packt
21 Oct 2009
7 min read
Save for later

Multimedia and Assessments with Moodle 1.9 (part 1)

Packt
21 Oct 2009
7 min read
Adding multimedia to multiple choice answers in Moodle quizzes and lessons Sometimes it can be useful to insert multimedia elements into the answers of a multiple choice question in a Moodle lesson or quiz. This can apply to situations where students are required to: Recognize audio excerpts corresponding to text, images, or videos (for example, in music or language courses students have to identify a melody from a music sheet excerpt, or the correct pronunciation of a given text) Recognize video scenes (for example, corresponding to a certain dialogue, gestural conversation, and so on) Adding multimedia to the question body is fairly easy because we can use the HTML editor and just link to a multimedia file, and the Moodle filter will do the rest. But adding questions for which the answer choices are multimedia files is a different story, as there is no HTML editor, just a simple text form. However, this is not complicated with the help of the correct HTML code. For example, in the course, Module 1 - Music Evolves—students have to post excerpts of songs from different moments of a musical genre to a forum topic as attachments. In the same module, we will create a quiz (Mini-quiz – history of music) that will use the excerpts posted by our students in its questions, as an incentive for other students to have a look at their colleagues' work. So, after creating a new quiz and adding a new multiple choice question to it (for example, "Which of the following excerpts refers to medieval music?") we can add links to the MP3 files submitted by students as choices. We can get these links by right-clicking (CTRL+click for Mac users) on the linked MP3 file in the forum post and then clicking on the Copy Link Location option, as shown in the following screenshot: Next, while editing the multiple choice question, we can paste the link location in the answer form, for example, for Choice 1. This is the easy way, as Moodle, with its multimedia filter, will do the rest: As a result, we'll get something like this: However, note that the entire link to the file shows up, which is not very aesthetically-pleasing (and can give clues to the correct answer to students in the filename). We can solve this by using a simple HREF HTML tag in the answer forms, so that we obtain something cleaner, such as this: In this case, we can use the following code: <a href="pasted link location"> link text </a> with a SPACE in the link text: The same concept applies for videos and music from online services (TeacherTube, YouTube, Imeem, and so on) as we can paste the embed code in the answer form. In this case, there is no need to use any extra HTML code. So adding the embed code in the following manner: will result in the following screenshot: When using this process, we should keep in mind a couple of things: The multimedia files that are linked in the choice options MUST be available to the students in the course. If we copy the link location from the files area but the file is not available to the students, we'll have problems. The same applies to attachments in forum posts, with separate groups. Consider the situation where the files linked to in the answer options are those of an attachment in a forum post on the course. Suppose the question is shared and the quiz is restored in another course or exported to another Moodle installation. In this case, there will be problems with the file access as the hyperlink will point to the original source in a particular course, which is not currently available. In the case of videos or audio from online services, embedding may be disabled by request, so these can later become unavailable in the course. Too many links to MP3 files on the same quiz page, and/or MP3 files of considerable size can slow down the page loading. As a possible solution to the first three issues, we can have the multimedia files in a public folder on our server. In this way, files can be accessed from different courses and domains. We could, for example, download a YouTube video and make it available on our server, if this service is blocked in our school or institution. Another option is to upload these files to the course files area (but in this case, the files must be made available to students in the course, by using the Display a directory resource, or they will not have permissions to listen to or see them). There is a trick that can be used to make content available in a course without showing it in the course topics. To do this, we can go to the course settings and add an extra topic, creating the resources and activities that we don't want to show to our students (however, everything for now should be visible, so no "eyes closed" icons!). After we're done, we should go again to the course settings and remove the extra topic. In this way, the content is there, is "visible" from a permissions point of view, but at the same doesn't show in the course. This can be a way of having the files available for quizzes and other activities. As a possible solution to the last problem, we can use page breaks, or have one question per page in the quiz, so that students can only load one question at a time. Another solution is to reduce the file sizes, either by slicing or encoding the files in other formats. In the case of a MP3, reducing the bitrate could be an option. Adding multimedia to quizzes, lessons, and assignments Remember that multimedia can be used in interesting ways in not only multiple choice answers but also in question bodies and lesson content and assignments. We can create lessons in a tutorial style, with videos followed by some questions on the video's content, leading to different lesson branches according to the answers, or assignments can be presented as quick briefing videos. And don't forget that if we want to receive multimedia assignments, we should set this activity to allow students' file uploads. Creating exercises with Hot Potatoes Hot Potatoes (http://hotpot.uvic.ca) from Half Baked Software allows us to create interactive web games and puzzles in a simple way. One of the advantages of Hot Potatoes over Moodle's quiz engine is that Hot Potatoes makes it easier to create exercises, and some of these are very different from the ones available in Moodle, for example crosswords, and finding pairs via drag and drop. The license for this software is a peculiar one, as it allows free use by individuals working for state-funded educational institutions that are non-profit making, on the condition that the material produced using the application is freely available to anyone via the Web (this means that a Moodle course without access to guests, without a key wouldn't probably qualify). Other uses require a license, so we should keep this in mind. We need to register the software at http://hotpot.uvic.ca/reg/register.htm. A key will be sent to our email inbox and we can then register it going to Help | Register and filling in the details. There are six different types of exercises that we can create with this software: JQuiz - question-based exercises JCloze - fill in the gaps exercises JMatch - matching exercises JMix - jumble exercises JCross - crosswords The Masher - linked exercises of the different types mentioned above We will only take a look at the JCross and JMix exercises, as the other formats can be achieved with the question types that Moodle provides in quizzes and lessons. However, you should try them and see for yourself how easy it can be!
Read more
  • 0
  • 0
  • 1861

article-image-change-control-personal-projects-subversion-style
Packt
21 Oct 2009
5 min read
Save for later

Change Control for Personal Projects - Subversion Style

Packt
21 Oct 2009
5 min read
Who Should Read This Read on if you are new to change control, or believe that change control only applies to software, or that it is only meant for large projects. If you are a software pro working with large software projects, you can still read this if you want a gentle introduction to Subversion or svn as it is called. Introduction We have all heard those trite remarks about change -- “... change is the only constant ...”, or similar ones, especially before an unpleasant corporate announcement. These overused remarks about change are unfortunately true. During the course of a day, we make numerous (hopefully!) interrelated changes, updates, or transformations to our work products to reach specific project goals. Needless to say, these changes need to be tracked along with the rationale behind each if we are to prevent ourselves from repeating mistakes, or simply want to recall why we did what we did one month ago! Note that we are not talking about only code or documents here; your work products could be a portfolios of photographs, animations, or some arbitrary binary format. A change control discipline also gives you additional advantages such as being able to develop simultaneous versions of work products for different purposes or clients, rolling back to a previous arbitrary version, or setting up trial development in a so-called branch to bring it back to the main work stream after due review. You also have a running history of how your work product has evolved over time and features. Fetching from a change managed repository also prevents you from creating those fancifully named multiple copies of a file just to keep track of its versions. To reiterate: we use the words 'work product' and 'development' in the broadest sense and not just as applied to software. You might as well be creating a banner ad for your client as much as a Firefox plugin. In the rest of this article we will see how to build a simple personal change control discipline for your day-to-day work using a version control tool. As you will note, 'control' and 'management' have been used interchangeably, though a little hair splitting will yield rich dividends in terms of how different these terms are. Subversion Subversion is version control system available on the Linux (and similar) platforms. If you are trapped in a proprietary world by choice, circumstance, or compulsion, you should try TortoiseSVN. Here, we confine ourselves to the Linux platform. Subversion works by creating a time line of your work products from their inception (or from the point they are brought under version control) to the present point in time, by capturing snapshots of your work products at discrete points that you decide. Each snapshot is a version. You can traverse this time line and extract specific versions for use. How does subversion do it? It versions entire directories. A new version of your directory will be created even if you change one file in it. Don't worry; this does not lead to an explosion of file size with each version. Explaining some terminology, albeit informally, should make the going easier from here. Subversion stores your project(s) in a repository. For the purpose of this article, our repository will stay on the local machine. A revision is nothing but a particular snapshot of the project directory. A working directory is your sandbox. This is where you check out a particular version of your project directory from the repository, make any modifications to it, and then do a check in back into the repository. Revision numbers are bumped up with each check in. You can revert a configuration item, which is like undoing any changes you made. If all this sounds a little abstruse, don't worry, because we will shortly set up our repository so that you can try things out. A commit is when you...., well commit a change done to a file into the repository. Subversion is mostly bundled with a Linux distribution. Find out if you have yours with a 'man svn' or 'svn -h' or a 'whereis svn' command. Setting up Your Repository You can set up your repository in your home directory if you are working on a shared environment. If you have a machine to yourself, you might want to create an 'svn' account with /sbin/nologin (politely refuses logins) as the shell. Your repository might then be '/home/svn/repos'. Subversion is a command line tool. But the only command you will ever issue for the purpose of this article will be to set up your repository: $ svnadmin create /path/to/your/repository The rest, as they say, is GUI! Let Us Get Visual A GUI for subversion is a great tool for learning and working even if you decide to settle for the command line once you get more proficient. eSvn (http://zoneit.free.fr/esvn/) is a Qt-based graphical front end for Subversion. Follow the instructions with the download to compile and install eSvn. Run esvn and this is how it will look with the File | Options... dialog open. Make sure you enter the correct path to svn if not for the other items.    
Read more
  • 0
  • 0
  • 1793
article-image-installing-and-using-openfire
Packt
21 Oct 2009
6 min read
Save for later

Installing and Using Openfire

Packt
21 Oct 2009
6 min read
The Openfire instant messaging server is very easy to install. In fact, it's totally newbie-proof. So much so, that unlike other complex server software, even if you've never setup up Openfire before, you'll be able to get it up and running on your first try. If you're sceptical, by the time we are done with this short article, we'll have ourselves a fully-functional Openfire server that will register users and connect with clients. Preparing Your System Openfire is a cross-platform server and can be installed under Linux, Solaris, Mac, or Windows operating system environments. Openfire reserves its enormity for its users. When it comes to system requirements, Openfire is very suave and a perfect gentleman who has very moderate demands. You don't need to spend much time preparing your system for installing Openfire. Just pick out the environment you're comfortable with—Windows or one of the popular Linux distributions such as Fedora, Debian, or Ubuntu, and you're good to go. You don't have to run around getting obscure libraries or worry about mismatched versions. But like any hard-working gentleman, Openfire has a thing for caffeine, so make sure you have Java on your system. No need to run to the kitchen—this isn't the Java in the cupboard. Openfire is written in the Java programming language, so it'll need a Java Runtime Environment (JRE) installed on your system. A JRE creates a simple (breathable, so to say) environment for Java applications to live and function in. It's available as a free download and is very easy to install. If you're installing under Windows, just skip to the "Installing Under Windows" section later in the article. Linux Users Get Your Cuppa! Sun's Java Runtime Environment is available as a free download from Sun's website (http://www.java.com/en/download/linux_manual.jsp) or it can also be installed from your distribution's software management repositories. Users of RPM-based systems can safely skip this section because the Openfire installer for their distribution already includes a JRE. On the other hand, users of Debian-based systems such as Ubuntu will have to install the JRE before installing Openfire. Thanks to the popular apt-get package management system, there isn't much to installing the JRE. Because Sun's JRE isn't free and is also not an open source software, most Linux distributions make the JRE package available in their non-free tree. If the following command doesn't work, check out the detailed installation instructions for your specific distribution, at  https://jdk-distros.dev.java.net. Open a console and issue the following command: $ sudo apt-get install sun-java6-jre Now the apt-get system will automatically fetch, install, and activate the JRE for you! Meet The Protagonists This article is about making sure that you have no trouble installing one file. This one file is the Openfire installer and it is available in multiple flavors. The four flavors we're concerned with aren't as exotic as Baskin Robbins' 31 flavors but that doesn't make the decision any easier. The Openfire project releases several installers. The four flavors we're concerned with are: Openfire-3.5.2-1.i386.rpm: RPM package for Fedora Linux and other RPM-based variants Openfire_3.5.2_all.deb: DEB package for Debian, Ubuntu Linux and their derivates Openfire_3_5_2.tar.gz: Compressed "tarball" archive that'll work on any Linux distribution Openfire_3_5_2.exe: Openfire installer for Windows We'll cover installing Openfire from all of these files, so that you may use Openfire from your favorite Linux distribution or from within Windows. Just to reiterate here, the Windows installer and the RPM Linux installer both bundle the JRE, while the other other versions do not. The Actual Install-Bit Alright, so you have the Java JRE setup and you've downloaded the Openfire installer. In this section, we'll install Openfire server from the various versions we discussed in the last section. Let's first install from the source tarball. The first step when dealing with .tar.gz source archive is to extract the files. Let's extract ours under /tmp and then move the extracted directory under /opt. # tar zxvf openfire_3_5_2.tar.gz# mv openfire /opt Now we'll create a non-priviledged user and group for running Openfire. # groupadd openfire# useradd -d /opt/openfire -g openfire openfire Next, we'll change ownership of the openfire/directory to the newly-created user and group. # chown -R openfire:openfire /opt/openfire Believe it or not, that's it! You've just installed Openfire server. Surprised? Get ready for more. It gets even simpler if you install using the precompiled RPM or DEB binaries. In the case of RPM, Openfire is installed under /opt/openfire and in case of the DEB file, Openfire resides under /etc/openfire. On RPM-based systems such as Fedora and its derivates (as root), use: # rpm -ivh openfire-3.5.2-1.i386.rpm On DEB-based systems such as Debian, Ubuntu, and so on, use: $ sudo dpkg -i openfire_3.5.2_all.deb Voila! You're done. Now, who thought my "installing Openfire is totally newbie-proof" comment was an exaggeration? Running Openfire on Linux/Unix So, we now have Openfire on our favourite Linux distribution, whichever distribution this may be. Now it's time to fire it up and get going. Depending on how you installed Openfire, the procedure to start it varies a little. If you've installed Openfire from the RPM or DEB, you'll be pleased to know that the Openfire developers have already done most of the hard work for you. These binaries contain some custom handling for the RedHat/Debian-like environments. You can start and stop Openfire just like any other service on your system: # /etc/init.d/openfire startStarting Openfire: You can also view the other options available: # /etc/init.d/openfireUsage /etc/init.d/Openfire {start|stop|restart|status|condrestart|reload} On the other hand, if you've installed Openfire using the .tar.gz archive, you can start and stop Openfire using the bin/openfire script in your Openfire installation directory. First, change to the user that owns the /opt/openfire directory: # su - openfire# cd /opt/openfire/bin/# ./openfire startStarting Openfire And now you have Openfire up and running! If you are using a firewall, which you most probably are, make sure to forward traffic on ports 5222 and 5223 (for SSL) which clients use for connecting with the Openfire server. Also forward traffic on port 7777 for file transfer. Linux users can skip the next section on installing Openfire under Windows and move directly to the section that discusses the preliminary Openfire setup.
Read more
  • 0
  • 0
  • 5933

article-image-first-steps-scalix-admin-console-and-scalix-web-access
Packt
21 Oct 2009
4 min read
Save for later

First Steps with Scalix Admin Console and Scalix Web Access

Packt
21 Oct 2009
4 min read
SAC at a Glance Point your Browser to the URL of your Scalix server, following this syntax: http:///sac. A pop-up window with the Administration Console Login is opened. If you are using Firefox or another browser with pop-up suppression, perhaps the configuration will need some corrections. Allow the Scalix server to open popups. In Firefox, you can easily configure this by clicking in the yellow bar on top of the displayed page. Other browsers may require editing the preferences. Otherwise, Scalix will provide a web page for you with a link, which opens the Admin Console in the same browser window. Logging In On Scalix 11, the Scalix Administration Login looks like this: Enter the Administrator's name in the field Login ID, exactly as configured during installation. Activate the reminder that you are connected via http and not through https by clicking on option field Not using a secure https connection. Once we have configured https for Scalix, the login dialog will not provide this option anymore. However, enabling https is not that easy, and therefore not standard in Scalix, except for the installations on Red Hat Enterprise. Click on the button Login to start the Administration console. A First Look Around The Scalix Administration Console is a Web application provided by a Tomcat application server. The only requirement for it is a modern browser supporting JavaScript. Firefox and Internet Explorer do fine, Konqueror may work soon. The Admin Console window is split in three parts: A menu with icons called Toolbar A list view on the lower left named Contents Pane and The main window on the right, called Display Pane The icons in the menu bar let you choose the administration task you want to accomplish, the content pane lists the possible entries that can be edited, and the options and parameters of a selected entry are presented in the display pane. By clicking on one of the icons on the Toolbar, you can access the different sections of the Scalix Administration Console. The first three sections are about users, groups, and resources, and will be used in daily administration for adding, deleting or modifying these objects. The section Plugins offers a management GUI for your own or third-party Scalix plug-ins. The Server Info icon leads to a concise list of running services, where the administrator can set the log level of these services and browse through the services' log files. The Settings Icon allows you to set preferences for the server and new users. A concise online help is available, and the icons Refresh and Logout complete the menu bar's icons. Navigating in the Admin Console A nice gadget in SAC is the little icon on the top left of the main window. Surrounded by four arrows, this icon displays the icon of the current section and enables the administrator to navigate in a quick and easy manner through the administration console. Clicking the up or down arrows will select and activate the next entry upwards or downwards in the list view to the left, and the left/right arrows navigate you back and forth in a browser-like fashion. Users, Groups, Resources... Now click on the Users icon in order to switch to the user management dialog. Click on the entry of the only user present at this time, sxadmin. For every user, there are six tabs where the user information is stored. The tab General holds the most important information: Username, Display Name, and Email address. This information is all that is necessary to add an user and use the new account. The other tabs contain contact information, group memberships, and administrative delegations. The mailbox quota, that is the amount of storage that the user's account may sum up to, is configured in the Mail dialog. On the Advanced tab, the administrator can add a role to the user, decide whether this user is a Standard or a Premium User, and give him a different authentication ID. Changing Passwords There are other features in the Admin Console that you will be using frequently once you are master of some Scalix users. One of them is probably the button Change Password on the lower right corner leading directly to the password dialog. This button is present in every user's configuration dialog.
Read more
  • 0
  • 0
  • 3468
Modal Close icon
Modal Close icon