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

How-To Tutorials

7019 Articles
article-image-extending-project-governance-for-service-oriented-architecture-part1
Packt
21 Oct 2009
12 min read
Save for later

Extending Project Governance for Service Oriented Architecture-part1

Packt
21 Oct 2009
12 min read
As a part of informative conversation, we have Adil — IT Manager for Home Insurance Systems, Elena — Chief Architect, Jennifer — Project Manager for Auto Insurance Systems, Mark — Project Manager for Home Insurance Systems and Service Manager for Customer Information Service, Mike — IT Manager for Insurance Products, Raj — Technical Lead and Member of SOA Center of Excellence, Ramesh — Solution Architect for Annuity Systems, Spencer — Member of Enterprise Architecture Team and finally Alexandra — Spencer's wife as the key characters. Every organization's journey to SOA adoption must begin somewhere. Some organizations may take a very top-down approach based upon direction from the Chief Information Officer (CIO) or other senior IT leader, while other organizations may begin with a grass-roots effort from within the IT organization, often times during a single project. Beginning the SOA Journey Spencer walked in through the main doors of Advasco, a leading financial conglomerate, on Monday morning knowing it was going to be a busy day. He was part of the Enterprise Architecture team at Advasco, and immediately headed for his weekly meeting with his boss, Elena, the Chief Architect. "Come on in, Spencer," she said. "As you know, we've been given a big challenge over the next few months." Late last week, the head of the sales and marketing for the insurance division announced that they needed to improve the way they interacted with their customers. Advasco began as a typical financial services company, but had recently expanded into the insurance area through acquisition. They began by acquiring a company that provided homeowner's policies in several Midwest states. Over the next few years, Advasco had acquired several other regional insurance companies. This resulted in an increase in the number of insurance products that it offered, as well as turning Advasco into a nationwide provider. Unfortunately, Advasco was struggling to increase the number of insurance products per customer. Analysis of the situation had determined that while the sales staff of the original organizations had been combined, each of the different insurance products relied on different applications for customer management. As a result, it was far more difficult for the sales agents to know what insurance products any given customer had. After discussing it with Mike, the IT manager supporting insurance products, IT was given the task of providing the sales agents and marketing staff for the insurance division with a single view of the customer. Elena then said to him, "I had a meeting with Mike to discuss their new initiative to provide a single view of the customer to the sales agents and marketing staff. While he has some great developers in his area, he asked me if Enterprise Architecture could provide some architectural guidance to their effort. Given the excellent integration work you did when Advasco acquired our first company in the insurance area, I think you'd do a great job on this effort." "It certainly sounds like an exciting project," said Spencer, "I'd love to help out. Just last week, I met with my own insurance agent and saw first hand the frustration he had in trying to see the different insurance products that I have for my family." "I'm glad to hear that," said Elena, "I'd like you to meet with Mike today and start coming up with an architecture for the effort. I know you've been reading about SOA. Perhaps this effort can serve as a good pilot for some of the techniques." Spencer agreed. He left Elena's office and went to his desk to set up a meeting with Mike. This was going to be an exciting effort. This initiative was highly visible within the organization, since Advasco's customer approval rating had been taking a beating over the past two years. In addition, Elena knew that Spencer had been researching SOA. In his reading, he felt that SOA had great potential to change the way that Advasco built applications. This effort would provide an opportunity to try out some of the technologies associated with it. Later that afternoon, Spencer met with Mike to go through the existing applications. Mike said, "Unfortunately, the situation is a mess. Right now, the application that handles our auto insurance business is completely independent from the application that handles our home insurance business. The same thing is true for the life insurance business. They each have their own databases, requiring our agents to enter all of the customer information in multiple times. It creates a nightmare for our billing department, especially when trying to compute discounts for multiple policy holders. These applications have all been built using different technologies, including COBOL, VB.NET, and Java." Spencer said, "Well, let's take a managed approach to this effort. Which are the two insurance lines where we most frequently see repeat customers?" Mike replied, "The most common case is for a customer to hold both an auto insurance policy and a homeowner's policy. It's an easy way to get a multiple policy discount." "Well, why don't we start with those two systems and see what we can do. I've been reading about SOA and I think it could provide the right approach for this effort." "I'll trust you on this one Spencer. Elena spoke very highly of you in our meeting last week. As long as you don't think adopting new approaches will impact the timelines, I'm okay with it. The insurance sales and marketing group is under a ton of pressure to get our customer approval rating back up where it should be as quickly as possible." The next day, Spencer met with the managers responsible for the auto insurance systems and the home insurance systems. Spencer kicked off the meeting, "We're here to discuss how we can make things better for our sales staff. Right now, they have to deal with two separate applications. As a result, sometimes they don't know when they're dealing with someone who is already a customer. Other times, we wind up with inconsistent records across the two systems, or have problems keeping records up-to-date when a customer moves." Tim, the manager for the auto insurance systems immediately jumped into the conversation, "If we could get the home insurance system to use our customer database, our problems would go away." Adil, the manager for the home insurance systems, responded to Tim, "We've spent the last 15 years evolving our application and database. It would be much more expensive for us to try to move all our data into your system." Spencer could sense the tension in the room. Both of these managers had invested many years in their systems, and neither one wanted to relinquish any amount of control. "I don't think consolidating the data will work with the timelines we've been given. What I'd like to do is to create a new customer information service that will provide an abstraction layer in front of both of your databases. You'll both need to modify your applications to use the service rather than going directly to the database, but the service will ensure that both systems remain in sync. In addition, you'll have access to additional information about the customers in each other's systems that you can now incorporate into your applications. Then, at a later time, we can pursue consolidating the databases into a single one. With the service in place, you won't need to make any changes to the front end of your applications when that occurs." Adil said, "How are you going to make this work? My system leverages a Java front-end talking to our mainframe, while Tim's system is based completely on Microsoft technologies?" Spencer responded, "I think this a great opportunity to leverage web services technology. It claims to provide interoperability across these platforms, let's give it a try." Tim said, "Who's going to write this service?" Spencer suggested, "Since we need to incorporate information from both of your systems, I suggest that we form a team with a developer from each of your groups to design and build the new service." Adil and Tim agreed, and told Spencer that they would let him know what developers they would contribute to the effort. Spencer went back to his desk and knew that he had a real challenge on his hands. While the managers involved had committed developers to the effort, he also sensed that there was some hesitancy about the effort. They knew that changes were needed, but it was clear that neither one wanted to give up the control they currently had over their systems. He was hoping that the right developers would get assigned. He knew that many of them had complained about the redundancy that existed across the various applications, but the scope and timeline of their projects prevented them from doing anything about it. This effort was beginning with the right scope, so as long they met timelines, there was a good chance to make it happen. Over the next few weeks, Spencer's team, including the developers from Adil and Tim's organizations, worked hard to define the new Customer service that both applications would use. The developers were very familiar with the current data models used by each application, and worked together to define the data models and schemas for the new service. While these developers had some knowledge of how the existing applications manipulated the data, they worked solely with each other in defining the functional interface of the service. In the end, the service interface contained some elements of Customer data that was specific to one of the two applications, but they felt that information could be safely ignored by the other application. The First Milestone Soon afterwards, Spencer met with Jennifer, the project manager for the auto insurance application, to discuss their schedule. Spencer said, "Hi Jennifer. I wanted to discuss our delivery schedule with you so we can ensure that you can integrate the new Customer service as part of your effort. I know you're making some additional changes to the application besides the migration to the service." Jennifer took a glance at her project plan and told Spencer, "We're currently planning on going live on October 6th. Our performance tests are planned for September 2nd, and user testing will begin on July 28th." Spencer said, "Okay, we'll plan on targeting those same dates for our service. Don't hesitate to contact me if you need anything else." Jennifer didn't. Just two weeks later she sent him an email that said, "Spencer, my developers want to know when they'll have a service they can test against. They've told me that they can't do anymore work until it's available." Spencer replied, "I'll have one of my developers provide you the URL for our development service right away." He had his team provide it, and didn't hear anything back from Jennifer's team, so he assumed everything was working well. That lasted for about one week when Jennifer came storming into his cubicle. "What did you do to the service? We were going to demonstrate where we were to one of our users today, and the application crashed when we tried retrieving data," she said. It was clear that it had not been a good morning for her. "We've been testing the integration with the home insurance data system, and have run into some issues, so our development environment has been up and down all day long as we try to determine what the problem is," he replied. "Well, you'd better get it fixed soon. I now have a key user who's very nervous about the stability of this new service-based approach, and my developers are simply telling me that they can't do anything about it. I'm going to report this as a serious issue in our Project Management Office (PMO) update on Thursday." "I'll get right on it, Jennifer. I apologize for this and we'll get it fixed as quickly as we can." Spencer immediately realized where his mistake was. By giving Jennifer's team the URL for the service in his development environment, he was exposing her application to all of the instability that is normally associated with any development environment. From her perspective, however, she didn't care about his development environment; she needed something that was stable so she could execute her tests and provide demonstrations. He gathered his developers and told them that they needed to create a stable version of the service that would be separate from their own development efforts that the auto insurance application could use. He suggested that they determine which of their iterations represented a key milestone from the perspective of the auto insurance application. When those iterations were successfully completed, it would be promoted to the stable environment in use by the auto insurance application. They implemented this plan and things got better, at least from Jennifer's perspective. Unfortunately, Jennifer wasn't the only project manager whose effort was dependent on Spencer's team. Mark was the project manager for the home insurance application, the other consumer of this new service. Like his initial meeting with Jennifer, Spencer met with Mark to find out what his plans were for the home insurance application. Like Jennifer, there were additional changes that Mark was putting into
Read more
  • 0
  • 0
  • 2312

