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-unveil-power-your-business-data-oracle-discoverer
Packt
08 Apr 2010
4 min read
Save for later

Unveil the Power of Your Business Data with Oracle Discoverer

Packt
08 Apr 2010
4 min read
A quick guide to Oracle Discoverer packaging Before proceeding to get the Oracle Discoverer software, it’s important to realize what you actually need and what the Oracle Discoverer packaging provides. At the moment, there are two options when it comes to the current Oracle Discoverer software: Oracle Business Intelligence suite, part of Oracle Application Server 10g Release 2 Portal, Forms, Reports and Discoverer suite, part of Oracle Fusion Middleware 11g Release 1 The first option – the Oracle Business Intelligence suite, part of Oracle Application Server 10g Release 2 – includes the following components: Oracle Business Intelligence Discoverer Oracle HTTP Server Oracle Application Server Containers for J2EE (OC4J) Oracle Enterprise Manager 10g Application Server Control Oracle Application Server Web Cache Oracle Application Server Reports Services The first component, Oracle Business Intelligence Discoverer, in the above list represents actually a group of components whose name starts with Discoverer. The package includes: Discoverer Plus Discoverer Viewer Discoverer Services Discoverer Portlet Provider Note, however, that the above list does not include all the Discoverer components. For example, you won’t find the following Discoverer components there: Discoverer Administrator Discoverer Desktop The above components are included in a complementary package called Oracle Business Intelligence Tools. As mentioned at the beginning of this section, another option to take advantage of the Discoverer components is to install the Portal, Forms, Reports and Discoverer suite, which is part of Oracle Fusion Middleware 11g Release 1. This package includes the following components: HTTP Server WebCache Portal Forms Services Forms Builder Reports Services Report Builder/Compiler Discoverer Administrator Discoverer Plus Discoverer Viewer Discoverer Services Discoverer Desktop Enterprise Manager Fusion Middleware Control As you can see, the Portal, Forms, Reports and Discoverer suite, unlike Oracle Business Intelligence suite, does include Discoverer Administrator and Discoverer Desktop. So you won’t need to install another package to obtain these components. A major downside to choosing the Portal, Forms, Reports and Discoverer suite, though, is that it requires some additional software to be installed in your system. Here is the list of the required additional software components: WebLogic Server Repository Creation Utility Identity Management SSO Metadata Repository Creation Assistant Patch Scripts Identity Management 10gR3 Oracle Database Due to this reason – to save you the trouble of installing a lot of software – the "Installation process" section later in this article will cover the installation of Oracle Business Intelligence suite, part of Oracle Application Server 10g Release 2 rather than the Portal, Forms, Reports and Discoverer suite of Oracle Fusion Middleware 11g Release 1. Getting the software Once you have decided on the package you want to install, you can go for it to the OTN’s Software Downloads page at http://www.oracle.com/technology/software/index.html. It’s important to remember that each software component available from this page comes with a Development License, which allows for free download and unlimited evaluation time. You can look at the license at http://www.oracle.com/technology/software/popup-license/standard-license.html. Later, if you so desire, you can always buy products with full-use licenses. So, the OTN’s Software Downloads page, go to the Middleware section and, assuming you want to download Oracle Business Intelligence suite, click the Business Intelligence SE link to proceed to the Oracle Application Server 10g Release 2 (10.1.2.0.2) page at http://www.oracle.com/technology/software/products/ias/htdocs/101202.html. On this page, go down to the Business Intelligence section and find the links to the packages provided for your operating system. Each package is supposed to be copied on a separate CD. The number of CDs and the size of packages to be copied on them may vary depending on the operating system. What you need to do is download the installation packages and then copy each to a CD. Looking through the links to the installation packages, you may notice that Tools CD – the link to the package containing the Oracle Business Intelligence Tools suite – is available only for Microsoft Windows operating system. This is because the components included in the Oracle Business Intelligence Tools suite are Windows-only applications. If, instead of the Oracle Business Intelligence suite, you decided on the Portal, Forms, Reports and Discoverer suite, you have to follow the Oracle Fusion Middleware 11g R1 link in the Middleware section on the OTN’s Software Downloads page. Following that link, you’ll be directed to the Oracle Fusion Middleware 11gR1 Software Downloads page at http://www.oracle.com/technology/software/products/middleware/htdocs/fmw_11_download.html. On this page, go down to the Portal, Forms, Reports and Discoverer section and pick up the distribution divided into several packages. Again, the number of packages within a distribution and their size may vary depending on the operating system.
Read more
  • 0
  • 0
  • 2317

article-image-service-oriented-java-business-integration-proxy
Packt
07 Apr 2010
9 min read
Save for later

Service Oriented Java Business Integration Proxy

Packt
07 Apr 2010
9 min read
Proxy—A Primer Wikipedia defines Proxy as: Proxy may refer to something which acts on behalf of something else. In the software a proxy is a substitute for a target instance and is a general pattern which appears in many other patterns in different variants. Proxy Design Pattern A proxy is a surrogate class for the target object. If a method call has to be invoked in the target object, it happens indirectly through the proxy object. The feature which makes proxy ideal for many situations is that the client or the caller is not aware that it is dealing with the proxy object. The proxy class is shown in the following figure: In the above figure, when a client invokes a method target towards the Target service, the proxy intercepts the call in between. The proxy also expose a similar interface to the target, hence the client is unaware of the dealing with the proxy. Thus the proxy method is invoked. The proxy then delegates the call to the actual target since it cannot provide the actual functionality. When doing so, the proxy can provide call management towards the actual method. The entire dynamics is shown in the following figure: A proxy is usually implemented by using a common, shared interface or super class. Both the proxy and the target share this common interface. Then, the proxy delegates the calls to the target class. JDK Proxy Class JDK provides both the class Proxy and the interface InvocationHandler in the java.lang.reflect package, since version 1.3. Using JDK Proxy classes, you can create your own classes implementing multiple interfaces of your choice, at run time. Proxy is the super class for any dynamic proxy instances you create at run time. Moreover, the Proxy class also accommodates a host of static methods which will help you to create your proxy instances. getProxyClass and newProxyInstance are two such utility methods. The Proxy API is listed in the following in brevity: package java.lang.reflect;public class Proxy implements java.io.Serializable{ protected InvocationHandler h; protected Proxy(InvocationHandler h); public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException; public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException; public static boolean isProxyClass(Class<?> cl); public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException} In the above code, you can invoke the Proxy.getProxyClass with a class loader and an array of interfaces for which you need to proxy, to get a Class instance for the proxy. Proxy objects have one constructor, to which you pass an InvocationHandler object associated with that proxy. When you invoke a method on the proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler. Let us also look at the InvocationHandler API reproduced as follows: package java.lang.reflect;public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object[] args) throws Throwable;} We need to implement this interface and provide code for the invoke method. Once you get a Class instance for the proxy by invoking the Proxy.getProxyClass with a class loader and an array of interfaces for which you need to proxy to. Now, you can get a Constructor object for this proxy from the Class instance. On the constructor you can use newInstance (passing in an invocation handler instance) to create the proxy instance. The created instance should be implementing all the interfaces that were passed to getProxyClass. The steps are shown in the following code: InvocationHandler handler = new SomeInvocationHandler(...);Class proxyClazz = Proxy.getProxyClass(Blah.class.getClassLoader(), new Class[] {Blah.class});Blah blah = (Blah) proxyClazz.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] {handler}); There is also a shortcut to get a proxy object. You can invoke Proxy.newProxyInstance, which takes a class loader, an array of interface classes, and an invocation handler instance. InvocationHandler handler = new SomeInvocationHandler(...);Blah blah = (Blah) Proxy.newProxyInstance(Blah.class. getClassLoader(),new Class[] {Blah.class}, handler); Now you can invoke methods on the proxy object during which these method invocations are turned into calls on to the invocation handler's invoke method is shown here: blah.interfaceMethod(); Sample JDK Proxy Class We will now write some simple code to demonstrate how you can write your own proxies at run time, for your interface classes. As a first step, if you haven't done it before, edit examples.PROPERTIES, and change the paths there to match your development environment. We will now look at the source code that can be found in the folder ch13JdkProxysrc. The files are explained here: ch13JdkProxysrcSimpleIntf.java public interface SimpleIntf { public void print(); } SimpleIntf is a simple interface with a single method print. print does not accept any parameters and also does not return any value. Our aim is that when we invoke methods on the proxy object for SimpleIntf, the method invocation should be turned into calls to an invocation handler's invoke method. Let us now define an invocation handler in the following code: ch13JdkProxysrcSimpleInvocationHandler.java import java.lang.reflect.InvocationHandler; import java.io.Serializable; import java.lang.reflect.Method; public class SimpleInvocationHandler implements InvocationHandler, Serializable { public SimpleInvocationHandler(){} public Object invoke(final Object obj, Method method, Object[] args) throws Throwable { if (method.getName().equals("print") && (args == null || args.length == 0)) { System.out.println("SimpleInvocationHandler.invoked"); } else { throw new IllegalArgumentException("Interface method does not support param(s) : " + args); } return null; }} Since SimpleIntf.print() does not accept any parameters and also does not return any value, in the invoke method of SimpleInvocationHandler, we double check the intention behind the actual invoker. In other words, we check that no parameters are passed and we return null only. Now, we have all the necessary classes to implement a proxy for SimpleIntf interface. Let us now execute it by writing a Test class. ch13JdkProxysrcTest.java import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; public class Test { public static void main(String[] args) { InvocationHandler handler = new SimpleInvocationHandler(); SimpleIntf simpleIntf = (SimpleIntf)Proxy.newProxyInstance (SimpleIntf.class.getClassLoader(),new Class[] { SimpleIntf. class }, handler); simpleIntf.print(); } } The wiring of the above described interfaces and classes are better represented in the UML class diagram in the following figure: The above figure shows the relationship between various classes and interfaces in the sample. $Proxy0 class represents the actual proxy class generated on the fly and as you can deduce it from the class diagram. $Proxy0 is a type of our interface (SimpleIntf). To build the sample, first change directory to ch13JdkProxy and execute ant as shown here: cd ch13JdkProxyant The command ant run will execute the Test class which will print out the following in the console: ServiceMix JBI Proxy Java proxies for the JBI endpoints can be created in ServiceMix using JSR181 components. For this, the requirement is that the JBI endpoints should expose a WSDL. A jsr181:endpoint takes a value for the serviceInterface attribute. The JBI container will be able to generate the WSDL out of this serviceInterface. Thus, if we have a jsr181:endpoint exposing service to the JBI bus, it is possible to provide a proxy for that service too. The basic configuration for defining a JBI proxy is shown as follows: <jsr181:proxy id="proxyBean" container="#jbi" interfaceName="test:HelloPortType" type="test.Hello" /> Once a proxy is defined, the same can then be referenced from your client bean or from one of your components. The proxied JBI endpoint can then be invoked just like a normal POJO. If you want to define a JBI proxy within a SU, you can follow the configuration given as follows: <jsr181:endpoint annotations="none" service="test:echoService" serviceInterface="test.Echo"> <jsr181:pojo> <bean class="test.EchoProxy"> <property name="echo"> <jsr181:proxy service="test:EchoService" context="#context" type="test.IService" /> </property> </bean> </jsr181:pojo></jsr181:endpoint> Let us now look into a few examples to make the concept clearer. JBI Proxy Sample Implementing Compatible Interface First, we will create a JBI proxy implementing an interface compatible with the target service. Then, in place of the target service we will use the proxy instance, so that any calls intended for the target service will be first routed to the proxy. The proxy in turn will delegate the call to the target service. The structural relationship between various classes participating in the interaction is shown in the following figure: Here, EchoProxyService is the class which we later expose in the JBI bus as the service. This class implements the IEcho interface. In order to demonstrate the proxy, EchoProxyService doesn't implement the service as such, instead depends on the JbiProxy derived out of another class TargetService. The TargetService contains the actual service code. As you can see, both the EchoProxyService and the TargetService implement the same interface. Proxy Code Listing The codebase for the sample is located in the folder ch13JbiProxy1_CompatibleInterface1_JsrProxysrc. This folder contains an interface IEcho and two other classes implementing the IEcho interface namely EchoProxyService and TargetService. These classes are explained here: IEcho.java: The IEcho interface declares a single method echo which takes a String parameter and returns a String. public interface IEcho{ public String echo(String input);} EchoProxyService.java: EchoProxyService is a convenient class which will act as mechanism for routing requests to the JBI proxy. Moreover, EchoProxyService implements the above interface IEcho. public class EchoProxyService implements IEcho{ private IEcho echo; public void setEcho(IEcho echo) { this.echo = echo; } public String echo(String input) { System.out.println("EchoProxyService.echo. this = " + this); return echo.echo(input); }} TargetService.java: TargetService also implements the interface IEcho. TargetService is supposed to be our target service, and we will be generating a JBI proxy for the TargetService. public class TargetService implements IEcho{ public String echo(String input) { System.out.println("TargetService.echo : String. this = " + this); return input; }}
Read more
  • 0
  • 0
  • 1600

