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

How-To Tutorials

7018 Articles
article-image-find-and-install-add-ons-expand-plone-functionality
Packt
10 Jun 2010
11 min read
Save for later

Find and Install Add-Ons that Expand Plone Functionality

Packt
10 Jun 2010
11 min read
(For more resources on Plone, see here.) Background It seems like every application platform uses a different name for its add-ons: modules, components, libraries, packages, extensions, plug-ins, and more. Add-on packages for the Zope web application server are generally called Products. A Zope product is a bundle of Zope or Plone functionality contained in a Python module or modules. Like Plone, add-on products are distributed in source code, so that you may always read and examine them. Plone itself is actually a set of tightly connected Zope products and Python modules. Plone add-on products may be divided into three major categories: Skins or themes that change Plone’s look and feel or add visual elements like portlets. These are typically the simplest of Plone products. Products that add new content types with specialized functionality. Some are simple extensions of built-in types, others have custom workflows and behaviours. Products that add to or change the behaviour of Plone itself. Where to Find Products Plone.org’s Products section at http://plone.org/products is the place to look for Plone products. At the time of this writing, the Plone.org contains listings for 765 products and 1,901 product releases. The Plone Products section is itself built with a Plone product, the Plone Software Center – often called the PSC – that adds content types for projects, software releases, project roadmaps, issue trackers, and project documentation. Using the Plone Product Pages Visiting the Plone product pages for the first time may be a bewildering experience due to the number of available products. However, by specifying a product category and target Plone version, you will quickly narrow the product selection to the point where it’s worth reading descriptions and following the links to product pages. Product pages typically contain product descriptions, software releases, and a list of available documentation, issue tracker, version control repository, and contact resources. Each release will have release notes, a change log, and a list of Plone versions with which the release has been tested. If the release has a product package available, it will be available here for download. Some releases do not have associated software packages. This may be because the release is still in a planning stage, and the listing is mainly meant to document the product’s development roadmap; or because the development is still in an early stage, and the software is only available from a version-control repository. The release notes commonly include a list of dependencies, and you should make special note of that along with compatible Plone versions. Many products require the installation of other, supporting products. Some require that your server or test workstation have particular system libraries or utilities. Product pages may also have links to a variety of additional resources: product-specific documentation, other release pages, an issue tracker, a roadmap for future development, contact form for the project, and a version-control repository. Playing it Safe with Add-On Products Plone 3 is probably one of the most rigorously tested open-source software packages in existence. While no software is defect free, Plone’s core development team is on the leading edge of software development methodologies and work under a strong testing culture that requires that they prove their components work correctly before they ever become part of Plone. Plone’s library of add-on products is a very different story. Add-on products are contributed by a diverse community of developers. Some add-on products follow the same development and maintenance methodologies as Plone itself; others are haphazard experiments. To complicate matters, today’s haphazard experiment may be – if it succeeds – next year’s rigorously developed and reliable product. (Much of the Plone core codebase began as add-on products.) And, this year’s reliable standby may lose the devotion of its developers and not be upgraded to work with the next version of Plone. If you’re new to the world of open source software, this may seem dismaying. Don’t be discouraged. It is not hard to evaluate the status of a product, and the Plone community is happy to help. Be encouraged by evidence of continual, exciting innovation. Most importantly, stop thinking of yourself as a consumer. Take an interest in the community process that produces good products. Test some early releases and file bug reports and feature requests. Participate in, or help document, test, and fund the development of the products that are most important to you. Product Choice Strategy Trying out new Plone add-on products is great fun, but incorporating them into production websites requires planning and judgement if you’re going to have good long-run results. New versions of Plone pose a particular challenge. Major new releases of Plone don’t just add features: with every major version of Plone the application programming interface (API) and presentation templates change. This is not done arbitrarily, and there is usually a good deal of warning before a major change, but it means that add-on products often need to be updated before they will work with a major new version of Plone. Probably worthwhile to point out that major versions are released very ~18 months, and that minor version upgrades generally do not pose compatibility problems for the vast majority of add-on products. This means that when a new version of Plone appears on the scene, you won’t be able to migrate your Plone site to use it until compatible product versions are available for all the add-on products in use on the site. If you’re using mainstream, well-supported products, this may happen very quickly. Many products are upgraded to work with new Plone versions during the beta and release-candidate stages of Plone development. Some products take longer, and some may not make the jump at all. The products least likely to be updated are often ones made obsolete by new functionality. This creates a somewhat ironic situation when a new version of Plone arrives: the quickest adopters are often those with the least history with the platform. The slowest adopters are sometimes the sites that are most heavily invested in the new features. Consider, as a prime example, Plone.org, a very active, very large, community site which must be conservatively managed and stick with proven versions of add-on products. Plone.org often does not migrate to a new Plone version until many months after release. Is this a problem? Not really – unless you need both the newest features of the newest Plone version and the functionality of a more slowly developed add-on product. If that’s the case, prepare to make an investment of time or money in supporting product development and possibly writing some custom migration scripts. If you want to be more conservative, try the following strategy: Enjoy testing many products and keeping up with new developments by trying them out on a test server. Learn the built-in Plone functionality well, and use it in preference to add-on products whenever possible. Make sure you have a good understanding of the maturity level and degree of developer support for add-on products. Incorporate the smallest number of add-on products reasonably possible into your production sites. Don’t be just a consumer: when you commit to a product, help support it by filing bug reports and feature requests, contributing translations, documentation or code, and answering questions about it on the Plone mailing lists or #plone IRC channel. Evaluating a Product Judging the maturity of a Plone product is generally easy. Start with a product’s project page on Plone.org. The product page may offer you a "Current release" and one or more "Experimental releases". Anything marked as a current release should be stable on its tested Plone versions. If you need a release to work with an earlier version of Plone than the ones supported by the current release, follow the "List all releases..." link. Releases in the "Experimental" list will be marked as "alpha", "beta", or "Release Candidate." These terms are well-defined in practice: Alpha releases are truly experimental, and are usually posted in order to get early feedback. Interfaces and implementations are likely still in flux. Download an alpha release only for testing in an experimental environment, and only for purposes of previewing new features and giving feedback to developers. Do not plan on keeping any content you develop using an alpha release, as there may be no upgrade path to later releases. With a beta release, feature sets and programming interfaces should be stable or changing only incrementally. It’s reasonable to start testing the integration of the product with the platform and with other products. There will typically be an upgrade path to future releases. Bug reports will be welcome and will help develop the product. Release candidates have a fixed feature set and no known major issues. Templates and messages should be complete, so that translators may work on language files with some confidence that their work won’t be lost. If you encounter a bug in release-candidate products, please immediately file an issue report. Products may be re-released repeatedly at any release state. For alpha, beta and RC releases, each additional release changes the release count, but not the version number. So, "PloneFormGen 1.2" (Beta release 6) is the sixth beta release of version 1.2 of PloneFormGen. Once a product release reaches current release status, new releases for maintenance will increment the version number by 0.0.1. "PloneFormGen 1.1.3" is thus the third maintenance release of version 1.1 of that product. Don’t make too much of version numbers or release counts. Release status is a better indicator of maturity. If your site is mission-critical, don’t use beta releases on it. However, if you test carefully before deploying, you may find that some products are ready for live use when late in their beta development on sites where an error or glitch wouldn’t be intolerable. Testing a Product Conscientious Plone site administrators maintain an off-line mirror of their production sites on a secondary server – or even a desktop computer – that they may use for testing purposes. Always test a new product on a test server. Before deploying, test it on a server that has precisely the combination of products in use on your production server. Ideally, test with a copy of the database of your live server. Check the functionality of not only the new product, but also the products you’re already using. The latter is particularly important if you’re using products that alter the base functionality of Plone or Zope. Looking to the Future Evaluating product maturity and testing the product will help you judge its current status, but what about the future? What are the signs of a product that’s likely to be well-maintained and available for future versions of Plone? There are no guarantees, but here are some signs that experienced Plone integrators look for: Developing in public. This is open-source software. Look to see if the product is being developed with a public roadmap for the future, and with a public version-control repository. Plone.org provides product authors with great tools for indicating release plans, and makes a Subversion (SVN) version-control repository available to all product authors. Look to see if they’re using these facilities. Issue tracker status. Every released product should have a public issue (bug) tracker. Look for it. Look to see if it’s being maintained, and if issues are actively responded to. No issue tracker, or lots of old, uncategorized issues are bad signs. Support for multiple Plone versions. If a product has been around a while look to see if versions are available for at least a couple of Plone releases. This might be the previous and current releases, or the current and next releases. Internationalization. Excellent products attract translations. Good development methodologies. This is the hardest criterion for a non-developer to judge, but a forthcoming version of the Plone Software Center will ask developers to rate themselves on compliance with a set of community standards. My guess is that product developers will be pretty honest about these ratings. Several of these criteria have something in common: they allow the Plone community to participate in product maintenance and development. The best projects belong to the community, and not any single author. One of the best ways to get a quick read on the quality of an add-on product is to hop on the #plone IRC channel and ask. Chances are you’ll run into someone who can share their experiences and offer insight. You may even run into the product author him/herself!
Read more
  • 0
  • 0
  • 3367

article-image-modeling-relationships-gorm
Packt
09 Jun 2010
6 min read
Save for later

Modeling Relationships with GORM

Packt
09 Jun 2010
6 min read
(For more resources on Groovy DSL, see here.) Storing and retrieving simple objects is all very well, but the real power of GORM is that it allows us to model the relationships between objects, as we will now see. The main types of relationships that we want to model are associations, where one object has an associated relationship with another, for example, Customer and Account, composition relationships, where we want to build an object from sub components, and inheritance, where we want to model similar objects by describing their common properties in a base class. Associations Every business system involves some sort of association between the main business objects. Relationships between objects can be one-to-one, one-to-many, or many-to-many. Relationships may also imply ownership, where one object only has relevance in relation to another parent object. If we model our domain directly in the database, we need to build and manage tables, and make associations between the tables by using foreign keys. For complex relationships, including many-to-many relationships, we may need to build special tables whose sole function is to contain the foreign keys needed to track the relationships between objects. Using GORM, we can model all of the various associations that we need to establish between objects directly within the GORM class definitions. GORM takes care of all of the complex mappings to tables and foreign keys through a Hibernate persistence layer. One-to-one The simplest association that we need to model in GORM is a one-to-one association. Suppose our customer can have a single address; we would create a new Address domain class using the grails create-domain-class command, as before. class Address { String street String city static constraints = { }} To create the simplest one-to-one relationship with Customer, we just add an Address field to the Customer class. class Customer { String firstName String lastName Address address static constraints = { }} When we rerun the Grails application, GORM will recreate a new address table. It will also recognize the address field of Customer as an association with the Address class, and create a foreign key relationship between the customer and address tables accordingly. This is a one-directional relationship. We are saying that a Customer "has an" Address but an Address does not necessarily "have a" Customer. We can model bi-directional associations by simply adding a Customer field to the Address. This will then be reflected in the relational model by GORM adding a customer_id field to the address table. class Address { String street String city Customer customer static constraints = { } }mysql> describe address;+-------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment || version | bigint(20) | NO | | | || city | varchar(255) | NO | | | || customer_id | bigint(20) | YES | MUL | NULL | || street | varchar(255) | NO | | | |+-------------+--------------+------+-----+---------+----------------+5 rows in set (0.01 sec)mysql> These basic one-to-one associations can be inferred by GORM just by interrogating the fields in each domain class via reflection and the Groovy metaclasses. To denote ownership in a relationship, GORM uses an optional static field applied to a domain class, called belongsTo. Suppose we add an Identity class to retain the login identity of a customer in the application. We would then use class Customer { String firstName String lastName Identity ident}class Address { String street String city}class Identity { String email String password static belongsTo = Customer} Classes are first-class citizens in the Groovy language. When we declare static belongsTo = Customer, what we are actually doing is storing a static instance of a java.lang.Class object for the Customer class in the belongsTo field. Grails can interrogate this static field at load time to infer the ownership relation between Identity and Customer. Here we have three classes: Customer, Address, and Identity. Customer has a one-to-one association with both Address and Identity through the address and ident fields. However, the ident field is "owned" by Customer as indicated in the belongsTo setting. What this means is that saves, updates, and deletes will be cascaded to identity but not to address, as we can see below. The addr object needs to be saved and deleted independently of Customer but id is automatically saved and deleted in sync with Customer. def addr = new Address(street:"1 Rock Road", city:"Bedrock")def id = new Identity(email:"email", password:"password")def fred = new Customer(firstName:"Fred", lastName:"Flintstone", address:addr,ident:id)addr.save(flush:true)assert Customer.list().size == 0assert Address.list().size == 1assert Identity.list().size == 0fred.save(flush:true)assert Customer.list().size == 1assert Address.list().size == 1assert Identity.list().size == 1fred.delete(flush:true)assert Customer.list().size == 0assert Address.list().size == 1assert Identity.list().size == 0addr.delete(flush:true)assert Customer.list().size == 0assert Address.list().size == 0assert Identity.list().size == 0 Constraints You will have noticed that every domain class produced by the grails create-domain- class command contains an empty static closure, constraints. We can use this closure to set the constraints on any field in our model. Here we apply constraints to the e-mail and password fields of Identity. We want an e-mail field to be unique, not blank, and not nullable. The password field should be 6 to 200 characters long, not blank, and not nullable. class Identity { String email String password static constraints = { email(unique: true, blank: false, nullable: false) password(blank: false, nullable:false, size:6..200) }} From our knowledge of builders and the markup pattern, we can see that GORM could be using a similar strategy here to apply constraints to the domain class. It looks like a pretended method is provided for each field in the class that accepts a map as an argument. The map entries are interpreted as constraints to apply to the model field. The Builder pattern turns out to be a good guess as to how GORM is implementing this. GORM actually implements constraints through a builder class called ConstrainedPropertyBuilder. The closure that gets assigned to constraints is in fact some markup style closure code for this builder. Before executing the constraints closure, GORM sets an instance of ConstrainedPropertyBuilder to be the delegate for the closure. We are more accustomed to seeing builder code where the Builder instance is visible. def builder = new ConstrainedPropertyBuilder()builder.constraints {} Setting the builder as a delegate of any closure allows us to execute the closure as if it was coded in the above style. The constraints closure can be run at any time by Grails, and as it executes the ConstrainedPropertyBuilder, it will build a HashMap of the constraints it encounters for each field. We can illustrate the same technique by using MarkupBuilder and NodeBuilder. The Markup class in the following code snippet just declares a static closure named markup. Later on we can use this closure with whatever builder we want, by setting the delegate of the markup to the builder that we would like to use. class Markup { static markup = { customers { customer(id:1001) { name(firstName:"Fred", surname:"Flintstone") address(street:"1 Rock Road", city:"Bedrock") } customer(id:1002) { name(firstName:"Barney", surname:"Rubble") address(street:"2 Rock Road", city:"Bedrock") } } }}Markup.markup.setDelegate(new groovy.xml.MarkupBuilder())Markup.markup() // Outputs xmlMarkup.markup.setDelegate(new groovy.util.NodeBuilder())def nodes = Markup.markup() // builds a node tree
Read more
  • 0
  • 0
  • 4844