article-image-date-and-calendar-module-drupal-5-part-2
Packt
21 Oct 2009
6 min read
Save for later

Date and Calendar Module in Drupal 5: Part 2

Packt
21 Oct 2009
6 min read
Recipe 40: Timeline Ingredients Timeline module: http://www.drupal.org/project/timeline Timeline widget:http://www.miccolis.net/random/timeline-1-2.tar.gz The Timeline module implements a nice interactive script developed originally by the SIMILE project at MIT. The project "graduated" in 2008, to become its own stand-alone open source project, hosted at Google Code. Log on to the host and enter the following commands. This is almost a garden-variety module installation, however, we also need to download all of the SIMILE timeline code and place it in an api subdirectory. The Timeline widget tarball expands to the timeline-1-2 directory, so in the last step we use the mv command to rename it to api. cd home/DRUPALACCOUNT/public_html/sites/all/moduleswget http://ftp.drupal.org/files/projects/timeline-5.x-1.0.tar.gztar xvf timeline-5.x-1.0.tar.gzcd timeline/wget http://www.miccolis.net/random/timeline-1-2.tar.gz tar xvf timeline-1-2.tar.gz mv timeline-1-2 api Enable the Timeline module. Explore the configuration settings at admin/settings/timeline. Here you may set the width, height, and initial date focus. Also note the Advanced settings for the path to the Timeline widget JavaScript. If, for some reason, you are unsuccessful making the widget available, you may temporarily try pointing to: http://simile.mit.edu/timeline/api/timeline-api.js. (This will work for as long as MIT continues to host this.) Read the README.txt file, and INSTALL.txt file (this is always a good practice when installing new modules). This is a summary of the Views field requirements for setting up a timeline in Drupal. If present If not present First field Date or Event determines location on the timeline Defaults to Node Created Time Second Field Title, with clickable link Node's default title is used Third Field Description Teaser, if available. (CCK Date fields do not have timeline) Additional Fields Additional fields are not used by Timeline. Edit the timeline view created in Recipe 34. In the Page fieldset, change the View Type to Timeline: Horizontal. Scroll down to the Fields fieldset. Note that in our original view, the Title is the first field followed by Date as the second field. We will reverse this. Click on the up arrow in the Date row to Move this item to the top. Add the Text: Description (field_workshop_description) as the third field. Save the view and browse to timeline. Move the cursor around the timeline. Click on the events to see the associated pop-up box. Click and drag to the left to go forward in time. Click and drag works in both the upper and lower timeline bands. Configuration settings for individual timelines are available at admin/build/timeline (these settings will override default settings at admin/settings/timeline). A particularly interesting setting is the one to enable controls. With controls enabled, the user will have the opportunity to filter, or highlight the timeline based on text either in the title or the description. Regular expressions will also work when filtering or highlighting timeline items. Cooking|Recipes Find items that contain either Cooking or Recipes in the title or description ^L Find titles that start with L asagna Find Lasagna-partial words work fine. hea[rl]t Find Health or Heart The searches are case-insensitive. Recipe notes For examples of basic and sophisticated SIMILE Timelines see http://simile.mit.edu/timeline/examples/. More information about Timeline is available at http://code.google.com/p/simile-widgets/ including a mailing list, a wiki, and an independent issue queue for various SIMILE web widgets. There is also an archived listerv available at http://www.nabble.com/SIMILE---General-f27660.html. The listserv remains active for other SIMILE projects but does not accept content regarding "graduated" projects such as Timeline. However, you may find older posts helpful. If you like Timeline, try some of the other SIMILE projects as well, at http://simile.mit.edu/. (Perhaps you can write the next module to make them available in Drupal.) Exposed Filters are incompatible with the Timeline module. Arguments will work. For instance, if you add a Taxonomy item argument the URL: http://YOURSITE.com/timeline/Cooking would show only the workshops in the Cooking category. To incorporate color coding by taxonomy, consider installing the patch at http://drupal.org/node/121298. There is also a nice patch to include icons by taxonomy term at http://drupal.org/node/104890. The Timeline module integrates with the Events module. If no fields are included in the timeline, the timeline displays the date the content was posted. Recipe 41: Views Popup Ingredients Completed Recipe 34, views_popup view Views Popup module: http://drupal.org/project/views_popup The Views Popup module displays a list of up to three fields and then, upon mouseover, displays additional fields in a pop-up box. This is not a date-specific module, but we'll use it to display a workshop description when you move the mouse over the date. We'll also take a look at the views_style_plugins hook, which in this article enabled the Date Browser, Timeline, Calendar, and now List View as Popup View Types. Install and enable the Views Popup module. Open the views_popup view at views_popup/edit. In the Page fieldset, change the View Type to List View as Popup, Show 2 Fields In the Fields fieldset, change the order of the Datestamp and Title fields so that the datestamp is first. Add the Text: Description (field_workshop_description) field. The first two of these fields will display. The third will be hidden by default. Save and view the views_popup view. Note than when you mouse over the date, the description appears Take a look at hook_views_style_plugins in the views_popup.module file: function views_popup_views_style_plugins() { return array( 'list_hint' => array( 'name' => t('List View as Popup, Show 1 field'), 'theme' => 'views_view_list_hint_popup1', 'validate' => 'views_ui_plugin_validate_list', 'needs_fields' => true, 'weight' => -10, ), 'list_hint2' => array( 'name' => t('List View as Popup, Show 2 fields'), 'theme' => 'views_view_list_hint_popup2', 'validate' => 'views_ui_plugin_validate_list', 'needs_fields' => true, 'weight' => -10, ), 'list_hint3' => array( 'name' => t('List View as Popup, Show 3 fields'), 'theme' => 'views_view_list_hint_popup3', 'validate' => 'views_ui_plugin_validate_list', 'needs_fields' => true, 'weight' => -10, ) ); The critical elements in this array are the name and the specified theme callback function. The function appears below in the same file and does the actual work of producing the output, in this case, creating a pop-up. Recipe notes Documentation on hook_views_style_plugins is available in the Drupal handbook at http://drupal.org/node/193448. Think of the style plugin as a way to modify the output of a whole node, while the field formatters apply to a single field.
Read more
  • 0
  • 0
  • 2321

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

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

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

article-image-radrails-views
Packt
21 Oct 2009
6 min read
Save for later

RadRails Views