article-image-core-principles-service-oriented-architecture-biztalk-server-2009
Packt
06 Apr 2010
11 min read
Save for later

The core principles of a service-oriented architecture with BizTalk Server 2009

Packt
06 Apr 2010
11 min read
So what exactly is a service? A service is essentially a well-defined interface to an autonomous chunk of functionality, which usually corresponds to a specific business process. That might sound a lot like a regular old object-oriented component to you. While both services and components have commonality in that they expose discrete interfaces of functionality, a service is more focused on the capabilities offered than the packaging. Services are meant to be higher-level, business-oriented offerings that provide technology abstraction and interoperability within a multipurpose "services" tier of your architecture. What makes up a service? Typically you'll find: Contract: Explains what operations the service exposes, types of messages, and exchange patterns supported by this service, and any policies that explain how this service is used. Messages: The data payload exchanged between the service consumer and provider. Implementation: The portion of the service which actually processes the requests, executes the expected business functionality, and optionally returns a response. Service provider: The host of the service which publishes the interface and manages the lifetime of the service. Service consumer: Ideally, a service has someone using it. The service consumer is aware of the available service operations and knows how to discover the provider and determine what type of messages to transmit. Facade: Optionally, a targeted facade may be offered to particularly service consumers. This sort of interface may offer a more simplified perspective on the service, or provide a coarse-grained avenue for service invocation. What is the point of building a service? I'd say it's to construct an asset capable of being reused which means that it's a discrete, discoverable, self-describing entity that can be accessed regardless of platform or technology. Service-oriented architecture is defined as an architectural discipline based on loosely-coupled, autonomous chunks of business functionality which can be used to construct composite applications. Through the rest of this article we get a chance to flesh out many of the concepts that underlie that statement. Let's go ahead and take a look at a few of the principles and characteristics that I consider most important to a successful service-oriented BizTalk solution. As part of each one, I'll explain the thinking behind the principle and then call out how it can be applied to BizTalk Server solutions. Loosely coupled Many of the fundamental SOA principles actually stem from this particular one. In virtually all cases, some form of coupling between components is inevitable. The only way we can effectively build software is to have interrelations between the various components that make up the delivered product. However, when architecting solutions, we have distinct design decisions to make regarding the extent to which application components are coupled. Loose coupling is all about establishing relationships with minimal dependencies. What would a tightly-coupled application look like? In such an application, we'd find components that maintained intimate knowledge of each others' working parts and engaged in frequent, chatty synchronous calls amongst themselves. Many components in the application would retain state and allow consumers to manipulate that state data. Transactions that take place in a tightly coupled application probably adhere to a two-phase commit strategy where all components must succeed together in order for each data interaction to be finalized. The complete solution has its ensemble of components compiled together and singularly deployed to one technology platform. In order to run properly, these tightly-coupled components rely on the full availability of each component to fulfill the requests made of them. On the other hand, a loosely-coupled application employs a wildly different set of characteristics. Components in this sort of application share only a contract and keep their implementation details hidden. Rarely preserving state data, these components rely on less frequent communication where chunky input containing all the data the component needs to satisfy its requestors is shared. Any transactions in these types of applications often follow a compensation strategy where we don't assume that all components can or will commit their changes at the same time. This class of solution can be incrementally deployed to a mix of host technologies. Asynchronous communication between components, often through a broker, enables a less stringent operational dependency between the components that comprise the solution. What makes a solution loosely coupled then? Notably, the primary information shared by a component is its interface. The consuming component possesses no knowledge of the internal implementation details. The contract relationship suffices as a means of explaining how the target component is used. Another trait of loosely coupled solutions is coarse-grained interfaces that encourage the transmission of full data entities as opposed to fine-grained interfaces, which accept small subsets of data. Because loosely-coupled components do not share state information, a thicker input message containing a complete impression of the entity is best. Loosely-coupled applications also welcome the addition of a broker which proxies the (often asynchronous) communication between components. This mediator permits a rich decoupling where runtime binding between components can be dynamic and components can forgo an operational dependency on each other. Let's take a look at an example of loose coupling that sits utterly outside the realm of technology. Completely non-technical loose coupling exampleWhen I go to a restaurant and place an order with my waiter, he captures the request on his pad and sends that request to the kitchen. The order pad (the contract) contains all the data needed by the kitchen chef to create my meal. The restaurant owner can bring in a new waiter or rotate his chefs and the restaurant shouldn't skip a beat as both roles (services) serve distinct functions where the written order is the intersection point and highlight of their relationship. Why does loose coupling matter? By designing a loosely-coupled solution, you provide a level of protection against the changes that the application will inevitably require over its life span. We have to reduce the impact of such changes while making it possible to deploy necessary updates in an efficient manner. How does this apply to BizTalk Server solutions? A good portion of the BizTalk Server architecture was built with loose coupling in mind. Think about the BizTalk MessageBox which acts as a broker facilitating communication between ports and orchestrations while limiting any tight coupling. Receive ports and send ports are very loosely coupled and in many cases, have absolutely no awareness of each other. The publish-and-subscribe bus thrives on the asynchronous transfer of self-describing messages between stateless endpoints. Let's look at a few recommendations of how to build loosely-coupled BizTalk applications. Orchestrations are a prime place where you can either go with a tightly-coupled or loosely-coupled design route. For instance, when sketching out your orchestration process, it's sure tempting to use that Transform shape to convert from one message type to another. However, a version change to that map will require a modification of the calling orchestration. When mapping to or from data structures associated with external systems, it's wiser to push those maps to the edges (receive/send ports) and not embed a direct link to the map within the orchestration. BizTalk easily generates schemas for line-of-business (LOB) systems and consumed services. To interact with these schemas in a very loosely coupled fashion, consider defining stable entity schemas (i.e. "canonical schemas") that are used within an orchestration, and only map to the format of the LOB system in the send port. For example, if you need to send a piece of data into an Oracle database table, you can certainly include a map within an orchestration which instantiates the Oracle message. However, this will create a tight coupling between the orchestration and the database structure. To better insulate against future changes to the database schema, consider using a generic intermediate data format in the orchestration and only transforming to the Oracle-specific format in the send port. How about those logical ports that we add to orchestrations to facilitate the transfer of messages in and out of the workflow process? When configuring those ports, the Port Configuration Wizard asks you if you want to associate the port to a physical endpoint via the Specify Now option. Once again, pretty tempting. If you know that the message will arrive at an orchestration via a FILE adapter, why not just go ahead and configure that now and let Visual Studio.NET create the corresponding physical ports during deployment? While you can independently control the auto-generated physical ports later on, it's a bad idea to embed transport details inside the orchestration file. On each subsequent deployment from Visual Studio.NET, the generated receive port will have any out-of-band changes overwritten by the deployment action. Chaining orchestration together is a tricky endeavor and one that can leave you in a messy state if you are too quick with a design decision. By "chaining orchestrations", I mean exploiting multiple orchestrations to implement a business process. There are a few options at your disposal listed here and ordered from most coupled to least coupled. Call Orchestration or Start Orchestration shape: An orchestration uses these shapes in order to kick off an additional workflow process. The Call Orchestration is used for synchronous connection with the new orchestration while the Start Orchestration is a fire-and-forget action. This is a useful tactic for sharing state data (for example variables, messages, ports) from the source orchestration to the target. However, both options require a tight coupling of the source orchestration to the target. Version changes to the target orchestration would likely require a redeployment of the source orchestration. Partner direct bound ports: These provide you the capability to communicate between orchestrations using ports. In the forward partner direct binding scenario, the sender has a strong coupling to the receiver, while the receiver knows nothing about the sender. This works well in situations where there are numerous senders and only one receiver. Inverse partner direct binding means that there is a tight coupling between the receiver and the sender. The sender doesn't know who will receive the command, so this scenario is intended for cases where there are many receivers for a single sender. In both cases, you have tight coupling on one end, with loose-coupling on the other. MessageBox direct binding: This is the most loosely-coupled way to share data between orchestrations. When you send a message out of an orchestration through a port marked for MessageBox direct binding, you are simply placing a message onto the bus for anyone to consume. The source orchestration has no idea where the data is going, and the recipients have no idea where it's been. MessageBox direct binding provides a very loosely-coupled way to send messages between different orchestrations and endpoints. Critical pointWhile MessageBox direct binding is great, you do lose the ability to send the additional state data that a Call Orchestration shape will provide you. So, as with all architectural decisions, you need to decide if the sacrifice (loose coupling, higher latency) is worth the additional capabilities. Decisions can be made during BizTalk messaging configuration that promote a loosely-coupled BizTalk landscape. For example, both receive ports and send ports allow for the application of maps to messages flying past. In each case, multiple maps can be added. This does NOT mean that all the maps will be applied to the message, but rather, it allows for sending multiple different message types in, and emitting a single type (or even multiple types) out the other side. By applying transformation at the earliest and latest moments of bus processing, you loosely couple external formats and systems from internal canonical formats. We should simply assume that all upstream and downstream systems will change over time, and configure our application accordingly. Another means for loosely coupling BizTalk solutions involves the exploitation of the publish-subscribe architecture that makes up the BizTalk message bus. Instead of building solely point-to-point solutions and figuring that a SOAP interface makes you service oriented, you should also consider loosely coupling the relationship between the service input and where the data actually ends up. We can craft a series of routing decision that take into account message content or context and direct the message to one or more relevant processes/endpoints. While point-to-point solutions may be appropriate for many cases, don't neglect a more distributed pattern where the data publisher does not need to explicitly know exactly how their data will be processed and routed by the message bus. When identifying subscriptions for our send ports, we should avoid tight coupling to metadata attributes that might limit the reuse of the port. For instance, you should try to create subscriptions on either the message type or message content instead of context attributes such as the inbound receive port name. Ports should be tightly coupled to the MessageBox and messages it stores, not to attributes of its publisher. That said, there are clearly cases where a subscriber is specifically looking for data that corresponds to a targeted piece of metadata such as the subject line of the email received by BizTalk. As always, design your solution in a way that solves your business problem in an efficient manner.
Read more
  • 0
  • 0
  • 2852

article-image-organizing-your-content-effectively-using-joomla-15-sequel
Packt
06 Apr 2010
5 min read
Save for later

Organizing your Content Effectively using Joomla 1.5- A Sequel

Packt
06 Apr 2010
5 min read
Time for action - move content from one category to another The Activities section contains some articles that you might want to move to the News section. Let's clean up the Activities - Meetings category and move anything topical into the News - General News category: Navigate to Content | Article Manager. From the list, select the items you want to move from the Meetings category to the General News category. In this example, we've selected two articles: Click on Move on the toolbar. You'll be taken to the Move Articles screen: In the Move to Section/Category list, select News/General News. At the far right-hand side, you can check which articles are being moved. Click on Save. In the Article Manager screen, the three articles are now part of the News section. You can check this by clicking on the News link on the frontend Main Menu. What just happened? You've stood the real life challenge of content management! Now, you're not only able to create a sound content structure for your website, but you also know how to improve on it. By adding a new container for all news items and moving existing news content there you've now made room for growth on the SRUP site. Have a go hero - moving entire categories Sometimes you might want to move an entire category and all its contents to another section. Try this out for yourself-it's not much different from moving articles. Imagine you'd like to move the Reviews category from the Ugly Paintings section to another section. In the Category Manager, select the category you want to move and click on the Move button. Select the section you want to move things to, and click on Save. It's just as straightforward to move the entire category including all of its article contents back again. This flexibility is great when you're setting up or rearranging your site. Renaming sections or categories As we've just seen, Joomla! allows you to easily rearrange your site structure and its contents. You can also rename sections and categories that already contain articles; no content will be lost. Time for action - rename a section On your client's website there's an Activities section. Your client wants to make it clear this section is not about activities organized by other art societies-it's only about SRUP. Could you please change the name of the section to SRUP Activities? It's a breeze. Navigate to Content | Section Manager and click on the title of the Activities section to open it for editing. In the Section: [Edit] screen, change the Title to SRUP Activities. In the Alias: field, remove the existing alias (remember, the Alias is Joomla!'s internal name for the article used when creating user-friendly URLs). Leave this box blank; Joomla! will fill it with srup-activities when you apply or save your changes. You can check that now by clicking on Apply. You'll notice the Alias box is filled out automatically. Click on Save. What just happened? By changing a section or category name, all of Joomla!'s internal references to the name are updated automatically. All articles and categories in the renamed section will reflect the changes you made. In the Article Manager, for example, all items that belonged to the Activities section are now updated to show they are in the SRUP Activities section. No manual labor here and more importantly, nothing is lost! On the frontend, the new section name shows up on the section overview page when the user clicks on the Activities link: Have a go hero - name and rename! Using appropriate, short, and descriptive labels for sections and categories (and for the menu links pointing to them) is really essential. After all, these are the words that guide your visitors to the content you want them to discover. It's a good idea to tweak these labels until you're perfectly happy with them. To modify the names of categories, navigate to the Category Manager; it's similar to changing section names. Maybe you would like to change menu link labels too, as these don't automatically change with the category or section name. Try to find short and appropriate menu link labels. To change menu link labels, navigate to the Main Menu, select any of the menu items and change what's in the Title field (that is, SRUP Activities). When changing Titles (of Sections/Categories/Menu Link Items) make sure to clear the contents of the Alias box. Joomla! will automatically create an Alias for the new Title. Changing section and category settings You've already created a good deal of sections and categories without altering any of the default settings. In some cases, however, you might want some more control over the section or category you're editing. In the table below you can see the options that are available in the Section/Category: [New] or Section/Category: [Edit] screen. Basically, you can customize these settings for two purposes: To determine whether a section or category is visible (and which user groups can see it) To add a short descriptive text whenever the section or category contents are displayed. We'll cover both the Section and Category edit screen in the overview next, as all settings and options are identical. The only difference is that when adding a category, Joomla! wants you to specify the section that holds the new category. This is what the Section: [New] and the Category: [New] screen look like:
Read more
  • 0
  • 0
  • 1582