article-image-implementing-wcf-service-real-world
Packt
09 Jun 2010
18 min read
Save for later

Implementing a WCF Service in the Real World

Packt
09 Jun 2010
18 min read
WCF is the acronym for Windows Communication Foundation. It is Microsoft's latest technology that enables applications in a distributed environment to communicate with each other. In this article by, Mike Liu, author of  WCF 4.0 Multi-tier Services Development with LINQ to Entities, we will create and test the WCF service by following these steps: Create the project using a WCF Service Library template Create the project using a WCF Service Application template Create the Service Operation Contracts Create the Data Contracts Add a Product Entity project Add a business logic layer project Call the business logic layer from the service interface layer Test the service Here ,In this article, we will learn how to separate the service interface layer from the business logic layer (Read more interesting articles on WCF 4.0 here.) Why layer a service? An important aspect of SOA design is that service boundaries should be explicit, which means hiding all the details of the implementation behind the service boundary. This includes revealing or dictating what particular technology was used. Furthermore, inside the implementation of a service, the code responsible for the data manipulation should be separated from the code responsible for the business logic. So in the real world, it is always good practice to implement a WCF service in three or more layers. The three layers are the service interface layer, the business logic layer, and the data access layer. Service interface layer: This layer will include the service contracts and operation contracts that are used to define the service interfaces that will be exposed at the service boundary. Data contracts are also defined to pass in and out of the service. If any exception is expected to be thrown outside of the service, then Fault contracts will also be defined at this layer. Business logic layer: This layer will apply the actual business logic to the service operations. It will check the preconditions of each operation, perform business activities, and return any necessary results to the caller of the service. Data access layer: This layer will take care of all of the tasks needed to access the underlying databases. It will use a specific data adapter to query and update the databases. This layer will handle connections to databases, transaction processing, and concurrency controlling. Neither the service interface layer nor the business logic layer needs to worry about these things. Layering provides separation of concerns and better factoring of code, which gives you better maintainability and the ability to split out layers into separate physical tiers for scalability. The data access code should be separated into its own layer that focuses on performing translation services between the databases and the application domain. Services should be placed in a separate service layer that focuses on performing translation services between the service-oriented external world and the application domain. The service interface layer will be compiled into a separate class assembly and hosted in a service host environment. The outside world will only know about and have access to this layer. Whenever a request is received by the service interface layer, the request will be dispatched to the business logic layer, and the business logic layer will get the actual work done. If any database support is needed by the business logic layer, it will always go through the data access layer. Creating a new solution and project using WCF templates We need to create a new solution for this example and add a new WCF project to this solution. This time we will use the built-in Visual Studio WCF templates for the new project. Using the C# WCF service library template There are a few built-in WCF service templates within Visual Studio 2010; two of them are Visual Studio WCF Service Library and Visual Studio WCF Service Application. In this article, we will use the service library template. Follow these steps to create the RealNorthwind solution and the project using the service library template: Start Visual Studio 2010, select menu option File New | Project…|, and you will see the New Project dialog box. From this point onwards, we will create a completely new solution and save it in a different location. In the New Project window, specify Visual C# WCF | WCF| Service Library as the project template, RealNorthwindService as the (project) name, and RealNorthwind as the solution name. Make sure that the checkbox Create directory for solution is selected. Click on the OK button, and the solution is created with a WCF project inside it. The project already has an IService1.cs file to define a service interface and Service1.cs to implement the service. It also has an app.config file, which we will cover shortly. Using the C# WCF service application template Instead of using the Visual Studio WCF Service Library template to create our new WCF project, we can use the Visual Studio Service Application template to create the new WCF project. Because we have created the solution, we will add a new project using the Visual Studio WCF Service Application template. Right-click on the solution item in Solution Explorer, select menu option Add New Project…| from the context menu, and you will see the Add New Project dialog box. In the Add New Project window, specify Visual C# | WCF Service Application as the project template, RealNorthwindService2 as the (project) name, and leave the default location of C:SOAWithWCFandLINQProjectsRealNorthwind unchanged. Click on the OK button and the new project will be added to the solution.The project already has an IService1.cs file to define a service interface, and Service1.svc.cs to implement the service. It also has a Service1.svc file and a web.config file, which are used to host the new WCF service. It has also had the necessary references added to the project such as System.ServiceModel. You can follow these steps to test this service: Change this new project, RealNorthwindService2, to be the startup project(right-click on it from Solution Explorer and select Set as Startup Project). Then run it (Ctrl + F5 or F5). You will see that it can now run. You will see that ASP.NET Development Server has been started, and a browser is open listing all of the files under the RealNorthwindService2 project folder.Clicking on the Service1.svc file will open the metadata page of the WCF service in this project. If you have pressed F5 in the previous step to run this project, you might see a warning message box asking you if you want to enable debugging for the WCF service. As we said earlier, you can choose enable debugging or just run in the non-debugging mode. You may also have noticed that the WCF Service Host is started together with ASP.NET Development Server. This is actually another way of hosting a WCF service in Visual Studio 2010. It has been started at this point because, within the same solution, there is a WCF service project (RealNorthwindService) created using the WCF Service Library template. So far we have used two different Visual Studio WCF templates to create two projects. The first project, using the C# WCF Service Library template, is a more sophisticated one because this project is actually an application containing a WCF service, a hosting application (WcfSvcHost), and a WCF Test Client. This means that we don't need to write any other code to host it, and as soon as we have implemented a service, we can use the built-in WCF Test Client to invoke it. This makes it very convenient for WCF development. The second project, using the C# WCF Service Application template, is actually a website. This is the hosting application of the WCF service so you don't have to create a separate hosting application for the WCF service. As we have already covered them and you now have a solid understanding of these styles, we will not discuss them further. But keep in mind that you have this option, although in most cases it is better to keep the WCF service as clean as possible, without any hosting functionalities attached to it. To focus on the WCF service using the WCF Service Library template, we now need to remove the project RealNorthwindService2 from the solution. In Solution Explorer, right-click on the RealNorthwindService2 project item and select Remove from the context menu. Then you will see a warning message box. Click on the OK button in this message box and the RealNorthwindService2 project will be removed from the solution. Note that all the files of this project are still on your hard drive. You will need to delete them using Windows Explorer. Creating the service interface layer In this article, we will create the service interface layer contracts. Because two sample files have already been created for us, we will try to reuse them as much as possible. Then we will start customizing these two files to create the service contracts. Creating the service interfaces To create the service interfaces, we need to open the IService1.cs file and do the following: Change its namespace from RealNorthwindService to: MyWCFServices.RealNorthwindService Change the interface name from IService1 to IProductService. Don't be worried if you see the warning message before the interface definition line, as we will change the web.config file in one of the following steps. Change the first operation contract definition from this line: string GetData(int value); to this line: Product GetProduct(int id); Change the second operation contract definition from this line: CompositeType GetDataUsingDataContract(CompositeType composite); to this line: bool UpdateProduct(Product product); Change the filename from IService1.cs to IProductService.cs. With these changes, we have defined two service contracts. The first one can be used to get the product details for a specific product ID, while the second one can be used to update a specific product. The product type, which we used to define these service contracts, is still not defined. The content of the service interface for RealNorthwindService.ProductService should look like this now: using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace MyWCFServices.RealNorthwindService{ [ServiceContract] public interface IProductService { [OperationContract] Product GetProduct(int id); [OperationContract] bool UpdateProduct(Product product); // TODO: Add your service operations here }} This is not the whole content of the IProductService.cs file. The bottom part of this file should still have the class, CompositeType. Creating the data contracts Another important aspect of SOA design is that you shouldn't assume that the consuming application supports a complex object model. One part of the service boundary definition is the data contract definition for the complex types that will be passed as operation parameters or return values. For maximum interoperability and alignment with SOA principles, you should not pass any .NET-specific types such as DataSet or Exceptions across the service boundary. You should stick to fairly simple data structure objects such as classes with properties and backing member fields. You can pass objects that have nested complex types such as 'Customer with an Order collection'. However, you shouldn't make any assumption about the consumer being able to support object-oriented constructs such as inheritance or base-classes for interoperable web services. In our example, we will create a complex data type to represent a product object. This data contract will have five properties: ProductID, ProductName, QuantityPerUnit, UnitPrice, and Discontinued. These will be used to communicate with client applications. For example, a supplier may call the web service to update the price of a particular product or to mark a product for discontinuation. It is preferable to put data contracts in separate files within a separate assembly but, to simplify our example, we will put DataContract in the same file as the service contract. We will modify the file, IProductService.cs, as follows: Change the DataContract name from CompositeType to Product. Change the fields from the following lines: bool boolValue = true;string stringValue = "Hello "; to these seven lines: int productID;string productName;string quantityPerUnit;decimal unitPrice;bool discontinued; Delete the old boolValue and StringValue DataMember properties. Then, for each of the above fields, add a DataMember property. For example, for productID, we will have this DataMember property: [DataMember]public int ProductID{ get { return productID; } set { productID = value; }} A better way is to take advantage of the automatic property feature of C#, and add the following ProductID DataMember without defining the productID field: [DataMember]public int ProductID { get; set; } To save some space, we will use the latter format. So, we need to delete all of those field definitions and add an automatic property for each field, with the first letter capitalized. The data contract part of the finished service contract file, IProductService.cs,should now look like this: [DataContract]public class Product{ [DataMember] public int ProductID { get; set; } [DataMember] public string ProductName { get; set; } [DataMember] public string QuantityPerUnit { get; set; } [DataMember] public decimal UnitPrice { get; set; } [DataMember] public bool Discontinued { get; set; }} Implementing the service contracts To implement the two service interfaces that we defined, open the Service1.cs file and do the following: Change its namespace from RealNorthwindService to MyWCFServices.RealNorthwindService. Change the class name from Service1 to ProductService. Make it inherit from the IProductService interface, instead of IService1. The class definition line should be like this: public class ProductService : IProductService Delete the GetData and GetDataUsingDataContract methods. Add the following method, to get a product: public Product GetProduct(int id){ // TODO: call business logic layer to retrieve product Product product = new Product(); product.ProductID = id; product.ProductName = "fake product name from service layer"; product.UnitPrice = (decimal)10.0; return product;} In this method, we created a fake product and returned it to the client.Later, we will remove the hard-coded product from this method and call the business logic to get the real product. Add the following method to update a product: public bool UpdateProduct(Product product){ // TODO: call business logic layer to update product if (product.UnitPrice <= 0) return false; else return true;} Also, in this method, we don't update anything. Instead, we always return true if a valid price is passed in. Change the filename from Service1.cs to ProductService.cs. The content of the ProductService.cs file should be like this: using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace MyWCFServices.RealNorthwindService{ public class ProductService : IProductService { public Product GetProduct(int id) { // TODO: call business logic layer to retrieve product Product product = new Product(); product.ProductID = id; product.ProductName = "fake product name from service layer"; product.UnitPrice = (decimal)10; return product; } public bool UpdateProduct(Product product) { // TODO: call business logic layer to update product if (product.UnitPrice <= 0) return false; else return true; } }} Modifying the app.config file Because we have changed the service name, we have to make the appropriate changes to the configuration file. Note that when you rename the service, if you have used the refactor feature of Visual Studio, some of the following tasks may have been done by Visual Studio. Follow these steps to change the configuration file: Open the app.config file from Solution Explorer. Change all instances of the RealNorthwindService string except the one in baseAddress to MyWCFServices.RealNorthwindService. This is for the namespace change. Change the RealNorthwindService string in baseAddress to MyWCFServices/RealNorthwindService. Change all instances of the Service1 string to ProductService. This is for the actual service name change. Change the service address port from 8731 to 8080. This is to prepare for the client application, which we will create soon. You can also change Design_Time_Addresses to whatever address you want, or delete the baseAddress part from the service. This can be used to test your service locally. We will leave it unchanged for our example. The content of the app.config file should now look like this: <?xml version="1.0" encoding="utf-8" ?><configuration> <system.web> <compilation debug="true" /> </system.web> <!-- When deploying the service library project, the content of the config file must be added to the host's app.config file. System.Configuration does not support config files for libraries. --> <system.serviceModel> <services> <service name="MyWCFServices.RealNorthwindService. ProductService"> <endpoint address="" binding="wsHttpBinding" contract="MyWCFServices. RealNorthwindService.IProductService"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8080/Design_Time_ Addresses/MyWCFServices/ RealNorthwindService/ProductService/" /> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="True"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration> Testing the service using WCF Test Client Because we are using the WCF Service Library template in this example, we are now ready to test this web service. As we pointed out when creating this project, this service will be hosted in the Visual Studio 2010 WCF Service Host environment. To start the service, press F5 or Ctrl + F5. WcfSvcHost will be started and WCF Test Client is also started. This is a Visual Studio 2010 built-in test client for WCF Service Library projects. In order to run the WCF Test Client you have to log into your machine as a local administrator. You also have to start Visual Studio as an administrator because we have changed the service port from 8732 to 8080 (port 8732 is pre-registered but 8080 is not). Again, if you get an Access is denied error, make sure you run Visual Studio as an administrator (under Windows XP you need to log on as an administrator). Now from this WCF Test Client we can double-click on an operation to test it.First, let us test the GetProduct operation. Now the message Invoking Service… will be displayed in the status bar as the client is trying to connect to the server. It may take a while for this initial connection to be made as several things need to be done in the background. Once the connection has been established, a channel will be created and the client will call the service to perform the requested operation. Once the operation has been completed on the server side, the response package will be sent back to the client, and the WCF Test Client will display this response in the bottom panel. If you started the test client in debugging mode (by pressing F5), you can set a breakpoint at a line inside the GetProduct method in the RealNorthwindService.cs file, and when the Invoke button is clicked, the breakpoint will be hit so that you can debug the service as we explained earlier. However, here you don't need to attach to the WCF Service Host. Note that the response is always the same, no matter what product ID you use to retrieve the product. Specifically, the product name is hard-coded, as shown in the diagram. Moreover, from the client response panel, we can see that several properties of the Product object have been assigned default values. Also, because the product ID is an integer value from the WCF Test Client, you can only enter an integer for it. If a non-integer value is entered, when you click on the Invoke button, you will get an error message box to warn you that you have entered a value with the wrong type. Now let's test the operation, UpdateProduct. The Request/Response packages are displayed in grids by default but you have the option of displaying them in XML format. Just select the XML tab at the bottom of the right-side panel, and you will see the XML-formatted Request/Response packages. From these XML strings, you can see that they are SOAP messages. Besides testing operations, you can also look at the configuration settings of the web service. Just double-click on Config File from the left-side panel and the configuration file will be displayed in the right-side panel. This will show you the bindings for the service, the addresses of the service, and the contract for the service. What you see here for the configuration file is not an exact image of the actual configuration file. It hides some information such as debugging mode and service behavior, and includes some additional information on reliable sessions and compression mode. If you are satisfied with the test results, just close the WCF Test Client, and you will go back to Visual Studio IDE. Note that as soon as you close the client, the WCF Service Host is stopped. This is different from hosting a service inside ASP.NET Development Server, where ASP.NET Development Server still stays active even after you close the client.
Read more
  • 0
  • 0
  • 13236

