Posts in Category "ADEP"

Real time notification using Data Services in ADEP

With the release of ADEP and the introduction of the Experience Server (RIA services running on the CRX stack), developers now have access to data services within the ADEP Core (previously known as CRX) runtime. This means that data services components are now deployed as OSGi bundles in ADEP Core. This opens now interesting doors for developers building content-oriented applications (like the app we will build during my BYOD lab at MAX), In this post, I will talk about how you can leverage the data services MessageBroker to push notifications to Flex clients that a node in the ADEP content repository has been added or changed. There are many use cases for this functionality, but the one I find most exciting is in the context of mobile application development.

Imagine you have a mobile application that displays information stored on a server – of course we would use the ADEP content repository for this! The challenge for these types of applications is how to keep that information in sync. Make the user request a refresh? Build some sort of polling mechanism? Why? ADEP data services already has this problem solved with real time messaging. The trick is how to send a message when a node is updated or added (or even removed) in the repository. Before we tackle this challenge, lets look at how data services has been adapted to run within the ADEP Experience Server.

If we are going to use data services messaging, we have to add a destination to the messaging-config.xml file right? You bet, but where can we find this file? Not on the file system that’s for sure. We have a content repository now. The best way to access the content repository as a developer is either to use CRXDE (an Eclipse-based IDE for ADEP Core) or CRXDE Lite (a web-based IDE for ADEP Core). For the purposes of this post, I am going to use CRXDE Lite.

Step 1: Creating a destination

To access CRXDE Lite on your machine (running ADEP Experience Server or the ADEP Solution Quickstart) navigate to http://localhost:4502/crx/de/ in your favorite browser. In this image, you see that the JCR repository path is /etc/aep/config/dataservices/messaging-config.xml.  You can open the file by double-clicking it. You will notice something different about the include statement in the file. Instead of pointing to a specific file to include, we are pointing to a repository folder location.

<destination-include directory-path=”destinations/messaging”/>

What this means is that the MessageBroker will iterate through each file located in the destinations/messaging folder and read in the configurations it finds. Which means that if we want to add a new destination, we need to add a new file in this location. In my sample, I created a file called com.adobe.tm.flex.broker.messaging-config.xml the contents of this file is typical destination config information:

Step 2: Loading configuration changes

This defines a new destination called “flexmobile“. The only thing left to activate this new destination is reload the MessageBroker class. In the J2EE version, this means bouncing the app server or some other weird incantation. Remember that in ADEP, Data Services is now a set of OSGi bundles.To reload MessageBroker to pick up the new configuration changes, we need to access the OSGi (Felix) console. On your machine, navigate to http://localhost:4502/system/console/configMgr. Click on the Components button in the toolbar and locate the following class: com.adobe.dataservices.impl.ApplicationManagerImpl

In the actions column, click on the stop icon. Once the component has stopped, the icon will change to a play button. Click it again to start the component. This will trigger the MessageBroker class to reload the configuration xml files.

Step 3: Creating a bundle to send a message via MessageBroker

Back to our original scenario. We want to send a message via message broker when a node in the content repository changes. A very simple approach to setting this up is to use the ADEP WEM workflow engine. It has built-in launchers that can be triggered by content repository node events like update, add and delete. What I did in this case, was build an ADEP OSGi bundle that implements the workflow execute() interface so it can be called from a workflow process. Since this post is not meant to be a complete tutorial on how to develop on ADEP Core, please refer to Defining a Process Step: with a Java Class for detailed steps and examples. Here is the code from the bundle class:

/*
 * @author: Marcel Boucher (mboucher@adobe.com)
 * MessageBrokerProxy class
 * This class is an implementation of a customer workflow step that can be used
 * to publish messages to the dataservices message broker running on this server.
 * 
 */
package com.adobe.tm.wf.dataservices.messaging;

import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

import flex.messaging.MessageBroker;
import flex.messaging.messages.AsyncMessage;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;



@SuppressWarnings("unused")
@Component
@Service
@Properties({
        @Property(name = Constants.SERVICE_DESCRIPTION, value = "Send Message to Data Services MessageBroker."),
        @Property(name = Constants.SERVICE_VENDOR, value = "Adobe"),
        @Property(name = "process.label", value = "Send to MessageBroker")})


