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

How-To Tutorials

7018 Articles
article-image-user-interface-production
Packt
01 Dec 2010
10 min read
Save for later

User Interface in Production

Packt
01 Dec 2010
10 min read
  Liferay User Interface Development Develop a powerful and rich user interface with Liferay Portal 6.0 Design usable and great-looking user interfaces for Liferay portals Get familiar with major theme development tools to help you create a striking new look for your Liferay portal Learn the techniques and tools to help you improve the look and feel of any Liferay portal A practical guide with lots of sample code included from real Liferay Portal Projects free for use for developing your own projects         Read more about this book       (For more resources on this subject, see here.) This section will introduce how to add workflow capabilities to any custom assets in plugins. Knowledge Base articles will be used as an example of custom assets. In brief, the Knowledge Base plugin enables companies to consolidate and manage the most accurate information in one place. For example, a user manual is always updated; users are able to rate, to add workflow and to provide feedback on these Knowledge Base articles. Preparing a plugin—Knowledge Base First of all, let's prepare a plugin with workflow capabilities, called Knowledge Base. Note that the plugin Knowledge Base here is used as an example only. You can have your own plugin as well. What's Knowledge Base? The plugin Knowledge Base allows authoring articles and organize them in a hierarchy of navigable categories. It leverages Web Content articles, structures, and templates; allows rating on articles; allows commenting on articles; allows adding hierarchy of categories; allows adding tags to articles; exports articles to PDF and other formats; supports workflow; allows adding custom attributes (called custom fields); supports indexing and advanced search; allows using the rule engine and so on. Most importantly the plugin Knowledge Base supports import of a semantic markup language for technical documentation called DocBook. DocBook enables its users to create document content in a presentation-neutral form that captures the logical structure of the content; that content can then be published in a variety of formats, such as HTML, XHTML, EPUB, and PDF, without requiring users to make any changes to the source. Refer to http://www.docbook.org/. In general, the plugin Knowledge Base provides four portlets inside: Knowledge Base Admin (managing knowledge base articles and templates), Knowledge Base Aggregator (publishing knowledge base articles), Knowledge Base Display (displaying knowledge base articles) and Knowledge Base Search (the ability to search knowledge base articles). Structure The plugin Knowledge Base has following folder structure under the folder $PLUGIN_SDK_HOME/knowledge-base-portlet. admin: View JSP files for portlet Admin aggregator: View JSP files for portlet Aggregator display: View JSP files for portlet Display icons: Icon images files js: JavaScript files META-INF: Contains context.xml search: View JSP files for portlet Search WEB-INF: Web info specification; includes subfolders classes, client, lib, service, SQL, src, and tld As you can see, JSP files such as init.jsp and css_init.jsp are located in the folder $PLUGIN_SDK_HOME/knowledge-base-portlet. Services and models As you may have noticed, the plugin Knowledge Base has specified services and models with the package named com.liferay.knowledgebase. You would be able to find details at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml. Service-Builder in Plugins SDK will automatically generate services and models against service.xml, plus XML files such as portlet-hbm.xml, portlet-model-hints.xml, portlet-orm.xml, portlet-spring.xml, base-spring.xml, cluster-spring.xml,dynamic-data-source-spring.xml, hibernate-spring.xml, infrastructure-spring.xml, messaging-spring.xml, and shard-data-source-spring.xml under the folder $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/META-INF. The service.xml specified Knowledge Base articles as entries: Article, Comment, and Template. The entry Article included columns: article Id as primary key, resource Prim Key, group Id, company Id, user Id, user Name, create Date, modified Date, parent resource Prim Key, version, title, content, description, and priority; the entry Template included columns: template Id as primary key, group Id, company Id, user Id, user Name, create Date, modified Date, title, content, and description; while the entity Comment included columns: comment Id as primary key, group Id, company Id, user Id, user Name, create Date, modified Date, class Name Id, class PK, content and helpful. As you can see, the entity Comment could be applied on either any core assets or custom assets like Article and Template by using class Name Id and class PK. By the way, the custom SQL scripts were provided at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/custom-sql/default.xml. In addition, resource actions, that is, permission actions specification—are provided at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/resource-actions/default.xml. Of course, you can use Ant target build-wsdd to generate WSDD server configuration file $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/server-config.wsdd and to use Ant target build-client plus namespace-mapping.properties to generate web service client JAR file like $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/client/known-base-portlet-client.jar. In brief, based on your own custom models and services specified in service.xml, you can easily build service, WSDD, and web service client in plugins of Liferay 6 or above version. Adding workflow instance link First, you have to add a workflow instance link and its related columns and finder in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml as follows. <column name="status" type="int" /> <column name="statusByUserId" type="long" /> <column name="statusByUserName" type="String" /> <column name="statusDate" type="Date" /> <!-- ignore details --> <finder name="R_S" return-type="Collection"> <finder-column name="resourcePrimKey" /> <finder-column name="status" /> </finder> <!-- ignore details --> <reference package-path="com.liferay.portal" entity="WorkflowInstance Link" /> As shown in the above code, the column element represents a column in the database, four columns like status, statusByUserId, statusByUserName, and statusDate are required for Knowledge Base workflow, storing workflow related status, and user info; the finder element represents a generated finder method, the method finder R_S is defined as Collection (an option) for return type with two columns, for example, resourcePrimkey and status; where the reference element allows you to inject services from another service.xml within the same class loader. For example, if you inject the Resource (that is, WorkflowInstanceLink) entity, then you'll be able to reference the Resource services from your service implementation via the methods getResourceLocalService and getResourceService. You'll also be able to reference the Resource services via the variables resourceLocalService and resourceService. Then, you need to run ANT target build-service to rebuild service based on newly added workflow instance link. Adding workflow handler Liferay 6 provides pluggable workflow implementations, where developers can register their own workflow handler implementation for any entity they build. It will appear automatically in the workflow admin portlet so users can associate workflow entities with available permissions. To make it happen, we need to add the Workflow Handler in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/liferay-portlet.xml of plugin as follows. <workflow-handler>com.liferay.knowledgebase.admin.workflow. ArticleWorkflowHandler</workflow-handler> As shown in the above code, the workflow-handler value must be a class that implements com.liferay.portal.kernel.workflow.BaseWorkflowHandler and is called when the workflow is run. Of course, you need to specify ArticleWorkflowHandler under the package com.liferay.knowledgebase.admin.workflow. The following is an example code snippet. public class ArticleWorkflowHandler extends BaseWorkflowHandler { public String getClassName(){/* get target class name */}; public String getType(Locale locale) {/* get target entity type, that is, Knowledge base article*/}; public Article updateStatus( int status, Map<String, Serializable> workflowContext) throws PortalException, SystemException {/* update workflow status*/}; protected String getIconPath(ThemeDisplay themeDisplay) {/* find icon path */ return ArticleLocalServiceUtil.updateStatus(userId, resourcePrimKey, status, serviceContext); }; } As you can see, ArticleWorkflowHandler extends BaseWorkflowHandler and overrode the methods getClassName, getType, updateStatus, and getIconPath. That's it. Updating workflow status As mentioned in the previous section, you added the method updateStatus in ArticleWorkflowHandler. Now you should provide implementation of the method updateStatus in com.liferay.knowledgebase.service.impl.ArticleLocalServiceImpl.java. The following is some example sample code: public Article updateStatus(long userId, long resourcePrimKey, int status, ServiceContext serviceContext) throws PortalException, SystemException { /* ignore details */ // Article Article article = getLatestArticle(resourcePrimKey, WorkflowConstants.STATUS_ANY); articlePersistence.update(article, false); if (status != WorkflowConstants.STATUS_APPROVED) { return article; } // Articles // Asset // Social // Indexer // Attachments // Subscriptions } As shown in above code, it first gets latest article by resourcePrimKey and WorkflowConstants.STATUS_ANY. Then, it updates the article based on the workflow status. And moreover, it updates articles display order, asset tags and categories, social activities, indexer, attachments, subscriptions, and so on. After adding new method at com.liferay.knowledgebase.service.impl.ArticleLocalServiceImpl.java, you need to run ANT target build-service to build services. Adding workflow-related UI tags Now it is time to add workflow related UI tags (AUI tags are used as an example) at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp. First of all, add the AUI input workflow action with value WorkflowConstants.ACTION_SAVE_DRAFT as follows. <aui:input name="workflowAction" type="hidden" value=" <%= WorkflowConstants.ACTION_SAVE_DRAFT %>" /> As shown in above code, the default value of AUI input workflowAction was set as SAVE DRAFT with type hidden. That is, this AUI input is invisible to end users. Afterwards, it would be better to add workflow messages by UI tag liferay-ui:message, like a-new-version-will-be-created-automatically-if-this-content-is-modified for WorkflowConstants.STATUS_APPROVED, and there-is-a-publication-workflow-in-process for WorkflowConstants.STATUS_PENDING. <% int status = BeanParamUtil.getInteger(article, request, "status", WorkflowConstants.STATUS_DRAFT); %> <c:choose> <c:when test="<%= status == WorkflowConstants.STATUS_APPROVED %>"> <div class="portlet-msg-info"> <liferay-ui:message key="a-new-version-will-be-created- automatically-if-this-content-is-modified" /> </div> </c:when> <c:when test="<%= status == WorkflowConstants.STATUS_PENDING %>"> <div class="portlet-msg-info"> <liferay-ui:message key="there-is-a-publication-workflow-in-process" /> </div></c:when> </c:choose> And then add AUI workflow status tag aui:workflow-status at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp. <c:if test="<%= article != null %>"> <aui:workflow-status id="<%= String.valueOf(resourcePrimKey) %>" status="<%= status %>" version="<%= GetterUtil.getDouble(String. valueOf(version)) %>" /> </c:if> As you can see, aui:workflow-status is used to represent workflow status. Similarly you can find other AUI tags like a button, button_row, column, field_wrapper, fieldset, form, input, layout, legend, option, panel, script, and select. Finally you should add the JavaScript to implement the function publishArticle() as follows. function <portlet:namespace />publishArticle() { document.<portlet:namespace />fm.<portlet:namespace />workflowAction.value = "<%= WorkflowConstants.ACTION_PUBLISH %>"; <portlet:namespace />updateArticle(); } As you can see, the workflow action value is set as WorkflowConstants.ACTION_PUBLISH. You have added workflow capabilities on Knowledge Base articles in plugins. From now on, you will be able to apply workflow on Knowledge Base articles through Control Panel.