article-image-jsf-20-features-extension
Packt
09 Jun 2010
5 min read
Save for later

JSF 2.0 Features: An Extension

Packt
09 Jun 2010
5 min read
(For more resources on JSF, see here.) JSF declarative event handling Starting with JSF 2.0 the event system has been really improved and the declarative event handling is exposed through a tag, f:event, and an annotation, @NamedEvent. In this recipe, you will see how to work with these two and how to subscribe to events like preRenderComponent, PostAddToView , and so on. Getting ready We developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library. How to do it... Starting with the f:event tag, we can say that this is a simple tag that should be fitted in the right place and configured with its two simple attributes. Speaking of fitting it in the right place, you should know that f:event can be placed in any component that you want—for example we put it in an h:inputText component: <h:inputText value="#{bean.number}"> <f:event type="preRenderComponent" listener="#{bean.initNumber}" /></h:inputText>... As you can see there are two attributes of the f:event tag , named type and listener. The value of the type attribute represents the name of the event for which to install a listener (in our example, we have used the preRenderComponent value—with other words, before the component is rendered). In the following table are the possible values, and the corresponding event type for which the listener action is registered. Value for type attribute Type of event sent to listener method preRenderComponent javax.faces.event.PreRenderComponentEvent postAddToView javax.faces.event.PostAddToViewEvent preValidate javax.faces.event.PreValidateEvent postValidate javax.faces.event.PostValidateEvent The listener attribute's value represents a MethodExpression pointing to a method that will be called when the listener's processEvent method would have been called. In our example, that method is named initNumber and it can be seen in the following managed bean: package beans;import javax.faces.bean.ManagedBean;import javax.faces.bean.SessionScoped;@ManagedBean@SessionScopedpublic class Bean { private String number = ""; public Bean() { } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public void initNumber(){ setNumber("2010"); }} While f:event works only with predefined events, the @NamedEvent provides support for exposing custom events. The application developer can make a custom event available to the page authors using the @NamedEvent annotation . This annotation can be placed on custom events to register them with the runtime, making them available to f:event. When the application starts, JSF scans for a set of annotations, including @NamedEvent. If it is found on a class, the following logic is applied to get the name/names for the event: Get the unqualified class name Cut off the trailing "Event", if present Convert the first character to lower-case Prepend the package name to the lower-cased name The preceding four rules are ignored if the shortName attribute is specified. In this case JSF registers the event by that name. URLs based on specified navigation outcome One of the most requested features in JSF 2.0 was a nice and smooth mechanism for achieving bookmarkability of JSF pages. As you will see in this recipe, this mechanism is finally provided by JSF 2.0 and is a very robust and easy-to-use solution. Getting ready We have developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library. How to do it... Now, let's get into the subject, and let's say that the JSF 2.0 bookmarkability mechanism is based on two new tags, named h:link and h:button. These tags will generate a URL based on the specified navigation outcome. In JSF 2.0, we can make use of implicit navigation, therefore the outcome can be defined in the view or using common navigation rules. OK, enough theory, let's see an example: ...<h:link outcome="page2" value="HelloToYou"> <f:param name="helloparam" value="#{bean.hello}"/></h:link>... In the previous example, we assume no navigation rule, therefore the outcome attribute indicates a navigation to page2.xhtml (the FacesServlet is mapped to *.xhtml). The value attribute indicates text that will be rendered as a link in the page. The f:param will add a query parameter to the generated URL. The result of this component will be: http://localhost:8080/ URLs_based_on_specified_navigation_outcome/ faces/page2.xhtml?helloparam=Adrian The Adrian value comes from a simple managed bean: package beans;import javax.enterprise.context.RequestScoped;import javax.faces.bean.ManagedBean;@ManagedBean@RequestScopedpublic class Bean { private String hello = "Adrian"; public Bean() { } public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; }} You can bookmark this page at any moment and conserve the URL. The h:button works in the same manner except that it renders a button instead of a link. How it works... Before the user uses the component—clicks on the hyperlink—the current view ID and the specified outcome are used to find the target view ID. Afterwards, it is translated into a bookmarkable URL and used as the hyperlink's target. Note that this is true even if the user never activates the component. The target view ID is placed in the attribute named outcome on the new bookmarkable component tags, h:link or/and h:button (those components inherit from a component class named UIOutcomeTarget). Notice that you are not targeting a view ID directly, but rather a navigation outcome, which may be interpreted as a view ID if the matching falls through to implicit navigation. We consider that this is a good place and time to point out some methods of creating the query string parameters, therefore we present them in the order that they are processed: Implicit query string parameter View parameter (the <f:metadata> of the target view ID) Nested <f:param> in UIOutcomeTarget (such as, <h:link>) Nested <view-param> in the navigation case <redirect> element in facesconfig.xml
Read more
  • 0
  • 0
  • 3418

article-image-amazon-simpledb-versus-rdbms
Packt
08 Jun 2010
7 min read
Save for later

Amazon SimpleDB versus RDBMS

Packt
08 Jun 2010
7 min read
(For more resources on SimpleDB, see here.) We have all used a Relational Database Management System (RDBMS) at some point in our careers. These relational databases are ubiquitous and are available from a wide range of companies such as Oracle, Microsoft, IBM, and so on. These databases have served us well for our application needs. However, there is a new breed of applications coming to the forefront in the current Internet-driven and socially networked economy. The new applications require large scaling to meet demand peaks that can quickly reach massive levels. This is a scenario that is hard to satisfy using a traditional relational database, as it is impossible to requisition and provision the hardware and software resources that will be needed to service the demand peaks. It is also non-trivial and difficult to scale a normal RDBMS to hundreds or thousands of nodes. The overwhelming complexity of doing this makes the RDBMS not viable for these kinds of applications. SimpleDB provides a great alternative to an RDBMS and can provide a solution to all these problems. However, in order to provide this solution, SimpleDB makes some choices and design decisions that you need to understand in order to make an informed choice about the data storage for your application domain. No normalization Normalization is a process of organizing data efficiently in a relational database by eliminating redundant data, while at the same time ensuring that the data dependencies make sense. SimpleDB data models do not conform to any of the normalization forms, and tend to be completely de-normalized. The lack of need for normalization in SimpleDB allows you a great deal of flexibility with your model, and enables you to use the power of multi-valued attributes in your data. Let's look at a simple example of a database starting with a basic spreadsheet structure and then design it for an RDBMS and a SimpleDB. In this example, we will create a simple contact database, with contact information as raw data. ID First_Name Last_Name Phone_Num 101 John Smith 555-845-7854 101 John Smith 555-854-9885 101 John Smith 555-695-7485 102 Bill Jones 555-748-7854 102 Bill Jones 555-874-8654 The obvious issue is the repetition of the name data. The table is inefficient and would require care to update to keep the name data in sync. To find a person by his or her phone number is easy. SELECT * FROM Contact_Info WHERE Phone_Num = '555-854-9885' So let's analyze the strengths and weaknesses of this database design. SCORE-Raw data Strength Weakness Efficient storage   No Efficient search by phone number Yes   Efficient search by name   No Easy-to-add another phone number Yes   The design is simple, but as the name data is repeated, it would require care to keep the data in sync. Searching for phone numbers by name would be ugly if the names got out of sync. To improve the design, we can rationalize the data. One approach would be to create multiple phone number fields such as the following. While this is a simple solution, it does limit the phone numbers to three. Add e-mail and Twitter, and the table becomes wider and wider. ID First_Name Last_Name Phone_Num_1 Phone_Num_2 Phone_Num_3 101 John Smith 555-845-7854 555-854-9885 555-695-7485 102 Bill Jones 555-748-7854 555-874-8654   Finding a person by a phone number is ugly. SELECT * FROM Contact_Info WHERE Phone_Num_1 = '555-854-9885'OR Phone_Num_2 = '555-854-9885'OR Phone_Num_3 = '555-854-9885' Now let's analyze the strengths and weaknesses of this database design. SCORE-Rationalize data Strength Weakness Efficient storage Yes   Efficient search by phone number   No Efficient search by name Yes   Easy to add another phone number   No The design is simple, but the phone numbers are limited to three, and searching by phone number involves three index searches. Another approach would be to use a delimited list for the phone number as follows: ID First_Name Last_Name Phone_Nums 101 John Smith 555-845-7854;555-854-9885;555-695-7485 102 Bill Jones 555-748-7854;555-874-8654 This approach has the advantage of no data repetition and is easy to maintain, compact, and extendable, but the only way to find a record by the phone number is with a substring search. SELECT * FROM Contact_Info WHERE Phone_Nums LIKE %555-854-9885% This type of SQL forces a complete table scan. Do this with a small table and no one will notice, but try this on a large database with millions of records, and the performance of the database will suffer. SCORE-Delimited Data Strength Weakness Efficient storage Yes   Efficient search by phone number   No Efficient search by name Yes   Easy to add another phone number Yes   A delimited field is good for data that is of one type and will only be retrieved. The normalization for relational databases results in splitting up your data into separate tables that are related to one another by keys. A join is an operation that allows you to retrieve the data back easily across the multiple tables. Let's first normalize this data. This is the Person_Info table: ID First_Name Last_Name 101 John Smith 102 Bill Jones And this is the Phone_Info table: ID Phone_Num 101 555-845-7854 101 555-854-9885 101 555-695-7485 102 555-748-7854 102 555-874-8654 Now a join of the Person_Info table with the Phone_Info can retrieve the list of phone numbers as well as the e-mail addresses. The table structure is clean and other than the ID primary key, no data is duplicated. Provided Phone_Num is indexed, retrieving a contact by the phone number is efficient. SELECT First_Name, Last_Name, Phone_num, Person_Info.IDFROM Person_Info JOIN Phone_InfoON Person_Info.ID = Phone_Info.IDWHERE Phone_Num = '555-854-9885' So if we analyze the strengths and weaknesses of this database design, we get: SCORE-Relational Data Strength Weakness Efficient storage Yes   Efficient search by phone number Yes   Efficient search by name Yes   Easy to add another phone number Yes   While this is an efficient relational model, there is no join command in SimpleDB. Using two tables would force two selects to retrieve the complete contact information. Let's look at how this would be done using the SimpleDB principles. No joins SimpleDB does not support the concept of joins. Instead, SimpleDB provides you with the ability to store multiple values for an attribute, thus avoiding the necessity to perform a join to retrieve all the values. ID       101 First_Name=John Last_Name=Smith Phone_Num =555-845-7854Phone_Num =555-854-9885Phone_Num =555-695-7485 102 First_Name=Bill Last_Name=Jones Phone_Num =555-748-7854Phone_Num =555-874-8654 In the SimpleDB table, each record is stored as an item with attribute/value pairs. The difference here is that the Phone_Num field has multiple values. Unlike a delimited list field, SimpleDB indexes all values enabling an efficient search each value. SELECT * FROM Contact_Info WHERE Phone_Num = '555-854-9885' This SELECT is very quick and efficient. It is even possible to use Phone_Num multiple times such as follows: SELECT * FROM Contact_Info WHERE Phone_Num = '555-854-9885'OR Phone_Num = '555-748-7854' Let's analyze the strengths and weaknesses of this approach: SCORE-SimpleDB Data Strength Weakness Efficient storage Yes   Efficient search by phone number Yes   Efficient search by name Yes   Easy to add another phone number Yes  
Read more
  • 0
  • 0
  • 2437

article-image-microsoft-dynamics-nav-2009-apply-reverse-engineering-customize-our-application
Packt
08 Jun 2010
6 min read
Save for later

Microsoft Dynamics NAV 2009: Apply reverse engineering to customize our application