article-image-understanding-dotnetnuke-core-architecture-extension
Packt
06 Apr 2010
8 min read
Save for later

Understanding the DotNetNuke Core Architecture- An Extension

Packt
06 Apr 2010
8 min read
The global files The Global.asax.vb and Globals.vb files share similar names but the parts they play in DotNetNuke are vastly different. The Global.asax.vb is used by DotNetNuke to handle application-level events raised by the ASP.NET runtime. The Globals.vb file, on the other hand, is a public module (which is the same as a static class in C#) that contains global utility functions. Before we take a look at these fi les, we first want to look at what object is being passed around in these transactions. Global.asax.vb Much of the logic that used to reside in the Global.asax.vb fi le has now been abstracted to the HTTP modules. We will look into the code that remains. Application_Start When the fi rst request is made to your application (when the fi rst user accesses the portal), a pool of HttpApplication instances are created and the Application_Start event is fi red. This will (theoretically) fire just once and on the first HttpApplication object in the pool. When there is inactivity on your portal for a certain amount of time, the application (or application pool) will be recycled. When the pool is recycled, your application will restart (and this event will fi re again) when the next request is made for your application. As the new version of DotNetNuke uses the .NET website structure, you will find the Global.asax.vb fi le in the App_Code folder. In the Application_Start, we are loading all of the confi gured providers to ensure they are available to the rest of the framework when needed. These are performed in the Application_Start because we want them to be called only once. Private Sub Application_Start(ByVal Sender As Object, ByVal E AsEventArgs)If Config.GetSetting("ServerName") = "" ThenServerName = Server.MachineNameElseServerName = Config.GetSetting("ServerName")End IfComponentFactory.Container = New SimpleContainer()'Install most Providers as Singleton LifeStyleComponentFactory.InstallComponents _(New ProviderInstaller("data", GetType(DotNetNuke.Data.DataProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("caching", GeType(Services.Cache.CachingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("logging", GetType(Services.Log.EventLog.LoggingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("scheduling", GetType(Services.Scheduling.SchedulingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("searchIndex", GetType(Services.Search.IndexingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("searchDataStore", GetType(Services.Search.SearchDataStoreProvider)))ComponentFactory.InstallComponents_(New ProviderInstaller("friendlyUrl", GetType(Services.Url.FriendlyUrl.FriendlyUrlProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("members", GetType(DotNetNuke.Security.Membership.MembershipProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("roles", GetType(DotNetNuke.Security.Roles.RoleProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("profiles", GetType(DotNetNuke.Security.Profile.ProfileProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("permissions", GetType(DotNetNuke.Security.Permissions.PermissionProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("outputCaching", GetType(DotNetNuke.Services.OutputCache.OutputCachingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("moduleCaching", GetType(DotNetNuke.Services.ModuleCache.ModuleCachingProvider)))Dim provider As DotNetNuke.Security.Permissions.PermissionProvider = _DotNetNuke.ComponentModel.ComponentFactory.GetComponent _(Of DotNetNuke.Security.Permissions.PermissionProvider)()If provider Is Nothing ThenComponentFactory.RegisterComponentInstance _(Of DotNetNuke.Security.Permissions.PermissionProvider) _(New DotNetNuke.Security.Permissions.PermissionProvider())End If'Install Navigation and Html Providers as NewInstanceLifestyle (ie a new instance is generated each time the type isrequested, as there are often multiple instances on the page)ComponentFactory.InstallComponents _(New ProviderInstaller("htmlEditor", _GetType(Modules.HTMLEditorProvider.HtmlEditorProvider), _ComponentLifeStyleType.Transient))ComponentFactory.InstallComponents _(New ProviderInstaller("navigationControl", _GetType(Modules.NavigationProvider.NavigationProvider), _ComponentLifeStyleType.Transient))End Sub In previous versions of DotNetNuke, there was a great deal happening in this method. However, this code has been moved into various methods inside of the Initialize class. This was done to support the integrated pipeline mode of IIS 7. If you would like to take a look at what is happening inside of the Initialize class, it can be found in the Common folder of the DotNetNuke.Library project. Examining Application_BeginRequest The Application_BeginRequest is called for each request made to your application. In other words, this will fi re every time a page (tab), or other web request handlers such as a web service or an ashx handler, is accessed in your portal. This section is used to implement the scheduler built into DotNetNuke. Starting in version 2.0, two items, "users online" and "site log", require recurring operations. Also in this method is the call to the Initialize.Init() method that was moved out of the Appli cation_Startup method as mentioned previously. You can fi nd out more about the scheduler by looking at the DotNetNuke Scheduler.pdf document (only if you download the documentation pack). Also note that, there is a host setting that defi nes the running mode of a scheduler, you can check for a scheduler run on every request to your portal, or run the scheduler in a timer mode. Private Sub Global_BeginRequest(ByVal sender As Object, _ByVal e As EventArgs) Handles Me.BeginRequestDim app As HttpApplication = CType(sender, HttpApplication)Dim Request As HttpRequest = app.RequestIf Request.Url.LocalPath.ToLower.EndsWith("scriptresource.axd") _OrElse Request.Url.LocalPath.ToLower.EndsWith("webresource.axd") _OrElse Request.Url.LocalPath.ToLower.EndsWith("gif") _OrElse Request.Url.LocalPath.ToLower.EndsWith("jpg") _OrElse Request.Url.LocalPath.ToLower.EndsWith("css") _OrElse Request.Url.LocalPath.ToLower.EndsWith("js") ThenExit SubEnd If' all of the logic which was previously in Application_Start' was moved to Init() in order to support IIS7 integrated pipelinemode' ( which no longer provides access to HTTP context withinApplication_Start )Initialize.Init(app)'run schedule if in Request modeInitialize.RunSchedule(Request)End Sub The Globals.vb file As part of the namespace-reorganization effort associated with DotNetNuke version 3.0, general utility functions, constants, and enumerations have all been placed in a public module (as just mentioned, module here refers to VB.NET module keyword, not a DotNetNuke module) named Globals . As items in a .NET module are inherently shared, you do not need to instantiate an object in order to use the functions found here. In this module, you will find not only global constants, as shown in the following code: Public Const glbRoleAllUsers As String = "-1"Public Const glbRoleSuperUser As String = "-2"Public Const glbRoleUnauthUser As String = "-3"Public Const glbRoleNothing As String = "-4"Public Const glbRoleAllUsersName As String = "All Users"Public Const glbRoleSuperUserName As String = "Superuser"Public Const glbRoleUnauthUserName As String ="Unauthenticated Users"Public Const glbDefaultPage As String = "Default.aspx"Public Const glbHostSkinFolder As String = "_default"Public Const glbDefaultControlPanel As String = "Admin/ControlPanel/IconBar.ascx"Public Const glbDefaultPane As String = "ContentPane"Public Const glbImageFileTypes As String = "jpg,jpeg,jpe,gif,bmp,png,swf"Public Const glbConfigFolder As String = "Config"Public Const glbAboutPage As String = "about.htm"Public Const glbDotNetNukeConfig As String = "DotNetNuke.config"Public Const glbSuperUserAppName As Integer = -1Public Const glbProtectedExtension As String = ".resources"Public Const glbEmailRegEx As String = "b[a-zA-Z0-9._%-+']+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}b"Public Const glbScriptFormat As String = "<script type=""text/javascript"" src=""{0}"" ></script>"   but a tremendous number of public functions to help you do everything, from retrieving the domain name, as shown: Public Function GetDomainName(ByVal Request As HttpRequest, ByValParsePortNumber As Boolean) As String to setting the focus on a page: Public Sub SetFormFocus(ByVal control As Control) This one file contains a wealth of information for the developer. As there are more than 3070 lines in the fi le and the methods are fairly straightforward, we will not be stepping through this code. The Globals.vb fi le can now be found in the DotNetNuke.Library project in the Common folder. Putting it all together We have spent some time looking at some of the major pieces that make up the core architecture. You might be asking yourself how all this works together. In this section, we will walk you through an overview version of what happens when a user requests a page on your portal. A shown in the preceding diagram, when a user requests any page on your portal, the HTTP Modules that have been declared in the web.config file are hooked into the pipeline. Typically, these modules use the Init method to attach event handlers to application events. The request then goes through the Global.asax page. As just mentioned, some of the events fi red here will be intercepted and processed by the HTTP modules, but the call to run the scheduler will happen in this fi le. Next, the page that was requested, Default.aspx, will be processed. As we stated at the beginning of this article, all requests are sent to the Default.aspx page and all the controls and skins needed for the page are created dynamically by reading the tabID from the requested URL. So let's begin by looking at the HTML for this page.
Read more
  • 0
  • 0
  • 1913

article-image-understanding-dotnetnuke-core-architecture
Packt
06 Apr 2010
13 min read
Save for later

Understanding the DotNetNuke Core Architecture

Packt
06 Apr 2010
13 min read
Architecture overview As opposed to traditional web applications that may rely on a multitude of web pages to deliver content, DotNetNuke uses a single main page called Default.aspx. The content for this page is generated dynamically by using a tabID value to retrieve the skin and modules needed to build the page requested, from the DotNetNuke database. Before we move on, we should discuss what is meant by a tab and a page. As you read this article, you will notice the word "tab" is sometimes used when referring to pages in your DotNetNuke portal. In the original IBuySpy application, pages were referred to as tabs because they resembled tabs when added to the page. IBuySpy application, the skeleton ASP.NET Framework, was created by Microsoft to demonstrate ASP.NET features, and DotNetNuke was originally derived from it. This continued in the original versions of the DotNetNuke project. Starting with version 3.0, and continuing with version 5.2.x, there has been an ongoing effort to rename most of these instances to reflect what they really are: pages. Most references to "tabs" have been changed to "pages", but the conversion is not complete. For this reason, you will see both—tabs and pages—in the database, in the project files, and in this text. We will use these terms interchangeably throughout this text as we look into the core architecture of DNN. We will begin with a general overview of what happens when a user requests a page on your DotNetNuke portal. The process for rendering a page in DotNetNuke works like this: a user navigates to a page on your portal; this calls the Default.aspx page, passing the tabid parameter in the querystring to let the application identify the page being requested. The example http://www.dotnetnuke.com/Default. aspx?tabid=476 demonstrates this. DotNetNuke 3.2 introduced something called URL rewriting. This takes the querystring shown above and rewrites it so that it is in a format that helps increase search engine hits. We will cover the HTTP module that is responsible for this in more detail later in this article. The rewritten URL would resemble http://localhost/DotNetNuke/Home.aspx. This assumes that the page name for tabid 476 is Home. While referring to URLs in this article we will be using the non-rewritten version of the URL. URL rewriting can be turned off in the friendly URL section of the Host Settings page. The querystring value (?tabid=476) is sent to the database, where the information required for the page is retrieved, as shown in the following diagram: The portal that the user is accessing can be determined in a number of ways, but as you can see from the Tabs table (see the following screenshot), each page/tab contains a reference to the portal it belongs to in the PortalID field. Once the server has a reference to the page that the user requested (using the tabID), it can determine what modules belong to that page. Although there are many more tables involved in this process, you can see that these tables hold not only the page and modules needed to generate the page, but also what pane to place them on (PaneName) and what container skin to apply (ContainerSrc). All of this information is returned to the web server, and the Default.aspx page is constructed with it and returned to the user who requested it along with the required modules and skins, as shown in the following diagram. Now, this is of course a very general overview of the process, but as we work through this article, we will delve deeper into the code that makes this process work, and in the end, show a request work its way through the framework to deliver a page to a user. Diving into the core There are over 160,000 lines of code in the DotNetNuke application. There is no practical (or even possible) way to cover the entire code base. In this section, we will go in depth into what I believe are the main portions of the code base: the PortalSettings as well as the companion classes found in the portals folder; the web.config file including the HTTP Modules and Providers; and the Global.asax and Globals.vb files. We will start our discussion of the core with two objects that play an integral part in the construction of the architecture. The Context object and the PortalSettings class will both be referred to quite often in the code, and so it is important that you have a good understanding of what they do. Using the Context object in your application ASP .NET has taken intrinsic objects like the Request and the Application objects and wrapped them together with other relevant items into an intrinsic object called Context. The Context object (HttpContext) can be found in the System.Web namespace. In the following table, you will find some of the objects that make up the HttpContext object. Title Description Application Gets the HttpApplicationState object for the current HTTP request. Cache Gets the Cache object for the current HTTP request. Current Gets the HttpContext object for the current HTTP request. This is a static (shared in VB) property of the HttpContext class, through which you access all other instance properties discussed in this table, that together enable you to process and respond to an HTTP request. Items Gets a key-value collection that can be used to organize and share data between an IHttpModule and an IHttpHandler during an HTTP request. Request Gets the HttpRequest object for the current HTTP request. This is used to extract data submitted by the client, and information about the client itself (for example, IP ), and the current request. Response Gets the HttpResponse object for the current HTTP response. This is used to send data to the client together with other response-related information such as headers, cacheability, redirect information, and so on. Server Gets the HttpServerUtility object that provides methods used in processing web requests. Session Gets the HttpSessionState instance for the current HTTP request. User Gets or sets security information for the current HTTP request. Notice that most of the descriptions talk about the "current" request object, or the "current" response object. The Global.asax file, which we will look at soon, reacts on every single request made to your application, and so it is only concerned with whoever is "currently" accessing a resource. The HttpContext object contains all HTTP-specific information about an individual HTTP request. In particular, the HttpContext.Current property can give you the context for the current request from anywhere in the application domain. The DotNetNuke core relies on the HttpContext.Current property to hold everything from the application name to the portal settings and through this makes it available to you. The PortalSettings class The portal settings play a major role in the dynamic generation of your pages and as such will be referred to quite often in the other portions of the code. The portal settings are represented by the PortalSettings class which you will find in the EntitiesPortalPortalSettings.vb file. As you can see from the private variables in this class, most of what goes on in your portal will at some point needto access this object. This object will hold everything from the ID of the portal to the default language, and as we will see later, is responsible for determining the skins and modules needed for each page. Private _PortalId As IntegerPrivate _PortalName As StringPrivate _HomeDirectory As StringPrivate _LogoFile As StringPrivate _FooterText As StringPrivate _ExpiryDate As DatePrivate _UserRegistration As IntegerPrivate _BannerAdvertising As IntegerPrivate _Currency As StringPrivate _AdministratorId As IntegerPrivate _Email As StringPrivate _HostFee As SinglePrivate _HostSpace As IntegerPrivate _PageQuota As IntegerPrivate _UserQuota As IntegerPrivate _AdministratorRoleId As IntegerPrivate _AdministratorRoleName As StringPrivate _RegisteredRoleId As IntegerPrivate _RegisteredRoleName As StringPrivate _Description As StringPrivate _KeyWords As StringPrivate _BackgroundFile As StringPrivate _GUID As GuidPrivate _SiteLogHistory As IntegerPrivate _AdminTabId As IntegerPrivate _SuperTabId As IntegerPrivate _SplashTabId As IntegerPrivate _HomeTabId As IntegerPrivate _LoginTabId As IntegerPrivate _UserTabId As IntegerPrivate _DefaultLanguage As StringPrivate _TimeZoneOffset As IntegerPrivate _Version As StringPrivate _ActiveTab As TabInfoPrivate _PortalAlias As PortalAliasInfoPrivate _AdminContainer As SkinInfoPrivate _AdminSkin As SkinInfoPrivate _PortalContainer As SkinInfoPrivate _PortalSkin As SkinInfoPrivate _Users As IntegerPrivate _Pages As Integer The PortalSettings class itself is simple. It is filled by using one of the constructors that accepts one or more parameters. These constructors then call the private GetPortalSettings method . The method is passed a tabID and a PortalInfo object. You already know that the tabID represents the ID of the page being requested, but the PortalInfo object is something new. This class can be found in the same folder as the PortalSettings class and contains the basic information about a portal such as PortalID, PortalName, and Description. However, from the PortalSettings object, we can retrieve all the information associated with the portal. If you look at the code inside the constructors, you will see that the PortalController object is used to retrieve the PortalInfo object. The PortalInfo object is saved in cache for the time that is specifi ed on the Host Settings page. A drop-down box on the Host Settings page (DesktopModulesAdminHostSettingsHostSettings.ascx) is used to set the cache. No caching:0 Light caching:1 Moderate caching:3 Heavy caching:6 The value in this dropdown ranges from 0 to 6; the code in the DataCache object takes the value set in the drop-down and multiplies it by 20 to determine the cache duration. Once the cache time is set, the method checks if the PortalSettings object already resides there. Retrieving these settings from the database for every request would cause your site to run slowly, so placing them in a cache for the duration you select helps increase the speed of your site. Recent versions of DotNetNuke have focused heavily on providing an extensive caching service. An example of this can be seen in the following code: Dim cacheKey As String = String.Format(DataCache.PortalCacheKey,PortalId.ToString())Return CBO.GetCachedObject(Of PortalInfo)(New CacheItemArgs(cacheKey, DataCache.PortalCacheTimeOut,DataCache.PortalCachePriority, PortalId),AddressOf GetPortalCallback) We can see in the previous code that the CBO object is used to return an object from the cache. CBO is an object that is seen frequently throughout the DotNetNuke core. This object's primary function is to return the populated business object. This is done in several ways using different methods provided by CBO. Some methods are used to map data from an IDataReader to the properties of a business object. However, in this example, the Get CachedObject method handles the logic needed to determine if the object should be retrieved from the cache or from the database. If the object is not already cached, it will use the GetPortalCallback method passed to the method to retrieve the portal settings from the database. This method is located in the PortalController class (EntitiesPortalPortalController.vb) and is responsible for retrieving the portal information from the database. Dim portalID As Integer = DirectCast(cacheItemArgs.ParamList(0),Integer)Return CBO.FillObject(Of PortalInfo)(DataProvider.Instance _.GetPortal(portalID, Entities.Host.Host.ContentLocale.ToString)) This will fi ll the PortalInfo object (EntitiesPortalPortalInfo.vb), which as we mentioned, holds the portal information. This object in turn is returned to the GetCachedObject method. Once this is complete, the object is then cached to help prevent the need to call the database during the next request for the portal information. There is also a section of code (not shown) that verifi es whether the object was successfully stored in the cache and adds an entry to the event log if the item failed to be cached. ' if we retrieved a valid object and we are using cachingIf objObject IsNot Nothing AndAlso timeOut > 0 Then' save the object in the cacheDataCache.SetCache(cacheItemArgs.CacheKey, objObject, _cacheItemArgs.CacheDependency, Cache.NoAbsoluteExpiration, _TimeSpan.FromMinutes(timeOut), cacheItemArgs.CachePriority, _cacheItemArgs.CacheCallback)…End If After the portal settings are saved, the properties of the current tab information are retrieved and populated in the ActiveTab property. The current tab is retrieved by using the tabID that was originally passed to the constructor. This is handled by the VerifyPortalTab method and done by getting a list of all of the tabs for the current portal. Like the portal settings themselves, the tabs are saved in cache to boost performance. The calls to the caching provider, this time, are handled by the TabController (EntitiesTabsTabController.vb). In the last VerifyPortalTab method, the code will loop through all of the host and non-host tabs, returned by the TabController, for the site until the current tab is located. ' find the tab in the portalTabs collectionIf TabId <> Null.NullInteger ThenIf portalTabs.TryGetValue(TabId, objTab) Then'Check if Tab has been deleted (is in recycle bin)If Not (objTab.IsDeleted) ThenMe.ActiveTab = objTab.Clone()isVerified = TrueEnd IfEnd IfEnd If' find the tab in the hostTabs collectionIf Not isVerified AndAlso TabId <> Null.NullInteger ThenIf hostTabs.TryGetValue(TabId, objTab) Then'Check if Tab has been deleted (is in recycle bin)If Not (objTab.IsDeleted) ThenMe.ActiveTab = objTab.Clone()isVerified = TrueEnd IfEnd IfEnd If If the tab was not found in either of these collections, the code attempts to use the splash page, home page, or the fi rst page of the non-host pages. After the current tab is located, further handling of some of its properties is done back in the GetPortalSettings method. This includes formatting the path for the skin and default container used by the page, as well as collecting information on the modules placed on the page. Me.ActiveTab.SkinSrc = _SkinController.FormatSkinSrc(Me.ActiveTab.SkinSrc, Me)Me.ActiveTab.SkinPath = _SkinController.FormatSkinPath(Me.ActiveTab.SkinSrc)…For Each kvp As KeyValuePair(Of Integer, ModuleInfo) In _objModules.GetTabModules(Me.ActiveTab.TabID)' clone the module object _( to avoid creating an object reference to the data cache )Dim cloneModule As ModuleInfo = kvp.Value.Clone' set custom propertiesIf Null.IsNull(cloneModule.StartDate) ThencloneModule.StartDate = Date.MinValueEnd IfIf Null.IsNull(cloneModule.EndDate) ThencloneModule.EndDate = Date.MaxValueEnd If' containerIf cloneModule.ContainerSrc = "" ThencloneModule.ContainerSrc = Me.ActiveTab.ContainerSrcEnd IfcloneModule.ContainerSrc = _SkinController.FormatSkinSrc(cloneModule.ContainerSrc, Me)cloneModule.ContainerPath = _SkinController.FormatSkinPath(cloneModule.ContainerSrc)' process tab panesIf objPaneModules.ContainsKey(cloneModule.PaneName) = False ThenobjPaneModules.Add(cloneModule.PaneName, 0)End IfcloneModule.PaneModuleCount = 0If Not cloneModule.IsDeleted ThenobjPaneModules(cloneModule.PaneName) = _objPaneModules(cloneModule.PaneName) + 1cloneModule.PaneModuleIndex = _objPaneModules(cloneModule.PaneName) - 1End IfMe.ActiveTab.Modules.Add(cloneModule)Next We have now discussed some of the highlights of the PortalSettings object as well as how it is populated with the information it contains. In doing so, we also saw abrief example of the robust caching service provided by DotNetNuke. You will see the PortalSettings class referenced many times in the core DotNetNuke code, so gaining a good understanding of how this class works will help you to become more familiar with the DNN code base. You will also fi nd this object to be very helpful while building custom extensions for DotNetNuke. The caching provider itself is a large topic, and reaches beyond the scope of this article. However, simply understanding how to work with it in the ways shown in these examples should satisfy the needs of most developers. It is important to note that, you can get any type of object cached by DNN by passing in a key for your object to DataCache.SetCache method, together with the data, and some optional arguments. While fetching the object back from DataCache.GetCache, you pass in the same key, and check the result. A non-null (non-Nothing in VB) return value means you have fetched the object successfully from the cache, otherwise you would need to fetch it from the database.
Read more
  • 0
  • 0
  • 4138
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-biztalk-server-standard-message-exchange-patterns-and-types-service
Packt
06 Apr 2010
4 min read
Save for later

BizTalk Server: Standard Message Exchange Patterns and Types of Service

Packt
06 Apr 2010
4 min read
Identifying Standard Message Exchange Patterns When we talk about Message Exchange Patterns, or MEPs, we're considering the direction and timing of data between the client and service. How do I get into the bus and what are the implications of those choices? Let's discuss the four primary options. Request/Response services This is probably the pattern that's most familiar to you. We're all comfortable making a function call to a component and waiting for a response. When a service uses this pattern, it's frequently performing a remote procedure call where the caller accesses functionality on the distant service and is blocked until either a timeout occurs or until the receiver sends a response that is expected by the caller. As we'll see below, while this pattern may set developers at ease, it may encourage bad behavior. Nevertheless, the cases where request/response services make the most sense are fine-grained functions and mashup services. If you need a list of active contracts that a hospital has with your company, then a request/response operation fits best. The client application should wait until that response is received before moving on to the next portion of the application. Or, let's say my web portal is calling an aggregate service, which takes contact data from five different systems and mashes them up into a single data entity that is then returned to the caller. This data is being requested for immediate presentation to an end user, and thus it's logical to solicit information from a service and wait to draw the screen until the completed result is loaded. BizTalk Server 2009 has full support for both consuming and publishing services adhering to a request/response pattern. When exposing request/response operations through BizTalk orchestrations, the orchestration port's Communication Pattern is set to Request-Response and the Port direction of communication is equal to I'll be receiving a request and sending a response. Once this orchestration port is bound to a physical request/response receive port, BizTalk takes care of correlating the response message with the appropriate thread that made the request. This is significant because by default, BizTalk is a purely asynchronous messaging engine. Even when you configure BizTalk Server to behave in a request/response fashion, it's only putting a facade on the standard underlying plumbing. A synchronous BizTalk service interface actually sits on top of a sophisticated mechanism of correlating MessageBox communication to simulate a request/response pattern. When consuming request/response services from BizTalk from an orchestration, the orchestration port's Communication Pattern is set to Request-Response and the Port direction of communication is equal to I'll be sending a request and receiving a response. The corresponding physical send port uses a solicit-response pattern and allows the user to set up both pipelines and maps for the inbound and outbound messages. One concern with either publishing or consuming request/response services is the issue of blocking and timeouts. From a BizTalk perspective, this means that whenever you publish an orchestration as a request/response service, you should always verify that the logic residing between inbound and outbound transmissions will either complete or fail within a relatively brief amount of time. This dictates wrapping this logic inside an orchestration Scope shape with a preset timeout that is longer than the standard web service timeout interval. For consuming services, a request/response pattern forces the orchestration to block and wait for the response to be returned. If the service response isn't necessary for processing to continue, consider using a Parallel shape that isolates the service interaction pattern on a dedicated branch. This way, the execution of unrelated workflow steps can proceed even though the downstream service is yet to respond.
Read more
  • 0
  • 0
  • 3516

article-image-installation-and-getting-started-firebug
Packt
05 Apr 2010
3 min read
Save for later

Installation and Getting Started with Firebug

Packt
05 Apr 2010
3 min read
What is Firebug? Firebug is a free, open source tool that is available as a Mozilla Firefox extension, and allows debugging, editing, and monitoring of any website's CSS, HTML, DOM, and JavaScript. It also allows performance analysis of a website. Furthermore, it has a JavaScript console for logging errors and watching values. Firebug has many other tools to enhance the productivity of today's web developer. Firebug integrates with Firefox to put a wealth of development tools at our fingertips while we browse a website. Firebug allows us to understand and analyze the complex interactions that take place between various elements of any web page when it is loaded by a browser. Firebug simply makes it easier to develop websites/applications. It is one of the best web development extensions for Firefox. Firebug provides all the tools that a web developer needs to analyze, debug, and monitor JavaScript, CSS, HTML, and AJAX. It also includes a debugger, error console, command line, and a variety of useful inspectors. Although Firebug allows us to make changes to the source code of our web page, the changes are made to the copy of the HTML code that has been sent to the browser by the server. Any changes to the code are made in the copy that is available with the browser. The changes don't get reflected in the code that is on the server. So, in order to ensure that the changes are permanent, corresponding changes have to be made in the code that resides on the server. The history of Firebug Firebug was initially developed by Joe Hewitt, one of the original Firefox creators, while working at Parakey Inc. Facebook purchased Parakey in July, 2007. Currently, the open source development and extension of Firebug is overseen by the Firebug Working Group. It has representation from Mozilla, Google, Yahoo, IBM, Facebook, and many other companies. Firebug 1.0 Beta was released in December 2006. Firebug usage has grown very fast since then. Approximately 1.3 million users have Firebug installed as of January 2009. The latest version of Firebug is 1.5. Today, Firebug has a very open and thriving community. Some individuals as well as some companies have developed very useful plugins on top of Firebug. The need for Firebug During the 90s, websites were mostly static HTML pages, JavaScript code was considered a hack, and there were no interactions between page components on the browser side. The situation is not the same anymore. Today's websites are a product of several distinct technologies and web developers must be proficient in all of them—HTML, CSS, JavaScript, DOM, and AJAX, among others. Complex interactions happen between various page components on the browser side. However, web browsers have always focused on the needs of the end users; as a result, web developers have long been deprived of a good tool on the client/browser side to help them develop and debug their code. Firebug fills this gap very nicely—it provides all the tools that today's web developer needs in order to be productive and efficient with code that runs in the browser. Firebug capabilities Firebug has a host of features that allow us to do the following (and much more!): Inspect and edit HTML Inspect and edit CSS and visualize CSS metrics Use a performance tuning application Profile and debug JavaScript Explore the DOM Analyze AJAX calls
Read more
  • 0
  • 0
  • 4306

article-image-managing-data-mysql
Packt
01 Apr 2010
8 min read
Save for later

Managing Data in MySQL

Packt
01 Apr 2010
8 min read
Exporting data to a simple CSV file While databases are a great tool to store and manage your data, you sometimes need to extract some of the data from your database to use it in another tool (a spreadsheet application being the most prominent example for this). In this recipe, we will show you how to utilize the respective MySQL commands for exporting data from a given table into a fi le that can easily be imported by other programs. Getting ready To step through this recipe, you will need a running MySQL database server and a working installation of a SQL client (like MySQL Query Browser or the mysql command line tool). You will also need to identify a suitable export target, which has to meet the following requirements: The MySQL server process must have write access to the target file The target file must not exist The export target file is located on the machine that runs your MySQL server, not on the client side! If you do not have file access to the MySQL server, you could instead use export functions of MySQL clients like MySQL Query Browser. In addition, a user with FILE privilege is needed (we will use an account named sample_install for the following steps; see also Chapter 8 Creating an installation user). Finally, we need some data to export. Throughout this recipe, we will assume that the data to export is stored in a table named table1 inside the database sample. As export target, we will use the file C:/target.csv (MySQL accepts slashes instead of backslashes in Windows path expressions). This is a file on the machine that runs the MySQL server instance, so in this example MySQL is assumed to be running on a Windows machine. To access the results from the client, you have to have access to the file (for example, using a fi le share or executing the MySQL client on the same machine as the server). How to do it... Connect to the database using the sample_install account. Issue the following SQL command: mysql> SELECT * FROM sample.table1 INTO OUTFILE 'C:/target.csv'FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"' LINESTERMINATED BY 'rn'; Please note that when using a backslash instead of a slash in the target file's path, you have to use C:target.csv (double backslash for escaping) instead. If you do not give a path, but only a fi le name, the target fi le will be placed in the data directory of the currently selected schema of your MySQL server. How it works... In the previous SQL statement, a file C:/target.csv was created, which contains the content of the table sample.table1. The file contains a separate line for each row of the table, and each line is terminated by a sequence of a carriage return and a line feed character. This line ending was defined by the LINES TERMINATED BY 'rn' portion of the command. Each line contains the values of each column of the row. The values are separated by semicolons, as stated in the TERMINATED BY ';' clause. Every value is enclosed by a double quotation mark ("), which results from the FIELDS ENCLOSED BY '"' option. When writing the data to the target fi le, no character conversion takes place; the data is exported using the binary character set. This should be kept in mind especially when importing tables with different character sets for some of its values. You might wonder why we chose the semicolon instead of a comma as the field separator. This is simply because of a greatly improved Microsoft Excel compatibility (you can simply open the resulting files), without the need to import external data from the fi les. But you can, however, open these fi les in a different spreadsheet program (like OpenOffice.org Calc) as well. If you think the usage of semicolons is in contradiction to the notion of a CSV file, think of it as a Character Separated File. The use of double quotes to enclose single values prevents problems when field values contain semicolons (or generally the field separator character). These are not recognized as field separators if they are enclosed in double quotes. There's more... While the previous SELECT … INTO OUTFILE statement will work well in most cases, there are some circumstances in which you still might encounter problems. The following topics will show you how to handle some of those. Handling errors if the target fi le already exists If you try to execute the SELECT … INTO OUTFILE statement twice, an error File 'C:/target.csv' already exists occurs. This is due to a security feature in MySQL that makes sure that you cannot overwrite existing fi les using the SELECT … INTO OUTFILE statement. This makes perfect sense if you think about the consequences. If this were not the case, you could overwrite the MySQL data files using a simple SELECT because MySQL server needs write access to its data directories. As a result, you have to choose different target files for each export (or remove old files in advance). Unfortunately, it is not possible to use a non-constant file name (like a variable) in the SELECT … INTO OUTFILE export statement. If you wish to use different file names, for example, with a time stamp as part of the file name, you have to construct the statement inside a variable value before executing it:   mysql> SET @selInOutfileCmd := concat("SELECT * FROM sample.table1 INTOOUTFILE 'C:/target-", DATE_FORMAT(now(),'%Y-%m-%d_%H%i%s'), ".csv' FIELDSENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"' LINES TERMINATED BY'rn';");mysql> PREPARE statement FROM @selInOutfileCmd;mysql> EXECUTE statement; The first SET statement constructs a string, which contains a SELECT statement. While it is not allowed to use variables for statements directly, you can construct a string that contains a statement and use variables for this. With the next two lines, you prepare a statement from the string and execute it. Handling NULL values Without further handling, NULL values in the data you export using the previous statement would show up as "N in the resulting file. This combination is not recognized, for example, by Microsoft Excel, which breaks the file (for typical usage). To prevent this, you need to replace NULL entries by appropriate values. Assuming that the table sample.table1 consists of a numeric column a and a character column b, you should use the following statement: mysql> SELECT IFNULL(a, 0), IFNULL(b, "NULL") FROM sample.table1 INTOOUTFILE 'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPEDBY '"' LINES TERMINATED BY 'rn'; The downside to this approach is that you have to list all fi elds in which a NULL value might occur. Handling line breaks If you try to export values that contain the same character combination used for line termination in the SELECT … INTO OUTFILE statement, MySQL will try to escape the character combination with the characters defined by the ESCAPED BY clause. However, this will not always work the way it is intended. You will typically define rn as the line separators. With this constellation, values that contain a simple line break n will not cause problems, as they are exported without any conversion and can be imported to Microsoft Excel flawlessly. If your values happen to contain a combination of carriage return and line feed, the rn characters will be prepended with an escape character ("rn), but still the target file cannot be imported correctly. Therefore, you need to convert the full line breaks to simple line breaks: mysql> SELECT a, REPLACE(b, 'rn', 'n') FROM sample.table1 INTO OUTFILE'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"'LINES TERMINATED BY 'rn'; With this statement, you will export only line breaks n, which are typically accepted for import by other programs. Including headers For better understanding, you might want to include headers in your target fi le. You can do so by using a UNION construct: mysql> (SELECT 'Column a', 'Column b') UNION ALL (SELECT * FROM sample.table1 INTO OUTFILE 'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY';' ESCAPED BY '"' LINES TERMINATED BY 'rn'); The resulting file will contain an additional first line with the given headers from the first SELECT clause.
Read more
  • 0
  • 0
  • 5928

article-image-rendering-web-pages-pdf-using-railo-open-source
Packt
01 Apr 2010
6 min read
Save for later

Rendering web pages to PDF using Railo Open Source

Packt
01 Apr 2010
6 min read
As a pre-requisite for this tutorial, you should be familiar with html, css and web technologies in general. You do not need to know any CFML (ColdFusion Markup Language). You should have an understanding of databases, particularly MySQL, which we will use in this example. Server environment For this tutorial, we are using a virtual machine (using VirtualBox) running Windows 2003 Server Standard, IIS, MySQL 5.1, and Railo 3.1. The code we will be writing is not platform specific. You can just as easily implement this on Linux or Mac OSX Server with MySQL and Apache. Website architecture Lets assume that we have the HTML layout code provided to us for our website, and that we need to make it “work” on the web server, pulling its page content from a MySQL database. In addition, we will add the capability for any page to render itself as a PDF for printing purposes. You will want to make sure you have done a few things first: Make sure Railo and MySQL are running on your server (or VM) Make sure you created a MySQL database, and a user that has permission to use your database For development (as opposed to production web servers), try running Railo Express, which runs in a terminal window. This allows you to see the templates it is running, and the full stack trace of errors when they occur. Setting up the Railo datasource The first thing we need to do is setup a Railo datasource. This named datasource will define our database credentials for our website. Open a web browser to the Railo Server Administrator, which is usually located at: http://your.server.com/railo-context/admin/server.cfm. Check the Railo documentation if you have trouble opening up the administrator. Enter your password to login. Once logged in, click on the Services / Datasource link in the left navigation. At the bottom of this page is where you can create a new datasource. Enter a datasource name (Letters and numbers only, no spaces, and start with a letter) and select MySQL as the database type. On the next screen, enter the MySQL server host name or ip address, and username and password for the user you created. All of the other settings can be kept with their default values. Scroll to the bottom and click on the “Create” button to complete the datasource configuration. Railo Administrator will test your connection, so you can confirm that it is setup properly. We created the datasource in the “server” context. When you deploy an application on a production server, you should create your datasources in the “web” context, so that it is only available to the website that needs it. Datasources created in the server context are accessible from any website on the same server. Setting up the website structure In the document root of your website (or in the directory you choose for this tutorial), you will need a couple of files. index.cfm – this is the default document, like index.html or default.htm header.cfm – this is the top portion of web pages, what appears above your page content. This is where you would put your html “design” code. footer.cfm – this is the bottom portion of your web pages, what shows up after your page content. This is where you would put your html “design” code. layout.css – the basic CSS layout for our pages styles.css – the CSS styles for your page content Let's look first at header.cfm: This file contains what you would expect to see at the top of a standard HTML web page, including head, title, meta tags, etc. There are a few different tags included in the content however. Any tags that begin with <cf…> are CFML language tags, that are processed by Railo and removed from the source code before the page is sent to your web browser. Just like PHP or ASP.net code, if somebody views the source of your web page, they won’t see your CFML code, but rather, they will see the html code, and any code that your CFML tags generate. <cfparam name="title" default="Untitled" /> This tag defines and sets a default value for a variable named “title.” This value can be overridden using a <cfset …> tag which we will see later. #title#</cfoutput> Any content inside <cfoutput>…</cfoutput> tags will be included in the output to your web browser. In this case, the title variable is written to the page output. As with all <cf..> tags, the <cfoutput> tags themselves will be removed from the web page output. Anything inside # characters will be evaluated as an expression. So if your code was <cfoutput>title</cfoutput>, then the literal word “title” would be included in your page output. When you put # characters around it, Railo will evaluate the expression and replace it with the result.</cfoutput></cf..> header.cfm also includes the two .css files we need for our layout and styles. These are standard css which should be familiar to you, and won’t be covered in this article. Let's next look at index.cfm <cfset title="Home Page"> This first tag sets a local variable called “title” and sets its value to “Home Page.” <cfinclude template="header.cfm"> This tag includes the file “header.cfm” into the current page, which means that any page output (the html, head, title, etc. tags) will be included in this page’s output. Notice that we set the local variable title in our page, and it gets used in the header.cfm file. Local variables are available to any pages that are included in the requested web page. The “Hello World” content is the main textual content of this web page, and can be any html or CFML generated content you want. After the main content, another <cfinclude…> tag includes footer.cfm, which includes the expected end of page tags such as </body> and </html> Take a look If you open your web browser and browse to index.cfm, you will see your basic web page layout, with a page title, and Hello World content. If you view the page source, you should see the combined content of the header.cfm, index.cfm and footer.cfm, with no <cf…> tags in the output, only pure HTML. You can easily organize and create static web pages like this, and like many other programming languages, structuring your website like this has many benefits. If you make a change to your header or footer, then all your pages inherit the change immediately. Likewise if you design a new layout or style for your site, applying it once to your header and footer then applies it to your entire website.
Read more
  • 0
  • 0
  • 11663
article-image-configuring-mysql
Packt
01 Apr 2010
14 min read
Save for later

Configuring MySQL

Packt
01 Apr 2010
14 min read
Let's get started. Setting up a fixed InnoDB tablespace When using the InnoDB storage engine of MySQL, the data is typically not stored in a per-database or per-table directory structure, but in several dedicated files, which collectively contain the so-called tablespace. By default (when installing MySQL using the configuration wizard) InnoDB is confi gured to have one small file to store data in, and this file grows as needed. While this is a very fl exible and economical confi guration to start with, this approach also has some drawbacks: there is no reserved space for your data, so you have to rely on free disk space every time your data grows. Also, if your database grows bigger, the file will grow to a size which makes it hard to handle—a dozen files of 1 GB each are typically easier to manage than one clumsy 12 GB file. Large data files might, for example, cause problems if you try to put those files into an archive for backup or data transmission purposes. Even if the 2 GB limit is not present any more for the current file systems, many compression programs still have problems dealing with large files. And finally, the constant adaptation of the file in InnoDB's default configuration size will cause a (small, but existent) performance hit if your database grows. The following recipe will show you how to define a fixed tablespace for your InnoDB installation, by which you can avoid these drawbacks of the InnoDB default configuration. Getting ready To install a fixed tablespace, you will have to reflect about some aspects: how much tablespace should be reserved for your database, and how to size the single data files which in sum constitute the tablespace. Note that once your database completely allocates your tablespace, you will run into table full errors (error code 1114) when trying to add new data to your database. Additionally, you have to make sure that your current InnoDB tablespace is completely empty. Ideally, you should set up the tablespace of a freshly installed MySQL instance, in which case this prerequisite is given. To check whether any InnoDB tables exist in your database, execute the following statement and delete the given tables until the result is empty: SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.tables WHERE engine="InnoDB"; If your database already contains data stored in InnoDB tables that you do not want to lose, you will have to create a backup of your database and recover the data from it when you are done with the recipe. Please refer to the chapter Backing Up and Restoring MySQL Data for further information on this. And finally, you have to make sure that the InnoDB data directory (as defined by the innodb_data_home_dir variable) features sufficient free disk space to store the InnoDB data files. For the following example, we will use a fixed tablespace with a size of 500 MB and a maximal file size of 200 MB. How to do it... Open the MySQL configuration file (my.ini or my.cnf) in a text editor. Identify the line starting with innodb_data_file_path in the [mysqld] section. If no such line exists, add the line to the file. Change the line innodb_data_file_path to read as follows: innodb_data_file_path=ibdata1:200M;ibdata2:200M;ibdata3:100M Save the changed configuration file. Shut down your database instance (if running). Delete previous InnoDB data files (typically called ibdata1, ibdata2, and so on) from the directory defined by the innodb_data_home_dir variable. Delete previous InnoDB logfiles (named ib_logfile0, ib_logfile1, so on) from the directory defined by the innodb_log_group_home_dir variable. If innodb_log_group_home_dir is not configured explicitly, it defaults to the datadir directory. Start your database. Wait for all data and log files to be created. Depending on the size of your tablespace and the speed of your disk system, creation of InnoDB data fi les can take a significant amount of time (several minutes is not an uncommon time for larger installations). During this initialization sequence, MySQL is started but it will not accept any requests. How it works... Steps 1 through 4—and particularly 3—cover the actual change to be made to the MySQL configuration, which is necessary to adapt the InnoDB tablespace settings. The value of the innodb_data_file_path variable consists of a list of data file definitions that are separated by semicolons. Each data file definition is constructed of a fi le name and a file size with a colon as a separator. The size can be expressed as a plain numeric value, which defines the size of the data file in bytes. If the numeric value has a K, M, or G postfix, the number is interpreted as Kilobytes, Megabytes, or Gigabytes respectively. The list length is not limited to the three entries of our example; if you want to split a large tablespace into relatively small files, the list can easily contain dozens of data file definitions. If your tablespace consists of more than 10 files, we propose naming the first nine files ibdata01 through ibdata09 (instead of ibdata1 and so forth; note the zero), so that the files are listed in a more consistent order when they are displayed in your file browser or command line interface. Step 5 is prerequisite to the steps following after it, as deletion of vital InnoDB files while the system is still running is obviously not a good idea. In step 6, old data files are deleted to prevent collision with the new files. If InnoDB detects an existing file whose size differs from the size defined in the innodb_data_file_path variable, it will not initialize successfully. Hence, this step ensures that new, properly saved files can be created during the next MySQL start. Note that deletion of the InnoDB data files is only suffi cient if all InnoDB tables were deleted previously (as discussed in the Getting ready section). Alternatively, you could delete all *.frm files for InnoDB tables from the MySQL data directory, but we do not encourage this approach (clean deletion using DROP TABLE statements should be preferred over manual intervention in MySQL data directories whenever possible). Step 7 is necessary to prevent InnoDB errors after the data files are created, as the InnoDB engine refuses to start if the log files are older than the tablespace files. With steps 8 and 9, the new settings take effect. When starting the database for the first time after changes being made to the InnoDB tablespace configuration, take a look at the MySQL error log to make sure the settings were accepted and no errors have occurred. The MySQL error log after the first start with the new settings will look similar to this:   InnoDB: The first specified data file E:MySQLInnoDBTestibdata1 didnot exist:InnoDB: a new database to be created!091115 21:35:56 InnoDB: Setting file E:MySQLInnoDBTestibdata1 sizeto 200 MBInnoDB: Database physically writes the file full: wait...InnoDB: Progress in MB: 100 200...InnoDB: Progress in MB: 100091115 21:36:19 InnoDB: Log file .ib_logfile0 did not exist: new tobe createdInnoDB: Setting log file .ib_logfile0 size to 24 MBInnoDB: Database physically writes the file full: wait......InnoDB: Doublewrite buffer not found: creating newInnoDB: Doublewrite buffer createdInnoDB: Creating foreign key constraint system tablesInnoDB: Foreign key constraint system tables created091115 21:36:22 InnoDB: Started; log sequence number 0 0091115 21:36:22 [Note] C:Program FilesMySQLMySQL Server 5.1binmysqld: ready for connections.Version: '5.1.31-community-log' socket: '' port: 3306 MySQLCommunity Server (GPL)   There's more... If you already use a fixed tablespace, and you want to increase the available space, you can simply append additional files to your fixed tablespace by adding additional data file definitions to the current innodb_data_file_path variable setting. If you simply append additional files, you do not have to empty your tablespace first, but you can change the confi guration and simply restart your database. Nevertheless, as with all changes to the confi guration, we strongly encourage creating a backup of your database first.   Setting up an auto-extending InnoDB tablespace The previous recipe demonstrates how to define a tablespace with a certain fixed size. While this provides maximum control and predictability, you have to block disk space based on the estimate of the maximum size required in the foreseeable future. As long as you store less data in your database than the reserved tablespace allows for, this basically means some disk space is wasted. This especially holds true if your setting does not allow for a separate file system exclusively for your MySQL instance, because then other applications compete for disk space as well. In these cases, a dynamic tablespace that starts with little space and grows as needed could be an alternative. The following recipe will show you how to achieve this. Getting ready When defining an auto-extending tablespace, you should first have an idea about the minimum tablespace requirements of your database, which will set the initial size of the tablespace. Furthermore, you have to decide whether you want to split your initial tablespace into files of a certain maximum size (for better file handling). If the above settings are identical to the current settings and you only want to make your tablespace grow automatically if necessary, you will be able to keep your data. Otherwise, you have to empty your current InnoDB tablespace completely (please refer to the previous recipe Setting up a fixed InnoDB tablespace for details). As with all major confi guration changes to your database, we strongly advise you to create a backup of your data first. If you have to empty your tablespace, you can use this backup to recover your data after the changes are completed. Again, please refer to the chapter Backing Up and Restoring MySQL Data for further information on this. And as before, you have to make sure that there is enough disk space available in the innodb_data_home_dir directory—not only for the initial database size, but also for the anticipated growth of your database. The recipe also requires you to shut down your database temporarily; so you have to make sure all clients are disconnected while performing the required steps to prevent conflicting access. As the recipe demands changes to your MySQL confi guration file (my.cnf or my.ini), you need write access to this file. For the following example, we will use an auto-extending tablespace with an initial size of 100 MB and a file size of 50 MB. How to do it... Open the MySQL configuration file (my.ini or my.cnf) in a text editor. Identify the line starting with innodb_data_file_path in the [mysqld] section. If no such line exists, add the line to the file. Change the line innodb_data_file_path to read as follows: innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend Note that no file defi nition except the last one must have the :autoextend option; you will run into errors otherwise. Save the changed confi guration file. Shut down your database instance (if running). Delete previous InnoDB data files (typically called ibdata1, ibdata2, and so on) from the directory defi ned by the innodb_data_home_dir variable. Delete previous InnoDB logfiles (named ib_logfile0, ib_logfile1, and so on) from the directory defined by the innodb_log_group_home_dir variable. If innodb_log_group_home_dir is not configured explicitly, it defaults to the datadir directory Start your database. Wait for all data and log files to be created. Depending on the size of your tablespace and the speed of your disk system, creation of InnoDB data files can take a signifi cant amount of time (several minutes is not an uncommon time for larger installations). During this initialization sequence, MySQL is started but will not accept any requests. When starting the database for the first time after changes being made to the InnoDB tablespace configuration, take a look at the MySQL error log to make sure the settings were accepted and no errors have occurred. How it works... The above steps are basically identical to the steps of the previous recipe Setting up a fixed InnoDB tablespace, the only difference being the definition of the innodb_data_file_path variable. In this recipe, we create two files of 50 MB size, the last one having an additional :autoextend property. If the innodb_data_file_path variable is not set explicitly, it defaults to the value ibdata1:10M:autoextend. As data gets inserted into the database, parts of the tablespace will be allocated. As soon as the 100 MB of initial tablespace is not sufficient any more, the file ibdata2 will become larger to match the additional tablespace requirements. Note that the :autoextend option causes the tablespace files to be extended automatically, but they are not automatically reduced in size again if the space requirements decrease. Please refer to the Decreasing InnoDB tablespace recipe for instructions on how to free unused tablespace. There's more... The recipe only covers the basic aspects of auto-extending tablespaces; the following sections provide insight into some more advanced topics. Making an existing tablespace auto-extensible If you already have a database with live data in place and you want to change your current fixed configuration to use the auto-extension feature, you can simply add the :autoextend option to the last file definition. Let us assume a current configuration like the following: innodb_data_file_path=ibdata1:50M;ibdata2:50M The respective configuration with auto-extension will look like this: innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend In this case, do not empty the InnoDB tablespace first, you can simply change the configuration file and restart your database, and you should be fine. As with all configuration changes, however, we strongly recommend to back up your database before editing these settings even in this case. Controlling the steps of tablespace extension The amount by which the size of the auto-extending tablespace file is increased is controlled by the innodb_autoextend_increment variable. The value of this variable defines the number of Megabytes by which the tablespace is enlarged. By default, 8 MB are added to the file if the current tablespace is no longer sufficient. Limiting the size of an auto-extending tablespace If you want to use an auto-extending tablespace, but also want to limit the maximum size your tablespace will grow to, you can add a maximum size for the auto-extended tablespace file by using the :autoextend:max:[size] option. The [size] portion is a placeholder for a size definition using the same notation as the size description for the tablespace file itself, which means a numeric value and an optional K, M, or G modifier (for sizes in Kilo-, Mega-, and Gigabytes). As an example, if you want to have a tiny initial tablespace of 10 MB, which is extended as needed, but with an upper limit of 2 GB, you would enter the following line to your MySQL configuration file: innodb_data_file_path=ibdata1:10M:autoextend:max:2G Note that if the maximum size is reached, you will run into errors when trying to add new data to your database. Adding a new auto-extending data file Imagine an auto-extending tablespace with an auto-extended file, which grew so large over time that you want to prevent the file from growing further and want to append a new auto-extending data file to the tablespace. You can do so using the following steps: Shut down your database instance. Look up the exact size of the auto-extended InnoDB data file (the last file in your current configuration). Put the exact size as the tablespace fi le size definition into the innodb_data_file_path configuration (number of bytes without any K, M, or G modifier), and add a new auto-extending data file. Restart your database. As an example, if your current confi guration reads ibdata1:10M:autoextend and the ibdata1 file has an actual size of 44,040,192 bytes, change configuration to innodb_data_file_path=ibdata1:44040192;ibdata2:10M:autoextend:max:2G.  
Read more
  • 0
  • 0
  • 4359

article-image-drupal-and-ubercart-2x-new-approach-drupal-theming
Packt
31 Mar 2010
3 min read
Save for later

Drupal and Ubercart 2.x: A new Approach to Drupal Theming

Packt
31 Mar 2010
3 min read
Fusion Theming System with Skinr module At the end of this article, we're going to give you a brief reference to the Fusion Theming System. It was introduced only a few months ago and it's still under heavy development. It's a base theme, meaning that you can create your own subthemes easily, using the Fusion Starter, a commented starter theme created especially for this reason. It uses a 960px or fluid 16-column grid, and its main advantage is that, with the help of Skinr module, it creates l ayout and style confi guration options that the site administrator can control using the website's User Interface, without messing with CSS. So, let's see how to install it, and how to use it for simple customizations. First navigate to http://drupal.org/project/skinr, and right after you download the module, upload and unzip to your site folder (/sites/all/modules). Then, activate the module from Administration | Site building | Modules. Navigate to http://drupal.org/project/fusion, and right after you download the theme, upload it and unzip it to your site folder (/sites/all/themes). Then, go to Administration | Site building | Themes, enable both Fusion Core and Fusion Starter themes and set the Fusion Starter theme as the default one. Browse to admin | build | themes | settings | fusion_starter to configure the settings of Fusion Starter theme. There you will find the default settings of every Drupal theme, such as logo image settings or shortcut icon settings. However, there is also a new section, named Fusion theme settings. There, you can easily change the basic styles and the layout of your theme, such as font family, font size, fixed or fluid layout without using any CSS at all. Click on Save configuration to store your settings. Now, if you hover the cursor over any block of your site, you will see a new icon. Clicking on it allows you to configure the properties of this block. You can change the width of the block, the block position, the content alignment, and apply custom styles to the elements of the block, such as padding, border, equal heights, or multi-column menus. There are also special settings for every content type. For example, if you go to Administer | Content Management | Content Types | Product, you will see two new sections, named Skinr node settings and Skinr comment settings, where you can apply custom styles to the product page and the product comments. If you want to create your own custom styles for your theme, and present them in the User Interface, you have to study the documentation of the Skinr module, available at http://www.drupal.org/node/578574.
Read more
  • 0
  • 0
  • 4042

article-image-documentation-phpdocumentor-part-1
Packt
31 Mar 2010
11 min read
Save for later

Documentation with phpDocumentor: Part 1

Packt
31 Mar 2010
11 min read
Code-level documentation The documentation we will be creating describes the interface of the code more than minute details of the actual implementation. For example, you might document an API that you have developed for the outside world to interact with some insanely important project on which you are working. Having an API is great, but for other developers to quickly get an overview of the capabilities of the API and being able to crank out working code within a short amount of time is even better. If you are following the proper conventions while writing the code, all you would have to do is run a utility to extract and format the documentation from the code. Even if you're not inviting the whole world to interact with your software, developers within your own team will benefit from documentation describing some core classes that are being used throughout the project. Just imagine reading your co-worker's code and coming across some undecipherable object instance or method call. Wouldn't it be great to simply pull up the API documentation for that object and read about its uses, properties, and methods? Furthermore, it would be really convenient if the documentation for the whole project were assembled and logically organized in one location. That way, a developer cannot only learn about a specific class, but also about its relationships with other classes. In a way, it would enable the programmer to form a high-level picture of how the different pieces fit together. Another reason to consider code-level documentation is that source code is easily accessible due to PHP being a scripting language. Unless they choose to open source their code, compiled languages have a much easier time hiding their code. If you ever plan on making your project available for others to download and run on their own server, you are unwittingly inviting a potential critic or collaborator. Since it is rather hard (but not impossible) to hide the source code from a user that can download your project, there is the potential for people to start looking at and changing your code. Generally speaking, that is a good thing because they might be improving the quality and usefulness of the project and hopefully they will be contributing their improvements back to the user community. In such a case, you will be glad that you stuck to a coding standard and added comments throughout the code. It will make understanding your code much easier and anybody reading the code will come away with the impression that you are indeed a professional. Great, you say, how do I make sure I always generate such useful documentation when I program? The answer is simple. You need to invest a little time learning the right tool(s). That's the easy part for someone in the technology field where skill sets are being expanded every couple of years anyway. The hard part is to consistently apply that knowledge. Like much else in this book, it is a matter of training yourself to have good habits. Writing API level documentation at the same time as implementing a class or method should become second nature as much as following a coding standard or properly testing your code. Luckily, there are some tools that can take most of the tedium out of documenting your code. Foremost, modern IDEs (Integrated Development Environments) are very good at extracting some of the needed information automatically. Templates can help you generate documentation tags rather rapidly. Levels of detail As you create your documentation, you have to decide how detailed you want to get. I have seen projects where easily half the source code consisted of comments and documentation that produced fantastic developer and end-user documentation. However, that may not be necessary or appropriate for your project. My suggestion is to figure out what level of effort you can reasonably expect of yourself in relation to what would be appropriate for your target audience. After all, it is unlikely that you will start documenting every other line of code if you are not used to adding any documentation at all. On one hand, if your audience is relatively small and sophisticated, you might get away with less documentation. On the other hand, if you are documenting the web services API for a major online service as you are coding it, you probably want to be as precise and explicit as possible. Adding plenty of examples and tutorials might enable even novice developers to start using your API quickly. In that case, your employer's success in the market place is directly tied to the quality and accessibility of the documentation. In this case, the documentation is very much part of the product rather than an afterthought or merely an add-on. On one end of the spectrum, you can have documentation that pertains to the project as a whole, such as a "README" file. At the next level down, you might have a doc section at the beginning of each file. That way, you can cover the functionality of the file or class without going into too much detail. Introducing phpDocumentor phpDocumentor is an Open Source project that has established itself as the dominanot tool for documenting PHP code. Although there are other solutions, phpDocumentor is by far the one you are most likely to encounter in your work–and for good reason. Taking a clue from similar documentation tools that came before it, such as JavaDoc, phpDocumentor offers many features in terms of user interface, formatting, and so on. PhpDocumentor provides you with a large library of tags and other markup, which you can use to embed comments, documentation, and tutorials in your source code. The phpDoc markup is viewed as comments by PHP when it executes your source file and therefore doesn't interfere with the code's functionality. However, running the phpDocumentor command line executable or using the web-based interface, you can process all your source files, extract the phpDoc related content, and compile it into functional documentation. There is no need to look through the source files because phpDocumentor assembles the documentation into nicely looking HTML pages, text files, PDFs, or CHMs. Although phpDocumentor supports procedural programming and PHP4, the focus in this article will be on using it to document applications developed with object-oriented design in mind. Specifically, we will be looking at how to properly document interfaces, classes, properties, and methods. For details on how to document some of the PHP4 elements that don't typically occur in PHP5's object-oriented implementation, please consult the phpDocumentor online manual: http://manual.phpdoc.org/ Installing phpDocumentor There are two ways of installing phpDocumentor. The preferred way is to use the PEAR repository. Typing pear install PhpDocumentor from the command line will take care of downloading, extracting, and installing phpDocumentor for you. The pear utility is typically included in any recent standard distribution of PHP. However, if for some reason you need to install it first, you can download it from the PEAR site: http://pear.php.net/ Before we proceed with the installation, there is one important setting to consider. Traditionally, phpDocumentor has been run from the command line, however, more recent versions come with a rather functional web-based interface. If you want pear to install the web UI into a sub-directory of your web server's document root directory, you will first have to set pear's data_dir variable to the absolute path to that directory. In my case, I created a local site from which I can access various applications installed by pear. That directory is /Users/dirk/Sites/phpdoc. From the terminal, you would see the following if you tell pear where to install the web portion and proceed to install phpDocumentor. As part of the installation, the pear utility created a directory for phpDocumentor's web interface. Here is the listing of the contents of that directory: The other option for installing phpDocumentor is to download an archive from the project's SourceForge.net space. After that, it is just a matter of extracting the archive and making sure that the main phpdoc executable is in your path so that you can launch it from anywhere without having to type the absolute path. You will also have to manually move the corresponding directory to your server's document root directory to take advantage of the web-based interface. DocBlocks Let's start by taking a look at the syntax and usage of phpDocumentor.The basic unit of phpDoc documentation is a DocBlock. All DocBocks take the following format: /** * Short description * * Long description that can span as many lines as you wish. * You can add as much detail information and examples in this * section as you deem appropriate. You can even <i>markup</i> * this content or use inline tags like this: * {@tutorial Project/AboutInlineTags.proc} * * @tag1 * @tag2 value2 more text * ... more tags ... */ A DocBlock is the basic container of phpDocumentor markup within PHP source code. It can contain three different element groups: short description, long description, and tags–all of which are optional. The first line of a DocBlock has only three characters, namely "/**". Similarly, the last line will only have these three characters: " */ ". All lines in between will start with " * ". Short and long descriptions An empty line or a period at the end of the line terminates short descriptions. In contrast, long descriptions can go on for as many lines as necessary. Both types of descriptions allow certain markup to be used: <b>, <br>, <code>, <i>, <kbd>, <li>, <ol>, <p>, <pre>, <samp>, <ul>, <var>. The effect of these markup tags is borrowed directly from HTML. Depending on the output converter being used, each tag can be rendered in differe nt ways. Tags Tags are keywords known to phpDocumentor. Each tag can be followed by a number of optional arguments, such as data type, description, or URL. For phpDocumentor to recognize a tag, it has to be preceded by the @ character. Some examples of common tags are: /** * @package ForeignLanguageParser * @author Dirk Merkel dirk@waferthin.com * @link http://www.waferthin.com Check out my site */class Translate{} In addition to the above "standard" tags, phpDocumentor recognizes "inline" tags, which adhere to the same syntax, with the only notable difference that they are enclosed by curly brackets. Inline tags occur inline with short and long descriptions like this: /** * There is not enough space here to explain the value and usefulness * of this class, but luckily there is an extensive tutorial available * for you: {@tutorial ForeignLanguageParser/Tran slate.cls} */ DocBlock templates It often happens that the same tags apply to multiple successive elements. For example, you might group all private property declarations at the beginning of a class. In that case, it would be quite repetitive to list the same, or nearly the same DocBlocks, over and over again. Luckily, we can take advantage of DocBlock templates, which allow us to define DocBlock sections that will be added to the DocBlock of any element between a designated start and end point. DocBlock templates look just like regular DocBlocks with the difference that the first line consists of /**#@+ instead of /**. The tags in the template will be added to all subsequent DocBlocks until phpDocumenter encounters the ending letter sequence /**#@-*/. The following two code fragments will produce the same documentation. First, here is the version containing only standard DocBlocks: <?phpclass WisdomDispenser{ /** * @access protected * @var string */ private $firstSaying = 'Obey the golden rule.'; /** * @access protected * @var string */ private $secondSaying = 'Get in or get out.'; /** * @access protected * @var string * @author Albert Einstein <masterof@relativity.org> */ private $thirdSaying = 'Everything is relative';}?> And here is the fragment that will produce the same documentation using a more concise notation by taking advantage of DocBlock templates: <?phpclass WisdomDispenser{ /**#@+ * @access protected * @var string */ private $firstSaying = 'Obey the golden rule.'; private $secondSaying = 'Get in or get out.'; /** * @author Albert Einstein <masterof@relativity.org> */ private $thirdSaying = 'Everything is relative'; /**#@-*/}?>
Read more
  • 0
  • 0
  • 3252
article-image-installing-coherence-35-and-accessing-data-grid-part-2
Packt
31 Mar 2010
10 min read
Save for later

Installing Coherence 3.5 and Accessing the Data Grid: Part 2

Packt
31 Mar 2010
10 min read
Using the Coherence API One of the great things about Coherence is that it has a very simple and intuitive API that hides most of the complexity that is happening behind the scenes to distribute your objects. If you know how to use a standard Map interface in Java, you already know how to perform basic tasks with Coherence. In this section, we will first cover the basics by looking at some of the foundational interfaces and classes in Coherence. We will then proceed to do something more interesting by implementing a simple tool that allows us to load data into Coherence from CSV files, which will become very useful during testing. The basics: NamedCache and CacheFactory As I have briefly mentioned earlier, Coherence revolves around the concept of named caches. Each named cache can be configured differently, and it will typically be used to store objects of a particular type. For example, if you need to store employees, trade orders, portfolio positions, or shopping carts in the grid, each of those types will likely map to a separate named cache. The first thing you need to do in your code when working with Coherence is to obtain a reference to a named cache you want to work with. In order to do this, you need to use the CacheFactory class, which exposes the getCache method as one of its public members. For example, if you wanted to get a reference to the countries cache that we created and used in the console example, you would do the following: NamedCache countries = CacheFactory.getCache("countries"); Once you have a reference to a named cache, you can use it to put data into that cache or to retrieve data from it. Doing so is as simple as doing gets and puts on a standard Java Map: countries.put("SRB", "Serbia");String countryName = (String) countries.get("SRB"); As a matter of fact, NamedCache is an interface that extends Java's Map interface, so you will be immediately familiar not only with get and put methods, but also with other methods from the Map interface, such as clear, remove, putAll, size, and so on. The nicest thing about the Coherence API is that it works in exactly the same way, regardless of the cache topology you use. For now let's just say that you can configure Coherence to replicate or partition your data across the grid. The difference between the two is that in the former case all of your data exists on each node in the grid, while in the latter only 1/n of the data exists on each individual node, where n is the number of nodes in the grid. Regardless of how your data is stored physically within the grid, the NamedCache interface provides a standard API that allows you to access it. This makes it very simple to change cache topology during development if you realize that a different topology would be a better fit, without having to modify a single line in your code. In addition to the Map interface, NamedCache extends a number of lower-level Coherence interfaces. The following table provides a quick overview of these interfaces and the functionality they provide: The "Hello World" example In this section we will implement a complete example that achieves programmatically what we have done earlier using Coherence console—we'll put a few countries in the cache, list cache contents, remove items, and so on. To make things more interesting, instead of using country names as cache values, we will use proper objects this time. That means that we need a class to represent a country, so let's start there: public class Country implements Serializable, Comparable {private String code;private String name;private String capital;private String currencySymbol;private String currencyName;public Country() {}public Country(String code, String name, String capital,String currencySymbol, String currencyName) {this.code = code;this.name = name;this.capital = capital;this.currencySymbol = currencySymbol;this.currencyName = currencyName;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCapital() {return capital;}public void setCapital(String capital) {this.capital = capital;}public String getCurrencySymbol() {return currencySymbol;}public void setCurrencySymbol(String currencySymbol) {this.currencySymbol = currencySymbol;}public String getCurrencyName() {return currencyName;}public void setCurrencyName(String currencyName) {this.currencyName = currencyName;}public String toString() {return "Country(" +"Code = " + code + ", " +"Name = " + name + ", " +"Capital = " + capital + ", " +"CurrencySymbol = " + currencySymbol + ", " +"CurrencyName = " + currencyName + ")";}public int compareTo(Object o) {Country other = (Country) o;return name.compareTo(other.name);}} There are several things to note about the Country class, which also apply to other classes that you want to store in Coherence: Because the objects needs to be moved across the network, classes that are stored within the data grid need to be serializable. In this case we have opted for the simplest solution and made the class implement the java.io.Serializable interface. This is not optimal, both from performance and memory utilization perspective, and Coherence provides several more suitable approaches to serialization. We have implemented the toString method that prints out an object's state in a friendly format. While this is not a Coherence requirement, implementing toString properly for both keys and values that you put into the cache will help a lot when debugging, so you should get into a habit of implementing it for your own classes. Finally, we have also implemented the Comparable interface. This is also not a requirement, but it will come in handy in a moment to allow us to print out a list of countries sorted by name. Now that we have the class that represents the values we want to cache, it is time to write an example that uses it: import com.tangosol.net.NamedCache;import com.tangosol.net.CacheFactory;import ch02.Country;import java.util.Set;import java.util.Map;public class CoherenceHelloWorld {public static void main(String[] args) {NamedCache countries = CacheFactory.getCache("countries");// first, we need to put some countries into the cachecountries.put("USA", new Country("USA", "United States","Washington", "USD", "Dollar"));countries.put("GBR", new Country("GBR", "United Kingdom","London", "GBP", "Pound"));countries.put("RUS", new Country("RUS", "Russia", "Moscow","RUB", "Ruble"));countries.put("CHN", new Country("CHN", "China", "Beijing","CNY", "Yuan"));countries.put("JPN", new Country("JPN", "Japan", "Tokyo","JPY", "Yen"));countries.put("DEU", new Country("DEU", "Germany", "Berlin","EUR", "Euro"));countries.put("FRA", new Country("FRA", "France", "Paris","EUR", "Euro"));countries.put("ITA", new Country("ITA", "Italy", "Rome","EUR", "Euro"));countries.put("SRB", new Country("SRB", "Serbia", "Belgrade","RSD", "Dinar"));assert countries.containsKey("JPN"): "Japan is not in the cache";// get and print a single countrySystem.out.println("get(SRB) = " + countries.get("SRB"));// remove Italy from the cacheint size = countries.size();System.out.println("remove(ITA) = " + countries.remove("ITA"));assert countries.size() == size - 1: "Italy was not removed";// list all cache entriesSet<Map.Entry> entries = countries.entrySet(null, null);for (Map.Entry entry : entries) {System.out.println(entry.getKey() + " = " + entry.getValue());}}} Let's go through this code section by section. At the very top, you can see import statements for NamedCache and CacheFactory, which are the only Coherence classes we need for this simple example. We have also imported our Country class, as well as Java's standard Map and Set interfaces. The first thing we need to do within the main method is to obtain a reference to the countries cache using the CacheFactory.getCache method. Once we have the cache reference, we can add some countries to it using the same old Map.put method you are familiar with. We then proceed to get a single object from the cache using the Map.get method , and to remove one using Map.remove. Notice that the NamedCache implementation fully complies with the Map.remove contract and returns the removed object. Finally, we list all the countries by iterating over the set returned by the entrySet method. Notice that Coherence cache entries implement the standard Map.Entry interface. Overall, if it wasn't for a few minor differences, it would be impossible to tell whether the preceding code uses Coherence or any of the standard Map implementations. The first telltale sign is the call to the CacheFactory.getCache at the very beginning, and the second one is the call to entrySet method with two null arguments. We have already discussed the former, but where did the latter come from? The answer is that Coherence QueryMap interface extends Java Map by adding methods that allow you to filter and sort the entry set. The first argument in our example is an instance of Coherence Filter interface. In this case, we want all the entries, so we simply pass null as a filter. The second argument, however, is more interesting in this particular example. It represents the java.util.Comparator that should be used to sort the results. If the values stored in the cache implement the Comparable interface, you can pass null instead of the actual Comparator instance as this argument, in which case the results will be sorted using their natural ordering (as defined by Comparable.compareTo implementation). That means that when you run the previous example, you should see the following output: get(SRB) = Country(Code = SRB, Name = Serbia, Capital = Belgrade,CurrencySymbol = RSD, CurrencyName = Dinar)remove(ITA) = Country(Code = ITA, Name = Italy, Capital = Rome,CurrencySymbol = EUR, CurrencyName = Euro)CHN = Country(Code = CHN, Name = China, Capital = Beijing, CurrencySymbol= CNY, CurrencyName = Yuan)FRA = Country(Code = FRA, Name = France, Capital = Paris, CurrencySymbol= EUR, CurrencyName = Euro)DEU = Country(Code = DEU, Name = Germany, Capital = Berlin,CurrencySymbol = EUR, CurrencyName = Euro)JPN = Country(Code = JPN, Name = Japan, Capital = Tokyo, CurrencySymbol =JPY, CurrencyName = Yen)RUS = Country(Code = RUS, Name = Russia, Capital = Moscow, CurrencySymbol= RUB, CurrencyName = Ruble)SRB = Country(Code = SRB, Name = Serbia, Capital = Belgrade,CurrencySymbol = RSD, CurrencyName = Dinar)GBR = Country(Code = GBR, Name = United Kingdom, Capital = London,CurrencySymbol = GBP, CurrencyName = Pound)USA = Country(Code = USA, Name = United States, Capital = Washington,CurrencySymbol = USD, CurrencyName = Dollar) As you can see, the countries in the list are sorted by name, as defined by our Country.compareTo implementation. Feel free to experiment by passing a custom Comparator as the second argument to the entrySet method, or by removing both arguments, and see how that affects result ordering. If you are feeling really adventurous and can't wait to learn about Coherence queries, take a sneak peek by changing the line that returns the entry set to: Set<Map.Entry> entries = countries.entrySet(new LikeFilter("getName", "United%"), null); As a final note, you might have also noticed that I used Java assertions in the previous example to check that the reality matches my expectations (well, more to demonstrate a few other methods in the API, but that's beyond the point). Make sure that you specify the -ea JVM argument when running the example if you want the assertions to be enabled, or use the run-helloworld target in the included Ant build file, which configures everything properly for you. That concludes the implementation of our first Coherence application. One thing you might notice is that the CoherenceHelloWorld application will run just fine even if you don't have any Coherence nodes started, and you might be wondering how that is possible. The truth is that there is one Coherence node—the CoherenceHelloWorld application. As soon as the CacheFactory.getCache method gets invoked, Coherence services will start within the application's JVM and it will either join the existing cluster or create a new one, if there are no other nodes on the network. If you don't believe me, look at the log messages printed by the application and you will see that this is indeed the case. Now that you know the basics, let's move on and build something slightly more exciting, and much more useful.
Read more
  • 0
  • 0
  • 1809

article-image-drupal-and-ubercart-2x-customizing-theme
Packt
31 Mar 2010
3 min read
Save for later

Drupal and Ubercart 2.x: Customizing a theme

Packt
31 Mar 2010
3 min read
Customizing a theme In this section, after we have elected our primary theme, we will go step-by-step customizing it and making it suit our business need. These configurations are necessary even if you choose to hire a designer or buy a ready-made theme. Changing basic elements Every Drupal theme using the template engine produces HTML code from Drupal core objects. Therefore, some content of the final HTML code generated is actually site-wide property such as site slogan, mission, and site name. We will have to change Drupal default settings and provide our business details. To do this, go to Home | Administer | Site configuration and edit the fields as we describe next. If you do not want to provide specific information, for instance if you do not have a corporate slogan, you need not fill this option. Nothing will appear if the attribute is not set to the main page of your online shop. You can edit the following elements: Name: This is your site's name and will be displayed in the site name theme section and can also be a part of the HTML <title> element. E-mail address: A valid e-mail address for your website, used by the mailer functionality during registration, new password requests, notifications, purchases, and all mail communication to your users. E-mail server details that your site uses are placed in your php.ini file. The majority of web hosting solutions have a preconfi gured mail server environment and you will not have to deal with it. Slogan: The slogan of your website. Some themes display a slogan when available. It will also display in the title bar of your user web browser, so if you decide to choose one, do it wisely. Mission: Your site's mission statement or focus. Your mission statement is enabled in your theme settings and requires that the theme supports its display. Footer: This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages. You can also use HTML tags to include an image for instance. Anonymous user: The user name for unregistered users is "Anonymous" by default. Drupal gives you the option to change this to something different according to your target user group (for example "New Customer"). Default front page: This setting gives site administrators control over what Drupal-generated content a user sees when they visit a Drupal installation's root directory. We quote from the Drupal documentation section for site configuration: This setting tells Drupal which URL users should be redirected to. It's important to note that the URL is relative to the directory your Drupal installation is in. So, instead of"http://www.example.com/node/83"or"http://www.example.com/drupal_installation_directory/node/83,"it is only necessary to type "node/83". For those not using clean URLs, note that there is no need to type in "?q=" before typing the URL.By default, the "Default front page" is set to "node," which simply displays articles that have been "Promoted to front page." Note that when changing the "Default front page" to something other than "node", nodes that are "Promoted to front page" will no longer appear on the front page. They can however, still be viewed by visiting the relative URL path "node".If the path specified is not a valid Drupal path the user will be confronted with a "Page not found" error. It is not possible to redirect users to any web documents (e.g. a static HTML page) not created by the Drupal site.
Read more
  • 0
  • 0
  • 2001
Modal Close icon
Modal Close icon