public class MessageBrokerProxy implements WorkflowProcess
{
        private static final Logger log = LoggerFactory.getLogger(MessageBrokerProxy.class);
        private static final String TYPE_JCR_PATH = "JCR_PATH";

        public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException 
        {
            //Collect Message information from the dialog.
            String destination = args.get("destination","not set");
            // Default Messagge.
            String messageBody = args.get("message", "not set");
            
            //Set the message to contain the path of the node that has changed.
            WorkflowData workflowData = item.getWorkflowData();
            if (workflowData.getPayloadType().equals(TYPE_JCR_PATH)) {
                String path = workflowData.getPayload().toString() + "/par";
                messageBody = path;
            }
            
            //Create a new message.
            AsyncMessage msg = new AsyncMessage();

            msg.setClientId("ADEP-Experience-Server");
            msg.setTimestamp(new Date().getTime());
            //you can create a unique id
            msg.setMessageId("ADEP-Experience-Server-Message");
            //destination to which the message is to be sent
            msg.setDestination(destination);        
            //set message body
            //msg.setBody(messageBody != null?messageBody:"");
            msg.setBody(messageBody);
            //set message header
            msg.setHeader("sender", "From the server");

            //send message to destination
            MessageBroker.getMessageBroker("__default__").routeMessageToService(msg, null);
          
    }
}

Notice that the getMessageBroker() uses the __default__ argument which is to indicate the instance currently running in the same container.

Step 4: Create and configure the workflow

The next step is defining a workflow that will invoke our custom class when something in a specified node tree changes. You can access the workflow console on you machine using this url: http://localhost:4502/libs/cq/workflow/content/console.html

In the Models tab within the Workflow Console, click the New button and give your new model a meaningful name. For example “Post to Message Broker”. Double click on the newly created model to edit it. Delete the default user task from the model and add the custom step you created in the previous step from the Workflow group in Sidekick. You can double click the step to access it’s property dialog and configure additional settings. When you are done editing, click the Save button to return to the Workflow Console.

That’s it for the workflow model. All we want it to do is call our custom class to post a message to the MessageBroker.

The next thing we need to define is how this new workflow model will be launched. From the Workflow Console, click on the Launcher tab. You will see a significant list of launchers that are pre-configured in the system. We are going to add a new launcher, so click on the Add… button. Complete the launcher configuration settings and click OK.

ADEP will now monitor the node located in the path provided and launch the specified workflow when that node is modified.

The next step is to build a Flex application that subscribed to the MessageBroker destination and handles the messages it receives.

Step 4: The message consumer

Create a typical Flex application, you will need the FDS.swc library of course to use messaging. Simply define a consumer like you would with regular data services


<span><<span>mx</span>:Consumer id="consumer"</span>
<span> destination="<span>flexmobile</span>"</span>
 message="messageHandler(event);"
<span> fault="<span>faultHandler</span>(event);"/></span>

All you have to do now is build your handler functions and you now have real time notification of ADEP content repository changes. Go on and start building your content-driven applications.

My BYOD Lab at MAX 2011: Content-Oriented application development using ADEP and Flash Builder.

This year at MAX, I am going to lead a BYOD (Bring Your Own Device) lab. The title of the lab is Content-Oriented Application Development using ADEP and Flash Builder. I know it’s a mouth full of a title, so here’s a simple description of what this lab will cover.

There are two technology parts to the session:

  • ADEP’s Web Experience Management Solution: With the acquisition of Day software, Adobe has re branded and packaged the CQ5 web content management product into the ADEP offering and is now known as Web Experience Management Solution. We will leverage this solution in the lab as a best in class platform for managing web content in a JCR (Java Content Repository). We will take this concept to the next level by not just managing web content, but also managing application functionality. Using an intuitive and fun to use web-based authoring environment, content owners and application specialists are able to publish new content without having to rely on IT. This leaves IT with the ability to focus on more pressing development projects.
  • Flash Builder 4.5.1: We will use Flash Builder to create a mobile application that queries the ADEP content repository for information that should be displayed within the application. We will learn how to parse the result using JCR APis and easily render the content to screen. While this is cool, You’ll really be blown away as we use a very similar approach to use content defined in the content repository to control what views are displayed in the mobile application.