Packt
08 Jun 2010
6 min read
(Further on Microsoft Dynamics NAV:here.) Fit-gap analysis When we do a fit-gap analysis we look at the company's processes and define what we can and cannot do with the standard package. When a business process can be handled with the standard software we call this a Fit. When it cannot be done it's a Gap, we can fill a gap by developing a solution or purchasing an add-on. But even when something could be done with standard software features, it does not necessarily mean that doing this is wise. The standard application should be used for what it was designed for. Using standard features for something else might work in the current version but if it changes in a new version it might no longer fit. For this reason it is better to design something new instead of wrongly using standard features. Designing a Squash Court application The basic process of a squash court company is renting the courts to squash players; both members and non-members. There is a reservation and invoicing process handling different rates for members and non-members. Although this could be implemented using items to represent squash courts and customers to represent players this would be a typical example of using standard features wrongly. Instead of doing this we will look at how items and customers are designed and use this to create a new Squash Court application. Look, learn, and love To determine the design for this application we will first look at the parts of the standard application (we could have used) to learn how they work. We will use this knowledge in our own design. In Microsoft Dynamics NAV, customer and vendor master data are maintained using Relationship Management (RM). For our solution we will create a new master data for squash players being the business part of application. This will also be integrated with RM. To design the Squash Court we will look at the design of items in the standard package. The Squash Court will be the product part of our application having a journal to create reservation entries, which we can invoice. For this invoicing process we will use and integrate with the Sales part of Microsoft Dynamics NAV. Drawing the table and posting schema After we have decided what the design of our application will be, we can draw the tables and post the routines. This will clarify the design for others and guide us through the development process. The objects in Relationship Management and Sales are standard objects that we will possibly need to modify. The objects for the Squash Application are new objects but based on similar objects in the standard application. The objects in Relationship Management and Sales are standard objects that we will possibly need to modify. The objects for the Squash Application are new objects but based on similar objects in the standard application. The Project approach In order to keep track of our project we'll cut the changes into smaller tasks. The first task will be to do the changes in Relationship Management to be able to create a squash player from a contact. The second task is to create squash courts. The reservation and invoice processes are tasks three and four. Interfacing with the standard application In our schema we can see that we have two processes where we need to touch the standard Microsoft Dynamics NAV processes, which are Relationship Management and Sales. Getting started In the first part of the design process we will look at how to reverse engineer the standard application in order to learn and reuse the knowledge in our own solution. Creating squash players For our squash players administration we will use the data from the Contact table. In the standard product it is possible to create a customer or vendor with the contact data. We require the same functionality to create squash players so let's have a look at how this is done by Microsoft. Open the contact card and try to find this function (as shown in the following screenshot): We want a function like this for our squash players. So let's get in and see what it does. For this we need to design the page and look at the actions. The page number in this case is 5050 which we can find by clicking on About This Page in the upright corner of the page as shown in the following screenshot: This option can be useful for finding information about the fields that are not on the page, the filters or the source table: To open the page we need to open the Object Designer (Shift F12) in the Classic client as shown in the following screenshot: Here in the Object Designer we can find page 5050, Contact Card, as shown: We are looking for the Actions on this page. They are kind of difficult to find if you are unfamiliar with the Page Designer. To open the Actions, the cursor should be on the blank line below the last populated line. Then press the right mouse button and Actions or select Actions from the View drop down menu: Now we are in the Action Designer and we can search for the Create as part. To see what it does we need to go into the C/AL code by pressing F9 or by selecting C/AL Code from the View drop down menu as shown in the following screenshot: CreateVendor versus CreateCustomer In Microsoft Dynamics NAV there is a small difference between creating a customer and a vendor from a contact. When creating a customer the system will ask us to select a customer template. The vendor option does not have this. Because of this simplicity we will look at and learn from the Vendor function in this article. The customer and vendor table are almost identical in structure and fields are numbered similar in both tables. This is called transaction mirroring between sales and purchasin. We will mirror our new table in a similar way to the other Microsoft Dynamics NAV tables. The C/AL code in the Action tells us that while pushing the menu option, the function CreateVendor in the contact table is started. To copy this feature we need to create a new function CreateSquashPlayer. Let's keep this in mind while we dive further into this code. Open the Contact table (no. 5050), and search the function CreateVendor. You can find functions in a table by going into the C/AL code (F9) from anywhere in the table designer, and use the Find (Ctrl+F) function as shown in the following screenshot:
Read more
  • 0
  • 0
  • 2338
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-grails-object-relational-mapping-gorm
Packt
08 Jun 2010
5 min read
Save for later

The Grails Object Relational Mapping (GORM)

Packt
08 Jun 2010
5 min read
(For more resources on Groovy DSL, see here.) The Grails framework is an open source web application framework built for the Groovy language. Grails not only leverages Hibernate under the covers as its persistence layer, but also implements its own Object Relational Mapping layer for Groovy, known as GORM. With GORM, we can take a POGO class and decorate it with DSL-like settings in order to control how it is persisted. Grails programmers use GORM classes as a mini language for describing the persistent objects in their application. In this section, we will do a whistle-stop tour of the features of Grails. This won't be a tutorial on building Grails applications, as the subject is too big to be covered here. Our main focus will be on how GORM implements its Object model in the domain classes. Grails quick start Before we proceed, we need to install Grails and get a basic app installation up and running. The Grails' download and installation instructions can be found at http://www.grails.org/Installation. Once it has been installed, and with the Grails binaries in your path, navigate to a workspace directory and issue the following command: grails create-app GroovyDSL This builds a Grails application tree called GroovyDSL under your current workspace directory. If we now navigate to this directory, we can launch the Grails app. By default, the app will display a welcome page at http://localhost:8080/GroovyDSL/. cd GroovyDSLgrails run-app The grails-app directory The GroovyDSL application that we built earlier has a grails-app subdirectory, which is where the application source files for our application will reside. We only need to concern ourselves with the grails-app/domain directory for this discussion, but it's worth understanding a little about some of the other important directories. grails-app/conf: This is where the Grails configuration files reside. grails-app/controllers: Grails uses a Model View Controller (MVC) architecture. The controller directory will contain the Groovy controller code for our UIs. grails-app/domain: This is where Grails stores the GORM model classes of the application. grails-app/view: This is where the Groovy Server Pages (GSPs), the Grails equivalent to JSPs are stored. Grails has a number of shortcut commands that allow us to quickly build out the objects for our model. As we progress through this section, we will take a look back at these directories to see what files have been generated in these directories for us. In this section, we will be taking a whistle-stop tour through GORM. You might like to dig deeper into both GORM and Grails yourself. You can find further online documentation for GORM at http://www.grails.org/GORM. DataSource configuration Out of the box, Grails is configured to use an embedded HSQL in-memory database. This is useful as a means of getting up and running quickly, and all of the example code will work perfectly well with the default configuration. Having an in-memory database is helpful for testing because we always start with a clean slate. However, for the purpose of this section, it's also useful for us to have a proper database instance to peek into, in order to see how GORM maps Groovy objects into tables. We will configure our Grails application to persist in a MySQL database instance. Grails allows us to have separate configuration environments for development, testing, and production. We will configure our development environment to point to a MySQL instance, but we can leave the production and testing environments as they are. First of all we need to create a database, by using the mysqladmin command. This command will create a database called groovydsl, which is owned by the MySQL root user. mysqladmin -u root create groovydsl Database configuration in Grails is done by editing the DataSource.groovy source file in grails-app/conf. We are interested in the environments section of this file. environments { development { dataSource { dbCreate = "create-drop" url = "jdbc:mysql://localhost/groovydsl" driverClassName = "com.mysql.jdbc.Driver" username = "root" password = "" } } test { dataSource { dbCreate = "create-drop" url = "jdbc:hsqldb:mem:testDb" } } production { dataSource { dbCreate = "update" url = "jdbc:hsqldb:mem:testDb" } }} The first interesting thing to note is that this is a mini Groovy DSL for describing data sources. In the previous version, we have edited the development dataSource entry to point to the MySQL groovydsl database that we created. In early versions of Grails, there were three separate DataSource files that need to be configured for each environment, for example, DevelopmentDataSource.groovy. The equivalent DevelopmentDataSource.groovy file would be as follows: class DevelopmentDataSource { boolean pooling = true String dbCreate = "create-drop" String url = " jdbc:mysql://localhost/groovydsl " String driverClassName = "com.mysql.jdbc.Driver" String username = "root" String password = ""} The dbCreate field tells GORM what it should do with tables in the database, on startup. Setting this to create-drop will tell GORM to drop a table if it exists already, and create a new table, each time it runs. This will keep the database tables in sync with our GORM objects. You can also set dbCreate to update or create. DataSource.groovy is a handy little DSL for configuring the GORM database connections. Grails uses a utility class—groovu.utl. ConfigSlurper—for this DSL. The ConfigSlurper class allows us to easily parse a structured configuration file and convert it into a java.util.Properties object if we wish. Alternatively, we can navigate the ConfigObject returned by using dot notation. We can use the ConfigSlurper to open and navigate DataSource.groovy as shown in the next code snippet. ConfigSlurper has a built-in ability to partition the configuration by environment. If we construct the ConfigSlurper for a particular environment, it will only load the settings appropriate to that environment. def development = new ConfigSlurper("development").parse(newFile('DataSource.groovy').toURL())def production = new ConfigSlurper("production").parse(newFile('DataSource.groovy').toURL())assert development.dataSource.dbCreate == "create-drop"assert production.dataSource.dbCreate == "update"def props = development.toProperties()assert props["dataSource.dbCreate"] == "create-drop"
Read more
  • 0
  • 0
  • 3389

article-image-jsf-20-features
Packt
07 Jun 2010
6 min read
Save for later

JSF 2.0 Features

Packt
07 Jun 2010
6 min read
(For more resources on JSF, see here.) JSF 2.0 annotations One of the most important and useful features of JSF 2.0 consists in annotations. Based on them, JSF 2.0 provides an easy way to accomplish important tasks. In this recipe, we will present the most commonly used annotations and we will see what they can do for us. How to do it... If you are a JSF 1.2 fan, then you are familiar with the faces-config.xml configuration file. Starting with JSF 2.0, the content of this descriptor can be partially (sometimes totally) replaced with annotations. Annotations for managed beans The most common case is represented by the managed bean, which can be annotated as shown, instead of placing a specific declaration in faces-config.xml: import javax.faces.bean.ManagedBean;@ManagedBeanpublic class MyBean { ...} In the previous example, the bean is referenced as myBean, but you may specify another name, as shown next: @ManagedBean(name="coolBean") And what is a managed bean without a context (a scope)? JSF 2.0 supports an entire list of scope annotation, as shown next: Annotation Annotation Class @RequestScoped javax.faces.bean.RequestScoped @SessionScoped javax.faces.bean.SessionScoped @ApplicationScoped javax.faces.bean.ApplicationScoped @ViewScoped javax.faces.bean.ViewScoped @NoneScoped javax.faces.bean.NoneScoped @CustomScoped(value="#{someMap}") javax.faces.bean.CustomScoped In addition, we can annotate a managed bean's properties using the @ManagedProperty annotation . The presence of this annotation on a field of a class annotated with @ManagedBean instructs the system to inject a value into this property: @ManagedProperty("fooval")private String foo;@ManagedProperty("#{fooval}")private String foo; Going further, you can react to the creation and the destruction of a managed bean, as shown next: public class MyBean { @PostConstruct public void postCreate(){ ... } @PreDestroy public void preDestroy(){ ... } If you use JSF inside of a JEE container you can inject resources, session, message-driven beans, and web services into your managed beans. Something like the following is perfectly legal: @ManagedBean@SessionScopedpublic class MyBean implements Serializable { @EJB private Facade facade;... @ResourceDependency annotation JSF 2.0 specification has added the @ResourceDependency annotation to allow component authors to declare the resources the component will need. For example: @ResourceDependency(name="my.css",library="libus")public class MyComponent extends UIComponentBase { ...} You may use more than one @ResourceDependency using the @ResourceDependencies annotation, as the following: @ResourceDependencies({ @ResourceDependency(name="my.css",library="libus"),@ResourceDependency(name="my.js",library="libus",target="head")})public class MyComponent extends UIComponentBase { ...} Now the components can be used without any knowledge about any of the CSS or JS code. The necessary dependencies will be rendered automatically. The @ListenerFor annotation A component will be annotated with the @ListenerFor annotation to indicate that it is subscribing to a particular set of events. Therefore, we will have two renderers that act as listeners for particular events and that implement the ComponentSystemEventListener interface (a detailed description of this interface is available at http://blogs.sun.com/ rlubke/entry/jsf_2_0_new_feature1, but as a quick description, system events are new in JSF 2.0, and there are system events that are global and others that are related to a component. They are created at various moments of application or request lifetime). Let's see what this looks like: @ListenerFor(systemEventClass=AfterAddToParentEvent.class,sourceClass=UIOutput.class) public class MyRenderer extends Renderer implements ComponentSystemEventListener { ... public void processEvent(ComponentSystemEvent event) throws AbortProcessingException { UIComponent component = event.getComponent(); FacesContext context = FacesContext.getCurrentInstance(); String target = (String)component.getAttributes().get("target"); if (target != null) { context.getViewRoot().addComponentResource(context, component, target); } }...} There is also a plural version, named @ListenersFor. There is one more annotation in which we are interested, named @NamedEvent, which will be discussed in the JSF declarative event handling recipe. How it works... Annotations for managed beans Once you have annotated a class as a managed bean, it can be referred to as a bean with #{beanName.foo}, where beanName is class name (except packages) with the first letter changed to lower case, and "foo" is either an exact method name or a shortcut for a getter and setter method. Regarding managed beans scopes we have: @RequestScope: (this is the default scope of a managed bean). This puts the bean in request scope. It makes a new instance for every HTTP request. Commonly, the bean is instantiated twice, once when form is displayed and once when it is submitted. @SessionScope: This puts a Serializable bean in session scope. When the same user with the same cookie returns then the same bean instance is used (for this, the session timeout should not be expired). @ApplicationScoped: This puts the bean in application scope. All users will have access to this bean, therefore the bean either should have no state or you must manually and carefully synchronize access to it. @ViewScoped: This puts the bean in view scoped. The same bean instance is used as long as the same user is on same page (for example, with AJAX). @CustomScope: This puts the bean in custom scope. The bean is stored in the Map, and the developer can control its lifecycle. @NoneScope: The bean is not put in a scope. Commonly these beans are referenced by other beans that are in scopes. @ViewScoped, @CustomScoped and @NoneScoped are available only in JSF 2.0. @ResourceDependency annotation Once a component is created, it will be added as a child to another component. Before returning from the add() method, the component will be checked for @ResourceDependency annotations (both versions). When the @ResourceDependency is found a new UIOutput component instance is created. The ResourceHandler is queried for an appropriate Renderer based on the content type of the resource. In our case this is text/css, therefore the style sheet renderer will be used as the Renderer for this UIOutput component. The values of the name, library (optional), and target (optional) attributes from the annotation are stored in the component's attribute map. UIViewRoot. addComponentResource() is called passing in the UIOutput and the value of the target attribute from the annotation (if exists). Now when we render the view, for the head renderer we encode each of the resources that have been targeted for the head, like so: ...UIViewRoot viewRoot = context.getViewRoot();for (UIComponent ui_comp:viewRoot.getComponentResources(context,"head")) {ui_comp.encodeAll(context);}... The @ListenerFor annotation When the Renderer for this component is obtained it is queried for @ListenerFor annotations. For each annotation, the Renderer will be added as a component listener for the corresponding event. Going further, when the component is added in the tree, the event is invoked and the processEvent method will be called for adding the component as a resource to the VewRoot with the corresponding target.
Read more
  • 0
  • 0
  • 3373

