Jeff D. Brown - Tech Notes

Senior Consultant with CityTech, Inc.

Jeff D. Brown - Tech Notes header image 1

JBoss Seam support in latest IntelliJ release

November 10th, 2008 · No Comments

IntelliJ IDEA v8 now has Seam support out of the box. For a list of capabilities included see:

http://www.jetbrains.com/idea/features/newfeatures.html

They seem to cover everything you would expect in an IDE in terms of Seam-specific functionality.  I was happy/suprised to see the visual jPDL pageflow support.  First thing I want to do is to see if this also supports the jPDL process definitions as well.  I suspect it does, since the only difference is some schema naming, but will report back once I verify this.

From my perspective, the inclusion of tooling into the IntelliJ product is a key indicator of the traction the Seam framework has generated in the industry.

To recap, developers now have 3 choices for Seam support in an IDE:

  • Use the free JBoss Tools Eclipse plug-in.
  • Purchase the supported JBoss Developer IDE (which is basically a pre-bundled and supported version of the 1st choice).
  • Purchase the latest IntelliJ release.
  • → No CommentsTags: Uncategorized

    Alfresco Share in the Enterprise

    October 31st, 2008 · No Comments

    Alfresco 3.0 Enterprise was released this week.  If you have been holding off previewing the new functionality while still in the Labs edition, you are in for a treat.   The thing that will catch your eye immediately is the new Share application that is included in Alfresco.

    Nothing against the “old” Alfresco web client, but it is really geared towards administrators and document management back-office work.  With the addition of Share, Alfresco delivers a “Web 2.0″ application leveraging Flash and AJAX with a polished interface any business person will enjoy.

    Share is heavily focused on Collaboration tasks and includes integration with popular Blogging, Wiki, and Forum/Discussion products out of the box.  And, of course, Share provides great interface into your more traditional document management library (think folders) as well.

    But what really caught me eye was Share’s ability for user site creation.  Any business user, given the proper authorities, can quickly set up a “Site” in Share, invite users to the site, and assign permissions to users within that Site.   We have gotten requests for this in past from clients and always had to build a custom-type solution to accommodate this need.  Now, Share provides this out of the box.   A few places where I see this fitting in rather nicely are:

    • Universities - Instructors can create a site for specific classes and students could then create sub-sites for team projects going on in the class.
    • Laboratories - A site can be created for any project going on that requires collaboration.  Site members could include internal as well as external members.
    • Manufacturers - Product development would benefit by having a site for each major product under design.  Engineers, vendors, and customers could use the site to collaborate on the specifications, testing, and design.

    Keep in mind, all Site content and documents are stored in the Alfresco repository still.  So they are secured, versioned, searchable, and auditable as well.

    Check out the screen shots here as they quickly give you a taste of the improvements Alfresco has made.

    I plan to post on the other features of 3.0 in the future, so stay tuned.  Also, Kudos to the Alfresco team on this major release!

    → No CommentsTags: ECM

    A Treat for Halloween - Performance Improvements in Alfresco Task Management

    October 31st, 2008 · No Comments

    I wanted to share an Alfresco customization that greatly increased the usability and performance when dealing with the workflow tasks.  First some background and then I will get into the solution.   On a recent project, we had the task of designing workflows to manage the client’s contract approval process.  We implemented these with several custom Advanced Workflows within Alfresco using the bundled JBoss jBPM tool.   It was the nature of the business that there were several parallel paths resulting in “lots” of active tasks at a given time.

    We quickly found that by the time the number of tasks reached a couple thousand, Alfresco began having serious performance issues in querying and returning the tasks for management.   For instance, if someone wanted to page through all the “active” tasks, this took minutes and at some point completely failed with a Hibernate exception.

    Paging through a large set of data is a common use case; however, Alfresco’s WorkflowService interface has no mechanism to handle this.  Instead it relies on returning all results to the client and it is up to the client to do the paging logic if needed.   In all fairness, this is probably because a majority of task management solutions are not dealing with thousands of tasks concurrently.   If however, your application does deal with many tasks or you just prefer a more efficient way to handle this, Alfresco can be extended without too much work.

    The Treat
    One of the simplest ways to visually page through data efficiently is to let the database do the heavy lifting for you and limit the number of rows returned.  Because both Alfresco and jBPM use Hibernate, the easiest solution I saw was to use Hibernate’s setMaxResults() and setFirstResult() functions.    These functions allow Hibernate to leverage the underlying database to return a large result set in chunks that work nicely within a UI page.

    Step 1
    Created a custom class called CustomWorkflowTaskQuery in order to pass the values for both MaxResults and FirstResult properties.  This class extends the org.alfresco.service.cmr.workflow.WorkflowTaskQuery .

    public class CustomWorkflowTaskQuery extends WorkflowTaskQuery {
    
    	Integer maxResults = null;
    	Integer firstResult = null;
    
    	public Integer getMaxResults() {
    		return maxResults;
    	}
    
    	public void setMaxResults(Integer maxResults) {
    		this.maxResults = maxResults;
    	}
    
    	public Integer getFirstResult() {
    		return firstResult;
    	}
    
    	public void setFirstResult(Integer firstResult) {
    		this.firstResult = firstResult;
    	}
    }

    Step 2
    Note that Alfresco class org.alfrecso.repo.workflow.jbpm.JBPMEngine is a plug-in implementation of the generic BPMEngine.  This is where the code dealing directly with the JBoss jBPM API resides.   This is the class we need to extend with our own customized version.   I created the CustomJBPMEngine class that extends Alfresco’s JBPMEngine class.  I really just need to “append” a few lines of code to the existing method JBMEngine.createTaskQueryCriteria().  If Alfresco had made this method protected, as one would maybe expect out of an extendable product, I could have overridden it, called super(), added my few lines and been handing out candy to the kids already.  Sadly they used private instead.   That means my subclass has no visibility to it and I am forced to copy the entire method and add my logic to the end.

    For the same reason, I am also forced to copy the JBPMEngine.queryTasks() as well since it calls createTaskQueryCriteria() and would automatically use the original private method if run from within the parent JBPMEngine class.  See below:

    public class CustomJBPMEngine extends JBPMEngine {
    
     /**
    * exact copy from JBPMEngine - had to copy since the other methods were made private.
     */
    public List queryTasks(final WorkflowTaskQuery query) {
    	try {
    		return (List) jbpmTemplate.execute(new JbpmCallback() {
    		 public List doInJbpm(JbpmContext context) {
    		  Session session = context.getSession();
    		  Criteria criteria = createTaskQueryCriteria(session, query);
    		  List tasks = criteria.list();
    
    		 // convert tasks to appropriate service response format
    		 List workflowTasks = new ArrayList(tasks.size());
    		 for (TaskInstance task : tasks) {
    		  WorkflowTask workflowTask = createWorkflowTask(task);
    		  workflowTasks.add(workflowTask);
    		 }
    		 return workflowTasks;
    	        }
    		});
    	}
    	catch (JbpmException e) {
    	  throw new WorkflowException("Failed to query tasks", e);
    	}
    }
    
    /**
     * Had to override the Alfresco version since it does not allow for Hibernate offsets that we need for
    * performance.
    * Copied from JBPMEngine except for the very bottom of the method.
     */
    private Criteria createTaskQueryCriteria(Session session, WorkflowTaskQuery query) {
      Criteria process = null;
      Criteria task = session.createCriteria(TaskInstance.class);
    
      // task id
      if (query.getTaskId() != null) {
     	task.add(Restrictions.eq("id", getJbpmId(query.getTaskId())));
      }
    
    // task state
     if (query.getTaskState() != null) {
    	WorkflowTaskState state = query.getTaskState();
    	if (state == WorkflowTaskState.IN_PROGRESS) {
    		task.add(Restrictions.eq("isOpen", true));
    		task.add(Restrictions.isNull("end"));
    	}
    	else if (state == WorkflowTaskState.COMPLETED) {
    		task.add(Restrictions.eq("isOpen", false));
    		task.add(Restrictions.isNotNull("end"));
    	}
    }
    
    // task name
    if (query.getTaskName() != null) {
    	task.add(Restrictions.eq("name", query.getTaskName().toPrefixString(namespaceService)));
    }
    // task actor
    if (query.getActorId() != null) {
    	task.add(Restrictions.eq("actorId", query.getActorId()));
    }
    
    // task custom properties
     if (query.getTaskCustomProps() != null) {
    	Map props = query.getTaskCustomProps();
    	if (props.size() > 0) {
    	   Criteria variables = task.createCriteria("variableInstances");
              Disjunction values = Restrictions.disjunction();
    		for (Map.Entry prop : props.entrySet()) {
    			Conjunction value = Restrictions.conjunction();
    			value.add(Restrictions.eq("name", mapQNameToName(prop.getKey())));
    			value.add(Restrictions.eq("value", prop.getValue().toString()));
    			values.add(value);
    		}
    		variables.add(values);
    	}
    }
    
    // process active?
    if (query.isActive() != null) {
    	process = (process == null) ? task.createCriteria("processInstance") : process;
    	if (query.isActive()) {
     	 process.add(Restrictions.isNull("end"));
    	}
    	else {
     	 process.add(Restrictions.isNotNull("end"));
    	}
    }
    
    // process id
    if (query.getProcessId() != null) {
    	process = (process == null) ? task.createCriteria("processInstance") : process;
    	process.add(Restrictions.eq("id", getJbpmId(query.getProcessId())));
    }
    
    // process name
    if (query.getProcessName() != null) {
    	process = (process == null) ? task.createCriteria("processInstance") : process;
    	Criteria processDef = process.createCriteria("processDefinition");
    	processDef.add(Restrictions.eq("name",    query.getProcessName().toPrefixString(namespaceService)));
    }
    
    // process custom properties
    if (query.getProcessCustomProps() != null) {
    	// TODO: Due to Hibernate bug http://opensource.atlassian.com/projects/hibernate/browse/HHH-957
    	// it's not possible to perform a sub-select with the criteria api. For now issue a
    	// secondary query and create an IN clause.
    	Map props = query.getProcessCustomProps();
    		if (props.size() > 0) {
    		// create criteria for process variables
    			Criteria variables = session.createCriteria(VariableInstance.class);
    			variables.setProjection(Property.forName("processInstance"));
    			Disjunction values = Restrictions.disjunction();
    			for (Map.Entry prop : props.entrySet()) {
     			  Conjunction value = Restrictions.conjunction();
    				value.add(Restrictions.eq("name", mapQNameToName(prop.getKey())));
    				value.add(Restrictions.eq("value", prop.getValue().toString()));
    				values.add(value);
    			}
    			variables.add(values);
    
    			// retrieve list of processes matching specified variables
    		List processList = variables.list();
    		Object[] processIds = null;
    		if (processList.size() == 0) {
    			processIds = new Object[] { new Long(-1) };
    		}
    		else {
    			processIds = new Object[processList.size()];
    			for (int i = 0; i < processList.size(); i++) {
    				processIds[i] = processList.get(i).getId();
    			}
    		}
    
    		// constrain tasks by process list
    		process = (process == null) ? task.createCriteria(”processInstance”) : process;
    		process.add(Restrictions.in(”id”, processIds));
           }
    }
    
    // order by
    if (query.getOrderBy() != null) {
    	WorkflowTaskQuery.OrderBy[] orderBy = query.getOrderBy();
    	for (WorkflowTaskQuery.OrderBy orderByPart : orderBy) {
    		if (orderByPart == WorkflowTaskQuery.OrderBy.TaskActor_Asc) {
    			task.addOrder(Order.asc(”actorId”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskActor_Desc) {
    			task.addOrder(Order.desc(”actorId”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskCreated_Asc) {
    			task.addOrder(Order.asc(”create”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskCreated_Desc) {
    			task.addOrder(Order.desc(”create”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskDue_Asc) {
    			task.addOrder(Order.asc(”dueDate”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskDue_Desc) {
    			task.addOrder(Order.desc(”dueDate”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskId_Asc) {
    			task.addOrder(Order.asc(”id”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskId_Desc) {
    			task.addOrder(Order.desc(”id”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskName_Asc) {
    			task.addOrder(Order.asc(”name”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskName_Desc) {
    			task.addOrder(Order.desc(”name”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskState_Asc) {
    			task.addOrder(Order.asc(”end”));
    		}
    		else if (orderByPart == WorkflowTaskQuery.OrderBy.TaskState_Desc) {
    			task.addOrder(Order.desc(”end”));
    		}
    	}
    }
    
    // custom code starts here.
    if (query instanceof CustomWorkflowTaskQuery){
    	CustomWorkflowTaskQuery tempQuery = (CustomWorkflowTaskQuery) query;
    	if (tempQuery.getMaxResults() != null) {
    		task.setMaxResults(tempQuery.getMaxResults().intValue());
    	}
    	if (tempQuery.getFirstResult() != null) {
    		task.setFirstResult(tempQuery.getFirstResult().intValue());
    	}
    }  // end of custom code.
    
    return task;
    }
    
    /**
     * Straight copy from JBPMEngine since we have no visibility to it.
     */
    private String mapQNameToName(QName name) {
    	String nameStr = name.toPrefixString(this.namespaceService);
    	return nameStr.replace(':', '_');
    }
    }
    

    Step 3
    The final step is to handle the Spring bean configuration files to ensure CustomJBPMEngine is used instead of JBPMEngine.   To do this, I created a custom-workflow-context.xml file under the Alfresco extension directory.  I copied the jbpm_engine bean configuration from Alfresco’s config/workflow-context.xml file and changed it to use my custom class instead.  This way, the custom class is registered with the generic BPM

     <bean id="jbpm_engine" class="org.cityofchicago.dhs.repo.workflow.jbpm.CustomJBPMEngine" parent="bpm_engine">
          	<property name="engineId" value="jbpm"/>
          	<property name="JBPMTemplate" ref="jbpm_template"/>
          	<property name="dictionaryService" ref="DictionaryService"/>
          	<property name="namespaceService" ref="namespaceService"/>
         	<property name="nodeService" ref="nodeService"/>
          	<property name="personService" ref="personService"/>
          	<property name="authorityDAO" ref="authorityDAO"/>
          	<property name="serviceRegistry" ref="ServiceRegistry"/>
          	<property name="companyHomeStore"><value>${spaces.store}</value></property>
          	<property name="companyHomePath"><value>/${spaces.company_home.childname}</value></property>
    	<property name="unprotectedSearchService" ref="searchService"/>
       </bean>

    Step 4
    Now, when you want to use this, just call Alfresco’s workflowService.queryTasks() as you normally would, but pass in the new CustomWorkflowTaskQuery created in Step 1 above.  Remember to set the maxResults to the number you want to show per page and then set firstResult to the page# your UI wants to display.

    Happy Halloween

    BTW - As this seems to be a common use case, I opened an enhancement request with Alfresco along these lines.  If you agree, please cast your vote there.  https://issues.alfresco.com/jira/browse/ETHREEOH-460

    → No CommentsTags: ECM

    Presenting at Alfresco Chicago MeetUp on Feb. 12th

    February 8th, 2008 · No Comments

    The Alfresco Community Meetup is a chance to learn about Alfresco and talk to your peers about how they are using Alfresco in their business space. CityTech will be teaming with Matria Healthcare to present a use case of how Alfresco is being used to solve their business challenges.

    There will also be several informal (IE: laptop on pub table) demonstrations during the happy hour portion of the MeetUp as well. If you are interested in the Alfresco’s Advanced Workflow functionality or in how Alfresco can be integrated into your operation’s current application monitoring system, please stop by one the tables during a break and take a look.

    The event is at a great Chicago location - Columbia Yacht Club, so we hope to see you there. You can register for the event at:

    http://webcms.meetup.com/43/calendar/6927116/ 

    → No CommentsTags: ECM

    Alfresco Advanced Workflow and task due dates.

    February 4th, 2008 · No Comments

    I recently developed a workflow where the requirements called to dynamically assign task due dates relative to the task creation date. For example, a particular task was required to automatically have a due date assigned that is 3 business days from the date the task is created.

    The challenge here is to ensure the due date is assigned to an actual business work day. Out of the box, Alfresco does not include this functionality. However, Alfresco does include the jBPM Business Calendar which we can use to solve this requirement. The org.jbpm.calendar.BusinessCalendar class comes bundled as part of the jBPM jar files included with Alfresco.

    The BusinessCalendar class allows you to set the normal working days and working hours for a company as well as to indicate any holidays observed by the company. This is done using an XML configuration file. This file is found within the same jBPM jar file, but can be copied out, customized, and placed in your classpath with the same directory structure and file name. The file can be found at org/jbpm/calandar/jbpm.business.calendar.properties within the 3rd-party JAR: /3rd Party/lib/jbpm/jbpm-jpdl-3.2-patched.jar (as of Alfresco EE2.1.1). Place a customized copy of this file, complete with the same directory structure under the WEB-INF/classes directory of your extension project.

    Alfresco already uses the BusinessCalendar class for the workflow Timer node and it can be leveraged for setting task due dates with a single custom class. To do so, create a custom class that extends the jBPM ActionHandler class. In the example below, I extended from the Spring-enabled descendant in case I needed access to any of of the Spring beans. Ends up I did not, but I left it in for future enhancements anyway. The custom action takes a String parameter that contains a valid jBPM duration string and adds that duration to the current date/time to set the current task’s due date.

    AssignBusinessDueDate.java

    The following example shows this class called from the task creation event in a process definition:

    <task-node name="some task">
    <task name="citytechwf:genericTask" swimlane="accountants">
    <event type="task-create">
    <action class="com.citytechinc.repo.workflow.jbpm.AssignBusinessDueDate">
    <addDuration>5 business days</addDuration>
    </action>
    </event>
    </task>
    </task-node>

    → No CommentsTags: ECM

    Ubuntu Gutsy (7.10) workaround for Apani Nortel VPN Client

    November 15th, 2007 · 1 Comment

     This is huge news for those that use Ubuntu Linux, or want to, but are limited by the need to also use the Nortel VPN client.  The folks over at the Ubuntu forums have a workaround that works on Ubuntu Gutsy  (7.10) and the Apani 3.5 client.

    http://ubuntuforums.org/showthread.php?t=110843&page=8 

    You can download a timed eval copy of the VPN client here: http://www.apani.com/vpn-clients/nortel-overview.php

    Note that the Ubuntu workaround discussed on the forum link above starts with the Red Hat tar file from Apani, not the vanilla Linux tar.

    → 1 CommentTags: Linux

    Great things from the Alfresco Community Conference

    November 8th, 2007 · No Comments

    Just returned from New York City where we attended the inaugural Alfresco Community Conference. The conference was attended by both community and enterprise Alfresco customers as well as Alfresco integration partners. We flew out late Tuesday night, attended the conference Wednesday and then flew back Wednesday night. Not even time to have dinner at a great NYC restaurant!

    The quick trip was well worth it however. Since most of the Alfresco team is quite spread out geographically, this was an opportunity to meet face-to-face with many we had worked with via email, phone, and the forums over the past few years.

    I won’t go into all the details of everything covered at the conference at this time. You can see the complete agenda here: Conference Agenda and I suspect others will detail the great discussions led by both John Powell and John Newton. However, I do want to discuss a few of the major new features we can expect to see in the coming months. These are major advancements in out-of-the-box functionality and two particularly are in areas that we are seeing growing interest in from our clients.

    Collaboration

    The first is the Collaboration module that will be available in the v2.9 Community Edition. This module integrates popular wiki and blogging tools (MediaWiki and WordPress) into Alfresco and allows Alfresco to serve as the repository for such content as well as to integrate it’s workflow and search capabilities with these tools. We also saw a demo of the use of email-addressable content and spaces that allowed emails be stored in the repository. The content type of the email was even dynamic based on the context. For example, an email addressed to the alias of a Forum Topic space was seen as a post content type.

    This module fills a major gap and now allows Alfresco to be the single source repository for all popular collaboration methods beyond the existing document collaboration. This code is already available in the v2.9 Community HEAD, so I can’t wait to check it out.

    Flex

    The integration with Flex http://flex.org/ for providing Rich Internet Applications (RIA) was the second major announcement. We saw a working demo of a Flex application being used to page through a virtual photo album of images stored in the Alfresco repository. This was done using the Flex API that is in v2.9 Community HEAD as well. The Alfresco team made it clear that they see Flex as the future of RIA and they plan to enhance the current JSP based web UI with a Flex version in the future. The difference in the user experience between a Flex application and a traditional HTML application is huge. I would compare it to watching football on a 50″ plasma HD versus the 36″ standard definition device. It is that type of jaw-dropping difference.

    While I am discussing Flex, we saw some screenshots of the planned future “Alfresco Network Application” to be built using Flex. This application is targeted for the consumer and will allow “everyone” to take advantage of ECM transparently. This application is based on the social networking sites that have huge following already and are starting to gain some traction for enterprise use as well. There rough target for this is 2nd Qtr 2008 with the v3.0EE. That feature alone is worth it’s own blog coming soon.

    iGoogle and FaceBook

    Other features with 2.9 are Google gadget creation and FaceBook integration. We saw a demo of the familiar workflow tasks and spaces dashlets both displayed in iGoogle. I am guessing they take advantage of the new JavaScript workflow API as we saw them completely manage a workflow task from within iGoogle. For the FaceBook demo, we saw content in FaceBook being served and stored within the Alfresco repository real-time.

    I also got a chance to pick David Caruana’s brain on some workflow ideas that I had as well as discuss the enhancements we can expect with version 2.2 and beyond. I have worked with David via the forums and support extensively over the last year, so it was a pleasure to finally talk in person.

    That’s it for now.

    → No CommentsTags: ECM

    Archived Alfresco Webinar available

    October 17th, 2007 · No Comments

    In case you missed the webinar from 10/04 on advanced workflow and enterprise integration with Alfresco, the slides and audio are linked below:

    Advanced Workflow and Enterprise Integration Webinar

    → No CommentsTags: ECM

    Alfresco web scripts on BEA Service Bus.

    October 5th, 2007 · No Comments

    We are just wrapping up a project where there was the need to expose Alfresco Web Scripts via the BEA AquaLogic Service Bus. This was a fairly simple process; however, there were a couple settings we had to tinker with. I will go over the details and hopefully it will save someone else some time down the road.

    First some background for those who are not familiar. Alfresco is a professionally supported, open-source enterprise content management system (ECM). For this project, we used Alfresco as the ECM framework for a custom application that was based on document management and workflow. We were using the 2.1 Enterprise version of Alfresco, but this should also work for the 2.1 Community Editions as well. You can read more about Alfresco at: http://www.alfresco.com

    AquaLogic Service Bus (ALSB) is a commercial product from BEA that serves as the ESB implementation for an SOA solution. The ALSB can be used to route, proxy, and orchestrate services. It also provides for centralized monitoring and governance of these services. The steps and screenshots I describe below are for ALSB v2.5. I suspect the steps would be the same with the new v2.6, but I have not had the chance to try. More info can be found at: http://www.bea.com

    On with the details…

    We leveraged the “Web Script” functionality available with Alfresco 2.1. This is a framework within Alfresco that allows you to create RESTful web services based on Alfresco content. In our case, we wrote a custom web script backed by a Java bean. That Java bean was responsible for pulling together several pieces of discreet content along with their properties and generating a single PDF summary document. Using the web script framework, we were able to expose this as an HTTP GET method and it returned a PDF document (CONTENT-TYPE = “application/pdf”).

    As I go through the steps on ALSB, I will assume you have used this product before so I will only cover details specific to this use case. I also assume you have signed into the ALSB console and have created a project.

    Step 1:

    The first thing to do is to create a Service Account object. The Service Account determines how security credentials are used for the service. For simplicity in this example, select a “Static” type and enter your Alfresco credentials where provided. Note that in production, you would select “Pass Through” if both Alfresco and ALSB authenticate against the same directory. If they did not use the same directory you would select “Map” and map the ALSB credentials to the appropriate Alfresco credentials. Note that I am using the default HTTP Basic Authentication within Alfresco.

    Step 2:

    Next, create a Business Service object in this project:

    • Service Type = Messaging Service
    • Request Message Type = None (in my case the HTTP get as no request params.)
    • Response Message type = Text (note that this not truly the case, but we will take care of later)
    • Protocol = http
    • Endpoint URI = the Alfresco URL used to call your service. For example: http://127.0.0.1:8080/alfresco/service/ui/mycustomscript
    • HTTP Request Method = GET (In my case. POST should also work if your web script was setup for that)
    • Basic Authentication is Required – Checked (Note that unless your Alfresco web script allows guest access you will need to send in credentials.
    • Service Account – browse to the Service Account object that we created in the first step.
    • Follow HTTP redirects - Checked

    Before clicking Save, your settings should look like this:

    ALSB Business Service Screen Shot

    Step 3:

    Next, we need to create a Proxy Service object based on the Business Service object created above. Select the Same Request and Response Message Types and the same Protocol. Enter an Endpoint URI that the client will call. For example: /alfservice.

    Since we used a Static Service Account type for the business service, leave the Basic Authentication Required unchecked. Note if you used a Map or Pass Through Service Account type, you would need to enable this option so that the proxy expected credentials to be passed from the client.

    Your settings should look something like this:

    ALSB Proxy Service screenshot

    If you tried to test the Proxy Service now, it would fail because your web script is most likely not returning a Text content type (text/plain) as we indicated in the Business Service object. We set this to Text because ALSB does not have a application/pdf response type option and also because we do not want to tie ALSB to the web script’s response type if we have a choice.

    Instead, we will instruct the Proxy to dynamically set the Content-Type within the HTTP Header to match the Content-Type coming from Alfresco. This way, your Alfresco web script can change content types without impacting the ALSB.

    Step 5:

    To do this, edit the proxy’s message flow and add a Pipeline Pair element. In the Response flow, add a Stage to handle this logic. Your message flow should now look something like this:

    ALSB Proxy Message Flow screenshot

    Next, edit the stage and add a Transport Headers Action. Select to set for the Inbound Response (inbound to the client, that is). Select the option to Pass all Headers thru the Pipeline.

    Finally, select the HTTP Content-Type Header and the Action is Copy Header from Outbound Response. Before you click Save button, your screen should look like this:

    ALSB Header screen shot


    Once the ALSB session is Activated, you can test the Alfresco web script via the ALSB by calling the Endpoint URI you indicated in the Proxy Service configuration. Make sure you are pointing to the ALSB server and port and not the Alfresco server. For example, if ALSB is running locally on port 7001 use:

    http://127.0.0.1:7001/alfservice

    That’s it. A simple example, but you now have the option to do other actions in the proxy’s message flow as your requirements demand. You can also now monitor and set SLA targets and alerts for Alfresco services the same as you may already be doing for SOAP web services.

    → No CommentsTags: ECM · SOA / Integration

    SOA - What is it again?

    November 27th, 2006 · No Comments

    SOA - What is it?

    In the past two years I have been asked multiple times by both technical and business people alike one question more than any other - “What is this SOA thing?” I think this is a common question because the marketing and press folks have done a very good job of muddying the water when it comes to tagging every piece of software as SOA-enabled, SOA-certified, etc.

    The challenge is to explain what SOA is to the client - the people that pay the bills. SOA stands for Service Oriented Architecture and to start with, it is easy to define what SOA is not. SOA is not a single product you simply install and are done with it. I have had customers tell me not to worry about business requirements for a new system because “the SOA will handle all that”. Their understanding was that “the SOA” was a product you installed and it magically solved all the business problems. Hmmmm…..where is that salesperson? SOA is also not web services. It is true that web services are usually employed as part of a modern SOA solution, but in of themselves, they are not SOA.

    So what is it and how do you explain it to your business customer?

    SOA is a philosophy or vision of how software should be developed. Those that adhere to this philosophy believe that the most efficient way to build software is through a series of re-usable services. By “service” I mean any type of function that accomplishes a specific task. The idea is to build a layer of fine-grained functions and then begin building out more coarse-grained functions on top of that layer. A great business example is to imagine offering a coarse grained business service called AcceptPayment that within itself calls two services that are more fine-grained - AuthorizeCreditCard and PostPaymentToAR. At a recent conference, the speaker compared this composition of services to Legos and I agree that is a good analogy.

    This service architecture promotes re-use, reduces maintenance, and is a more efficient way to design. The apex of SOA occurs once all the fine-grained services have been built and are easily available to coordinate into new coarse-grained business services as needed. This philosophy has been around for decades, but with the emergence of web services, it became much more popular and started to receive press and marketing attention.

    So why is the term “SOA” in every article I have read in the past 2 years?

    The reason for this surge is two-fold. First, with the introduction of web services, architects can now expose their services/functions in an accepted standard that is platform/language agnostic. Before web services, one could build using an SOA driven design and expose services within the firewall via RMI/EJB or JMS (assuming J2EE shop). To expose services outside the firewall to vendors for instance, one used CORBA or perhaps some custom format between the service producer and service consumer over HTTP.

    The second reason for the increase in press was that a “look-up” technology known as UDDI was introduced. Before UDDI, one could build a business function as a service and expose it, but no one else could know about it. UDDI solved that problem by providing an agreed upon standard for marketing services to potential clients. Think of UDDI as a library for services. Because web services and UDDI are both open standards that began to get traction (web services much more than UDDI), this allowed software vendors to begin to make tools based on these standards.

    The major software vendors started creating tools to easily expose web services and create web service clients for developers. They also began providing registry software based on the UDDI standard. These tools made the development of SOA driven design easier and MUCH more efficient. At that point, things really started to take off.

    → No CommentsTags: SOA / Integration