Packt
21 Oct 2009
6 min read
Opening the RadRails Views Some of the views that we will go through in this article are available as part of the Rails default perspective, which means you don't need to do anything special to open them; they will appear as tabbed views in a pane at the bottom of your workbench. Just look for the tab name of the view you want to see and click on it to make it visible. However, there are some views that are not opened by default, or maybe you closed them at some point accidentally, or maybe you changed to the Debug perspective and you want to display some of the RadRails views there. When you need to open a view whose tab is not displaying, you can go to the Window menu, and select the Show View option. If you are in the Rails perspective, all the available views will be displayed in that menu, as you can see in the screenshot above. When opening this menu from a different perspective, you will not see the RadRails views here, but you can select Other.... If this is the case, in the Show View dialog, most of the views will appear under the Ruby category, except for the Generators, Rails API, and Rake Tasks views, which are located under Rails. Documentation Views As happens with any modern programming language, Ruby has an extensive API. There are lots of libraries and classes and even with Ruby being an intuitive language with a neat consistent API, often we need to read the documentation. As you probably know, Ruby provides a standard documentation format called RDoc, which uses the comments in the source code to generate documentation. We can access this RDoc documentation in different ways, mainly in HTML format through a browser or by using the command-line tool RI. This produces a plain-text output directly at the command shell, in a similar way to the man command in a UNIX system. RadRails doesn't add any new functionality to the built-in documentation, but provides some convenient views so we can explore it without losing the context of our project's source. Ruby Interactive (RI) View This view provides a fast and comfortable way of browsing the local documentation in the same way as you would use RI from the command line. You can look either for a class or a method name. Just start typing at the input box at the top left corner of the view and the list below will display the matching entries. That's a nice improvement over the command line interface, since you can see the results as you type instead of having to run a complete search every time. If you know the name of both the class and the method you are looking for, then you can write them using the hash (pound) sign as a separator. For example, to get the documentation for the sum method of the class Enumerable you would write Enumerable#sum. The documentation will display in the right pane, with a convenient highlighting of the referenced methods and classes. Even if the search results of RI don't look very attractive compared to the output of the HTML-based documentation views, RI has the advantage of searching locally on your computer, so you can use it even when working off-line. Ruby Core, Ruby Standard Library, and Rails API There are three more views related to documentation in RadRails: Ruby Core API, Ruby Standard Library API, and Rails API. Unlike the RI view, these ones look for the information over the Internet, so you will not be able to use them unless you are on-line. On the other hand, the information is displayed in a more attractive way than with RI, and it provides links to the source code of the consulted methods, so if the documentation is not enough, you can always take a look at the inner details of the implementation. The Ruby Core API view displays the documentation of the classes included in Ruby's core. These are the classes you can directly use without a previous require statement. The documentation rendered is that at http://www.ruby-doc.org/core/. You are probably familiar with this type of layout, since it's the default RDoc output. The upper pane displays the navigation links, and the lower pane shows the detail of the documentation. The navigation is divided into three frames. The one to the left shows the files in which the source code is, the one in the middle shows the Classes and Modules, and in the third one you can find all the methods in the API. The Ruby Standard Library API is composed of all the classes and modules that are not a part of Ruby's core, but are typically distributed as a part of the Ruby installation. You can directly use these classes after a require statement in your code. The Ruby Standard Library API View displays the information from http://www.ruby-doc.org/stdlib. In this case, the navigation is the same as in Ruby Core, but with an additional area to the left, in which you can see all the available packages (the ones you would require for using the classes within your code). When you select a package link, you will see the files, classes, and methods for that single package. The last of the documentation views displays information about the Rails API. It includes the documentation of ActiveRecord, the ActionPack, ActiveSupport, and the rest of the Rails components. The information is obtained from http://api.rubyonrails.org. In this case the layout is slightly different because the information about the files, classes, and methods is displayed to the left instead at the top of the view. Apart from that, the behavior is identical to that of the Ruby Core API view. Since some of the API descriptions are fairly long, it can be convenient to maximize the documentation views when you are using them. Remember you can maximize any of the views by double-clicking its tab or by using the maximize icon on the view's toolbar. Double-clicking again will restore the view to the original size and position.
Read more
  • 0
  • 0
  • 2953

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

Multiple Templates in Django

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

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

Using jQuery Script for Creating Dynamic Table of Contents

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

First Steps with Scalix Admin Console and Scalix Web Access

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

article-image-osworkflow-and-quartz-task-scheduler
Packt
21 Oct 2009
10 min read
Save for later

OSWorkflow and the Quartz Task Scheduler

Packt
21 Oct 2009
10 min read
Task Scheduling with Quartz Both people-oriented and system-oriented BPM systems need a mechanism to execute tasks within an event or temporal constraint, for example, every time a state change occurs or every two weeks. BPM suites address these requirements with a job-scheduling component responsible for executing tasks at a given time. OSWorkflow, the core of our open-source BPM solution, doesn't include these temporal capabilities by default. Thus, we can enhance OSWorkflow by adding the features present in the Quartz open-source project. What is Quartz? Quartz is a Java job-scheduling system capable of scheduling and executing jobs in a very flexible manner. The latest stable Quartz version is 1.6. You can download Quartz from http://www.opensymphony.com/quartz/download.action. Installing The only file you need in order to use Quartz out of the box is quartz.jar. It contains everything you need for basic usage. Quartz configuration is in the quartz. properties file, which you must put in your application's classpath. Basic Concepts The Quartz API is very simple and easy to use. The first concept that you need to be familiar with is the scheduler. The scheduler is the most important part of Quartz, managing as the word implies the scheduling and unscheduling of jobs and the firing of triggers. Task Scheduling with Quartz A job is a Java class containing the task to be executed and the trigger is the temporal specification of when to execute the job. A job is associated with one or more triggers and when a trigger fires, it executes all its related jobs. That's all you need to know to execute our Hello World job. Integration with OSWorkflow By complementing the features of OSWorkflow with the temporal capabilities of Quartz, our open-source BPM solution greatly enhances its usefulness. The Quartz-OSWorkflow integration can be done in two ways—Quartz calling OSWorkflow workflow instances and OSWorkflow scheduling and unscheduling Quartz jobs. We will cover the former first, by using trigger-functions, and the latter with the ScheduleJob function provider. Creating a Custom Job Job's are built by implementing the org.quartz.Job interface as follows: public void execute(JobExecutionContext context) throws JobExecutionException; The interface is very simple and concise, with just one method to be implemented. The Scheduler will invoke the execute method when the trigger associated with the job fires. The JobExecutionContext object passed as an argument has all the context and environment data for the job, such as the JobDataMap. The JobDataMap is very similar to a Java map but provides strongly typed put and get methods. This JobDataMap is set in the JobDetail file before scheduling the job and can be retrieved later during the execution of the job via the JobExecutionContext's getJobDetail().getJobDataMap() method. Trigger Functions trigger-functions are a special type of OSWorkflow function designed specifically for job scheduling and external triggering. These functions are executed when the Quartz trigger fires, thus the name. trigger-functions are not associated with an action and they have a unique ID. You shouldn't execute a trigger-function in your code. To define a trigger-function in the definition, put the trigger-functions declaration before the initial-actions element. ... <trigger-functions> <trigger-function id="10"> <function type="beanshell"> <arg name="script"> propertySet.setString("triggered", "true"); </arg> </function> </trigger-function> </trigger-functions> <initial-actions> ... This XML definition fragment declares a trigger-function (having an ID of 10), which executes a beanshell script. This script will put a named property inside the PropertySet of the instance but you can define a trigger-function just like any other Java- or BeanShell-based function. To invoke this trigger-function, you will need an OSWorkflow built-in function provider to execute trigger-functions and to schedule a custom job—the ScheduleJob FunctionProvider. More about Triggers Quartz's triggers are of two types—the SimpleTrigger and the CronTrigger. The former, as its name implies, serves for very simple purposes while the latter is more complex and powerful; it allows for unlimited flexibility for specifying time periods. SimpleTrigger SimpleTrigger is more suited for job firing at specific points in time, such as Saturday 1st at 3.00 PM, or at an exact point in time repeating the triggering at fixed intervals. The properties for this trigger are the shown in the following table: s. The properties for this trigger are the shown in the following table: Property Description Start time The fire time of the trigger. End time The end time of the trigger. If it is specified, then it overrides the repeat count. Repeat interval The interval time between repetitions. It can be 0 or a positive integer. If it is 0, then the repeat count will happen in parallel. Repeat count How many times the trigger will fire. It can be 0, a positive integer, or SimpleTrigger.REPEAT_INDEFINITELY.     CronTrigger The CronTrigger is based on the concept of the UN*X Cron utility. It lets you specify complex schedules, like every Wednesday at 5.00 AM, or every twenty minutes, or every 5 seconds on Monday. Like the SimpleTrigger, the CronTrigger has a start time property and an optional end time. A CronExpression is made of seven parts, each representing a time component: Each number represents a time part: 1 represents seconds 2 represents minutes 3 represents hours 4 represents the day-of-month 5 represents month 6 represents the day-of-week 7 represents year (optional field) Here are a couple of examples of cron expression: 0 0 6 ? * MON: This CronExpression means "Every Monday at 6 AM". 0 0 6 * *: This CronExpression mans "Every day at 6 am". For more information about CronExpressions refer to the following website: http://www.opensymphony.com/quartz/wikidocs/CronTriggers%20Tutorial.html. Scheduling a Job We will get a first taste of Quartz, by executing a very simple job. The following snippet of code shows how easy it is to schedule a job.     SchedulerFactory schedFact = new                                             org.quartz.impl.StdSchedulerFactory();     Scheduler sched = schedFact.getScheduler();     sched.start();        JobDetail jobDetail = new JobDetail("myJob", null, HelloJob.class);        Trigger trigger = TriggerUtils.makeHourlyTrigger();                                                       // fire every hour        trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));                                                     // start on the next even hour        trigger.setName("myTrigger");        sched.scheduleJob(jobDetail, trigger); The following code assumes a HelloJob class exists. It is a very simple class that implements the job interface and just prints a message to the console. package packtpub.osw; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * Hello world job. */ public class HelloJob implements Job { public void execute(JobExecutionContext ctx) throws JobExecutionException { System.out.println("Hello Quartz world."); } }   The first three lines of the following code create a SchedulerFactory, an object that creates Schedulers, and then proceed to create and start a new Scheduler. SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(); Scheduler sched = schedFact.getScheduler(); sched.start(); This Scheduler will fire the trigger and subsequently the jobs associated with the trigger. After creating the Scheduler, we must create a JobDetail object that contains information about the job to be executed, the job group to which it belongs, and other administrative data. JobDetail jobDetail = new JobDetail("myJob", null, HelloJob.class); This JobDetail tells the Scheduler to instantiate a HelloJob object when appropriate, has a null JobGroup, and has a Job name of "myJob". After defining the JobDetail, we must create and define the Trigger, that is, when the Job will be executed and how many times, etc. Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every hour trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date())); // start on the next even hour trigger.setName("myTrigger"); The TriggerUtils is a helper object used to simplify the trigger code. With the help of the TriggerUtils, we will create a trigger that will fire every hour. This trigger will start firing the next even hour after the trigger is registered with the Scheduler. The last line of code puts a name to the trigger for housekeeping purposes. Finally, the last line of code associates the trigger with the job and puts them under the control of the Scheduler. sched.scheduleJob(jobDetail, trigger); When the next even hour arrives after this line of code is executed, the Scheduler will fire the trigger and it will execute the job by reading the JobDetail and instantiating the HelloJob.class. This requires that the class implementing the job interface must have a no-arguments constructor. An alternative method is to use an XML file for declaring the jobs and triggers. This will not be covered in the book, but you can find more information about it in the Quartz documentation. Scheduling from a Workflow Definition The ScheduleJob FunctionProvider has two modes of operation, depending on whether you specify the jobClass parameter or not. If you declare the jobClass parameter, ScheduleJob will create a JobDetail with jobClass as the class implementing the job interface. <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.ScheduleJob </arg> <arg name="jobName">Scheduler Test </arg> <arg name="triggerName">SchedulerTestTrigger</arg> <arg name="triggerId">10 </arg> <arg name="jobClass">packtpub.osw.SendMailIfActive </arg> <arg name="schedulerStart">true </arg> <arg name="local">true </arg> </function> </pre-functions> This fragment will schedule a job based on the SendMailIfActive class with the current time as the start time. The ScheduleJob like any FunctionProvider can be declared as a pre or a post function. On the other hand, if you don't declare the jobClass, ScheduleJob will use the WorkflowJob.class as the class implementing the job interface. This job executes a trigger-function on the instance that scheduled it when fired.    <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.ScheduleJob </arg> <arg name="jobName">Scheduler Test </arg> <arg name="triggerName">SchedulerTestTrigger </arg> <arg name="triggerId">10 </arg> <arg name="schedulerStart">true </arg> <arg name="local">true </arg> </function> </pre-functions>   This definition fragment will execute the trigger-function with ID 10 as soon as possible, because no CronExpression or start time arguments have been specified. This FunctionProvider has the arguments shown in the following table:
Read more
  • 0
  • 0
  • 3216