article-image-customize-backend-component-joomla-15
Packt
04 Jun 2010
13 min read
Save for later

Customize backend Component in Joomla! 1.5

Packt
04 Jun 2010
13 min read
(Read more interesting articles on Joomla! 1.5here.) Itemized data Most components handle and display itemized data. Itemized data is data having many instances; most commonly this reflects rows in a database table. When dealing with itemized data there are three areas of functionality that users generally expect: Pagination Ordering Filtering and searching In this section we will discuss each of these areas of functionality and how to implement them in the backend of a component. Pagination To make large amounts of itemized data easier to understand, we can split the data across multiple pages. Joomla! provides us with the JPagination class to help us handle pagination in our extensions. There are four important attributes associated with the JPagination class: limitstart: This is the item with which we begin a page, for example the first page will always begin with item 0. limit: This is the maximum number of items to display on a page. total: This is the total number of items across all the pages. _viewall: This is the option to ignore pagination and display all items. Before we dive into piles of code, let's take the time to examine the listFooter, the footer that is used at the bottom of pagination lists: The box to the far left describes the maximum number of items to display per page (limit). The remaining buttons are used to navigate between pages. The final text defines the current page out of the total number of pages. The great thing about this footer is we don't have to work very hard to create it! We can use a JPagination object to build it. This not only means that it is easy to implement, but that the pagination footers are consistent throughout Joomla!. JPagination is used extensively by components in the backend when displaying lists of items. In order to add pagination to our revues list we must make some modifications to our backend revues model. Our current model consists of one private property $_revues and two methods: getRevues() and delete(). We need to add two additional private properties for pagination purposes. Let's place them immediately following the existing $_revues property: /** @var array of revue objects */var $_revues = null;/** @var int total number of revues */var $_total = null;/** @var JPagination object */var $_pagination = null; Next we must add a class constructor, as we will need to retrieve and initialize the global pagination variables $limit and $limitstart. JModel objects store a state object in order to record the state of the model. It is common to use the state variables limit and limitstart to record the number of items per page and starting item for the page. We set the state variables in the constructor: /** * Constructor */function __construct(){ global $mainframe; parent::__construct(); // Get the pagination request variables $limit = $mainframe->getUserStateFromRequest( 'global.list.limit', 'limit', $mainframe->getCfg('list_limit')); $limitstart = $mainframe->getUserStateFromRequest( $option.'limitstart', 'limitstart', 0); // Set the state pagination variables $this->setState('limit', $limit); $this->setState('limitstart', $limitstart);} Remember that $mainframe references the global JApplication object. We use the getUserStateFromRequest() method to get the limit and limitstart variables. We use the user state variable, global.list.limit, to determine the limit. This variable is used throughout Joomla! to determine the length of lists. For example, if we were to view the Article Manager and select a limit of five items per page, if we move to a different list it will also be limited to five items. If a value is set in the request value limit (part of the listFooter), we use that value. Alternatively we use the previous value, and if that is not set we use the default value defined in the application configuration. The limitstart variable is retrieved from the user state value $option, plus .limitstart. The $option value holds the component name, for example com_content. If we build a component that has multiple lists we should add an extra level to this, which is normally named after the entity. If a value is set in the request value limitstart (part of the listFooter) we use that value. Alternatively we use the previous value, and if that is not set we use the default value 0, which will lead us to the first page. The reason we retrieve these values in the constructor and not in another method is that in addition to using these values for the JPagination object, we will also need them when getting data from the database. In our existing component model we have a single method for retrieving data from the database, getRevues(). For reasons that will become apparent shortly we need to create a private method that will build the query string and modify our getRevues() method to use it. /** * Builds a query to get data from #__boxoffice_revues * @return string SQL query */function _buildQuery(){ $db =& $this->getDBO(); $rtable = $db->nameQuote('#__boxoffice_revues'); $ctable = $db->nameQuote('#__categories'); $query = ' SELECT r.*, cc.title AS cat_title' . ' FROM ' . $rtable. ' AS r' . ' LEFT JOIN '.$ctable.' AS cc ON cc.id=r.catid; return $query;} We now must modify our getRevues() method: /** * Get a list of revues * * @access public * @return array of objects */function getRevues(){ // Get the database connection $db =& $this->_db; if( empty($this->_revues) ) { // Build query and get the limits from current state $query = $this->_buildQuery(); $limitstart = $this->getState('limitstart'); $limit = $this->getState('limit'); $this->_revues = $this->_getList($query, $limitstart, $limit); } // Return the list of revues return $this->_revues;} We retrieve the object state variables limit and limitstart and pass them to the private JModel method _getList(). The _getList() method is used to get an array of objects from the database based on a query and, optionally, limit and limitstart. The last two parameters will modify the first parameter, a query, in such a way that we only return the desired results. For example if we requested page 1 and were displaying a maximum of five items per page, the following would be appended to the query: LIMIT 0, 5. To handle pagination we need to add a method called getPagination() to our model. This method will handle items we are trying to paginate using a JPagination object. Here is our code for the getPagination() method: /** * Get a pagination object * * @access public * @return pagination object */function getPagination(){ if (empty($this->_pagination)) { // Import the pagination library jimport('joomla.html.pagination'); // Prepare the pagination values $total = $this->getTotal(); $limitstart = $this->getState('limitstart'); $limit = $this->getState('limit'); // Create the pagination object $this->_pagination = new JPagination($total, $limitstart, $limit); } return $this->_pagination;} There are three important aspects to this method. We use the private property $_pagination to cache the object, we use the getTotal() method to determine the total number of items, and we use the getState() method to determine the number of results to display. The getTotal() method is a method that we must define in order to use. We don't have to use this name or this mechanism to determine the total number of items. Here is one way of implementing the getTotal() method: /** * Get number of items * * @access public * @return integer */function getTotal(){ if (empty($this->_total)) { $query = $this->_buildQuery(); $this->_total = $this->_getListCount($query); } return $this->_total;} This method calls our model's private method _buildQuery() to build the query, the same query that we use to retrieve our list of revues. We then use the private JModel method _getListCount()to count the number of results that will be returned from the query. We now have all we need to be able to add pagination to our revues list except for actually adding pagination to our list page. We need to add a few lines of code to our revues/view.html.php file. We will need to access to global user state variables so we must add a reference to the global application object as the first line in our display method: global $mainframe; Next we need to create and populate an array that will contain user state information. We will add this code immediately after the code that builds the toolbar: // Prepare list array$lists = array();// Get the user state$filter_order = $mainframe->getUserStateFromRequest( $option.'filter_order', 'filter_order', 'published');$filter_order_Dir = $mainframe->getUserStateFromRequest( $option.'filter_order_Dir', 'filter_order_Dir', 'ASC');// Build the list array for use in the layout$lists['order'] = $filter_order;$lists['order_Dir'] = $filter_order_Dir;// Get revues and pagination from the model$model =& $this->getModel( 'revues' );$revues =& $model->getRevues();$page =& $model->getPagination();// Assign references for the layout to use$this->assignRef('lists', $lists);$this->assignRef('revues', $revues);$this->assignRef('page', $page); After we create and populate the $lists array, we add a variable $page that receives a reference to a JPagination object by calling our model's getPagination() method. And finally we assign references to the $lists and $page variables so that our layout can access them. Within our layout default.php file we must make some minor changes toward the end of the existing code. Between the closing </tbody> tag and the </table> tag we must add the following: <tfoot> <tr> <td colspan="10"> <?php echo $this->page->getListFooter(); ?> </td> </tr></tfoot> This creates the pagination footer using the JPagination method getListFooter(). The final change we need to make is to add two hidden fields to the form. Under the existing hidden fields we add the following code: <input type="hidden" name="filter_order" value="<?php echo $this->lists['order']; ?>" /><input type="hidden" name="filter_order_Dir" value="" /> The most important thing to notice is that we leave the value of the filter_order_Dir field empty. This is because the listFooter deals with this for us. That is it! We now have added pagination to our page. Ordering Another enhancement that we can add is the ability to sort or order our data by column, which we can accomplish easily using the JHTML grid.sort type. And, as an added bonus, we have already completed a significant amount of the necessary code when we added pagination. Most of the changes to revues/view.html.php that we made for pagination are used for implementing column ordering; we don't have to make a single change. We also added two hidden fields, filter_order and filter_order_Dir, to our layout form, default.php. The first defines the column to order our data and the latter defines the direction, ascending or descending. Most of the column headings for our existing layout are currently composed of simple text wrapped in table heading tags (<th>Title</th> for example). We need to replace the text with the output of the grid.sort function for those columns that we wish to be orderable. Here is our new code: <thead> <tr> <th width="20" nowrap="nowrap"> <?php echo JHTML::_('grid.sort', JText::_('ID'), 'id', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="20" nowrap="nowrap"> <input type="checkbox" name="toggle" value="" onclick="checkAll( <?php echo count($this->revues); ?>);" /> </th> <th width="40%"> <?php echo JHTML::_('grid.sort', JText::_('TITLE'), 'title', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="20%"> <?php echo JHTML::_('grid.sort', JText::_('REVUER'), 'revuer', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="80" nowrap="nowrap"> <?php echo JHTML::_('grid.sort', JText::_('REVUED'), 'revued', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="80" nowrap="nowrap" align="center"> <?php echo JHTML::_('grid.sort', 'ORDER', 'ordering', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="10" nowrap="nowrap"> <?php if($ordering) echo JHTML::_('grid.order', $this->revues); ?> </th> <th width="50" nowrap="nowrap"> <?php echo JText::_('HITS'); ?> </th> <th width="100" nowrap="nowrap" align="center"> <?php echo JHTML::_('grid.sort', JText::_('CATEGORY'), 'category', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> <th width="60" nowrap="nowrap" align="center"> <?php echo JHTML::_('grid.sort', JText::_('PUBLISHED'), 'published', $this->lists['order_Dir'], $this->lists['order'] ); ?> </th> </tr></thead> Let's look at the last column, Published, and dissect the call to grid.sort. Following grid.sort we have the name of the column, filtered through JText::_() passing it a key to our translation file. The next parameter is the sort value, the current order direction, and the current column by which the data is ordered. In order for us to be able to use these headings to order our data we must make a few additional modifications to our JModel class. We created the _buildQuery() method earlier when we were adding pagination. We now need to make a change to that method to handle ordering: /** * Builds a query to get data from #__boxoffice_revues * @return string SQL query */function _buildQuery(){ $db =& $this->getDBO(); $rtable = $db->nameQuote('#__boxoffice_revues'); $ctable = $db->nameQuote('#__categories'); $query = ' SELECT r.*, cc.title AS cat_title' . ' FROM ' . $rtable. ' AS r' . ' LEFT JOIN '.$ctable.' AS cc ON cc.id=r.catid' . $this->_buildQueryOrderBy(); return $query;} Our method now calls a method named _buildQueryOrderBy() that builds the ORDER BY clause for the query: /** * Build the ORDER part of a query * * @return string part of an SQL query */function _buildQueryOrderBy(){ global $mainframe, $option; // Array of allowable order fields $orders = array('title', 'revuer', 'revued', 'category', 'published', 'ordering', 'id'); // Get the order field and direction, default order field // is 'ordering', default direction is ascending $filter_order = $mainframe->getUserStateFromRequest( $option.'filter_order', 'filter_order', 'ordering'); $filter_order_Dir = strtoupper( $mainframe->getUserStateFromRequest( $option.'filter_order_Dir', 'filter_order_Dir', 'ASC')); // Validate the order direction, must be ASC or DESC if ($filter_order_Dir != 'ASC' && $filter_order_Dir != 'DESC') { $filter_order_Dir = 'ASC'; } // If order column is unknown use the default if (!in_array($filter_order, $orders)) { $filter_order = 'ordering'; } $orderby = ' ORDER BY '.$filter_order.' '.$filter_order_Dir; if ($filter_order != 'ordering') { $orderby .= ' , ordering '; } // Return the ORDER BY clause return $orderby;} As with the view, we retrieve the order column name and direction using the application getUserStateFromRequest() method. Since this data is going to be used to interact with the database, we perform some data sanity checks to ensure that the data is safe to use with the database. Now that we have done this we can use the table headings to order itemized data. This is a screenshot of such a table: Notice that the current ordering is title descending, as denoted by the small arrow to the right of Title.
Read more
  • 0
  • 0
  • 2596

article-image-objects-and-types-documentum-65-content-management-foundations
Packt
04 Jun 2010
11 min read
Save for later

Objects and Types in Documentum 6.5 Content Management Foundations