Read more
  • 0
  • 0
  • 2758

article-image-advanced-theme-liferay-user-interface-development
Packt
01 Dec 2010
16 min read
Save for later

Advanced Theme in Liferay User Interface Development

Packt
01 Dec 2010
16 min read
Liferay User Interface Development Develop a powerful and rich user interface with Liferay Portal 6.0 Design usable and great-looking user interfaces for Liferay portals Get familiar with major theme development tools to help you create a striking new look for your Liferay portal Learn the techniques and tools to help you improve the look and feel of any Liferay portal A practical guide with lots of sample code included from real Liferay Portal Projects free for use for developing your own projects Changing theme.parent property in theme Liferay provides four different theme implementations out-of-box in the ${PORTAL_ROOT_HOME}/html/themes/ folder as shown in the following screenshot: When you create a new theme in the themes/ directory of the Plugins SDK, the Ant script will copy some files to the new theme from one of these three folders, _styled/, _unstyled/, and classic/, which can be specified in the ${PLUGINS_SDK_HOME}/themes/build-common-theme.xml file. For example, you can go to the ${PLUGINS_SDK_HOME}/themes/ directory and run create.bat palmtree "Palm-Tree Publications theme" on Windows or ./create.sh palmtree "Palm-Tree Publications theme" on Linux, respectively. Or you can use Liferay IDE to create same New Liferay Theme Plugin Project. This will create a theme folder named palmtree-theme in the Liferay Plugins SDK environment. When you run ant to build and deploy the theme and then apply the newly created theme to your page, you will find out that the look and feel of the page is messed up, as shown in the following screenshot: If you are familiar with theme development in Liferay Portal 5.2, you may wonder what has happened to the theme created in Liferay Portal 6 Plugins SDK because you would expect a fully working theme with two simple commands, create and ant. This is because the following build.xml file in your theme specifies _styled as the value for the theme.parent property: <?xml version="1.0"?> <project name="palmtree-theme" basedir="." default="deploy"> <import file="../build-common-theme.xml" /> <property name="theme.parent" value="_styled" /> </project> This means that when your newly created theme is built, it will copy all the files from the _styled/ folder in the ${PORTAL_ROOT_HOME}/html/themes/ directory to the docroot/ folder of your theme. The default _styled/ folder does not have enough files to create a completely working theme and that is why you see a messed-up page when the theme is applied to a page. The reason why this default _styled/ folder does not include enough files is that some Liferay users prefer to have minimal set of files to start with. You can modify the build.xml file for your theme in the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/ folder by changing value of the theme.parent property from _styled to classic, if you prefer to use the Classic theme as the basis for your theme modification. <property name="theme.parent" value="classic" /> Now you will see that your page looks exactly the same as that with the Classic theme after you build and apply your theme to the page (refer to the following screenshot): Adding color schemes to a theme When you create a theme in the Plugins SDK environment, the newly created theme by default supports one implementation and does not automatically have color schemes as variations of the theme. This fits well if you would like to have a consistent look and feel, especially in terms of the color display, across all the pages that the theme is applied to. In your portal application, you might have different sites with slightly different look and feel for different groups of users such as physicians and patients. You might also need to display different pages such as public pages with one set of colors and the private pages with a different set of colors. However, you don't want to create several different themes for reasons such as easy maintenance. In this case, you might consider creating different color schemes in your theme. Color schemes are specified using a Cascading Style Sheets (CSS) class name, with which you are able to not only change the colors, but also choose different background images, border colors, and so on. In the previous section, we created a PalmTree Publication theme, which takes the Classic theme as its parent theme. Now we can follow the mentioned steps to add color schemes to this theme: Copy the ${PORTAL_ROOT_HOME}/webapps/palmtree-theme/WEB-INF/liferay-look-and-feel.xml file to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/WEB-INF/ folder. Open the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/WEB-INF/liferay-look-and-feel.xml file in your text editor. Change <theme id="palmtree" name="PalmTree Publication Theme" /> as shown in the highlighted lines here, and save the change: <look-and-feel> <compatibility> <version>6.0.5+</version> </compatibility> <theme id="palmtree" name="Palm Tree Publications Theme"> <color-scheme id="01" name="Blue"> <css-class>blue</css-class> <color-scheme-images-path>${images-path}/color_schemes/ blue</color-scheme-images-path> </color-scheme> <color-scheme id="02" name="Green"> <css-class>green</css-class> </color-scheme> <color-scheme id="03" name="Orange"> <css-class>orange</css-class> </color-scheme> </theme> </look-and-feel> Go to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/palmtree-theme/_diffs/ folder and create a css/ subfolder. Copy both custom.css and custom_common.css from the ${PORTAL_ROOT_HOME}/html/themes/classic/_diffs/css/ folder to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/css/ folder. This is to let the default styling handle the first color scheme blue. Create a color_schemes/ folder under the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/palmtree-theme/_diffs/css/ folder. Place one .css file for each of your additional color schemes. In this case, we are going to create two additional color schemes: green and orange. To make the explanation simpler, copy both the green.css and orange.css files from the ${PORTAL_ROOT_HOME}/html/themes/classic/_diffs/css/color_schemes/ folder to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/css/color_schemes/ folder. Copy all images from the ${PORTAL_ROOT_HOME}/html/themes/classic/_diffs/images/ folder to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/images/ folder. Add the following lines in your ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/css/custom.css file: @import url(color_schemes/green.css); @import url(color_schemes/orange.css); If you open either the green.css or the orange.css file, you will be able to identify the styling for the CSS by using a color prefix for each CSS definition. For example, in the orange.css file you would find that each item is defined like this: orange .dockbar { background-color: #AFA798; background-image: url(../../images/color_schemes/orange/dockbar /dockbar_bg.png); } .orange .dockbar .menu-button-active { background-color: #DBAC5C; background-image: url(../../images/color_schemes/orange/dockbar /button_active_bg.png); } In the green.css file, the style is defined like this: green .dockbar { background-color: #A2AF98; background-image: url(../../images/color_schemes/green/dockbar/ dockbar_bg.png); } .green .dockbar .menu-button-active { background-color: #95DB5C; background-image: url(../../images/color_schemes/green/dockbar/ button_active_bg.png); } Also, notice that the related images used for the different color schemes are included in the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/images/color_schemes/ folder. Re-build and deploy the PalmTree Publication theme. Log in as administrator and go to the Control Panel to apply this theme to the PalmTree Publications Inc. organization. You will be able to see three color schemes available under this theme. Select any of them to apply it to the Public Pages. Take a screenshot of the page when each of the color schemes is applied and save it as thumbnail.png in the corresponding blue, green, and orange subfolders in the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/images/color_scheme/ folder. Three screenshots are used to distinguish between the three color schemes in the Control Panel as seen in the following screenshot: The following screenshots shows how each of the three color schemes looks when applied to a portal page: As shown in above screenshot, color scheme blue has been applied on the Home page, by default. The following screenshot shows applying color scheme green on the current page. Of course, you would be able to apply color schemes blue or green in the entire site, if required. Similar to color schemes blue and green, you can apply color scheme orange as well on the current page or the entire site, as shown in following screenshot: So it works! The page background is with a hue of gray color. Now, what if we want to change the page background color to red for the green color schema? Update the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/css/color_schemes/green.css file as follows. The commented outline is the original content. The next line after the comment is the new content. The #FF0000 code is for the red color. body.green, .green .portlet { /*background-color: #F1F3EF;*/ background-color: #FF0000; } Re-deploy the PalmTree theme and refresh the portal page that uses the green color scheme. Now, you should be able to see the portal page with a red background color. As you can see, you can use theme color schemes to create some variants of the same theme without creating multiple themes. This is useful when you have different but related user roles such as physicians, nurses, and patients and you need to build a different site for each of them. You can use the color schemes to display each of these sites in a slightly different look and feel. Configurable theme settings There are many use cases where you would like to change some default settings in the theme so that you can modify the values after the theme is built and deployed. Fortunately, each theme can define a set of settings to make this configurable. The settings are defined as key-value pairs in the liferay-look-and-feel.xml file of the theme with the following syntax: <settings> <setting key="my-setting1" value="my-value1" /> <setting key="my-setting2" value="my-value2" /> </settings> These settings can then be accessed in the theme templates using the following code: $theme.getSetting("my-setting1") $theme.getSetting("my-setting2") For example, I need to create two themes—PalmTree Publications theme and AppleTree Publications theme. They are exactly the same except for some differences in the footer content that includes copyright, terms of use, privacy policy, and so on. Instead of creating two themes packaged as separate .war files, we create one set of two themes that share the majority of the code including CSS, JavaScript, images, and most templates; but with one configurable setting and two different implementations of the footer Velocity files. Here is how this can be done: Open ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/WEB-INF/liferay-look-and-feel.xml in the above sample PalmTree theme. Copy the PalmTree theme section and paste it in the same file but after this section. Rename the values of id and name from palmtree and PalmTree Publications theme to appletree and AppleTree Publications theme in the second section. Add the following setting to the palmtree section before the color-scheme definition: <settings> <setting key="theme-id" value="palmtree" /> </settings> Add the following setting to the appletree section before the color-scheme definition: <settings> <setting key="theme-id" value="appletree" /> </settings> Find the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/WEB-INF/liferay-look-and-feel.xml file as follows: <look-and-feel> // ignore details <theme id="palmtree" name="PalmTree Publications Theme"> <settings> <setting key="theme-id" value="palmtree" /> </settings> <color-scheme id="01" name="Blue"> // ignore details </color-scheme> </theme> <theme id="appletree" name="AppleTree Publications Theme"> <settings> <setting key="theme-id" value="appletree" /> </settings> <color-scheme id="01" name="Blue"> // ignore details </color-scheme> </theme> </look-and-feel> Copy the portal_normal.vm file of the Classic theme from the ${PORTAL_ROOT_HOME}/html/themes/classic/_diffs/templates/ folder to the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/templates/ folder. Open the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/templates/portal_normal.vm file Replace the default footer section with the following code: #set ($theme_id = $theme.getSetting("theme-id")) #if ($theme_id == "palmtree") #parse ("$full_templates_path/footer_palmtree.vm") #else #parse ("$full_templates_path/footer_appletree.vm") #end Create your own version of the two footer Velocity templates in the ${PLUGINS_SDK_HOME}/themes/palmtree-theme/docroot/_diffs/templates/ folder. Add related CSS definitions for your footer in your custom.css file. Build and deploy the theme .war file. Now you should be able to see both the PalmTree and AppleTree themes when you go to the Control Panel to apply either theme to your page. Based on the theme to be used, you should also notice that your footer is different. Of course, we can take other approaches to implement a different footer in the theme. For example, you can dynamically get the organization or community name and render the footer differently. However, the approach we explained previously can be expanded to control the UI of the other theme components such as the header, navigation, and portlets. Portal predefined settings in theme In the previous section, we discussed that theme engineers can add configurable custom settings in the liferay-look-and-feel.xml file of a theme. Liferay portal can also include some predefined out-of-the-box settings such as portlet-setup-show-borders-default and bullet-style-options in a theme to control certain default behavior of the theme. Let us use portlet-setup-show-borders-default as an example to explain how Liferay portal controls the display of the portlet border at different levels. If this predefined setting is set to false in your theme, Liferay portal will turn off the borders for all portlets on all pages where this theme is applied to. <settings> <setting key="portlet-setup-show-borders-default" value="false" /> </settings> By default, the value is set to true, which means that all portlets will display the portlet border by default. If the predefined portlet-setup-show-borders-default setting is set to true, it can be overwritten for individual portlets using the liferay-portlet.xml file of a portlet as follows: <liferay-portlet-app> // ignore details <portlet> <portlet-name>sample</portlet-name> <icon>/icon.png</icon> <use-default-template>false</use-default-template> <instanceable>true</instanceable> <header-portlet-css>/css/main.css</header-portlet-css> <footer-portlet-javascript>/js/main.js</footer-portlet-javascript> <css-class-wrapper>sample-portlet</css-class-wrapper> </portlet> // ignore details </liferay-portlet-app> Set the use-default-template value to true if the portlet uses the default template to decorate and wrap content. Setting it to false will allow the developer to maintain the entire output content of the portlet. The default value is true. The most common use of this is when you want the portlet to look different from the other portlets or if you want the portlet not to have borders around the output content. The use-default-template setting of each portlet, after being set to either true or false, in the liferay-portlet.xml file, can be further overwritten by the portlet's popup CSS setting. Users with the appropriate permissions can change it by going to the Look and Feel | Portlet Configuration | Show Borders checkbox of the portlet, as shown in the next screenshot: Embedding non-instanceable portlets in theme One common requirement in theme development is to add some portlets in different components of a theme. For example, you might want to add the Sign In portlet in the header of your theme, the Web Content Search portlet in the navigation area, and the Site Map portlet in the footer area. All the Liferay out-of-the-box portlets can be referred in the ${PORTAL_ROOT_HOME}/WEB-INF/liferay-portlet.xml file. How can this be achieved? Well, it can be quite easy or pretty tricky to embed an out-of-the-box portlet in a theme. Embedding Dockbar and Breadcrumb portlets in a theme The Dockbar portlet is embedded at the very top in the default Classic theme in the portal_normal.vm file as shown next: #if($is_signed_in) #dockbar() #end In the same way, the Breadcrumb portlet can be embedded in the content area of the Classic theme in the portal_normal.vm file: #breadcrumbs() Embedding Language and Web Content Search portlets in a theme Some other Liferay out-of-the-box portlets such as the Language and Web Content Search portlets can be embedded in a theme or a layout template easily. For example, the Web Content Search portlet can be added to the far right side of the horizontal navigation area of your theme as follows in the navigation.vm file of your theme. <div id="navbar"> <div id="navigation" class="sort-pages modify-pages"> <div id="custom"> $theme.journalContentSearch() </div> // ignore details </div> </div> In the same way, the Language portlet can be embedded in the portal_normal.vm Velocity template file of your theme: $theme.language() Again, you need to add the necessary CSS definitions in your custom.css file to control the look and feel and the location of your embedded portlet(s). Embedding Sign In portlet in the header area of a theme Sometimes the theme design requires that the Liferay Sign In portlet be in the header area. By default, the Sign In portlet has a portlet border but we need to disable it. The previously mentioned approaches for embedding a portlet in a theme through Velocity attributes in a template do not work in this case because we need to customize the default UI of the embedded portlet. Instead, we can add the following code to the header section in the portal_normal.vm file in our sample PalmTree theme: #if(!$is_signed_in) #set ($locPortletId = "58") $velocityPortletPreferences.setValue("portlet-setup-show-borders", "false") #set($locRenderedPortletContent = $theme.runtime($locPortletId, "", $velocityPortletPreferences.toString())) $locRenderedPortletContent $velocityPortletPreferences.reset() #end After the theme is re-built and re-deployed, we can see that the Sign In portlet is rendered in the header area underneath the logo without the portlet border. The next step for us is to modify the custom.css file and the related files by adding CSS definition to control the location and look and feel of this Sign In portlet. The following screenshot shows the Sign In portlet in the header area and the Web Content Search portlet in the navigation area in a working theme in the production environment:
Read more
  • 0
  • 0
  • 6685