By using this content-driven application development approach for mobile, you will now have the ability to enable content owners and application specialists to manage defined parts of your mobile apps without having to recompile code and re-distribute the apps to the various application stores!

Here is a recording I made that showcases what we will be building, check it out.

If you have not registered for this session, WHAT ARE YOU WAITING FOR? :o)

 

 

,,,

How to configure white list for the new CSRF filter in ADEP

,,

Today, I installed the latest build of the Adobe Digital Enterprise Platform (ADEP) on one of my servers. I remotely administer this server - so once the installation was complete, the first thing I wanted to do is access the administration ui (adminui) using my browser to perform additional configurations. The URL is http:<fully_qualified_server_name>:8080/adminui. To my surprise, I received a denied access message when I attempted to log in. If I used the browser on the same server I just installed ADEP, it worked fine. I know what you are thinking… firewall blocking the port right? Nope. I have used this server for previous versions of LiveCycle ES and had opened port 8080 previously. Furthermore, if I used the server’s IP address, I could successfully access adminui. Now that’s a head scratcher! Let’s see what the application server log file has to say:

2011-08-05 12:32:08,898 WARNING [com.adobe.idp.um.auth.filter.CSRFFilter] (http-0.0.0.0-8080-1) Blocked request for resource:/adminui/login.faces due to invalid referer:http://<fully_qualified_server_name>:8080/adminui/login.faces. More information is available at http://www.adobe.com/go/learn_lc_hardening_10

What’s this CSRFFilter thing??? After a little digging I found out that in ADEP we have implemented a Cross Site Request Forgery (CSRF) defense filter. The ADEP CSRFFilter ensures that ADEP resources or URIs such as /adminui and /workspace can only be accessed through predefined referers (address of the source page requesting access to the resource). The goal is to prevent malicious requests riding piggy back on an authenticated browser session. During the installation process of ADEP, specifically in Configuration Manager, there is a system bootstrapping process that occurs. During this process, the ADEP document server determines the fully qualified host name of the server you are installing on and adds it (as well as IP address and localhost references) to the whitelist automatically. In ADEP, you can access the whitelist configuration page by logging into adminui and navigating to: Settings > User Management > Configuration > Configure Allowed Referer URL’s.

Why did it not work for me then? If the host name is automatically added to the whitelist, why was my request denied? The issue was actually cause by how the Windows machine name and domain configuration is set when I joined the corporate domain. The domain I joined was (I’ll leave out actual details to be sure the IT guys don’t hunt me down) ourdomain.xyz.org.com, which means that the fully qualified name is myserver.ourdomain.xyz.org.com which is what was automatically added to the whitelist during the bootstrap process. Here’s the rub… The way the network is setup at Adobe, that’s not the domain name we use in a URL to access our servers. The suffix we use is geo.org.com, so I would hit my server with http://myserver.geo.org.com:8080/adminui which of course is NOT in the whitelist. To correctly configure my ADEP server, I simply added that qualified server name to the whitelist and restart the application server. Yes, a restart of the application is required for the change to take effect. In case I forgot to mention it, remember to restart the application server :o). As I am sure you can tell, I did forget.

I doubt many people will run into this anomaly, but better be on the safe side.

Announcing Adobe Digital Enterprise Platform

Today, we announced the Adobe Digital Enterprise Platform. This is a very exciting time for Adobe and every organization looking to deliver customer experience solutions that truly meet market requirements. Too many times software companies talk about things to come and how they can make it better. Customer Experience Management is not a future trend, the time is now. The Adobe Digital Enterprise Platform is built to enable developers to deliver the best multi-channel experience possible – whether it’s HTML5, Flash or AIR.

You may be asking yourself, so what’s the big deal about ADEP, I could do the above with Flex and jQuery, etc. The big deal is that with the combination of CRX (from the Day acquisition) and LiveCycle ES which is now ADEP, you now have a modular platform where web scalable capabilities such as data services and composite application framework (previously known as Mosaic) run on the lightweight Experience Server core (CRX) and enterprise scalable capabilities like process management and document services run on the Document Server on JEE(LiveCycle).