Packt
04 Jun 2010
11 min read
Objects Documentum uses an object-oriented model to store information within the repository. Everything stored in the repository participates in this object model in some way. For example, a user, a document, and a folder are all represented as objects. An object store s data in its properties (also known as attributes) and has methods that can be used to interact with the object. Properties A content item stored in the repository has an associated object to store its metadata. Since metadata is stored in object properties, the terms metadata and properties are used interchangeably. For example, a document stored in the repository may have its title, subject, and keywords stored in the associated object. However, note that objects can exist in the repository without an associated content item. Such objects are sometimes referred to as contentless objects. For example, user objects and permission set objects do not have any associated content. Each object property has a data type, which can be one of boolean, integer, string, double, time, or ID. A boolean value is true or false. A string value consists of text. A double value is a floating point number. A time value represents a timestamp, including dates. An ID value represents an object ID that uniquely identifi es an object in the repository. Object IDs are discussed in detail later in this article. A property can be single-valued or repeating. Each single-valued property holds one value. For example, the object_name property of a document contains one value and it is of type string. This means that the document can only have one name. On the other hand, keywords is a repeating property and can have multiple string values. For example, a document may have object_name='LoanApp_1234567891.txt' and keywords='John Doe','application','1234567891'. The following figure shows a visual representation of this object. Typically, only properties are shown on the object while methods are shown when needed. Furthermore, only the properties relevant to the discussion are shown. Objects will be illustrated in this manner throughout the article series: Methods Methods are operations that can be performed on an object. An operation often alters some properties of the object. For example, the checkout method can be used to check out an object. Checking out an object sets the r_lock_owner property with the name of the user performing the checkout. Methods are usually invoked using Documentum Foundation Classes (DFCs) programmatically, though they can be indirectly invoked using API. In general, Documentum Query Language (DQL) cannot be used to invoke arbitrary methods on objects. DQL is discussed later in this article. Note that the term method may be used in two different contexts within Documentum. A method as a defined operation on an object type is usually invoked programmatically through DFC. There is also the concept of a method representing code that can be invoked via a job, workflow activity, or a lifecycle operation. This qualification will be made explicit when the context is not clear. Working with objects We used Webtop for performing various operations on documents, where the term document referred to an object with content. Some of these operations are not specific to content and apply to objects in general. For example, checkout and checkin can be performed on contentless objects as well. On the other hand, import, export, and renditions deal specifi cally with content. Talking specifically about operations on metadata, we can view, modify, and export object properties using Webtop. Viewing and editing properties Using Webtop, object properties can be viewed using the View | Properties menu item, shortcut P, or the right-click context menu. The following screenshot shows the properties of the example object discussed earlier. Note that the same screen can be used to modify and save the properties as well. Multiple objects can be selected before viewing properties. In this case, a special dialog shows the common properties for the selected objects, as shown in the following figure. Any changes made on this dialog are applied to all the selected objects. On the properties screen, single-valued properties can be edited directly while repeating properties provide a separate screen for editing through Edit links. Some properties cannot be modified by users at any time. Other properties may not be editable because object security prevents it or if the object is immutable. Object immutability Certain operations on an object mark it as immutable, which means that object properties cannot be changed. An object is marked immutable by setting r_immutable_flag to true. Content Server prevents changes to the content and metadata of an immutable object with the exception of a few special attributes that relate to the operations that are still allowed on immutable objects. For example, users can set a version label on the object, link the object to a folder, unlink it from a folder, delete it, change its lifecycle, and perform one of the lifecycle operations such as promote/demote/suspend/resume. The attributes affected by the allowed operations are allowed to be updated. An object is marked immutable in the following situations: When an object is versioned or branched, it becomes an old version and is marked immutable. An object can be frozen which makes it immutable and imposes some other restrictions. Some virtual document operations can freeze the involved objects. A retention policy can make the documents under its control immutable. Certain operations such as unfreezing a document can reset the immutability flag making the object changeable again. Exporting properties Metadata can be exported from repository lists, such as folder contents and search results. Property values of the objects are exported and saved as a .csv (comma-separated values) file, which can be opened in Microsoft Excel or in a text editor. Metadata export can be performed using Tools | Export to CSV menu item or the right-click context menu. Before exporting the properties, the user is able to choose the properties to export from the available ones. Object types Objects in a repository may represent different kinds of entities – one object may represent a workflow while another object may represent a document, for example. As a result, these objects may have different properties and methods. Every time Content Server creates an object, it needs to determine the properties and methods that the object is going to possess. This information comes from an object type (also referred to as type). The term attribute is synonymous with property and the two are used interchangeably. It is common to use the term attribute when talking about a property name and to use property when referring to its value. We will use a dot notation to indicate that an attribute belongs to an object or a type. For example, objectA.title or dm_sysobject. object_name. This notation is succinct and unambiguous and is consistent with many programming languages. An object type is a template for creating objects. In other words, an object is an instance of its type. A Documentum repository contains many predefined types and allows addition of new user-defined types (also known as custom types). The most commonly used predefined object type for storing documents in the repository is dm_document. We have already seen how folders are used to organize documents. Folders are stored as objects of type dm_folder. A cabinet is a special kind of folder that does not have a parent folder and is stored as an object of type dm_cabinet. Users are represented as objects of type dm_user and a group of users is represented as an object of dm_group. Workflows use a process definition object of type dm_process, while the definition of a lifecycle is stored in an object of type dm_policy. The following figure shows some of these types: Just like everything else in the repository, a type is also represented as an object, which holds structural information about the type. This object is of type dm_type and stores information such as the name of the type, name of its supertype, and details about the attributes in the type. The following figure shows an object of type dm_document and an object of type dm_type representing dm_document. It also indicates how the type hierarchy information is stored in the object of type dm_type. The types present in the repository can be viewed using Documentum Administrator (DA). The following screenshot shows some attributes for the type dm_sysobject. This screen provides controls to scroll through the attributes when there are a large number of attributes present. The Info tab provides information about the type other than the attributes. While the obvious use of a type is to define the structure and behavior of one kind of object, there is another very important utility of types. A type can be used to refer to all the objects of that type as a set. For example, queries restrict their scope by specifying a type where only the objects of that type are considered for matches. In our example scenario, the loan officer may want to search for all loan applications assigned to her. This query will be straightforward if there is an object type for loan applications. Queries are introduced later in this article. As another example, audit events can be restricted to a particular object type resulting in only the objects of this type being audited. Type names and property names Each object type uses an internal type name, such as dm_document, which is used for uniquely identifying the type within queries and application code. Each type also has a label, which is a user-friendly name often used by applications for displaying information to the end users. For example, the type dm_document has the label Document. Conventionally, internal names of predefined (defined by Documentum for Content Server or other client products) types start with dm, as described here: dm_: (general) represents commonly used object types such as dm_document, which is generally used for storing documents. dmr_: (read only) represents read-only object types such as dmr_content, which stores information about a content file. dmi_: (internal) represents internal object types such as dmi_workitem, which stores information about a task. dmc_: (client) represents object types supporting Documentum client applications. For example, dmc_calendar objects are used by Collaboration Services for holding calendar events. Just like an object type each property also has an internal name and a label. For example, the label for property object_name is Name. There are some additional conventions for internal names for properties. These names may begin with the following prefixes: r_: (read only) normally indicates that the property is controlled by the Content Server and cannot be modified by users or applications. For example, r_object_id represents the unique ID for the object. On the other hand, r_version_label is an interesting property. It is a repeating property and has at least one value supplied by the Content Server while others may be supplied by users or applications. i_: (internal) is similar to r_ except that this property is used internally by the Content Server and normally not seen by users and applications. i_chronicle_id binds all the versions together in to a version tree and is managed by the Content Server. a_: (application) indicates that this property is intended to be used by applications and can be modified by applications and users. For example, the format of a document is stored in a_content_type. This property helps Webtop launch an appropriate desktop application to open a document. The other three prefixes can also be considered to imply system or non-application attributes, in general. _: (computed) indicates that this property is not stored in the repository and is computed by Content Server as needed. These properties are also normally read-only for applications. For example, each object has a property called _changed, which indicates whether it has been changed since it was last saved. Many of the computed properties are related to security and most are used for caching information in user sessions.
Read more
  • 0
  • 0
  • 14293
article-image-red5-video-demand-flash-server
Packt
04 Jun 2010
6 min read
Save for later

Red5: A video-on-demand Flash Server

Packt
04 Jun 2010
6 min read
Plone does not provide a responsive user experience out of the box. This is not because the system is slow, but because it simply does (too) much. It does a lot of security checks and workflow operations, handles the content rules, does content validation, and so on. Still, there are some high-traffic sites running with the popular Content Management System. How do they manage? "All Plone integrators are caching experts." This saying is commonly heard and read in the Plone community. And it is true. If we want a fast and responsive system, we have to use caching and load-balancing applications to spread the load. The article discusses a practical example. We will set up a protected video-on-demand solution with Plone and a Red5 server. We will see how to integrate it with Plone for an effective and secure video-streaming solution. The Red5 server is an open source Flash server. It is written in Java and is very extensible via plugins. There are plugins for transcoding, different kinds of streaming, and several other manipulations we might want to do with video or audio content. What we want to investigate here is how to integrate video streams protected by Plone permissions. (For more resources on Plone, see here.) Requirements for setting up a Red5 server The requirement for running a Red5 Flash server is Java 6. We can check the Java version by running this: $ java -versionjava version "1.6.0_17"Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-9M3125)Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode) The version needs to be 1.6 at least. The earlier versions of the Red5 server run with 1.5, but the plugin for protecting the media files needs Java 6. To get Java 6, if we do not have it already, we can download it from the Sun home page. There are packages available for Windows and Linux. Some Linux distributions have different implementations of Java because of licensing issues. You may check the corresponding documentation if this is the case for you. Mac OS X ships with its own Java bundled. To set the Java version to 1.6 on Mac OS X, we need to do the following: $ cd /System/Library/Frameworks/JavaVM.framework/Versions$ rm Current*$ ln -s 1.6 Current$ ln -s 1.6 CurrentJDK After doing so, we should double-check the Java version with the command shown before. The Red5 server is available as a package for various operating systems. In the next section, we will see how we can integrate a Red5 server into a Plone buildout. A Red5 buildout Red5 can be downloaded in several different ways. As it is open source, even the sources are available as a tarball from the product home page. For the buildout, we use the bundle of ready compiled Java libraries. This bundle comes with everything needed to run a standalone Red5 server. There are startup scripts provided for Windows and Bash (usable with Linux and Mac OS X). Let's see how to configure our buildout. The buildout needs the usual common elements for a Plone 3.3.3 installation. Apart from the application and the instance, the Red5-specific parts are also present: a fss storage part and a part for setting up the supervisor. [buildout]newest = falseparts =zope2instancefssred5red5-webappred5-protectedVODsupervisorextends =http://dist.plone.org/release/3.3.3/versions.cfgversions = versionsfind-links =http://dist.plone.org/release/3.3.3http://dist.plone.org/thirdpartyhttp://pypi.python.org/simple/ There is nothing special in the zope2 application part. [zope2]recipe = plone.recipe.zope2installfake-zope-eggs = trueurl = ${versions:zope2-url} On the Plone side, we need—despite of the fss eggs—a package called unimr.red5.protectedvod. This package with the rather complicated name creates rather complicated one-time URLs for the communication with Red5. [instance]recipe = plone.recipe.zope2instancezope2-location = ${zope2:location}user = admin:adminhttp-address = 8080eggs =Ploneunimr.red5.protectedvodiw.fsszcml =unimr.red5.protectedvodiw.fssiw.fss-meta First, we need to configure FileSystemStorage.FileSystemStorage is used for sharing the videos between Plone and Red5. The videos are uploaded via the Plone UI and they are put on the filesystem. The storage strategy needs to be either site1 or site2. These two strategies store the binary data with its original filename and file extension. The extension is needed for the Red5 server to recognize the file. [fss]recipe = iw.recipe.fsszope-instances =${instance:location}storages =global /site /site site2 The red5 part downloads and extracts the Red5 application. We have to envision that everything is placed into the parts directory. This includes configurations, plugins, logs, and even content. We need to be extra careful with changing the recipe in the buildout if running in production mode. The content we share with Plone is symlinked, so this is not a problem. For the logs, we might change the position to outside the parts directory and symlink them back. [red5]recipe = hexagonit.recipe.downloadurl = http://www.red5.org/downloads/0_8/red5-0.8.0.tar.gz The next part adds our custom application, which handles the temporary links used for protection, to the Red5 application. The plugin is shipped together with the unimr.red5.protectedvod egg we use on the Plone side. It is easier to get it from the Subversion repository directly. [red5-webapp]recipe = infrae.subversionurls = http://svn.plone.org/svn/collective/unimr.red5.protectedvod/trunk/unimr/red5/protectedvod/red5-webapp red5-webapp The red5-protectedVOD part configures the protectedVOD plugin. Basically, the WAR archive we checked out in the previous step is extracted. If the location of the fss storage does not exist already, it is symlinked into the streams directory of the plugin. The streams directory is the usual place for media files for Red5. [red5-protectedVOD]recipe = iw.recipe.cmdon_install = trueon_update = falsecmds =mkdir -p ${red5:location}/webapps/protectedVODcd ${red5:location}/webapps/protectedVODjar xvf ${red5-webapp:location}/red5-webapp/protectedVOD_0.1-red5_0.8-java6.warcd streamsif [ ! -L ${red5:location}/webapps/protectedVOD/streams/fss_storage_site ];then ln -s ${buildout:directory}/var/fss_storage_site .;fi The commands used above are Unix/Linux centric. Until Vista/ Server 2008, Windows didn't understand symbolic links. That's why the whole idea of the recipe doesn't work. The recipe might work with Windows Vista, Windows Server 2008, or Windows 7; but the commands look different Finally, we add the Red5 server to our supervisor configuration. We need to set the RED5_HOME environment variable, so that the startup script can find the necessary libraries of Red5. [supervisor]recipe = collective.recipe.supervisorprograms =30 instance2 ${instance2:location}/bin/runzope ${instance2:location}true40 red5 env [RED5_HOME=${red5:location} ${red5:location}/red5.sh]${red5:location} true After running the buildout, we can start the supervisor by issuing the following command: bin/supervisord The supervisor will take care of running all the subprocesses. To find out more on the supervisor, we may visit its website. To check if everything worked, we can request a status report by issuing this: bin/supervisorctl statusinstance RUNNING pid 2176, uptime 3:00:23red5 RUNNING pid 7563, uptime 0:51:25
Read more
  • 0
  • 0
  • 3252

article-image-objects-and-types-documentum-65-content-management-foundations-sequel
Packt
04 Jun 2010
11 min read
Save for later

Objects and Types in Documentum 6.5 Content Management Foundations- A Sequel