article-image-python-graphics-animation-principles
Packt
01 Dec 2010
7 min read
Save for later

Python graphics: animation principles

Packt
01 Dec 2010
7 min read
Animation is about making graphic objects move smoothly around a screen. The method to create the sensation of smooth dynamic action is simple: First present a picture to the viewer's eye. Allow the image to stay in view for about one-twentieth of a second. With a minimum of delay, present another picture where objects have been shifted by a small amount and repeat the process. Besides the obvious applications of making animated figures move around on a screen for entertainment, animating the results of computer code gives you powerful insights into how code works at a detailed level. Animation offers an extra dimension to the programmers' debugging arsenal. It provides you with an all encompassing, holistic view of software execution in progress that nothing else can. Static shifting of a ball with Python We make an image of a small colored disk and draw it in a sequence of different positions. How to do it... Execute the program shown and you will see a neat row of colored disks laid on top of each other going from top left to bottom right. The idea is to demonstrate the method of systematic position shifting. # moveball_1.py #>>>>>>>>>>>>> from Tkinter import * root = Tk() root.title("shifted sequence") cw = 250 # canvas width ch = 130 # canvas height chart_1 = Canvas(root, width=cw, height=ch, background="white") chart_1.grid(row=0, column=0) # The parameters determining the dimensions of the ball and its # position. # ===================================== posn_x = 1 # x position of box containing the ball (bottom) posn_y = 1 # y position of box containing the ball (left edge) shift_x = 3 # amount of x-movement each cycle of the 'for' loop shift_y = 2 # amount of y-movement each cycle of the 'for' loop ball_width = 12 # size of ball - width (x-dimension) ball_height = 12 # size of ball - height (y-dimension) color = "violet" # color of the ball for i in range(1,50): # end the program after 50 position shifts posn_x += shift_x posn_y += shift_y chart_1.create_oval(posn_x, posn_y, posn_x + ball_width, posn_y + ball_height, fill=color) root.mainloop() #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> How it works... A simple ball is drawn on a canvas in a sequence of steps, one on top of the other. For each step, the position of the ball is shifted by three pixels as specified by the size of shift_x. Similarly, a downward shift of two pixels is applied by an amount to the value of shift_y. shift_x and shift_y only specify the amount of shift, but they do not make it happen. What makes it happen are the two commands posn_x += shift_x and posn_y += shift_y. posn is the abbreviation for position. posn_x += shift_x means "take the variable posn_x and add to it an amount shift_x." It is the same as posn_x = posn_x + shift_x. Another minor point to note is the use of the line continuation character, the backslash "". We use this when we want to continue the same Python command onto a following line to make reading easier. Strictly speaking for text inside brackets "(...)" this is not needed. In this particular case you can just insert a carriage return character. However, the backslash makes it clear to anyone reading your code what your intention is. There's more... The series of ball images in this recipe were drawn in a few microseconds. To create decent looking animation, we need to be able to slow the code execution down by just the right amount. We need to draw the equivalent of a movie frame onto the screen and keep it there for a measured time and then move on to the next, slightly shifted, image. This is done in the next recipe. Time-controlled shifting of a ball Here we introduce the time control function canvas.after(milliseconds) and the canvas.update() function that refreshes the image on the canvas. These are the cornerstones of animation in Python. Control of when code gets executed is made possible by the time module that comes with the standard Python library. How to do it... Execute the program as previously. What you will see is a diagonal row of disks being laid in a line with a short delay of one fifth of a second (200 milliseconds) between updates. The result is shown in the following screenshot showing the ball shifting in regular intervals. # timed_moveball_1.py #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> from Tkinter import * root = Tk() root.title("Time delayed ball drawing") cw = 300 # canvas width ch = 130 # canvas height chart_1 = Canvas(root, width=cw, height=ch, background="white") chart_1.grid(row=0, column=0) cycle_period = 200 # time between fresh positions of the ball # (milliseconds). # The parameters determining the dimensions of the ball and it's # position. posn_x = 1 # x position of box containing the ball (bottom). posn_y = 1 # y position of box containing the ball (left edge). shift_x = 3 # amount of x-movement each cycle of the 'for' loop. shift_y = 3 # amount of y-movement each cycle of the 'for' loop. ball_width = 12 # size of ball - width (x-dimension). ball_height = 12 # size of ball - height (y-dimension). color = "purple" # color of the ball for i in range(1,50): # end the program after 50 position shifts. posn_x += shift_x posn_y += shift_y chart_1.create_oval(posn_x, posn_y, posn_x + ball_width, posn_y + ball_height, fill=color) chart_1.update() # This refreshes the drawing on the canvas. chart_1.after(cycle_period) # This makes execution pause for 200 # milliseconds. root.mainloop() How it works... This recipe is the same as the previous one except for the canvas.after(...) and the canvas.update() methods. These are two functions that come from the Python library. The first gives you some control over code execution time by allowing you to specify delays in execution. The second forces the canvas to be completely redrawn with all the objects that should be there. There are more complicated ways of refreshing only portions of the screen, but they create difficulties so they will not be dealt with here. The canvas.after(your-chosen-milliseconds) method simply causes a timed-pause to the execution of the code. In all the preceding code, the pause is executed as fast as the computer can do it, then when the pause, invoked by the canvas.after() method is encountered, execution simply gets suspended for the specified number of milliseconds. At the end of the pause, execution continues as if nothing ever happened. The canvas.update() method forces everything on the canvas to be redrawn immediately rather than wait for some unspecified event to cause the canvas to be refreshed. There's more... The next step in effective animation is to erase the previous image of the object being animated shortly before a fresh, shifted clone is drawn on the canvas. This happens in the next example. The robustness of Tkinter It is also worth noting that Tkinter is robust. When you give position coordinates that are off the canvas, Python does not crash or freeze. It simply carries on drawing the object 'off-the-page'. The Tkinter canvas can be seen as just a tiny window into an almost unlimited universe of visual space. We only see objects when they move into the view of the camera which is the Tkinter canvas.
Read more
  • 0
  • 0
  • 12819