Add that to what you can now build in Flex 4.5 for mobile and browser as well as HTML5 within dreamweaver, you now have one killer platform and best of breed tooling to leverage your existing IT investments.

Now that we have reached public announce, you will see a lot of backlogged information hit the bloggosphere pretty fast. Actually, I am hosting two sessions this week: one on Tuesday as part of the Developer Deep Dive sessions and another on Thursday as part of Flex Developer Week. You can also check out the new CEM website for more information on the awesome solutions that we will be releasing on top of ADEP. Rob Tarkoff also posted on the Adobe blogs an excellent overview.

Of course we will be showcasing all of this great stuff at Adobe MAX 2011and for the first time, we will also be hosting our first Digital Enterprise Summit October 3-4 in LA as well.

Stay tuned, we’re just getting started!

 

Custom LiveCycle ES component that communicates with CRX

With the acquisition of Day, there has been a lot of work within engineering to integrate CRX into the LiveCycle ES technology stack. However, since LiveCycle ES is an extensible platform – as I have been preaching for the last few years :) – there is no need to wait until the next version of the product is available to take advantage of CQ and CRX.

To demonstrate this point, I have build a custom component (DSC) for LiveCycle ES that uses the JCR api. Of course, I used the Component Development Tool posted on labs.adobe.com to create this component.

I built this component with service configuration parameters that enable you to define the CRX server URI and account information. Since this is just a sample, I took a shortcut and enabled hardcoded credentials to connect to CRX. The service has two operations addContent and retrieveContent. The operation properties are very straight forward. All you need to do is specify the CRX path where to save or retrieve the content, file name, etc.

Custom Component Eclipse Project (compiled JAR in the dist folder)

This does not replace the great work that will be coming out in the next release of LiveCycle ES. If you have not registered for the LiveCycle ES prerelease program, you need to check it out. This is a closed beta. to enroll, contact your Adobe sales rep.

Custom Ant Task to Generate LCA Files from Scratch

After posting the previous article about being able to merge LCA files, another colleague contacted to say “This is great – but we need to generate LCA files from source as part of our build process”. It’s never enough is it? :) Since most of the work was done I figured, why not add this functionality. I learned some interesting things along the way too.

I created a new class (com.adobe.tm.ant.tasks.GenerateAppInfoFile) that extends the Ant MatchingTask. My goal for this task is scan the src folder specified in the build.xml and process any LiveCycle ES applications it finds. Yes, you can create LCAs in batch! The rule is that you create a folder in src for each LC ES application you want to package. each folder MUST follow typical LCA structure. My Ant task will process each folder as a separate application and generate one LCA file per LiveCycle ES app.

Now that I have a little more experience with writing Ant tasks, I realize that it’s better practice to simply have a ant task property that points to the src folder and include the folder processing logic in the Java code [versus my approach in the previous post where I left file processing up to the build.xml author]. You will notice the simplicity in build.xml task definition. However, I feel that it’s up to the build.xml author to choose to support batch LCA file generation. For that reason, I have left the ant-contrib loop.

Here is an interesting tidbit… In the app.info file, each top-level-object (application asset) node contains a child element called properties. When I first had a look at some sample LCA files, I noticed that this node was different than the others. It’s value is clearly a Base64 encoded string. When I decoded the string, imagine my surprise when I realized that the value that was encoded is actually a serialized java.util.Properties object. After doing some investigations with my contacts in engineering, I found out that this was an element that was originally planned to contain LiveCycle ES asset configuration information, but in the end never gets used. It was planned to remove this element in the 2.5 release, but fell off the priority list. The bottom line is that although the properties element must be present with a Base64 encoded serialized java.util.Properies object – even if it’s empty. The reason is that the LCA importer looks for this entry, even if it’s not used, to validate the app.info file. I explain this, because if you look at the Java source code you’ll wonder what I am doing :o).

Binary Distribution: CustomAntTask.0.4_dist.zip

Project Source: CustomAntTask.0.4_src.zip

Programmatically merge multiple LCA files using Apache Ant