Packt
04 Jun 2010
11 min read
Content persistence We have seen so far how metadata is persisted but it is not obvious how content is persisted and associated with its metadata. All sysobjects (objects of type dm_sysobject and its subtypes) other than folders (objects of type dm_folder and its subtypes) can have associated content. We saw that a document can have content in the form of renditions as well as in primary format. How are these content files associated with a sysobject? In other words, how does Content Server know what metadata is associated with a content fi le? How does it know that one content fi le is a rendition of another one? Content Server manages content files using content objects, which (indirectly) point to the physical locations of content files and associate them with sysobjects. Locating content files Recall that Documentum repositories can store content in various types of storage systems including a file system, a Relational Database Management System (RDBMS), a content-addressed storage (CAS), or external storage devices. Content Server decides to store each file in a location based on the configuration and the presence of products like Content Storage Services. In general, users are not concerned about where the file is stored since Content Server is able to retrieve the file from the location where it was stored. We will discuss the physical location of a content file without worrying about why Content Server chose to use that location. Content object Every content file in the repository has an associated content object, which stores information about the location of the fi le and identifi es the sysobjects associated with it. These sysobjects are referred to as the parent objects of the content object. A content object is an object of type dmr_content, whose key attributes are listed as follows: Attribute Description parent_count Number of parent objects parent_id List of object IDs of the parent objects storage_id Object ID of the store object representing the storage area holding the content. data_ticket A value used internally to retrieve the content. The value and its usage depend upon the type of storage used. i_contents When the content is stored in turbo storage, this property contains the actual content. If the content is larger than the size of this property (2000 characters for databases other than Sybase, 255 for Sybase), the content is stored in a dmi_subcontent object and this property is unused. If the content is stored in content addressed storage, it contains the content address. If the content is stored in external storage, it contains the token used to retrieve the content. rendition Identifies if it's a rendition and its related behavior 0 means original content 1 means rendition generated by server 2 means rendition generated by client 3 means rendition not to be removed when its primary content is updated or removed format Object ID of the format object representing the format of the content full_content_size Content file size in bytes, except when the content is stored in external storage Object-content relationship Content Server manages content objects while performing content-related operations. Content associated with a sysobject is categorized as primary content or a rendition. A rendition is a content fi le associated with a sysobject that is not its primary content. Content in the first content file added to a sysobject is called its primary content and its format is referred to as the primary format for the parent object. Any other content added to the parent object in the same format is also called primary content, though it is rarely done by users manually. This ability to add multiple primary content files is typically utilized programmatically by applications for their internal use. While a sysobject can have multiple primary content files it is also possible for one content object to have multiple parent objects. This just means that a content file can be shared by multiple objects. Putting it together The details about content persistence can become confusing due to the number of objects involved and the relationships among various attributes. It becomes even more complicated when the full Content Server capabilities (such as multiple content files for one sysobject) are manifested. We will look at a simple scenario to visually grasp how content persistence works in common situations. Documentum provides multiple options for locating the content file. DFC provides the getPath() method and DQL provides get_file_url administration method for this purpose. This section has been included to satisfy the reader's curiosity about content persistence and works through the information manually. This discussion can be treated as supplementary to technical fundamentals.. The sysobject is named paystub.jpg. The primary content file is in jpg format and the rendition is in pdf format, as shown in the following figure: The following figure shows the objects involved in the content persistence for this document. The central object is of type dm_document. The figure also includes two content objects and one format object. Let's try to understand the relationships by asking specific questions. How many content files, primary or renditions, are there for the document paystub.jpg? This question can be answered by looking for the corresponding content objects. We look for dmr_content objects that have the document's object ID in one of their parent_id values. This figure shows that there are two such content objects. Which of these content objects represents the primary content and which one is a rendition? This can be determined by looking at the rendition attribute. The content object on the left shows rendition=0, which indicates primary content. The content object on the right shows rendition=2, which indicates rendition generated by client (recall that we manually imported this rendition). What is the primary format for this document? This is easy to answer by looking at the a_content_type attribute on the document itself. If we need to know the format for a content object we can look for the dm_format object which has the same object ID as the value present in the format property of the content object. In the fi gure above, the format object for the primary content object is shown which represents a JPEG image. Thus, the format determined for the primary content of the object is expected to match the value of a_content_type property of the object. The format object for the rendition is not shown but it would be PDF. What is the exact physical location of the primary content file? As mentioned in the beginning of this section, there are DFC and DQL methods which can provide this information. For understanding content persistence, we will deduce this manually for a file store, which represents storage on a file system. For other types of storage, an exact location might not be evident since we need to rely on the storage interface to access the content file. Deducing the exact file path requires the ability to convert a decimal number to a hexadecimal (hex) number; this can be done with pen and paper or using one of the free tools available on the Web. Also remember that negative numbers are represented with what is known as a 2's-complement notation and many of these tools either don't handle 2's complement or don't support enough digits for our purposes. There are two parts of the file path—the root path for the file store and the path of the file relative to this root path. In order to fi gure out the root path, we identify the fi le store first. Find the dm_filestore object whose object ID is the same as the value in storage_id property of the content object. Then find the dm_location object whose object name is the same as the root property on the file store object. The file_ system_path property on this location object has the root path for the fi le store, which is C:Documentumdatalocaldevcontent_storage_01 in the figure above. In order to find the relative path of the content fi le, we look at data_ticket (data type integer) on the content object. Find the 8-digit hex representation for this number. Treat the hex number as a string and split the string with path separators (slashes, / or depending on the operating system) after every two characters. Suffi x the right-most two characters with the file extension (.jpg), which can be inferred from the format associated with the content object. Prefix the path with an 8-digit hex representation of the repository ID. This gives us the relative path of the content file, which is 000000108009be.jpg in the figure above. Prefix this path with the file store root path identified earlier to get the full path of the content file. Content persistence in Documentum appears to be complicated at first sight. There are a number of separate objects involved here and that is somewhat similar to having several tables in a relational database when we normalize the schema. At a high level, this complexity in the content persistence model serves to provide scalability, flexibility by supporting multiple kinds of content stores, and ease of managing changes in such an environment. Lightweight and shareable object types So far we have primarily dealt with standard types. Lightweight and shareable object types work together to provide performance improvements, which are significant when a large number of lightweight objects share information. The key performance benefits are in terms of savings in storage and in the time it takes to import a large number of documents that share metadata. These types are suitable for use in transactional and archival applications but are not recommended for traditional content management. The term transactional content (as in business transactions) was coined by Forrester Research to describe content typically originating from external parties, such as customers and partners, and driving transactional back-office business processes. Transactional Content Management (TCM) unifi es process, content, and compliance to support solutions involving transactional content. Our example scenario of mortgage loan approval process management is a perfect example of TCM. It involves numerous types of documents, several external parties, and sub-processes implementing parts of the overall process. Lightweight and shareable types play a central role in the High Volume Server, which enhances the performance of Content Server for TCM. A lightweight object type (also known as LwSO for Lightweight SysObject ) is a subtype of a shareable type. When a lightweight object is created, it references an object of its shareable supertype called the parent object of the lightweight object. Conversely, the lightweight object is called the child object of the shareable object. Additional lightweight objects of the same type can share the same parent object. These lightweight objects share the information present in the common parent object rather than each carrying a copy of that information. In order to make the best use of lightweight objects we need to address a couple of questions. When should we use lightweight objects? Lightweight objects are useful when there are a large number of attribute values that are identical for a group of objects. This redundant information can be pushed into one parent object and shared by the lightweight objects. What kind of information is suitable for sharing in the parent object? System-managed metadata, such as policies for security, retention, storage, and so on, are usually applied to a group of objects based on certain criteria. For example, all the documents in one loan application packet could use a single ACL and retention information, which could be placed into the shareable parent object. The specific information about each document would reside in a separate lightweight object. Lightweight object persistence Persistence for lightweight objects works much the same way it works for objects of standard types, with one exception. A lightweight object is a subtype of a shareable type and these types have their separate tables as usual. For a standard type, each object has separate records in all of these tables, with each record identified by the object ID of the object. However, when multiple lightweight objects share one parent object there is only one object ID (of the parent object) in the tables of the shareable type. The lightweight objects need to refer to the object ID of the parent object, which is different from the object ID of any of the lightweight objects, in order to access the shared properties. This reference is made via an attribute named i_sharing_parent, as shown in the last figure.
Read more
  • 0
  • 0
  • 10250

article-image-working-jrockit-runtime-analyzer-sequel
Packt
03 Jun 2010
7 min read
Save for later

Working with JRockit Runtime Analyzer- A Sequel

Packt
03 Jun 2010
7 min read
Code The Code tab group contains information from the code generator and the method sampler. It consists of three tabs —the Overview, Hot Methods, and Optimizations tab. Overview This tab aggregates information from the code generator with sample information from the code optimizer. This allows us to see which methods the Java program spends the most time executing. Again, this information is available virtually "for free", as the code generation system needs it anyway. For CPU-bound applications, this tab is a good place to start looking for opportunities to optimize your application code. By CPU-bound, we mean an application for which the CPU is the limiting factor; with a faster CPU, the application would have a higher throughput.   In the first section, the amount of exceptions thrown per second is shown. This number depends both on the hardware and on the application—faster hardware may execute an application more quickly, and consequently throw more exceptions. However, a higher value is always worse than a lower one on identical setups. Recall that exceptions are just that, rare corner cases. As we have explained, theJVM typically gambles that they aren't occurring too frequently. If an application throws hundreds of thousands exceptions per second, you should investigate why. Someone may be using exceptions for control flow, or there may be a configuration error. Either way, performance will suffer. In JRockit Mission Control 3.1, the recording will only provide information about how many exceptions were thrown. The only way to find out where the exceptions originated is unfortunately by changing the verbosity of the log. An overview of where the JVM spends most of the time executing Java code can be found in the Hot Packages and Hot Classes sections. The only difference between them is the way the sample data from the JVM code optimizer is aggregated. In Hot Packages, hot executing code is sorted on a per-package basis and in Hot Classes on a per-class basis. For more fine-grained information, use the Hot Methods tab. As shown in the example screenshot, most of the time is spent executing code in the weblogic.servlet.internal package. There is also a fair amount of exceptions being thrown. Hot Methods This tab provides a detailed view of the information provided by the JVM code optimizer. If the objective is to find a good candidate method for optimizing the application, this is the place to look. If a lot of the method samples are from one particular method, and a lot of the method traces through that method share the same origin, much can potentially be gained by either manually optimizing that method or by reducing the amount of calls along that call chain. In the following example, much of the time is spent in the method com.bea.wlrt.adapter.defaultprovider.internal.CSVPacketReceiver.parseL2Packet(). It seems likely that the best way to improve the performance of this particular application would be to optimize a method internal to the application container (WebLogic Event Server) and not the code in the application itself, running inside the container. This illustrates both the power of the JRockit Mission Control tools and a dilemma that the resulting analysis may reveal—the answers provided sometimes require solutions beyond your immediate control.   Sometimes, the information provided may cause us to reconsider the way we use data structures. In the next example, the program frequently checks if an object is in a java. util.LinkedList. This is a rather slow operation that is proportional to the size of the list (time complexity O(n)), as it potentially involves traversing the entire list, looking for the element. Changing to another data structure, such as a HashSet would most certainly speed up the check, making the time complexity constant (O(1)) on average, given that the hash function is good enough and the set large enough.   Optimizations This tab shows various statistics from the JIT-compiler. The information in this tab is mostly of interest when hunting down optimization-related bugs in JRockit. It shows how much time was spent doing optimizations as well as how much time was spent JIT-compiling code at the beginning and at the end of the recording. For each method optimized during the recording, native code size before and after optimization is shown, as well as how long it took to optimize the particular method.   Thread/Locks The Thread/Locks tab group contains tabs that visualize thread- and lock-related data. There are five such tabs in JRA—the Overview, Thread, Java Locks, JVM Locks, and Thread Dumps tab. Overview The Overview tab shows fundamental thread and hardware-related information, such as the number of hardware threads available on the system and the number of context switches per second.   A dual-core CPU has two hardware threads, and a hyperthreaded core also counts as two hardware threads. That is, a dual-core CPU with hyperthreading will be displayed as having four hardware threads. A high amount of context switches per second may not be a real problem, but better synchronization behavior may lead to better total throughput in the system. There is a CPU graph showing both the total CPU load on the system, as well as the CPU load generated by the JVM. A saturated CPU is usually a good thing — you are fully utilizing the hardware on which you spent a lot of money! As previously mentioned, in some CPU-bound applications, for example batch jobs, it is normally a good thing for the system to be completely saturated during the run. However, for a standard server-side application it is probably more beneficial if the system is able to handle some extra load in addition to the expected one. The hardware provisioning problem is not simple, but normally server-side systems should have some spare computational power for when things get hairy. This is usually referred to as overprovisioning, and has traditionally just involved buying faster hardware. Virtualization has given us exciting new ways to handle the provisioning problem. Threads This tab shows a table where each row corresponds to a thread. The tab has more to offer than first meets the eye. By default, only the start time, the thread duration, and the Java thread ID are shown for each thread. More columns can be made visible by changing the table properties. This can be done either by clicking on the Table Settings icon, or by using the context menu in the table. As can be seen in the example screenshot, information such as the thread group that the thread belongs to, allocation-related information, and the platform thread ID can also be displayed. The platform thread ID is the ID assigned to the thread by the operating system, in case we are working with native threads. This information can be useful if you are using operating system-specific tools together with JRA.   Java Locks This tab displays information on how Java locks have been used during the recording. The information is aggregated per type (class) of monitor object.   This tab is normally empty. You need to start JRockit with the system property jrockit.lockprofiling set to true, for the lock profiling information to be recorded. This is because lock profiling may cause anything from a small to a considerable overhead, especially if there is a lot of synchronization. With recent changes to the JRockit thread and locking model, it would be possible to dynamically enable lock profiling. This is unfortunately not the case yet, not even in JRockit Flight Recorder. For R28, the system property jrockit.lockprofiling has been deprecated and replaced with the flag -XX:UseLockProfiling. JVM Locks This tab contains information on JVM internal native locks. This is normally useful for the JRockit JVM developers and for JRockit support. An example of a native lock would be the code buffer lock that the JVM acquires in order to emit compiled methods into a native code buffer. This is done to ensure that no other code generation threads interfere with that particular code emission. Thread Dumps The JRA recordings normally contain thread dumps from the beginning and the end of the recording. By changing the Thread dump interval parameter in the JRA recording wizard, more thread dumps can be made available at regular intervals throughout the recording.  
Read more
  • 0
  • 0
  • 1914
article-image-using-javascript-effects-joomla-15
Packt
03 Jun 2010
7 min read
Save for later

Using Javascript effects with Joomla! 1.5