article-image-vaadin-portlets-liferay-user-interface-development
Packt
01 Dec 2010
1 min read
Save for later

Vaadin Portlets in Liferay User Interface Development

Packt
01 Dec 2010
1 min read
Vaadin portlets are developed with Vaadin framework. The Vaadin framework can also be used to develop standalone web applications. Liferay portal supports the Vaadin portlets. In this section, we will write a Vaadin portlet for Liferay portal using the Vaadin Eclipse plugin. Required software Install the following software for the development environment, if they are not already there: Eclipse Java EE IDE Liferay portal 6.x.x with Tomcat 6.0.x Configuring Tomcat 6.0 in Eclipse If you have not already done so, configure Tomcat 6.0 in Eclipse as follows: Start Eclipse. Click on Window | Preferences. Expand Server. Click on Runtime Environment. Click on Add .... Select Apache Tomcat v6.0. Click on Next. Click on Browse and open the tomcat-6.0.x directory. Click on Finish. Installing Vaadin Eclipse plugin You can automatically create a Vaadin portlet prototype for Liferay portal with the Vaadin Eclipse plugin. Here is how you can install it: Assuming that Eclipse is open. Click on Help. Select Install New Software ... Click on Add .... Input Name: Vaadin, Location: http://vaadin.com/eclipse. Click on OK. Click on Finish. The Vaadin Eclipse plugin will be installed. It will take several minutes.
Read more
  • 0
  • 0
  • 2142

article-image-animating-graphic-objects-using-python
Packt
01 Dec 2010
9 min read
Save for later

Animating Graphic Objects using Python