article-image-facebook-application-development-ruby-rails
Packt
21 Oct 2009
4 min read
Save for later

Facebook Application Development with Ruby on Rails

Packt
21 Oct 2009
4 min read
Technologies needed for this article RFacebook RFacebook (http://rfacebook.rubyforge.org/index.html) is a Ruby interface to the Facebook APIs. There are two parts to RFacebook—the gem and the plug-in. The plug-in is a stub that calls RFacebook on the Rails library packaged in the gem. RFacebook on Rails library extends the default Rails controller, model, and view. RFacebook also provides a simple interface through an RFacebook session to call any Facebook API. RFacebook uses some meta-programming idioms in Ruby to call Facebook APIs. Indeed Indeed is a job search engine that allows users to search for jobs based on keywords and location. It includes job listings from major job boards and newspapers and even company career pages. Acquiring candidates through Facebook We will be creating a Facebook application and displaying it through Facebook. This application, when added into the list of a user's applications, allows the user to search for jobs using information in his or her Facebook profile. Facebook applications, though displayed within the Facebook interface, are actually hosted and processed somewhere else. To display it within Facebook, you need to host the application in a publicly available website and then register the application. We will go through these steps in creating the Job Board Facebook application. Creating a Rails application Next, create a Facebook application. To do this, you will need to first add a special application in your Facebook account—the Developer application. Go to http://www.facebook.com/developers and you will be asked to allow Developer to be installed in your Facebook account. Add the Developer application and agree to everything in the permissions list. You will not have any applications yet, so click on the create one link to create a new application. Next you will be asked for the name of the application you want to create. Enter a suitable name; in our case, enter 'Job Board' and you will be redirected to the Developer application main page, where you are shown your newly created application with its API key and secret. You will need the API key and secret in a while. Installing and configuring RFacebook RFacebook consists of two components—the gem and the plug-in. The gem contains the libraries needed to communicate with Facebook while the plug-in enables your Rails application to integrate with Facebook. As mentioned earlier, the plug-in is basically a stub to the gem. The gem is installed like any other gem in Ruby: $gem install rfacebook To install the plug-in go to your RAILS_ROOT folder and type in: $./script/plugin install svn://rubyforge.org/var/svn/rfacebook/trunk/rfacebook/plugins/rfacebook Next, after the gem and plug-in is installed, run a setup rake script to create the configuration file in the RAILS_ROOT folder: $rake facebook:setup This creates a facebook.yml configuration file in RAILS_ROOT/config folder. The facebook.yml file contains three environments that mirror the Rails startup environments. Open it up to configure the necessary environment with the API key and secret that you were given when you created the application in the section above. development: key: YOUR_API_KEY_HERE secret: YOUR_API_SECRET_HERE canvas_path: /yourAppName/ callback_path: /path/to/your/callback/ tunnel: username: yourLoginName host: www.yourexternaldomain.com port: 1234 local_port: 5678 For now, just fill in the API key and secret. In a later section when we configure the rest of the Facebook application, we will need to revisit this configuration. Extracting the Facebook user profile Next we want to extract the user's Facebook user profile and display it on the Facebook application. We do this to let the user confirm that this is the information he or she wants to send as search parameters. To do this, create a controller named search_controller.rb in the RAILS_ROOT/app/controllers folder. class SearchController < ApplicationController before_filter :require_facebook_install layout 'main' def index view render :action => :view end def view if fbsession.is_valid? response = fbsession.users_getInfo(:uids => [fbsession.session_user_id], :fields => ["current_location", "education_history", "work_history"]) @work_history = response.work_history @education_history = response.education_history @current_location = response.current_location endend
Read more
  • 0
  • 0
  • 3936

article-image-creating-pseudo-3d-imagery-gimp-part-1
Packt
21 Oct 2009
9 min read
Save for later

Creating Pseudo-3D Imagery with GIMP: Part 1

Packt
21 Oct 2009
9 min read
In the previous article I've written ( Creating Convincing Images with Blender Internal Renderer-part1), I discussed about creating convincing 3D still images through color manipulation, proper shadowing, minimal lighting, and a bit of post-processing, all using but one application – Blender. This time, the article you're about to read will give us some thoughts on how to mimic a 3D scene with the use of some basic 2D tools. Here again, I would stress that nothing beats a properly planned image, that applies to all genres you can think of. Some might think it's a waste of precious time to start sitting and planning without having a concrete output at the end of the thought process. But believe me, the ideas you planned will be far more powerful and beautiful than those ideas you just had, when you were just messing around and playing with the tool directly. In this article, I wouldn't be teaching you how to paint since I'm not good at it, rather I'll be leading you through a series of steps on how to digitally sketch/draw your scenes, give them subtle color shifts, add fake lighting, and apply filter effects to further emulate how 3D does its job. Primarily, this all leads you into a guide on how I create my digital drawings (though I admit they're not the best of its kind), but somehow I'm very proud, I eventually gave life to them from concept stage to digital art stage. It might be a bit daunting at first, but as you go along the series, you'll notice it gets simpler.  However, some might get confused as to how this applies to other applications since we're focusing on The GIMP in this article. That's not a problem at all once you are familiar with your own tool; it will just be a matter of working around the tools and options. I have been using The GIMP for a long time already, and as far as I can remember, I haven't complained on its shortcomings since those shortcomings are only but bits of features which I wouldn't be need at all.  So to those of you who have been and are using other image editing programs like Adobe Photoshop, Corel, etc., you're welcome to wander around and feel free to interpret some GIMP tools to that of yours.  It's all the same after all, just a tad bit difference on the interface. Just like what Jeremy Birn has said on one of his books: “Being an expert user of a 3D Program, bit itself, does not make the user into an artist more than learning to run a Word Processor makes someone into a good writer.” Additionally, one vital skill you have to develop is the skill of observation, which I myself ham yet to master. Methods Used Basic Drawing Selection Addition, Subtraction, Intersection Gradient Coloring Color Mixing Layering Layer Modes Layer Management Using Filters Requirements Latest version of The GIMP (download at http://www.gimp.org/downloads) Basic knowledge of image editing programs with layering capabilities Patience Let's Get Started! I would already assume you have the latest version of GIMP installed on your system and is running properly, otherwise, fix the problem or ask help from the forum (http://www.gimptalk.com). I'm also assuming you have all your previous tasks done before sitting down and going over this article (which I'm pretty much positive you are). And then lastly, be patient. Sketch it out The very first thing we're going to do is to sketch our ideas for the image, much like a single panel of a storyboard. It doesn't matter how good you draw it as long as you understand it yourself and you know what's going on in the drawing. This time, you can already visualize and create a picture of your final output and it's great if you did, if not, it's fine still. The important thing is we have laid down our scene one way or another. You can take your time sketching out your scenes and adding details to them like how many objects are seen, how many are in focus, what colors do they represent, how are your characters' facial expressions, what is the size of your image, etc. So just in case we forgot how it's going to look like in the end, we have a reference to call upon and that is your initial sketch. This way, you'll also be affected by the persistence of vision where after hours and hours (yay!) of looking on your sketch, you somehow see an afterimage of what you are about to create, and that's a good thing! I'm not good at sketching so please bear with my drawing: After this, it's now time to open up The GIMP and begin the actual fun part! First Run After executing GIMP, this should (and most likely) be the initial screen that's going to be displayed on your screen: The GIMP Initial Screen We don't want Wilbur (GIMP's Mascot) to be glaring at us from a blank empty window all the time, do we? And right now we could go ahead and add a canvas with which we'll be adding our aesthetic elements into, but before that you might want to inspect your application and tool preferences just to make sure you have set everything right. Activate the window with the menu bar at the top (since we currently have three windows to choose from), and then locate Edit > Preferences, as seen below: Locating GIMP's Preferences GIMP Preferences Everything you see here should be self-explanatory, if it isn't, just leave it for the moment and check the manual later, since I'm pretty much sure that thing you didn't understand on the Preferences must be something we will not use here.  So go ahead and save whatever changes you did and sometimes, GIMP might ask you to restart the application for the changes to take effect, then do what she says and we should be back on the black canvas shortly after application restart. By now, we should be having three windows, the main Toolbox Window (located on the left), the main Image Window (located on the middle), and the Layers Window (located on the right).  If, by any chance, the Layer Window is not there, go ahead and activate the Image Window and go to Windows > Layers or press CTRL + L to bring up the Layer Window. Showing the Layers Window Creating the Canvas Now that everything's set up, we'll go ahead and add a properly-sized canvas that we'll paint on, which will be the entire universe for our creation at a later stage. Let's go and create than now by going to File > New or by pressing CTRL+ N. A window will pop up asking you to edit and confirm the image settings for the canvas you're creating. You can choose from a variety of templates to use or you can manually input sizes (which we are going to do).  Before that, change the unit for coordinate display to inches just so we could have a better visual reference of how big our drawing canvass will be. Then on the Width input box, type 9 (for nine inches), and for the Height input box, type 6 (for six inches) respectively. This, however, is a very subjective portion, since you can just have any size you prefer, I just chose nine inches by six inches for the purposes of this article. Clicking the Advanced Options drop-down menu will reveal more options for you.  But right now, we'll never deal with that, just the width and height are sufficient for what we'll be need. When you're done setting up the dimensions and settings, click OK to confirm (is there a chance we could chance the OK buttons to “Alright” buttons, which sounds, uhmmm, better). Creating a New Image At this moment, we should be seeing a blank canvas with the dimensions that we've set awhile back. Then just at the right window (Layers Window), you'll notice there's already one layer present as compared to the default which is none. So everytime we add a new layer (which is very vital), we'll be referencing them over to the Layers Window. Since the creation of the layering system in image editors, it has been a blast to organize elements of an image and apply special effects on them as necessary. We can imagine layers as transparent sheets overlaying each other to form one final image; one transparent sheet can have a landscape drawn, another sheet contains trees and vegetation, and another sheet (which is above the tree sheets) is our main character. So together, we see a character with trees on a landscape in one. But as far as traditional layering is concerned, digital layering has been far more superior in terms of flexibility and the amount of modes we can experiment with. New Image with Layer This time might be a good idea to save our file natively, by that I mean save it in a format that is recognizable only by GIMP and that is lossless in format, so whether we save it a couple of times as such, no image compression happens and the image quality is not compromised. However, the native format is only related to GIMP and is not known elsewhere, so uploading such file to your website will show no image at all because it isn't recognized by the browser. In order to make it generally compatible, we export our image to known formats like JPEG, PNG, GIF, etc. depending on your need. Saving an image file on its native format preserves all the options we have like selections, paths, layers, layer modes, palettes, and many more. This native format that GIMP uses is known as .XCF which stands for “eXperimental Computing Facility”. Throughout this article, we'll save our files mainly in .xcf format and later on, when our tasks are done and we call our image finished, that's the time we export it to a readable and viewable format. Let's go ahead and save our file by going to File > Save, or by pressing CTRL + S. This brings up a window that we can type our filename into and browse and create the location for our files. Type whatever filename you wish and append the “.xcf” file extension at the end of the filename, or you can choose “GIMP xcf image” from a list on the lower half of the window. Saving an Image as XCF
Read more
  • 0
  • 1
  • 7704
article-image-putting-sakai-work
Packt
21 Oct 2009
16 min read
Save for later

Putting Sakai to Work

Packt
21 Oct 2009
16 min read
The fundamental determinants of course quality have always been, and remain, the course content, the instructor(s), the learning activities in which the students are engaged, and the students themselves. We do not make any exaggerated promises about the transformative nature of technology in education. Technology like Sakai can be used to improve your course by allowing you and your students to do things that might have been impractical without the technology or by reducing the amount of time spent on administrative issues. But the tools Sakai provides are just that—tools—and unless they are used purposefully they will not make much of a difference. So it is most important for you to consider what you want to accomplish with your students and how the capabilities Sakai provides can support the course activities. There is not a single "best" way of teaching. What works in a small graduate seminar in philosophy may not work in a large introductory computer science class, and what works for one instructor may not work for another. The good news is that Sakai is designed with this variety in mind. The tools and structure of a Sakai site You can think of Sakai as a framework that allows you to create the kind of online experience you want for your students. There is not a single way that a Sakai course site needs to function—it is ultimately up to you, with assistance from your Sakai user support team, to determine how the course is presented to the students online. Not all Sakai sites are used for courses. In many institutions, it is common to find Sakai used for research work groups and administrative collaboration. In fact, at many institutions, there are more "collaboration sites", as they are called in the Sakai community, than there are course sites. So, these types of sites are included in the overview. Many institutions integrate Sakai with other enterprise systems—automatically creating a Sakai site for each course being taught, for example, and adding students who are registered for the course to the site. Other organizations require instructors to create a site online but, once that's created, students are added and removed based on data from the registrar's office. Regardless of the type of course (or collaboration site) you might be teaching, there is a basic structure to Sakai that is useful to understand. This section describes that basic structure and common tools. It also gives you a quick and easy way to customize a Sakai site, so we recommend having a browser window handy with access to an instance of Sakai. If you have not yet created a Sakai site or if you don't have access to an instance of Sakai at your organization, several Sakai Commercial Affiliates host trial versions of Sakai that you can access free of charge. Check www.sakaiproject.org for the current listing. At the time of writing, hosted trials were available from rSmart (http://sakaisandbox.com), Serensoft (http://sakaisthelimit.com), and Unicon (http://testdrivesakai.com). When you create your account, a site is automatically created for you. Sakai's site structure Once you've logged into Sakai the top of the screen consists of a Sakai banner that contains your organization's branding and a logout button. Just below that banner is a series of tabs, one for each Sakai site that you are a member of. Every course or project consists of a Sakai site and is accessed by clicking a tab labeled with the name of the site. If you are a member of more than one site, you have more than one tab across the top of your screen. If you have too many sites to fit, a More Sites menu (often renamed My Sites or My Active Sites) is present; it enables you to access the appropriate site. Always be sure you're in the correct site when you're doing your work. My Workspace There is also a tab called My Workspace, a special site that only you have access to. You use it to manage your preferences, store personal files, manage site memberships, and even provide a calendar that pulls information from all the Sakai sites to which you belong. Contact your local Sakai support team for more information about uses of My Workspace. You can modify which sites appear across the top of the page so that your most frequently accessed sites are a single click away. To do that, go to your My Workspace site and choose the Preferences tool. The Customize Tabs function enables you to change which sites are visible. A basic Sakai site is a collection of tools that users have access to, typically presented to users in a sidebar on the left of the screen. In most Sakai installations, each link in the left sidebar corresponds to a single tool. To access the Assignments tool, for example, a user clicks the Assignments link in the sidebar. The Assignments tool then appears in the main content area of Sakai. In most cases, it is as simple as that. The major exception to this rule is the site Home page. It is a significant exception because it is the first page you see when you access a site. The Home tool contents Unlike most tools, the Home tool is not a tool at all. It is really a summary page. It generally includes information pulled from several different tools. Sakai tries to be helpful by providing the most commonly useful information and, therefore, a typical course site Home page includes areas (called panels) that present the following information: A site description (a description of the course or project) Recent course announcements Recent discussion forum posts Recent chat messages A course calendar Most of the panels on the Home page can be configured directly from the Home page. The Calendar panel, for example, allows you to specify whether the calendar is presented by week or by month. To add events to the Calendar, however, you need to use the Calendar tool itself. The Announcements panel lets you to determine how many recent announcements are shown (you can specify either a certain number of announcements or have the panel display announcements that have been created since a specific number of days in the past). Some panels enable you to edit the content itself. The Site Description panel, for example, provides an Options link that allows you to edit the content directly, obviating the need to access the tool directly. Of course, if you are not planning to use a tool in your site you do not want its information panel to appear on the course Home page. If you are not going to make a chat room available in your course, for instance, you do not want your course Home page to include a summary of recent chat messages because that would make your site look unfinished. Thankfully, Sakai is generally very smart about this—if you turn off the Chat tool in your site, the recent chat messages summary panel on the Home page simply disappears. Except for editing the Course Description content, you can mostly ignore the Home page and let Sakai take care of it for you. To edit the Site Description, simply click on the Options button. There are four things you can do: Specify the title for the panel. A good title reflects the type of site you have (for example changing the default Site Description to Course Description or, better yet, Welcome to Theater 101). Create the content that appears in the body of the panel. An easy-to-use HTML editor enables you to enter whatever content you want. If you don't know HTML, the default WYSIWYG mode can be used like a simple word processor. Just type away using the built-in text styling buttons to add bold, italics, bulleted lists, and so on. You can also add images, hyperlinks, and tables quite easily. If you know HTML, you can use the source code mode to view and edit the HTML directly. Specify the height for the panel. You want to make the panel large enough so there is no scroll bar within the panel itself. This is easy if there is not another panel just below it. If there is, make the panel just large enough to hold your content but not so large that there is excessive white space between the panels. This may take a bit of trial and error. Enter a URL instead of writing content. If you already have an HTML page that describes the site published elsewhere, you can simply enter that web address. Sakai will display that page in the Site Description panel. Then simply click Update Options to save the changes you've made. If you have access to Sakai, this would be a good time to try it out. Remember to ensure you are working in the correct site. There are, certainly, many instructors who want their course Home page to appear in a very specific manner. There are risks to that level of customization—remember that your students are likely taking several courses at one time and they may benefit from a consistent Home page experience. Nonetheless, it is often quite appropriate to create a custom Home page. Later, you'll see a number of ways to significantly customize the appearance of your site, including the Home page. First, though, let's review tools to make available and just let the Sakai Home page do most of the work. The basic collaboration tools There are four basic tools that almost every Sakai site uses, regardless of whether it is a course or a collaboration site: Resources. The tool for storing files that can be accessed by other members of the site. You can create folders to organize these files, and even make certain files publicly viewable (such as a web page you want to show to those who aren't part of your site). Announcements. Use it to send announcements to members of the site. These announcements appear on the site Home page and can be sent to all site members via email. Email Archive. This tool provides a dedicated email address for your site (mysitename@sakai.myschool.edu, for instance). While permissions can be configured to make Sakai behave differently, typically members of your site can send email to this address and everyone belonging to the site will get the email. All emails are archived and accessible using the Email Archive tool. Calendar. Sometimes called Schedule, the Calendar tool allows you to put important events on a calendar. The Sakai Calendar supports recurring events and has different icons for different types of events such as class meetings, exams, and special events. Site administration As a site owner, there are certain tasks that you may want to undertake to modify the site and/or the members of the site. The Site Info tool allows you to: Modify the tools available in your site, including modifying the order in which those tools appear in the toolbar and changing the names of the tools. Manage access to the site, including specifying whether individuals can join your site without your approval. Manage the membership of your site. What you can and cannot do with membership depends on your local Sakai installation and often varies based on organizational policies, but typically includes the capability to add and remove members and change the role of individual members. Manage groups of users in your site. Many Sakai tools have special features that allow you to work with a particular set of users inside your site. Groups and class sections are good examples of predefined groups that may be automatically created by your Sakai administrators. You can also create ad hoc groups for particular purposes. If you have project teams in your course, for example, it might be useful to create a group for each team. Import content from an existing site or export content from the current site to a new one. As a site owner, you always have access to the Site Info tool. Depending on how you use Sakai and how Sakai is integrated with other systems on your campus, you may never use Site Info. Still, you should take a quick look to familiarize yourself with what is available to you. Every Sakai installation is different from every other. Your organization may not make the same Sakai tools available as another organization. This article mainly restricts itself to those tools that will be commonly available in installations of Sakai version 2.6.x, but there may be instances where we mention a tool that is not available in your instance of Sakai. In many cases, you can request these tools from your Sakai administrator. We also try to mention alternatives to the recommended tool where they exist. The basic teaching and learning tools In addition to the basic collaboration and administration tools, there are three tools that are commonly used in Sakai Course sites: Syllabus, Assignments, and Gradebook. Syllabus. Use this tool to put your syllabus (clear guidelines and expectations for your course) online. You can upload a document (such as a Microsoft Word document or a PDF), build a structured syllabus in Sakai, or even point to an existing syllabus you have posted online in another location. Regardless of how you use the tool, you can have Sakai automatically email students when you've made a change to the syllabus. Assignments. This tool allows you to create and post assignments that students can submit electronically. Using the tool can help eliminate paper assignments and reduce class time spent collecting and returning student work. It allows students to send questions about assignments and enables you to post online comments, grade assignments, and transfer grades to the Gradebook automatically. The tool lets you set opening and closing times for each assignment, supports resubmissions, and marks each student submission with a date and time stamp. Gradebook. The Gradebook tool allows instructors to record and compute cumulative student grades. Students can refer to the Gradebook to check their progress in a course. The Gradebook tool is often used hand-in-hand with the Assignments tool although they can be used separately. With these three tools and the four basic collaboration tools reviewed earlier, you can create a solid online presence for your class. Students will get course announcements and can send and receive emails via the class email address and can check past messages online. You can post reading material and other resources for students online and build a course calendar to remind students of important events and deadlines. Your syllabus is available online and students are automatically updated with any modifications to it. You've provided a facility for students to submit their assignments electronically, and they can receive feedback on those assignments via Sakai as well. Their grades are computed online and they can check to see how they are doing at any time. Now that you have your course's online infrastructure set up, we can begin to add some more sophisticated uses of online tools. We'll do this by turning our attention to the several common types of courses and discuss how a Sakai site can be structured to support each type of course. Types of Sakai sites There are more than four thousand universities and colleges in the United States alone. Each of these teaches hundreds or even thousands of classes every year. Trying to create some structure from such a diverse world would be an exercise in oversimplification. The categories discussed here along with the associated recommendations about how to support them in Sakai are not meant to be rules or even best practices but rather a place to start when thinking about structuring your Sakai site. Do read through all of the site types because it is likely that your course mixes the structures and activities in two or more site types. And your own personal comfort with technology will also determine how many (and which) tools you might want to use. The site types you'll be working with are as follows: Problem-based courses Small discussion courses Large, introductory courses Project-based courses Collaboration sites The following sections highlight a small number of tools that are especially useful in a site used for that purpose. Other tools are often useful as well, but because you're just starting out, you'll have more success using a few tools well. Still, we encourage you to read through all the class types and mix and match the tools you feel will work best for your situation. Problem-based courses A problem-based course presents learners with one or more problems to solve on a regular basis (weekly, for instance). The problems are presented by the instructor and generally have either correct answers (such as a Calculus problem set) or at least a fairly clear way to distinguish better solutions (such as an analysis of a poem in an English literature class). Problem-based courses are often targeted at developing skills related to the topic at hand and students are therefore asked to apply what they've learned by solving problems. Math courses might include weekly problem sets, computer science courses might include small programming assignments, creative writing classes may have weekly writing exercises, an acting class may have a series of small scene studies—the general approach is to increase the level of student skill through repeated practice with frequent feedback. The tools introduced so far serve this type of course very well, with a special emphasis on the Assignments and Resources tools, and with the addition of just a few extra tools, you can make the online aspect of your problem-based class very effective: Assignments. Use this tool to enter all or most of the term's assignments at the beginning of the term. That provides students with an excellent guide to the weeks ahead and helps them plan their time accordingly. Resources. For problems with correct answers, use this tool to share sample problems and solutions to past problem sets. For classes where high-quality answers are less well defined (such as a performing arts or product design class), share samples of previous classes' best work. You can even upload video or audio recordings. By providing examples of excellent solutions to open-ended problems, you help your students understand what you're looking for. Forums. This tool provides online discussion that allows students to help each other with difficult problems. You can set up a forum for each problem set. (Be sure to monitor the forum to ensure that students are giving each other good advice and aren't crossing the boundaries by helping too much.) Chat. Use this tool to provide online problem-set help two nights before an assignment is due (don't encourage procrastination by scheduling it the night before the assignment is due). From the comfort of your home, you can take student questions about the assignment and suggest resources they might refer to while working on it.
Read more
  • 0
  • 0
  • 3694

article-image-showing-drupals-cck-module-fields-flash
Packt
21 Oct 2009
6 min read
Save for later

Showing Drupal's CCK Module Fields in Flash

Packt
21 Oct 2009
6 min read
Building a Recipe widget in Flash We will start out by first increasing the size of our stage in Flash to 500 x 640. Once we have done this, we will need to resize our background so that it fits to the new stage. We will start this by first selecting the whole background region, and then converting that into a new Movie Clip by selecting Modify | Convert to Symbol from the Flash menu. This will t hen bring up a new dialog, where we can give our new Movie Clip a name, which we will call mcBackground. We then need to make sure that we check the Enable guides for 9-slice scaling, which will allow us to resize the background without affecting the rounded edges. Once we create a new movie clip from our background, we will then enter this Movie Clip and then adjust the 9-scale guides so that they only cover the rounded edges. We can now ex it the background movie clip, and then resize the movie clip to a new height of 632 using the Properties panel. Our next task is to move the current title field to the top-left of our Flash application, and then create some background regions that will hold our new fields. The design of how this will look is completely up to you, but here is an illustration of what I just described: Now that our layout is ready for new content, the next step is to add new TextFields to hold our recipe content. Adding dynamic TextFields for Drupal content The important thing to note here is that we will need to create a new layer for each text element within our Flash application, so that we can keep track of each field separately. We will do this within the timeline by creating three new layers for each of our new fields, and by then labeling them so that we can easily determine what they contain. Now that we have each one of these separated, we can add new text fields in each layer, to be used for the description, ingredients, and the instructions. For each new Text field that we create, we will need to make sure to give them an instance name so that we can reference them within ActionScript. Each of these instance names should reflect the names of the fields that we created for our Recipe content type, which will be description, ingredients, and instructions respectively. When we are done, we should have something that resembles the following: We are now ready to hook up these TextFields to real Drupal content. Using ActionScript to show Drupal CCK fields We can start this off by opening up our main.as file, and then we will shift our focus to the onNodeLoad function. // Called when Drupal returns with our node.function onNodeLoad( node:Object ){ // Print out the node title. title.text = node.title;} This function gets called after our service call to Drupal's node.get service call and returns with the contents of the node. Since we have new TextFields for each custom recipe field, we can use the node object, passed to the onNodeLoad function, to reference the data from these custom fields, and populate our TextFields with that data. Since the contents of this node object are somewhat a mystery, there is a fantastic tool that is provided with Drupal that will allow us to examine how this node is structured. We will then be able to use that information to fill out the contents of our onNodeLoad function to show our complete recipe node. Using the Services Administrator We now need to shift our focus back to Drupal, where we will navigate to the Service Administrator section by going to Administer | Services. The Services module comes equipped with a fantastic tool for analyzing any service routine when working with external applications. It allows for you to call any service routine, with any specified argument, and then see the result of that routine call. This can be used to easily analyze the data structure that our Flash application will receive after it makes a call to any of the service routines available. Since we are using the node.get service routine to load each recipe node, we should be able to examine how the Description, Ingredients, and Instructions fields are represented, and then easily apply that to our Flash application. Let's do this by clicking on the link that says node.get in the node section. This will bring up the following page: The Services module automatically places a valid Session id in the session field, so we can just keep this field as it is. Because of this, all we really need to provide is the nid (node ID) of our Recipe node—since the fields field is optional. In order to determine the node ID for any node within the Drupal web site, simply navigate to Administer | Content, which will list all the content within the Drupal web site. The node ID can be found by hovering over any content link and then reading the last number in the URL. For example, if we hover over our Recipe node, we should see a URL similar to http://localhost/drupal6/node/5, which means that our node ID for this node is 5. After we have the entered the node ID in the nid field, we can now click on the button that says Call Method. This will then show the results of that call within the Results section just below the Call Method button. To the untrained eye, this may look intimidating, but really what this is showing is the results for all the data contained within the recipe node that we just created, including the Ingredients and Instructions. If we look within this data structure, we should see something that looks similar to the following: [field_ingredients] => Array( [0] => Array ( [value] => 1 skinless, boneless chicken breast half 2 tablespoons minced green onion 2 tablespoons minced red bell pepper 3/4 cup shredded Monterey Jack cheese 5 (6 inch) flour tortillas [format] => 1 )) Within our Flash application, we can now access the Ingredients field in the node object (which is what is returned when you call node.get). The ActionScript code to reference this field should look similar to the following: node.field_ingredients[0]["value"] Now, let's apply this concept to show the ingredients and instructions in our Flash application.
Read more
  • 0
  • 0
  • 1964

article-image-configuring-opencms-search
Packt
21 Oct 2009
6 min read
Save for later

Configuring OpenCms Search

Packt
21 Oct 2009
6 min read
A Quick Overview of Lucene Included with OpenCms is a distribution of the Lucene search engine. Lucene is an open source, high-performance text search engine that is both easy to use and full-featured. Lucene is not a product. It is a Java library providing data indexing, and search and retrieval support. OpenCms integrates with Lucene to provide these features for its VFS content. Though Lucene is simple to use, it is highly flexible and has many options. We will not go into the full details of all the options here, but will provide a basic overview, which will help us in developing our search code. A full understanding of Lucene is not required for completing this article, but interested readers can find more information at the Lucene website: http://jakarta.apache.org/lucene. There are also several excellent books available, which can easily be found with a web search. Search Indexes For any data to be searched, it must first be indexed. Lucene supports both disk and memory based indexes, but OpenCms uses the more suitable disk based indexes. There are three basic concepts to understand regarding Lucene search indexes: Documents, Analyzers, and Fields. Document: A document is a collection of Lucene fields. A search index is made up of documents. Although each document is built from some actual source content, there is no need for the document to exactly resemble it. The fields stored in the document are indexed and stored and used to locate the document. Analyzer: An analyzer is responsible for breaking down source content into words (or terms) for indexing. An analyzer may take a very simple approach of only parsing content at whitespace breaks or a more complex approach by removing common words, identifying email and web addresses, and understanding abbreviations or other languages. Though Lucene provides many optional analyzers, the default one used by OpenCms is usually the best choice. For more advanced search applications, the other analyzers should be looked at in more depth. Field: A field consists of data that can be stored, indexed, or queried. Field values are searched when a query is made to the index. There are two characteristics of a field that determine how it gets treated when indexed: Field Storage: The storage characteristic of a field determines whether or not the field data value gets stored into the index. It is not necessary to store field data if the value is unimportant and is used only to help locate a document. On the other hand, field data should be stored if the value needs to be returned with the search result. Field Indexing: This characteristic determines whether a field will get indexed, and if so, how. There is no need to index fields that will not be used as search terms, and the value should not be indexed. This is useful if we need to return a field value but will never search for the document using that field in a search term. However, for fields that are searchable, the field may be indexed in either a tokenized or an un-tokenized fashion. If a field is tokenized, then it will first be run through an analyzer. Each term generated by the analyzer will be indexed for the field. If it is un-tokenized, then the field's value is indexed, verbatim. In this case, the term must be searched for using an exact match of its value, including the case. The two field types may be combined to form four combinations. While choosing a field type, consideration should thus be given to how the item will need to be located, as well as what data will need to be returned from the index. Lucene also provides the ability to define a boost value for a field. This affects the relevance of the field when it is used in a search. A value other than the default value of 1.0 may be used to raise or lower the relevance. These are the important concepts to be understood while creating a Lucene search index. After an index has been created, documents may be searched through queries. Search Queries Querying Lucene search indexes is supported through a Java API and a search querying language. Search queries are made up of terms and operators. A term can be a simple word such as "hello" or a phrase such as "hello world". Operators are used to form logical expressions with terms, such as AND or NOT. With the Java API, terms can be built and aggregated together along with operators to form a query. When using the query language, a Java class is provided to parse the query and convert it into a format suitable for passing to the engine. In addition to these search features, there are more advanced operations that may be performed such as fuzzy searches, range searches, and proximity searches. All these options and flexibility allow Lucene to be used in an application in many ways. OpenCms does a good job of using these options to provide search capabilities for a wide range of content types. Next, we will look at how OpenCms interfaces with Lucene to provide this support. Configuring OpenCms Search OpenCms maintains search settings in the opencms-search.xml configuration file located in the WEB-INF/config directory. Prior to OpenCms 7, most of the settings in this configuration file needed to be made by hand. With OpenCms 7, the Search Management tool in the Administration View has been improved to cover most of the settings. We will first go over the settings that are controlled through the Search Management view, and will then visit the settings that must still be changed by hand. The first thing we'll do is define our own search index for the blog content. Creating a new search index is simple with the Administration tool. We access it by clicking on the Search Management icon of the Administrative View, and then clicking on the New Index icon: The Name field contains the name of the index file. This name can also be passed to a Java API. If the content differs between the online and offline areas, we can create an index for each one. For now, we will start with the offline index. We'll name it: Blogs – Offline. The other fields are: Rebuild mode: This determines if the index is to be built manually or automatically as content changes. We want automatic updating and will hence choose auto. Locale: We must select a locale for the content. OpenCms will extract the content for the given locale when it builds our index. If we were supporting more than one locale, then it would be a good idea to include the locale in the index name. Project: This selects content from either the Online or Offline project. Field configuration: This selects a field configuration to be used for the index. We do not have our own field configuration yet; so for now press OK to save the index. Next, we will define a field configuration for the blog content.
Read more
  • 0
  • 0
  • 3529
article-image-access-control-php5-cms-part-2
Packt
21 Oct 2009
17 min read
Save for later

Access Control in PHP5 CMS - Part 2

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

article-image-customizing-plugins-joomla-15x-part-1
Packt
21 Oct 2009
9 min read
Save for later

Customizing Plugins in Joomla! 1.5x (Part 1)

Packt
21 Oct 2009
9 min read
The code used in this article can be downloaded from here. Plugin composition and operation     Like a module, in its simplest form, a plugin can consist of only two files, a PHP file with the actual code for the plugin, and an XML manifest that tells Joomla! what to do with the plugin. Despite this apparent simplicity, plugins are very powerful, and more difficult to understand than modules and components. Plugins are designed to run at certain times during the execution of our site, and they perform actions that can only be done at these times. For example, in our sample site we want to hide some of our content from guests, and only show it to paid subscribers. This action can only be performed when we are actually preparing the content to be displayed, because we need to wait until we identify if the viewer is a guest or subscriber, and then make the changes to the content dynamically. In a different example, checking if a subscriber's subscription is valid is something that only needs to be done when they try to login, and not on every page load. Plugin types Plugins are divided into eight types, as follows: Authentication Content Editors Editors-XTD Search System User XML-RPC Authentication Authentication plugins are designed to allow the site to check the user's authentication against a variety of sources. The default is to check the user's authentication against a username and password stored in the Joomla! database, which, as of Joomla! 1.5, will be the username and password fields in the #__user table (#__ is the table prefix we chose when setting up Joomla!). However, any source with a public API can be used to verify someone's authentication details. Common uses are LDAP, OpenID, a Google account, a subscription, community component, and more. On our site, for example, we are already using an authentication plugin to verify the subscriptions of users when they attempt to login. Content Possibly the most commonly used of all plugins, content plugins allow content items to be modified or have additional features added to them. We could, for example, use content plugins to cloak email addresses, embed audio or video into our pages, or do text replacements. We can even embed components and modules into our pages via plugins. We will later look at a content plugin that we will use to hide and show content depending on a user's subscription. Editors Editors plugins add WYSIWYG editors that we can use when editing our content. We installed JCE on our site earlier, which is the most popular Joomla! editor plugin as of this publication according to Joomla.org. Editors-XTD Editors-XTD (extended) plugins allow us to add additional buttons to the editors. The Image, Read more, and Pagebreak buttons on the default Joomla! WYSIWYG editor, for example, are actually plugins. Search Search plugins allow us to search through the data from different components. By default, Joomla! comes with plugins that search through content articles and the Contacts and Weblinks components. These can be expanded upon by creating or installing search plugins for other extensions. System System plugins are arguably the most powerful and most flexible types of plugins for Joomla!, as they can execute at several different pre-defined points during the execution of a Joomla! page plugin. They can be used to perform a vast array of functions, such as loading extra scripts or CSS into the header of a web page, redirecting people away from pages, logging statistics, and more. User User plugins allow us to perform actions at different times with respect to users. Such times include logging in and out, and also when saving changes to a user's profile. User plugins are often used to create a "bridge" between Joomla! and other web applications (such as the phpBB forum or the osCommerce e-commerce platform.). XML-RPC XML-RPC plugins are for communicating between our Joomla! site and other external applications, such as a desktop application or a different web site. Plugin events As a Joomla! site loads a page, it steps through a series of events as part of that process. The events it steps through are determined by the type of page it is loading. Plugins are always tied to one or more of these events, and are executed during those events as required. When loading a page of content, for example, we would step through a mix of the system and some of the content events. When loading the same page for editing, we will step through the system events, different content events, and also possibly editor events. The events triggered in Joomla! are: Authentication onAuthenticate Content onPrepareContent onAfterDisplayTitle onBeforeDisplayContent onBeforeContentSave onAfterContentSave Editors onInit onGetContent onSetContent onSave onDisplay onGetInsertMethod Editors XTD (Extended) onDisplay Search onSearch onSearchAreas System onAfterInitialise onAfterRoute onAfterDispatch onAfterRender User onLoginUsexr onLoginFailure onLogoutUser onLogoutFailure onBeforeStoreUser onAfterStoreUser onBeforeDeleteUser onAfterDeleteUser XML-RPC onGetWebServices Most of these events are easy to understand from their name, but just in case, more information can be found on the Joomla! documentation wiki at http://docs.joomla.org/CategoryPlugins. Some events are only activated at specific times, such as onAuthenticate, which is only activated when someone logs into their account. Others are activated on every page load. Content events are activated on all content pages and only on content pages, not on pages with components other than com_content. Content plugins are also only executed on the main body content itself and don't have access to the template or other module data. So a text replacement content plugin, for example, wouldn't change any text in modules or the template, only in the main content itself. It is actually possible for modules and components to manually activate plugin events with clever programming, but this is not the default Joomla! behavior. It is usually done when a developer wants to apply content plugin restrictions/changes to a module. Plugin order Aside from the events and types, there is a third important factor to consider when setting up our plugins. That is the order in which the plugins of a particular type are executed. This order is best observed on the Plugin Manager screen that can be found under the Extensions menu. The order in which the plugins execute is something not many people think about, but is really quite powerful and useful. This is because the plugins which execute later, can then use the output or effects of the earlier executing plugins as input. For example, imagine we have a plugin that displays different text for different user types, and we have another plugin that reads certain text values and replaces them with embedded video or audio. If we wanted to be able to show different videos to different groups, then we could use the first plugin to generate the different command strings for the second plugin, and have it generate them based on the user type. The second plugin, our media embedding plugin, doesn't even know that the first plugin exists. All it knows is which videos it needs to display based on what is in the content item. If the media plugin executes first, then it will generate both videos regardless of the user type. As another example, imagine we have some sort of external application and we log users into it after they authenticate via an authentication plugin. We need to make sure that this plugin is executed after all of our other authentication plugins that may check a user's credentials or account status. Otherwise, someone may get logged into our external application even though they were prevented from login into our Joomla! site. So a hacker, for example, could get access to our external application without needing to even successfully get into our main site. This was all because we had the order of our plugins wrong. So when we install and activate plugins, it is well worth taking the time to double check that everything happens in the order it is meant to be in. If one of our plugins is not behaving how it should, it might be worth checking the order to see if another plugin is conflicting with it. Customizing a Plugin Now that we have a better understanding of how our plugins work and fit together, we are going to try our hand at customizing one for our site. This will hopefully give us the understanding and confidence to make any other customizations we need in the future. As with modules, it is often easier to find a plugin that does most of what we want it to do and then make changes to it so that it meets our needs more completely. Looking back over our goals, one that requires a plugin is that we want to limit access to certain parts of our content to only our paying subscribers. This effect is going to be best achieved via content plugin, so we chose the Ninja Access plugin to fill this need. To use Ninja Access we first need to mark the content we want to restrict with special tags and indicate the user groups we want to see what is contained within the tags. When the page is produced, the plugin reads the visitor's user group and then compares it to the ones in the list provided by the tag. If the user groups match, then the content is displayed, if not, then it is hidden. For example: {njaccess 0}shows only to guest users{/njaccess}{njaccess 18,19,20,21,23,24,25}shows to all users who are not a guest{/njaccess} The numbers in the examples above indicate the default Joomla! user group ids. The most important ones are: 0 = Guests 18 = Registered 24 = Administrators 25 = Super Administrators We could use this as it is, but as we don't have a component installed to create new access groups, it won't be very flexible. We could get into trouble in the future if we decide to let people register without getting a subscription, or create a free subscription. In this instance, we will have paying and free subscribers all in the number 18 user group. Also, as we are always going to be restricting the same groups, we don't really need to type the parameters in every single time. Making our plugins always restrict the same groups automatically will save us some time and reduce mistakes. Lastly, do we really need to type njaccess every time? Let's shorten it to something like soc—subscriber only content. For our first dilemma, a better idea than groups might be to associate the access to certain AEC subscriptions that are currently active. That way if people's subscriptions expire, or they get a free account, the content is still properly controlled regardless of their user groups.
Read more
  • 0
  • 0
  • 2042
Modal Close icon
Modal Close icon