Packt
03 Jun 2010
7 min read
(Read more interesting articles on Joomla! 1.5 here.) Using JavaScript effects Joomla! includes mootools—a powerful compact JavaScript framework. Mootools enables us to do many things, but it is used extensively in Joomla! to create client-side effects. Some of these, such as the accordion, are accessible through Joomla! classes. Others require special attention. In some instances it may be necessary to manually add the mootools library to the document. We can do this using the JHTML behavior.mootools type: JHTML::_('behavior.mootools'); JPane A pane is an XHTML area that holds more than one set of information. There are two different types of panes: Tabs: Tabs provides a typical tabbed area with tabs to the top that are used to select different panes. Sliders: Sliders, based on the mootools accordion, are vertical selections of headings above panels that can be expanded and contracted. We use the JPane class to implement panes. This example demonstrates a basic tabular pane with two panels: $pane =& JPane::getInstance('Tabs');echo $pane->startPane('myPane');{ echo $pane->startPanel('Panel 1', 'panel1'); echo "This is Panel 1"; echo $pane->endPanel(); echo $pane->startPanel('Panel 2', 'panel2'); echo "This is Panel 2"; echo $pane->endPanel();}echo $pane->endPane(); There are essentially two elements to a pane: the pane itself and the panels within the pane. We use the methods startPane() and endPane() to signify the start and end of the pane. When we use startPane() we must provide one string parameter, which is a unique identifier used to identify the pane. Panels are always created internally to a pane and use the methods startPanel() and endPanel(). We must provide the startPanel() method with two parameters, the name, which appears on the tab, and the panel ID. The following is a screenshot of the pane created from the previous code: Had we wanted to create a slider pane instead of a tab pane when we used the getInstance() method, we would need to have supplied the parameter Sliders instead of Tabs. This is a screenshot of the same pane as a slider: Panes are used extensively in Joomla! As a general rule, tabs are used for settings and sliders are used for parameters. Tooltips Tool tips are small boxes with useful information in them that appear in response to onmouseover events. They are used extensively in forms to provide more information about fields and their contents. Tooltips can be extremely helpful to users by providing small helpful hints such as what value should be put into a field or what is the purpose of a field. It takes a small amount of code to implement but adds a lot of value for our users. So how do we add a tooltip? We use JHTML to render tips easily. There are two types that we use: behavior.tooltip is used to import the necessary JavaScript to enable tooltips to work and it does not return anything. We only ever need to call this type once in a page. tooltip is used to render a tooltip in relation to an image or a piece of text. There are six parameters associated with tooltip, of which five are optional. We will explore the more common uses of these parameters. The most basic usage of tooltip returns a small information icon that onmouseover displays as a tooltip; as this example demonstrates: echo JHTML::_('tooltip', $tooltip); The next parameter allows us to define a title that is displayed at the top of the tooltip: echo JHTML::_('tooltip', $tooltip, $title); The next parameter allows us to select an image from the includes/js/ThemeOffice directory. This example uses the warning.png image: echo JHTML::_('tooltip', $tooltip, $title, 'warning.png'); The next obvious leap is to use text instead of an image and that is just what the next parameter allows us to do: echo JHTML::_('tooltip', $tooltip, $title, null, $text); There are some additional parameters that relate to using hypertext links. A full description of these is available in Appendix E, Joomla! HTML Library. We can modify the appearance of tooltips using CSS. There are three style classes that we can use: .tool-tip, .tool-title, and .tool-text. The tooltip is encapsulated by the .tool-tip class, and the .tool-title and .tool-text styles relate to the title and the content. This code demonstrates how we can add some CSS to the document to override the default tooltip CSS: // prepare the cSS$css = '/* Tooltips */.tool-tip{ min-width: 100px; opacity: 0.8; filter: alpha(opacity=80); -moz-opacity: 0.8;}.tool-title{ text-align: center;}.tool-text { font-style: italic;}';// add the CSS to the document$doc =& JFactory::getDocument();$doc->addStyleDeclaration($css); Let's add tooltips to our com_boxoffice/views/revue/tmpl/default.php layout file. The first step is to enable tooltips by adding behavior.tooltip to the beginning of our layout file as follows: <?php // No direct access defined('_JEXEC') or die('Restricted access'); // Enable tooltips JHTML::_('behavior.tooltip');?> This should be placed at the beginning as illustrated. This adds the mootool JavaScript class Tips to our document and adds the following JavaScript code to the document heading: <script type="text/javascript"> window.addEvent('domready', function(){ var JTooltips = new Tips($$('.hasTip'), { maxTitleChars: 50, fixed: false}); });</script> Next, we identify those elements that we wish to have a tooltip enabled for. There are two documented ways to implement a tooltip. We will create both for the movie title to illustrate: <tr> <td width="100" align="right" class="key"> <span class="editlinktip hasTip" title="::<?php echo JText::_('TIP_001');?>"> <label for="title"> <?php echo JText::_('Movie Title'); ?>: </label> </span> </td> <td> <input class="inputbox" type="text" name="title" id="title" size="25" value="<?php echo $this->revue->title;?>" /> <?php echo JHTML::_('tooltip', JText::_('TIP_001')); ?> </td></tr> The first approach wraps the label with a <span> that has two CSS classes declared editlinktip and hasTip, and a title attribute. The title attribute is a two part string with the parts separated by double colons; the first part is the tooltip title and the second is the tooltip text. Both methods will produce similar results. There are a few differences that you should keep in mind. The first approach displays the tip when you hover over the spanned element (in this case the label field). The second approach will generate a small icon next to the input field; the tip will appear when you move your mouse over the icon. You can duplicate the results of the first approach using the tooltip method with the following code: <?php $label = '<label for ="title">' . JText::_('Movie Title') . '</label>'echo JHTML::_('tooltip', JText::_('TIP_001'), '', '', $label);?> Note that the tip text is passed through JText with a key from our translation file. Here are the entries for our tips: # Tip TextTIP_001=Enter the film title.TIP_002=Choose the MPAA film rating.TIP_003=Provide a brief impression of the film.TIP_004=Enter the name of the reviewer.TIP_005=Enter 1-5 asterisks (*) for overall quality of the film.TIP_006=Enter the date of the review (mm/dd/yyyy).TIP_007=Do you wish to publish this revue? In the end the method you choose to implement tooltips is largely a personal preference.
Read more
  • 0
  • 0
  • 1812

article-image-testing-students-knowledge-using-moodle-modules
Packt
03 Jun 2010
11 min read
Save for later

Testing Students' Knowledge using Moodle Modules

Packt
03 Jun 2010
11 min read
(For more resources on Moodle, see here.) There are a number of tools in Moodle to find out the students' depth of understanding—some formal and some informal. There are also some tools that allow the students to assist themselves in their own knowledge consolidation. We will now investigate these tools in more detail. Implementing a glossary The glossary is a well known and commonly used module in Moodle, but it may not always be used as the effective teaching and learning tool that it can be. Given the jargon-rich nature of design and technology, it is also an important glue for the whole subject area. Checking the settings The key options here relate to the functioning of the glossary and how you use it as a teaching and learning tool. The first thing that needs to be done is to check the overall settings for the module in the administration section of the site. The settings are divided into three key areas: Default settings for the glossary module Settings for the entries in the glossary Format of the display styles The previous settings can be found on the administration panel in the Site Administration | Modules | Activities | Glossary section. Default settings The first section determines which functions of the glossary are generally available to the users of the module on the site. In the previous screenshot, the main options relate to the linking functions and comments on the entries themselves. For example, do you want to allow students to comment on the glossary entries? For a subject such as DT, you might wish to allow students to add their own understanding of terms. In some cases, there may be regional terms for some things which are different from the "formal" definition of a term, such as the term used for certain woodworking tools. As woodworking is an ancient craft, there are many different local terms to describe some of the equipments used. The glossary would then reinforce the social nature of the design as a part of a teaching method. Preventing duplicate entries As you can see in the previous screenshot, the default setting here would be to not allow duplicate entries in the glossary—although it can be enabled to perhaps show the nuances in a term or allow the term to be defined in another language, if your school has a partner school in another country. In some instances, you might have a definition that is the accepted definition, but also one that students might come across such as a building term. Likewise, you might have a definition relating to a usage as opposed to how a manufacturer might determine an item. Allowing duplication gives students a sense of how terms change, depending on how they are used and by whom. Allowing comments Allowing comments on the entries is useful for students to build up an internal dialog whereby they may be able to add examples of best practice to the definitions in the glossary relating to their on-the-job work experience. This is useful because students who had previously worked in a company and gained some experience of the job can leave a historical record to help the students who have just started the course or work. Automatically linking comments The linking of the glossary terms is useful if you use a consistent approach throughout your course design; in particular, if you use the Compose a web page function under Add a resource, as discussed earlier, rather than uploading the proprietary word-processed files, then Moodle will be able to link the terms through the database. However, please bear in mind that the linking function will add some load to your server and may not be appropriate in all cases, such as when using a server on a shared system. Linking definitions throughout the site allows students to have a better understanding of all the elements, as they work through them and when they forget some key terms. However, you need to remember that this links across an entire site and some definitions may clash across curriculum subjects. Therefore, there is a need for the duplicate entries. The ability to create a glossary for all the users on a site is only available to site administrators. Entry level default settings The following screenshot shows the options that are available for the entries, which are added to the glossaries. If enabled, the options shown in the following screenshot will automatically be enabled when the entries are made. Users still have the choice to disable the options like the automatic linking shown as follows: Again, you can link terms in the course to the glossary definitions, and if necessary, make the terms case sensitive. The case-sensitive option as well as the matching of whole words allows some fine tuning of the glossary. For example, you may make an entry for a law, which is HAM. If you enable the case-sensitive option on this entry, then a link will be created in the database when the specific term HAM is entered on a page in the course and not for every instance of hammer. This may be more useful with younger students when it is important for them to learn the key terms, but perhaps not so with older students. You can now save the settings you have chosen. If the changes have been applied for you by your site administrator, you can move directly to your course to begin using a glossary. Creating a glossary Once you or the site administrator have set up the module in the way that is most appropriate for your institution, teachers can then begin to apply them to their courses. We are assuming here that you have other subject areas on your Moodle site, therefore, we will focus on the course-level entries, but the principles are same. Enabling the glossary For this example, we will add a glossary of terms to our construction-based course. Younger students may be unfamiliar with this subject in many cases and they will, therefore, have a greater need for some ways of understanding the wealth of the terms. The same is true for Food Technology or Resistant Materials, but it is more likely that they would have at least encountered food-based products or materials in their lives. It is less likely that they had been involved in the construction of their environment or have working knowledge of these key terms. As with all the modules, the first action is to enable editing on the course to activate the activities drop-down menu. This requires clicking the button that follows: This will then show the activities menu from which you can select the glossary module Glossary from one of the many Add an activity' drop down menus, as shown in the following screenshot, to create a new glossary activity module. Editing the glossary Once enabled, added, or created, you can then name the glossary and determine some of the functionality you want in it to be available. Like all the other modules, these are related to time and display elements. The following screenshot shows some of the key settings such as the type of glossary and the display format. Most of these settings were determined at the site level, such as allowing duplicate entries or comments, but they can be changed by the staff as required. The key point here is that we make one glossary—a main glossary for the course. We make all the subsequent glossaries secondary, which means that we can export the terms into this main one, but this is the overall glossary for the course. We might have secondary glossaries for the human aspects of construction or health and safety, as opposed to the material elements for example. As this is a very graphical subject, we have enabled the display to be like an encyclopedia. This will allow staff and students to add images and video files to explain the terms they are defining in a better way. Rating entries If you are going to use the glossary in a more formal way, it would be useful to allow the students to rate the entries, so that they can peer assess each other's terms. If you set each student a number of terms to define as a homework exercise, you can allow the students to research and populate the glossary and for the other students to award marks. This makes the terms far more dynamic and real for the students. You might also invite your contacts from local companies to rate the students' definitions and give them feedback to help develop their understanding on a deeper level. This is enabled through the grading option, as shown in the following screenshot: The glossary can now be saved. Adding entries (categories) When we are adding entries, the first real requirement is to create some categories in which you can organize the terms. A category in this instance is a group of terms such as tools or techniques. If we had created one Moodle course to cover all the DT subjects, we might have a main glossary for DT and secondary glossaries for Food and Construction. This makes it more organized as well as making it easier to search for items. In this example, we are creating some glossary items relating to the term 'carpentry'. We need to create an overall category for this area. This is achieved by first adding a new category item by clicking on the Browse by category tab and then on Edit categories, as shown in the following screenshot: This will open the dialog window to create a new category for this glossary, as shown in the following screenshot: If you select to link the category, this whole sub-section will be revealed by a hyperlink to this term, which could be useful for newer students. Adding entries If the course you are managing incorporates all of the DT subjects, then you may wish to create a main glossary for DT and secondary glossaries for Food or Resistant Materials and so on. In this example, we have a course for Construction and the Built Environment, which is the main glossary. We are going to create categories to group the terms in the glossary for areas such as carpentry or electrical. With the categories set, it is now possible to add and organize the definitions for your course. This can be managed entirely by the staff or can be an exercise that allows student participation, such as a homework exercise as mentioned earlier. In this example, we are building up a definition for a particular woodworking joint. Once we have set the name and basic details, we can then categorize the entry and add some keywords for searches, as shown in the following screenshot: The entry can now be viewed by students as well as rated and commented upon. In the following instance, the student has not only rated the entry, but also added a comment with a link to a website they have found, which further illustrates the particular woodworking joint. Students could also embed a video stream from a video site, which would also help to explain the process more clearly. This level of collaborative learning is immensely powerful with this type of kinesthetic information. Students can now add their own entries as part of a homework routine or teaching strategy. As shown in the following screenshot, items added to the glossary are linked to other pages through the database. The terms are highlighted by Moodle and clicking on them will take users to the glossary page, which defines them. In this example, the word 'wood' is highlighted in green. When you click on this link, it will open the corresponding entry for wood in the glossary, as shown in the following screenshot. Mapping their minds Many aspects of design require students to sketch out their ideas in a graphical form in order to get to grips with the complexity and the various components. These sketches could be scanned and uploaded as formal assignments, but they could also be incorporated into the Moodle site through the use of an add-on called Mindmap. This is a third-party module that allows the students to map out their ideas using a basic interface and permits them to link and label the items on a screen. It can be saved by them in their area and can be viewed by the staff for guidance and support. The Mindmap module can be found at: http://moodle.org/mod/data/view.php?d=13&rid=1628&filter=1 Once the module has been installed, it is added to a course in a similar way as we add any other module, by turning the editing on. After choosing the drop-down activities menu, you can then add theMindmap module, as shown in the following screenshot: This will activate the dialog to set up the name and settings for the Mindmap module for the course.
Read more
  • 0
  • 0
  • 1398
Modal Close icon
Modal Close icon