Packt
01 Dec 2010
9 min read
Python 2.6 Graphics Cookbook Over 100 great recipes for creating and animating graphics using Python Create captivating graphics with ease and bring them to life using Python Apply effects to your graphics using powerful Python methods Develop vector as well as raster graphics and combine them to create wonders in the animation world Create interactive GUIs to make your creation of graphics simpler Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to accomplish the task of creation and animation of graphics as efficiently as possible        Precise collisions using floating point numbers Here the simulation flaws caused by the coarseness of integer arithmetic are eliminated by using floating point numbers for all ball position calculations. How to do it... All position, velocity, and gravity variables are made floating point by writing them with explicit decimal points. The result is shown in the following screenshot, showing the bouncing balls with trajectory tracing. from Tkinter import * root = Tk() root.title("Collisions with Floating point") cw = 350 # canvas width ch = 200 # canvas height GRAVITY = 1.5 chart_1 = Canvas(root, width=cw, height=ch, background="black") chart_1.grid(row=0, column=0) cycle_period = 80 # Time between new positions of the ball # (milliseconds). time_scaling = 0.2 # This governs the size of the differential steps # when calculating changes in position. # The parameters determining the dimensions of the ball and it's # position. ball_1 = {'posn_x':25.0, # x position of box containing the # ball (bottom). 'posn_y':180.0, # x position of box containing the # ball (left edge). 'velocity_x':30.0, # amount of x-movement each cycle of # the 'for' loop. 'velocity_y':100.0, # amount of y-movement each cycle of # the 'for' loop. 'ball_width':20.0, # size of ball - width (x-dimension). 'ball_height':20.0, # size of ball - height (y-dimension). 'color':"dark orange", # color of the ball 'coef_restitution':0.90} # proportion of elastic energy # recovered each bounce ball_2 = {'posn_x':cw - 25.0, 'posn_y':300.0, 'velocity_x':-50.0, 'velocity_y':150.0, 'ball_width':30.0, 'ball_height':30.0, 'color':"yellow3", 'coef_restitution':0.90} def detectWallCollision(ball): # Collision detection with the walls of the container if ball['posn_x'] > cw - ball['ball_width']: # Collision # with right-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] # reverse direction. ball['posn_x'] = cw - ball['ball_width'] if ball['posn_x'] < 1: # Collision with left-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = 2 # anti-stick to the wall if ball['posn_y'] < ball['ball_height'] : # Collision # with ceiling. ball['velocity_y'] = -ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ball['ball_height'] if ball['posn_y'] > ch - ball['ball_height']: # Floor # collision. ball['velocity_y'] = - ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ch - ball['ball_height'] def diffEquation(ball): # An approximate set of differential equations of motion # for the balls ball['posn_x'] += ball['velocity_x'] * time_scaling ball['velocity_y'] = ball['velocity_y'] + GRAVITY # a crude # equation incorporating gravity. ball['posn_y'] += ball['velocity_y'] * time_scaling chart_1.create_oval( ball['posn_x'], ball['posn_y'], ball['posn_x'] + ball['ball_width'], ball ['posn_y'] + ball['ball_height'], fill= ball['color']) detectWallCollision(ball) # Has the ball collided with # any container wall? for i in range(1,2000): # end the program after 1000 position shifts. diffEquation(ball_1) diffEquation(ball_2) chart_1.update() # This refreshes the drawing on the canvas. chart_1.after(cycle_period) # This makes execution pause for 200 # milliseconds. chart_1.delete(ALL) # This erases everything on the root.mainloop() How it works... Use of precision arithmetic has allowed us to notice simulation behavior that was previously hidden by the sins of integer-only calculations. This is the UNIQUE VALUE OF GRAPHIC SIMULATION AS A DEBUGGING TOOL. If you can represent your ideas in a visual way rather than as lists of numbers you will easily pick up subtle quirks in your code. The human brain is designed to function best in graphical images. It is a direct consequence of being a hunter. A graphic debugging tool... There is another very handy trick in the software debugger's arsenal and that is the visual trace. A trace is some kind of visual trail that shows the history of dynamic behavior. All of this is revealed in the next example. Trajectory tracing and ball-to-ball collisions Now we introduce one of the more difficult behaviors in our simulation of ever increasing complexity – the mid-air collision. The hardest thing when you are debugging a program is to try to hold in your short term memory some recently observed behavior and compare it meaningfully with present behavior. This kind of memory is an imperfect recorder. The way to overcome this is to create a graphic form of memory – some sort of picture that shows accurately what has been happening in the past. In the same way that military cannon aimers use glowing tracer projectiles to adjust their aim, a graphic programmer can use trajectory traces to examine the history of execution. How to do it... In our new code there is a new function called detect_ball_collision (ball_1, ball_2) whose job is to anticipate imminent collisions between the two balls no matter where they are. The collisions will come from any direction and therefore we need to be able to test all possible collision scenarios and examine the behavior of each one and see if it does not work as planned. This can be too difficult unless we create tools to test the outcome. In this recipe, the tool for testing outcomes is a graphic trajectory trace. It is a line that trails behind the path of the ball and shows exactly where it went right since the beginning of the simulation. The result is shown in the following screenshot, showing the bouncing with ball-to-ball collision rebounds. # kinetic_gravity_balls_1.py # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> from Tkinter import * import math root = Tk() root.title("Balls bounce off each other") cw = 300 # canvas width ch = 200 # canvas height GRAVITY = 1.5 chart_1 = Canvas(root, width=cw, height=ch, background="white") chart_1.grid(row=0, column=0) cycle_period = 80 # Time between new positions of the ball # (milliseconds). time_scaling = 0.2 # The size of the differential steps # The parameters determining the dimensions of the ball and its # position. ball_1 = {'posn_x':25.0, 'posn_y':25.0, 'velocity_x':65.0, 'velocity_y':50.0, 'ball_width':20.0, 'ball_height':20.0, 'color':"SlateBlue1", 'coef_restitution':0.90} ball_2 = {'posn_x':180.0, 'posn_y':ch- 25.0, 'velocity_x':-50.0, 'velocity_y':-70.0, 'ball_width':30.0, 'ball_height':30.0, 'color':"maroon1", 'coef_restitution':0.90} def detect_wall_collision(ball): # detect ball-to-wall collision if ball['posn_x'] > cw - ball['ball_width']: # Right-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = cw - ball['ball_width'] if ball['posn_x'] < 1: # Left-hand wall. ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ restitution'] ball['posn_x'] = 2 if ball['posn_y'] < ball['ball_height'] : # Ceiling. ball['velocity_y'] = -ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ball['ball_height'] if ball['posn_y'] > ch - ball['ball_height'] : # Floor ball['velocity_y'] = - ball['velocity_y'] * ball['coef_ restitution'] ball['posn_y'] = ch - ball['ball_height'] def detect_ball_collision(ball_1, ball_2): #detect ball-to-ball collision # firstly: is there a close approach in the horizontal direction if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25: # secondly: is there also a close approach in the vertical # direction. if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25: ball_1['velocity_x'] = -ball_1['velocity_x'] # reverse # direction. ball_1['velocity_y'] = -ball_1['velocity_y'] ball_2['velocity_x'] = -ball_2['velocity_x'] ball_2['velocity_y'] = -ball_2['velocity_y'] # to avoid internal rebounding inside balls ball_1['posn_x'] += ball_1['velocity_x'] * time_scaling ball_1['posn_y'] += ball_1['velocity_y'] * time_scaling ball_2['posn_x'] += ball_2['velocity_x'] * time_scaling ball_2['posn_y'] += ball_2['velocity_y'] * time_scaling def diff_equation(ball): x_old = ball['posn_x'] y_old = ball['posn_y'] ball['posn_x'] += ball['velocity_x'] * time_scaling ball['velocity_y'] = ball['velocity_y'] + GRAVITY ball['posn_y'] += ball['velocity_y'] * time_scaling chart_1.create_oval( ball['posn_x'], ball['posn_y'], ball['posn_x'] + ball['ball_width'], ball['posn_y'] + ball['ball_height'], fill= ball['color'], tags="ball_tag") chart_1.create_line( x_old, y_old, ball['posn_x'], ball ['posn_y'], fill= ball['color']) detect_wall_collision(ball) # Has the ball # collided with any container wall? for i in range(1,5000): diff_equation(ball_1) diff_equation(ball_2) detect_ball_collision(ball_1, ball_2) chart_1.update() chart_1.after(cycle_period) chart_1.delete("ball_tag") # Erase the balls but # leave the trajectories root.mainloop() How it works... Mid-air ball against ball collisions are done in two steps. In the first step, we test whether the two balls are close to each other inside a vertical strip defined by if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25. In plain English, this asks "Is the horizontal distance between the balls less than 25 pixels?" If the answer is yes, then the region of examination is narrowed down to a small vertical distance less than 25 pixels by the statement if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25. So every time the loop is executed, we sweep the entire canvas to see if the two balls are both inside an area where their bottom-left corners are closer than 25 pixels to each other. If they are that close then we simply cause a rebound off each other by reversing their direction of travel in both the horizontal and vertical directions. There's more... Simply reversing the direction is not the mathematically correct way to reverse the direction of colliding balls. Certainly billiard balls do not behave that way. The law of physics that governs colliding spheres demands that momentum be conserved. Why do we sometimes get tkinter.TckErrors? If we click the close window button (the X in the top right) while Python is paused, when Python revives and then calls on Tcl (Tkinter) to draw something on the canvas we will get an error message. What probably happens is that the application has already shut down, but Tcl has unfinished business. If we allow the program to run to completion before trying to shut the window then termination is orderly.
Read more
  • 0
  • 0
  • 8314

article-image-creating-custom-themes-and-zen-drupal-6
Packt
01 Dec 2010
9 min read
Save for later

Creating Custom Themes and Zen in Drupal 6

Packt
01 Dec 2010
9 min read
Drupal 6 Theming Cookbook Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes Take control of the look and feel of your Drupal website Tips and tricks to get the most out of Drupal's theming system Learn how to customize existing themes and create unique themes from scratch Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible         Read more about this book       (For more resources on Drupal, see here.) Introduction Sub-themes of core and contributed themes are convenient and efficient in modifying and reusing elements of their base themes, circumstances often require a completely unique approach specific to our site. Custom themes are the solution for websites which demand a fresh look, using complex layouts, or need so much customization that it would be prudent to start with a clean slate. Custom themes are the equivalent of handcrafted pieces of art as the themer controls every piece of the puzzle from a design or implementational point of view. This includes setting up the theme using .info files, choosing the layout, implementing it in a page template, adding regions, styling nodes using node templates, blocks using block templates, and so on. But over time, developers have identified a list of common tasks, characteristic layouts, and file and folder hierarchies which are logical, efficient, and promote reuse. This has evolved into what have been dubbed starter themes, themes upon which custom themes are built, usually as sub-themes. The most popular starter theme for Drupal is Zen. As advertised on its project page, the Zen theme is a flexible standards-compliant and semantically correct XHTML theme that can be highly modified through CSS and an enhanced version of Drupal's template system. It is designed in modular fashion making it straightforward to change layouts, override templates and theme functions, and to add or remove features. Additionally, the Zen theme comes with extensive documentation within each file which make things all the more convenient. With respect to CSS, Zen maintains a number of well documented CSS files segregated by functionality or location. For example, layout rules are contained within a dedicated layout.css (or similar) file and page backgrounds are styled within page-backgrounds.css and so on. This makes it convenient when it comes to managing and tracking code changes. A Zen-based theme contains the following file and folder structure: File/folder name Purpose template.php A file where theme overrides and other theme and engine-related code is placed. theme-settings.php A file where settings particular to a theme can be placed. These settings are usually exposed on the theme's configuration page. css/ A folder to store stylesheets. images/ A folder to store images used in the theme. images-source/ The folder where the source files for the optimized images in the images folder are available. js/ A folder to store JavaScript files. templates/ A folder where tpl.php template files are to be placed. There are a number of other starter themes available on drupal.org. Some of the more popular ones include Fusion (http://drupal.org/project/fusion), Blueprint (http://drupal.org/project/blueprint), Ninesixty (http://drupal.org/ project/ninesixty), and Adaptivetheme (http://drupal.org/project/ adaptivetheme). We will be looking only at the Zen starter theme in this article. Clearing the theme registry Before we begin, we need to familiarize ourselves with a seemingly trivial yet crucial task that needs to be performed on a routine basis during theme development—clearing the theme registry. The theme registry is essentially a table that Drupal uses to list and track the files and features of a theme, as well as the theme functions which are being exposed by modules and the theme itself. While it is recommended practice to turn on Drupal's cache feature only for production sites, the theme registry is built and cached regardless of other caching options. As a result, any changes that affect the structure of the theme will necessitate the clearing of the theme registry. Getting ready Rebuilding the registry is an intensive operation which is required only when changes have been made to the theme's files. How to do it... There are a number of ways of clearing the registry. In a stock Drupal installation, visiting admin/settings/performance (Home | Administer | Site configuration | Performance) and clicking on the Clear cached data button will clear all cached data, including the registry, and force a rebuild. A shortcut It is sometimes handy to know that the cache and registry can also be cleared by visiting admin/build/themes (Home | Administer | Site building | Themes) and just clicking the Save configuration button. However, during development or debugging, we will want to clear the registry with great regularity. Rather than having to do so manually, it is often handy to be able to instruct Drupal to perform this operation automatically on every page load. Some themes, including the Zen-based theme which we will be familiarizing ourselves with later in this article, offer an option on their configuration pages to rebuild the registry on every page load. While this is certainly convenient, the recommended method of managing this and other development-oriented operations is through the use of the Devel module. As the name suggests, the Devel module is one which is tailor-made for use during development. It can be downloaded from http://drupal.org/project/devel. Once the module has been downloaded and installed, navigate to admin/settings/devel (Home | Administer | Site configuration | Devel settings) where the option to Rebuild the theme registry on every page load can be enabled. How it works... Drupal maintains a cache of all .info files, template files, and theme functions in the theme registry. This registry is a part of the cache table in the Drupal database. When we click on the Clear cache data button in the performance settings page, all Drupal is doing is clearing this entry in the cache table, which automatically forces a rebuild of the registry. The Devel module does the same thing when the Rebuild the theme registry on every page load setting is enabled, except that it does this automatically on every page view. It is important to keep in mind that rebuilding the registry, or for that matter, clearing any of the caches is an expensive operation which adversely affects the performance of the site. Therefore, it is recommended that this setting only be enabled during development and not in production sites. Clearing the registry is an important factor to keep in mind during development and especially during debugging. There's more... The Devel module also provides a block with handy shortcuts to oft-used areas of the site. Clearing the cache using the Development block The Devel module provides a Development block which can be enabled via the block management page at admin/build/blocks (Home | Administer | Site building | Blocks). Once enabled, the block lists, as in the following screenshot, a number of links to perform operations such as emptying the Drupal cache, rebuilding the menu cache, and even reinstalling modules. Emptying the cache will also force a rebuild of the theme registry. Creating a theme from scratch While we have previously looked at installing contributed themes and extending base themes using sub-themes, this recipe will outline the steps required to create a custom theme. Getting ready It is assumed that the sites/all/themes folder has already been created. This is the recommended location to place custom and contributed themes. How to do it... While creating a brand new custom theme, files such as page.tpl.php will need to be explicitly defined and there is no base theme. Create a folder with the new theme's name inside the sites/all/themes folder. In this example, we are going to call our theme mytheme. Create a file named mytheme.info and open it in an editor. Add details about the theme as follows: name = My themedescription = My custom themecore = 6.xengine = phptemplate Save the file. Visit the theme administration page at admin/build/themes (Home | Administer | Site building | Themes) and we should be able to see a new entry for our theme. Enable the theme by checking its Enabled checkbox. Also, set it as the default theme by selecting its Default radio button. Click the Save configuration button at the bottom of the page to save the changes. How it works... Just as with other themes, Drupal scans the sites/all/themes folder looking for .info files which indicate the presence of a theme. Seeing mytheme.info, it parses the file and loads the details of the theme, and saves them in the database. When the new theme is enabled, what we will see is largely unstyled content not unlike the following screenshot. The problem here is that we have not specified any CSS stylesheets to ay out the page. The only styles being loaded are those that are module-specific as opposed o theme-specific. The styles being used in the preceding screenshot are as follows: <link type="text/css" rel="stylesheet" media="all"href="/mysite/modules/node/node.css?u" /><link type="text/css" rel="stylesheet" media="all"href="/mysite/modules/system/defaults.css?u" /><link type="text/css" rel="stylesheet" media="all"href="/mysite/modules/system/system.css?u" /><link type="text/css" rel="stylesheet" media="all"href="/mysite/modules/system/system-menus.css?u" /><link type="text/css" rel="stylesheet" media="all"href="/mysite/modules/user/user.css?u" /> As we can see, the only stylesheets in evidence are those belonging to core modules and none from our theme. In addition, Drupal has noticed that we do not have any template files in our theme, most notably, page.tpl.php. Therefore, it has loaded an inbuilt page template file from modules/system/page.tpl.php and used it instead. Similarly, it is using the node.tpl.php file from modules/node/ as the basis for each node's layout. In other words, we have a lot of work ahead of us in getting things up and running especially if our eventual requirements are going to be complicated. As we will see in the next recipe, this is one of the reasons why most themers prefer to use a starter theme and hit the ground running.
Read more
  • 0
  • 0
  • 1969
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-data-modeling-and-scalability-google-app
Packt
30 Nov 2010
12 min read
Save for later