A couple of colleagues needed a solution where they could take multiple unrelated LiveCycle ES applications already exported as LCA (LiveCycle Archive) files and programmatically merge them into a single LCA file. What’s the use case? Let’s say that you have a source repository of small LiveCycle ES applications that are re-usable. Then, based on a set of requirements, you need to build a new LiveCycle ES application that would include those re-usable smaller apps. Of course, you could just import each application individually into your LiveCycle ES development environment. But that’s not real exciting is it? And what is more exciting than building an Apache Ant build script to do some magic?

I created a build.xml file that will grab all LCA files stored in a src folder(see the build.properties file for configuration) and extract them into a work folder. This is pretty trivial since LCA files are just ZIP files that contain the application assets as well as a file called app.info. This app.info file is the key. It’s an XML file that describes the LiveCycle ES application and what operations should be executed when imported into a LiveCycle ES server. Here comes the tricky part…

To create a “merged” LCA file, I needed to parse each app.info file of the source LCA files, build a new master and inject the individual application descriptors from the source LCA files. Can you imagine my surprise when I realized that there was no existing Ant task that does this?!?! Yeah, right! OK, so I have to create a custom Ant task – great! Turns out, yet another trivial job. It was very easy to create my own custom Ant task and expose it in the build.xml. As a reference, I used this short tutorial. All I had to do at that point is write the Java code to load each app.info file into an XML DOM, extract the necessary nodes, build a new master app.info and import the previously extracted nodes. Piece of cake ;o).

Once I included my new custom Ant task into my build.xml, I just passed in the fileset reference that contained all of the app.info files and voila… I got my first merged app.info file. We just then drop that bad boy into the build folder, copy the asset folders that came with each LCA file in there too; and with one final zip ant task package up the combined LCA file.

Note: I also used the ant-contrib package because I needed a for loop in my build.xml in order to loop through each LCA file.

You must have Apache Ant installed and configured on your machine.

Attached Files:

Binary Distribution – Includes build.properties, build.xml, lib folder.

Source – Includes the Java source files for the custom Ant task.

Tech Soft 3D to take over Adobe’s 3D technologies delivery

Adobe and Tech Soft 3D announced that Tech Soft 3D will be taking on development and delivery of Adobe’s 3D technologies. This includes LiveCycle PDF Generator 3D and Acrobat Professional Extended. For more information, read the Tech Soft 3D announcement and Kumar Vora’s blog post.

iPhone and iPad added to the list of targeted clients for LiveCycle ES

Yesterday, Apple announced that it has lifted restrictions in regards to third-party developer guidelines. I think this is good news for some enterprise developers that are looking to target “iDevices” as clients for their enterprise applications. By using the Adobe’s Packager for iPhone in CS5, developers can deploy their apps via the App Store. As mentioned in the blog post from Adobe Corporate Communications, the strong partnership between Adobe and other device manufacturers to get Flash Player and AIR running on their devices provides enterprise developers with an impressive reach for mobile.

My designer to developer preconference session at MAX

I plan on running a preconference session this year at MAX to showcase some really cool stuff for enterprise application developers. If you have not signed up for this session, you should have a look at this. It might change you mind :-)

With the release of CS5 which includes Photoshop, Flash Builder 4 and Catalyst; provides a completely different approach to building enterprise applications. Imagine being able to start from a Photoshop image that represents the application interface. Blow is a screen shot of the login state of the application in Photoshop.

image

The second step is to import that image into Catalyst and use it to convert the artwork from Photoshop into controls. There is much more to Catalyst. You can define design-time data which enables you to run your prototype to see how it would work. The image below shows Catalyst processing the image from Photoshop. This image shows that a second state has been defined. Many properties like transitions can be easily configured.

image

Then, once all of the user interaction patterns have been defined, import the project (FXP) into Flash Builder 4. All of the components are available for coding. This is where we will leverage the LiveCycle Service Discover Plugin to hook up the application to LiveCycle ES. This could be any service made available by your LiveCycle ES server. In our case, we are using two simple processes that expose Content Services functionality. The first service retrieves a list of documents in a specific space. The second service enables the application to retrieve a document based on the user’s selection. And while we are at it, apply a Rights Management policy to the document to encrypt it on the way out. In the following image, you can see our project in Flash Builder 4. At the bottom are the LiveCycle ES services.

image

As you can see, this stuff is really cool and is just a sample of all the stuff we will cover in the preconference session.