Data Modeling and Scalability in Google App

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

article-image-plone-books-packt
Packt
30 Nov 2010
1 min read
Save for later

Plone Books from Packt

Packt
30 Nov 2010
1 min read
Plone 3 Theming Published: July 2009 Plone 3.3 Site Administration Published: July 2010 Plone 3 Multimedia Published: May 2010 Plone 3 Products Development Cookbook               Published: May 2010 Plone 3 Intranets Published: August 2010   Bundle Price: $171.95/£90.95/ €133.95 Packt special offer: $40.00 / £25 / €30 (save $131.95/ £65.95/ €103.95)You can buy all 5 of these Plone ebooks with just one click.           You may also be interested in our other Plone titles: Practical Plone 3: A Beginner's Guide to Building Powerful Websites A beginner’s practical guide to building Plone websites through graphical interface Click for more information Professional Plone Development Building robust, content-centric web applications with Plone 3, an open source Content Management System. Click for more information Building Websites with Plone An in-depth and comprehensive guide to the Plone content management system. Click for more information Plone 3 for Education Break the webmaster bottleneck by empowering instructors and staff Click for more information Professional Plone 4 Development Build robust, content-centric web applications with Plone 4. Click for more information  
Read more
  • 0
  • 0
  • 1348

article-image-tips-tricks-ext-js-3x
Packt
30 Nov 2010
3 min read
Save for later

Tips & Tricks for Ext JS 3.x

Packt
30 Nov 2010
3 min read
  Learning Ext JS 3.2 Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS Learn to build consistent, attractive web interfaces with the framework components Integrate your existing data and web services with Ext JS data support Enhance your JavaScript skills by using Ext's DOM and AJAX helpers Extend Ext JS through custom components An interactive tutorial packed with loads of example code and illustrative screenshots           Read more about this book       (For more resources on Ext JS, see here.) Objective: Button focus and tab orders are built in. Tip: Button focus and tab orders are built into Ext JS Components. For the MessageBox Component, the OK or Yes button will be the default action, so pressing Enter on our keyboard when a MessageBox appears will trigger that button, and pressing Tab will move us through the buttons and other items in the MessageBox. Windows have the ESC key mapped to the Close tool. When using button bars in other Componenets, tabbing through the buttons is enabled by default and in Toolbars like the PagingToolbar tabbing is also built in. Objective: Duplicate Component ID's must be avoided. Tip: Having duplicate IDs in our document can lead to strange behavior, such as a widgets always showing up in the upper-left corner of the browser, and must therefore be avoided. Objective: Other uses of Button config on a MessageBox. Tip: The buttons config for a MessageBox can also specify the text to display on the button. Instead of passing a Boolean value, just pass it the desired text to display, for example, {yes: 'Maybe'}. Objective: Ext does not require any pre-existing markup. Tip: Ext does not require any pre-existing markup for it to function, this is because it generates everything it needs on its own. This let's us start with a very simple HTML document containing an empty body. Objective: Avoid using the built in JavaScript alert messages. Tip: Standard JavaScript alert messages pause code execution, which can cause unexpected results. You should not be using the built in JavaScript alert messages, and instead use Ext's MessageBox widget or console messages (when available), which does not pause that code execution. Objective: Creating form Field validation types (vType). Tip: A search of the Ext JS forum is likely to come back with a vType that someone else has created with exactly what you need, or close enough to use as a starting point for your own requirements, so search the Ext JS Forums before trying to write your own. Objective: Simple and quick static options for a ComboBox. Tip:; A quick way to specify a few static options for a ComboBox is to pass an array to the store config, which will auto-create the store for you. So if we wanted a ComboBox that had 'Yes' and 'No' as options, we would provide ['Yes','No'] as the store config value.
Read more
  • 0
  • 0
  • 3093

article-image-using-datastore-transactions-google-app
Packt
30 Nov 2010
12 min read
Save for later

Using Datastore Transactions in Google App

Packt
30 Nov 2010
12 min read
Google App Engine Java and GWT Application Development Build powerful, scalable, and interactive web applications in the cloud Comprehensive coverage of building scalable, modular, and maintainable applications with GWT and GAE using Java Leverage the Google App Engine services and enhance your app functionality and performance Integrate your application with Google Accounts, Facebook, and Twitter Safely deploy, monitor, and maintain your GAE applications A practical guide with a step-by-step approach that helps you build an application in stages        As the App Engine documentation states, A transaction is a Datastore operation or a set of Datastore operations that either succeed completely, or fail completely. If the transaction succeeds, then all of its intended effects are applied to the Datastore. If the transaction fails, then none of the effects are applied. The use of transactions can be the key to the stability of a multiprocess application (such as a web app) whose different processes share the same persistent Datastore. Without transactional control, the processes can overwrite each other's data updates midstream, essentially stomping all over each other's toes. Many database implementations support some form of transactions, and you may be familiar with RDBMS transactions. App Engine Datastore transactions have a different set of requirements and usage model than you may be used to. First, it is important to understand that a "regular" Datastore write on a given entity is atomic—in the sense that if you are updating multiple fields in that entity, they will either all be updated, or the write will fail and none of the fields will be updated. Thus, a single update can essentially be considered a (small, implicit) transaction— one that you as the developer do not explicitly declare. If one single update is initiated while another update on that entity is in progress, this can generate a "concurrency failure" exception. In the more recent versions of App Engine, such failures on single writes are now retried transparently by App Engine, so that you rarely need to deal with them in application-level code. However, often your application needs stronger control over the atomicity and isolation of its operations, as multiple processes may be trying to read and write to the same objects at the same time. Transactions provide this control. For example, suppose we are keeping a count of some value in a "counter" field of an object, which various methods can increment. It is important to ensure that if one Servlet reads the "counter" field and then updates it based on its current value, no other request has updated the same field between the time that its value is read and when it is updated. Transactions let you ensure that this is the case: if a transaction succeeds, it is as if it were done in isolation, with no other concurrent processes 'dirtying' its data. Another common scenario: you may be making multiple changes to the Datastore, and you may want to ensure that the changes either all go through atomically, or none do. For example, when adding a new Friend to a UserAccount, we want to make sure that if the Friend is created, any related UserAcount object changes are also performed. While a Datastore transaction is ongoing, no other transactions or operations can see the work being done in that transaction; it becomes visible only if the transaction succeeds. Additionally, queries inside a transaction see a consistent "snapshot" of the Datastore as it was when the transaction was initiated. This consistent snapshot is preserved even after the in-transaction writes are performed. Unlike some other transaction models, with App Engine, a within-transaction read after a write will still show the Datastore as it was at the beginning of the transaction. Datastore transactions can operate only on entities that are in the same entity group. We discuss entity groups later in this article. Transaction commits and rollbacks To specify a transaction, we need the concepts of a transaction commit and rollback. A transaction must make an explicit "commit" call when all of its actions have been completed. On successful transaction commit, all of the create, update, and delete operations performed during the transaction are effected atomically. If a transaction is rolled back, none of its Datastore modifications will be performed. If you do not commit a transaction, it will be rolled back automatically when its Servlet exits. However, it is good practice to wrap a transaction in a try/finally block, and explicitly perform a rollback if the commit was not performed for some reason. This could occur, for example, if an exception was thrown. If a transaction commit fails, as would be the case if the objects under its control had been modified by some other process since the transaction was started the transaction is automatically rolled back. Example—a JDO transaction With JDO, a transaction is initiated and terminated as follows: import javax.jdo.PersistenceManager; import javax.jdo.Transaction; ... PersistenceManager pm = PMF.get().getPersistenceManager(); Transaction tx; ... try { tx = pm.currentTransaction(); tx.begin(); // Do the transaction work tx.commit(); } finally { if (tx.isActive()) { tx.rollback(); } } A transaction is obtained by calling the currentTransaction() method of the PersistenceManager. Then, initiate the transaction by calling its begin() method . To commit the transaction, call its commit() method . The finally clause in the example above checks to see if the transaction is still active, and does a rollback if that is the case. While the preceding code is correct as far as it goes, it does not check to see if the commit was successful, and retry if it was not. We will add that next. App Engine transactions use optimistic concurrency In contrast to some other transactional models, the initiation of an App Engine transaction is never blocked. However, when the transaction attempts to commit, if there has been a modification in the meantime (by some other process) of any objects in the same entity group as the objects involved in the transaction, the transaction commit will fail. That is, the commit not only fails if the objects in the transaction have been modified by some other process, but also if any objects in its entity group have been modified. For example, if one request were to modify a FeedInfo object while its FeedIndex child was involved in a transaction as part of another request, that transaction would not successfully commit, as those two objects share an entity group. App Engine uses an optimistic concurrency model. This means that there is no check when the transaction initiates, as to whether the transaction's resources are currently involved in some other transaction, and no blocking on transaction start. The commit simply fails if it turns out that these resources have been modified elsewhere after initiating the transaction. Optimistic concurrency tends to work well in scenarios where quick response is valuable (as is the case with web apps) but contention is rare, and thus, transaction failures are relatively rare. Transaction retries With optimistic concurrency, a commit can fail simply due to concurrent activity on the shared resource. In that case, if the transaction is retried, it is likely to succeed. So, one thing missing from the previous example is that it does not take any action if the transaction commit did not succeed. Typically, if a commit fails, it is worth simply retrying the transaction. If there is some contention for the objects in the transaction, it will probably be resolved when it is retried. PersistenceManager pm = PMF.get().getPersistenceManager(); // ... try { for (int i =0; i < NUM_RETRIES; i++) { pm.currentTransaction().begin(); // ...do the transaction work ... try { pm.currentTransaction().commit(); break; } catch (JDOCanRetryException e1) { if (i == (NUM_RETRIES - 1)) { throw e1; } } } } finally { if (pm.currentTransaction().isActive()) { pm.currentTransaction().rollback(); } pm.close(); } As shown in the example above, you can wrap a transaction in a retry loop, where NUM_RETRIES is set to the number of times you want to re-attempt the transaction. If a commit fails, a JDOCanRetryException will be thrown. If the commit succeeds, the for loop will be terminated. If a transaction commit fails, this likely means that the Datastore has changed in the interim. So, next time through the retry loop, be sure to start over in gathering any information required to perform the transaction. Transactions and entity groups An entity's entity group is determined by its key. When an entity is created, its key can be defined as a child of another entity's key, which becomes its parent. The child is then in the same entity group as the parent. That child's key could in turn be used to define another entity's key, which becomes its child, and so on. An entity's key can be viewed as a path of ancestor relationships, traced back to a root entity with no parent. Every entity with the same root is in the same entity group. If an entity has no parent, it is its own root. Because entity group membership is determined by an entity's key, and the key cannot be changed after the object is created, this means that entity group membership cannot be changed either. As introduced earlier, a transaction can only operate on entities from the same entity group. If you try to access entities from different groups within the same transaction, an error will occur and the transaction will fail. In App Engine, JDO owned relationships place the parent and child entities in the same entity group. That is why, when constructing an owned relationship, you cannot explicitly persist the children ahead of time, but must let the JDO implementation create them for you when the parent is made persistent. JDO will define the keys of the children in an owned relationship such that they are the child keys of the parent object key. This means that the parent and children in a JDO owned relationship can always be safely used in the same transaction. (The same holds with JPA owned relationships). So in the Connectr app, for example, you could create a transaction that encompasses work on a UserAccount object and its list of Friends—they will all be in the same entity group. But, you could not include a Friend from a different UserAccount in that same transaction—it will not be in the same entity group. This App Engine constraint on transactions—that they can only encompass members of the same entity group—is enforced in order to allow transactions to be handled in a scalable way across App Engine's distributed Datastores. Entity group members are always stored together, not distributed. Creating entities in the same entity group As discussed earlier, one way to place entities in the same entity group is to create a JDO owned relationship between them; JDO will manage the child key creation so that the parent and children are in the same entity group. To explicitly create an entity with an entity group parent, you can use the App Engine KeyFactory.Builder class . This is the approach used in the FeedIndex constructor example shown previously. Recall that you cannot change an object's key after it is created, so you have to make this decision when you are creating the object. Your "child" entity must use a primary key of type Key or String-encoded Key; these key types allow parent path information to be encoded in them. As you may recall, it is required to use one of these two types of keys for JDO owned relationship children, for the same reason. If the data class of the object for which you want to create an entity group parent uses an app-assigned string ID, you can build its key as follows: // you can construct a Builder as follows: KeyFactory.Builder keyBuilder = new KeyFactory.Builder(Class1.class.getSimpleName(), parentIDString); // alternatively, pass the parent Key object: Key pkey = KeyFactory.Builder keyBuilder = new KeyFactory.Builder(pkey); // Then construct the child key keyBuilder.addChild(Class2.class.getSimpleName(), childIDString); Key ckey = keyBuilder.getKey(); Create a new KeyFactory.Builder using the key of the desired parent. You may specify the parent key as either a Key object or via its entity name (the simple name of its class) and its app-assigned (String) or system-assigned (numeric) ID, as appropriate. Then, call the addChild method of the Builder with its arguments—the entity name and the app-assigned ID string that you want to use. Then, call the getKey() method of Builder. The generated child key encodes parent path information. Assign the result to the child entity's key field. When the entity is persisted, its entity group parent will be that entity whose key was used as the parent. This is the approach we showed previously in the constructor of FeedIndex, creating its key using its parent FeedInfo key . See http://code.google.com/appengine/docs/java/javadoc/ com/google/appengine/api/datastore/KeyFactory.Builder. html for more information on key construction. If the data class of the object for which you want to create an entity group parent uses a system-assigned ID, then (because you don't know this ID ahead of time), you must go about creating the key in a different way. Create an additional field in your data class for the parent key, of the appropriate type for the parent key, as shown in the following code: @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; ... @Persistent @Extension(vendorName="datanucleus", key="gae.parent-pk", value="true") private String parentKey; Assign the parent key to this field prior to creating the object. When the object is persisted, the data object's primary key field will be populated using the parent key as the entity group parent. You can use this technique with any child key type.
Read more
  • 0
  • 0
  • 2327
article-image-wordpress-books-packt
Packt
30 Nov 2010
2 min read
Save for later

WordPress Books from Packt

Packt
30 Nov 2010
2 min read
WordPress MU 2.8: Beginner's GuidePublished: October 2009   WordPress 2.7 Cookbook Published: July 2009 WordPress 2.8 Themes CookbookPublished: July 2010   WordPress 2.8 Theme Design Published: November 2009 WordPress 2.9 E-CommercePublished: March 2010      Bundle Price: $167.95/ £88.95/ €130.95Packt special offer: $40/ £25 /€30(save $127.95/ £63.95/  €100.95)You can buy 5 of these WordPress ebooks with just one click.           You may also be interested in our other WordPress titles: WordPress Complete A comprehensive, step-by-step guide on how to set up, customize, and market your blog using WordPress. Click for more information WordPress Theme Design A complete guide to creating professional WordPress themes. Click for more information WordPress Top Plugins Find and install the best plugins for generating and sharing content, building communities and generating revenue. Click for more information WordPress Plugin Development: Beginner's Guide Build powerful, interactive plug-ins for your blog and to share online. Click for more information WordPress 3 Site Blueprints Ready-made plans for 9 different professional WordPress sites. Click for more information WordPress 2.7 Complete Create your own complete blog or web site from scratch with WordPress. Click for more information WordPress and Flash 10x Cookbook Over 50 simple but incredibly effective recipes to take control of dynamic Flash content in Wordpress. Click for more information WordPress 3.0 jQuery Enhance your WordPress website with the captivating effects of jQuery. Click for more information WordPress for Business Bloggers Promote and grow your WordPress blog with advanced plug-ins, analytics, advertising, and SEO. Click for more information  
Read more
  • 0
  • 0
  • 1242

article-image-soa-books-packt
Packt
30 Nov 2010
2 min read
Save for later

SOA Books from Packt

Packt
30 Nov 2010
2 min read
WS-BPEL 2.0 for SOA Composite Applications with Oracle SOA Suite 11g Published: September  2010   WS-BPEL 2.0 for SOA Composite Applications with IBM WebSphere 7Published: October 2010 SOA Patterns with BizTalk Server 2009Published: April 2009   SOA Governance  Published: October 2008 Building SOA-Based Composite Applications Using NetBeans IDE 6 Published: February 2008 Bundle Price: $231.95/ £124.95/ €180.95 Packt special offer: $40/ £25 / €30 (save $191.95/ £99.95/ €150.95) You can buy 5 of these SOA ebooks with just one click.           You may also be interested in our other SOA titles: Oracle SOA Suite 11g R1 Developer's Guide Develop Service-Oriented Architecture Solutions with the Oracle SOA Suite. Click for more information Getting Started With Oracle SOA Suite 11g R1 – A Hands-On Tutorial Fast track your SOA adoption – Build a service-oriented composite application in just hours! Click for more information SOA and WS-BPEL Composing Service-Oriented Architecture Solutions with PHP and Open-Source ActiveBPEL. Click for more information SOA Cookbook Master SOA process architecture, modeling, and simulation in BPEL, TIBCO's BusinessWorks, and BEA's Weblogic Integration. Click for more information Business Process Driven SOA using BPMN and BPEL From Business Process Modeling to Orchestration and Service Oriented Architecture. Click for more information BPEL Cookbook: Best Practices for SOA-based integration and composite applications development Ten practical real-world case studies combining business process management and web services orchestration Click for more information Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications Over 85 easy recipes for managing communication between applications Click for more information SOA Approach to Integration XML, Web services, ESB, and BPEL in real-world SOA projects Click for more information  
Read more
  • 0
  • 0
  • 1124

article-image-ordered-and-generic-tests-visual-studio-2010
Packt
30 Nov 2010
5 min read
Save for later

Ordered and Generic Tests in Visual Studio 2010

Packt
30 Nov 2010
5 min read
  Software Testing using Visual Studio 2010 Ordered tests The following screenshot shows the list of all the tests. You can see that the tests are independent and there is no link between the tests. We have different types of tests like Unit Test, Web Performance Test, and Load Test under the test project. Let's try to create an ordered test and place some of the dependent tests in an order so that the test execution happens in an order without breaking. Creating an ordered test There are different ways of creating ordered tests similar to the other tests: Select the test project from Solution Explorer, right-click and select Add Ordered Test, and then select ordered test from the list of different types of tests. Save the ordered test by choosing the File | Save option. Select the menu option Test then select New Test..., which opens a dialog with different test types. Select the test type and choose the test project from the Add to Test Project List drop-down and click on OK. Now the ordered test is created under the test project and the ordered test window is shown to select the existing tests from the test project and set the order. The preceding window shows different options for ordering the tests. The first line is the status bar, which shows the number of tests selected for the ordered test. The Select test list to view dropdown has the option to choose the display of tests in the available Test Lists. This dropdown has the default All Loaded Tests, which displays all available tests under the project. The other options in the dropdown are Lists of Tests and Tests Not in a List. The List of Tests will display the test lists created using the Test List Editor. It is easier to include the number of tests grouped together and order them. The next option, Tests Not in a List, displays the available tests, which are not part of any Test Lists. The Available tests list displays all the tests from the test project based on the option chosen in the dropdown. Selected tests contains the tests that are selected from the available tests list to be placed in order. The two right and left arrows are used for selecting and unselecting the tests from the Available tests list to the Selected Tests list. We can also select multiple tests by pressing the Ctrl key and selecting the tests. The up-down arrows on the right of the selected tests list are used for moving up or down the tests and setting the order for the testing in the Selected tests list. The last option, the Continue after failure checkbox at the bottom of the window, is to override the default behavior of the ordered tests, aborting the execution after the failure of any test. If the option Continue after failure is unchecked, and if any test in the order fails, then all remaining tests will get aborted. In case the tests are not dependent, we can check this option and override the default behavior to allow the application to continue running the remaining tests in order. Properties of an ordered test Ordered tests have properties similar to the other test types, in addition to some specific properties. To view the properties, select the ordered test in the Test View or Test List Editor window, right-click and select the Properties option. The Properties dialog box displays the available properties for the ordered test. The preceding screenshot shows that most of the properties are the same as the properties of the other test types. We can associate this test with the TFS work items, iterations, and area. Executing an ordered test An ordered test can be run like any other test. Open the Test View window or the Test List Editor and select the ordered test from the list, then right-click and choose the Run Selection option from Test View or Run Checked Tests from the Test List Editor. Once the option is selected, we can see the tests running one after the other in the same order in which they are placed in the ordered test. After the execution of the ordered tests, the Test Results window will show the status of the ordered test. If any of the tests in the list fails, then the ordered test status will be Failed. The summary of statuses of all the tests in the ordered test is shown in the following screenshot in the toolbar. The sample ordered test application had four tests in the ordered tests, but two of them failed and one had an error. Clicking the Test run failed hyperlink in the status bar shows a detailed view of the test run summary: The Test Results window also provides detailed information about the tests run so far. To get these details, choose the test from the Test Results window and then right-click and choose the option, View Test Results Details, which opens the details window and displays the common results information such as Test Name, Result, Duration of the test run, Start Time, End Time, and so on. The details window also displays the status of each and every test run within the ordered test. In addition it displays the duration for each test run, name, owner, and type of test in the list. Even though the second test in the list fails, the other tests continue to execute as if the Continue after failure option was checked.
Read more
  • 0
  • 0
  • 3462
article-image-moodle-books-packt
Packt
30 Nov 2010
2 min read
Save for later

Moodle Books from Packt

Packt
30 Nov 2010
2 min read
Moodle 1.9 Extension Development Published: April 2010 Moodle 1.9 for Second Language Teaching Published: October 2009 Moodle 1.9 E-Learning Course Development Published: June 2008 Moodle 1.9 Theme Design: Beginner's GuidePublished: April 2010      Moodle 1.9 Multimedia Published: May 2009   Bundle Price: $187.95 /£100.95/ €145.95 Packt special offer: $40/£25 /€30 (save $147.95/ £75.95/  €115.95)You can buy all 5 of these Moodle ebooks with just one click.           You may also be interested in our other Moodle titles:   Moodle 1.9 Theme Design: Beginner's Guide Customize the appearance of your Moodle Theme using its powerful theming engine. Click for more information Moodle 1.9 for Teaching 7-14 Year Olds: Beginner's Guide Effective e-learning for younger students using Moodle as your Classroom Assistant. Click for more information Moodle 1.9 Teaching Techniques Creative ways to build powerful and effective online courses. Click for more information Moodle 2.0 First Look Discover what's new in Moodle 2.0, how the new features work, and how it will impact you. Click for more information Moodle 1.9 E-Learning Course Development A complete guide to successful learning using Moodle. Click for more information Moodle Teaching Techniques Creative Ways to Use Moodle for Constructing Online Learning Solutions Click for more information Moodle 1.9 Top Extensions Cookbook Over 60 simple and incredibly effective recipes for harnessing the power of the best Moodle modules to create effective online learning sites. Click for more information Moodle 1.9 for Teaching Special Education Children (5-10): Beginner's Guide Create courses and therapies for children with special educational needs using Moodle for effective e-learning. Click for more information Moodle 1.9 Multimedia Create and share multimedia learning materials in your Moodle courses. Click for more information Moodle 1.9 Testing and Assessment Develop and evaluate quizzes and tests using Moodle modules. Click for more information Moodle Course Conversion: Beginner's Guide Taking existing classes online quickly with the Moodle LMS. Click for more information Moodle 1.9 Math Integrate interactive math presentations, build feature-rich quizzes, set online quizzes and tests, incorporate Flash games, and monitor student progress using the Moodle e-learning platform. Click for more information Moodle 1.9 for Design and Technology Support and Enhance Food Technology, Product Design, Resistant Materials, Construction, and the Built Environment using Moodle VLE. Click for more information Moodle 1.9: The English Teacher's Cookbook 80 simple but incredibly effective recipes for teaching reading comprehension, writing, and composing using Moodle 1.9. Click for more information  
Read more
  • 0
  • 0
  • 1503

article-image-does-your-company-use-ibm-lotus-notes-or-sametime
Packt
30 Nov 2010
1 min read
Save for later

Does your Company use IBM Lotus Notes or Sametime?

Packt
30 Nov 2010
1 min read
IBM Lotus Notes 8.5 User Guide is a practical hands-on user guide with time saving tips and comprehensive instructions for using Lotus Notes effectively and efficiently.  If you are a business user who wants to get the most out of Lotus Notes, then this book is for you.  This book aims to cover the features, best practices, tips, tricks, and tools that enable you to work smarter—almost effortlessly—in Lotus Notes 8.5. If you’re also interested in learning Lotus Sametime then the IBM Sametime 8 Essentials: A User’s Guide  This book will allow users to master Online Enterprise Communication with Sametime; any Sametime user in an organization will be able to take this book, sit down at their computer, and learn how to use each feature of Sametime from start to finish.  is the ideal guide.
Read more
  • 0
  • 0
  • 1179
Modal Close icon
Modal Close icon