cancel
Showing results for 
Search instead for 
Did you mean: 

Non-interactive Capture of XML Content

varsenault
Champ in-the-making
Champ in-the-making
Hi,

My client has an ERP/Business Intelligence system that produces XML reports for web publication. We would like this client to use Alfresco's WCM for that to allow some CIFS access, XSLT/XSL-FO transformations, versioning, sandbox, staging and overall workflow/BPM. In short, we would like the ERP to be able to publish the XML content exactly as a human would capture the content through the XSD form.

So, is it possible, through web services or space rules or javascript API to "capture a form" by dropping some XML content (compliant to the form's XSD)?

Thanks in advance.
11 REPLIES 11

kvc
Champ in-the-making
Champ in-the-making
Great question.

Today, the best means of supporting this includes setting up a drop folder for your XML reports.  This drop folder would be a formal Alfresco space, and you can output reports into it either via CIFS or FTP.  On this space, you would configure a rule that would initiate a workflow.  This workspace would move the XML to the appropriate AVM store, where you can do your staging, versioning, snapshoting, deployment and more.

An alternative - if you do not want to auto-trigger on every XML asset create a new workflow - is to use the built-in Quartz scheduler to run a job every so many minutes to package up a set of XMLs and then initiate a workflow.  If a particular set need to go as a package, they should get sent into Alfresco as a ZIP, and the job triggered by Quartz would unpack each ZIP and start a workflow unique for each.  If doing this route, you would dump your XMLs direct into an AVM store, as the need for an asset-level create trigger is not needed.

Let me know if you've more questions.  I'd like to help with this use case.


Kevin

varsenault
Champ in-the-making
Champ in-the-making
Sorry for taking so long, I wanted to think about what we want to do. Here's what I came up with…

Ideally, there are two things I would like to do with the CMS (Alfresco) in conjunction with the KMS (custom ERP). It's fairly simple :
* Get data from the CMS to the KMS (data entry in the KMS from, based/inspired by unstructured content from the CMS, following a workflow controlled by the CMS).
* Get data from the KMS to the CMS (XML reports generated from structured data from the KMS that are handled, transformed, published, controlled by a workflow and WCM features from the CMS).

I wanted to abstract the Alfresco-ERP paradigm into CMS-KMS, because it simplifies the use I want to make of Alfresco, without getting into the details of the actual data that is managed. So first, let me explain what I mean by KMS and CMS :
* KMS : repository of structured, queriable, analyzable data elements called the entities (or resources or instances). The backend for this is a combination of RDBMS, object database and triplestore. Amongst other things, it has the capacity to generate XML reports following a schema that matches a determined ontology (defined by a UML model). Example of entities: "Blue Dress", "Mr. John Lee", "Microsoft".
* CMS : repository of unstructured, unqueriable (but usually searcheable) content : the document. Documents in the CMS are representations or serializations of a entity/resource's state (to recuperate REST vocabulary)  from the KMS. A resource state is simply a snapshot of the entity/resource in time. The backend for, this, at least with Alfresco, is simply the filesystem, with a light database for metadata persistence. Example of representations: "Blue Dress Product Sheet", "Mr. John Lee's Business Card", "Microsoft's Corporate Profile on June 1 2007".

So, for the KMS–>CMS problem, you partially answered my question, however, the thing is that I want to reuse the WCM workflows for forms and XSLT content transformations I created so that I can either initiate the same WCM workflows both by manual form capture or by sending one or more XML documents from the KMS. I don't want to maintain two workflow paths, one for the KMS and one for the data entry people. I would like the WCM to expose an API or webservices or something to enable the KMS to interact with the CMS as a human would.

Also, I'd like to tackle the CMS->KMS problem. If, for example, a workflow that is controlled by Alfresco's JBPM engine contains a task that requires the actor to manually input data into the KMS from information contained in documents from the CMS, what are my options? The KMS already exposes simple, AJAX-compliant webservices and has a very granular UI framework allowing the inclusion of form snippets (HTML+Javascript) in other applications. Would it be possible to integrate that in a task's UI so that it can automatically be sent to the KMS?

Thank you so much for your time. It is greatly appreciated.

kvc
Champ in-the-making
Champ in-the-making
This sounds exciting.

Alfresco's workflow services (or assets) can be programmatically controlled by another application (your workflow engine) - our workflow is specific to content creation and approval processes, which oftentimes are a subset of an overall business process.  And yes you can either embed your own custom actions into our task dialog.

If you'd like assistance with designing this custom application, we'd love to help - easier to do via a Skype call / Acrobat Connection session rather than forums, however.  Do send an email to info@alfresco.com, and we'll see how we can help.

Kevin

varsenault
Champ in-the-making
Champ in-the-making
Hello Kevin,

I'm currently preparing a formal use case for what we want to do and I'll contact you when it is ready. Thanks for you help! Talk to you soon.

kvc
Champ in-the-making
Champ in-the-making
Keep us posted!  You can email us details of your project and what help you need to info@alfresco.com.

Cheers.

varsenault
Champ in-the-making
Champ in-the-making
Hello,

I posted something at info@alfresco.com, but I no one got back to me, yet.

We are slowly getting around some of the problems that we initially encountered. However, we still have some unresolved issues about the "Move/copy/commit to my sandbox action" :

- Does the AVM and general Alfresco Javascript API exposes enough functionalities to do this in Javascript? Let's assume it does… If it doesn't is it possible to do it in the Java Foundation API? I hope the Javascript option will work, because the Foundation API Javadoc is really scary.

- We first want to have a manual process by which users would be able to copy/move/commit any nodes (documents or spaces) from the "normal" spaces to their sandbox, so how do we make sure the action is available on a node in the web client only if the user has an AVM sandbox? Also, we don't wan't the user to have to run the Script action, then select the "copy to AVM" script… We want a simple "copy to AVM" with a nice desrciptive icon, in the "more actions" on a node, if the user has the AVM setup to do so.


- Should we move or copy, or is there a special "commit" action to the AVM we should use?

Thanks

kvc
Champ in-the-making
Champ in-the-making
You do have a JavaScript API for moving/copying items from a space to a sandbox.  You will need to use the interstore copy service here:

http://wiki.alfresco.com/wiki/JavaScript_API#Cross_Repository_Copy

You can also create a rule on a space that executes any Javascript you've written - you'll see this custom Javascript execution as one of your available actions in the rules wizard (you'll also see a default 'copy item to web project' action there as well that uses the interstore copy service).

If you do this as a rule, in your Javascript you can first check to see if a user has a sandbox in the targeted web project, and, if not, use our new Javascript API support for the AVM to create a sandbox for that user - or just write everything into a default sandbox used for general contributions (say, the Admin sandbox).

Let me know if you have more questions.  If you can email me directly at kevinc@alfresco.com, I can also put you in touch with an appropriate person who can work with you more directly to help you accomplish what you need.

Kevin

varsenault
Champ in-the-making
Champ in-the-making
hello,

So here's what I got so far (Alfresco 2.1).

In the configuration file :


<alfresco-config>
   <config>
      <actions>
         <!– Copy to My Sandbox –>
         <action id="copy_to_my_sandbox">
            <label>Copy to My Sandbox</label>
            <image>/images/icons/user_sandbox.gif</image>
            <script>/GIR/Data Dictionary/Scripts/CopyToMySandbox.js</script>
            <params>
               <!– IMPORTANT : allows the script to fetch its context with default objects (document, person, etc.) –>
               <param name="nodeRef">#{actionContext.nodeRef}</param>
            </params>
         </action>
           
         <!– Add action to more actions menu –>
         <action-group id="document_browse_menu">
            <action idref="copy_to_my_sandbox" />
         </action-group>
      </actions>
   </config>
</alfresco-config>


And the javascript file per se :


var output = null;

if(logger.isLoggingEnabled()) logger.log("Starting CopyToMySandbox.js script.");

// Fetch document from action context
var document = search.findNode(args["nodeRef"])

if(document != null) {
   if(logger.isLoggingEnabled()) logger.log("Document found.");
   
   
   // Fetch document path
   var documentPath = document.displayPath;

   // Fetch document name
   var documentName = document.name;

   // Fetch current user's name
   var currentUserName = new String(person.properties['cm:userName']);

   // Fetch current user's AVM store
   var targetUserAVMStore = null;
   for(var i in avm.stores) {
      var currentStore = avm.stores[i];

      // Check that the store's owner is the current user and that
      // it's its personnal sandbox and not the preview
      // repository or the staging sandbox.
      var storeName = new String(currentStore.name);
      if(logger.isLoggingEnabled()) logger.log("Iterating over store : " + storeName);

      var storeOwnerUserName = new String(currentStore.lookupRoot().owner);

      var storeSuffix = '–' + currentUserName;
      if(logger.isLoggingEnabled()) logger.log("Store suffix : " + storeSuffix);

      var storeSuffixPosition = storeName.length - storeSuffix.length;
      if(logger.isLoggingEnabled()) logger.log("Store suffix position : " + storeSuffixPosition);

      var storeSuffixLastIndex = storeName.lastIndexOf(storeSuffix);
      if(logger.isLoggingEnabled()) logger.log("Store suffix last index : " + storeSuffixLastIndex);

      if(logger.isLoggingEnabled()) logger.log("Current user name : " + currentUserName);
      if(logger.isLoggingEnabled()) logger.log("Current user name length : " + currentUserName.length);
      if(logger.isLoggingEnabled()) logger.log("Store owner : " + storeOwnerUserName);
      if(logger.isLoggingEnabled()) logger.log("Store owner length : " + storeOwnerUserName.length);
      if(logger.isLoggingEnabled()) logger.log("storeOwnerUserName == currentUserName : " + new String(storeOwnerUserName == currentUserName));
      if(logger.isLoggingEnabled()) logger.log("storeSuffixLastIndex == storeSuffixPosition : " + new String(storeSuffixLastIndex == storeSuffixPosition));

      // TODO : why "storeOwnerUserName == currentUserName" doesn't work?
      if(storeSuffixLastIndex == storeSuffixPosition) {
         // Set the sandbox
         targetUserAVMStore = currentStore;
         if(logger.isLoggingEnabled()) logger.log("Setting personal sandbox : " + storeName);

         break;
      }
   }


   // If personal sandbox found, copy document to sandbox.
   if(targetUserAVMStore) {
      document.copy(currentStore.lookupRoot());
      if(logger.isLoggingEnabled()) logger.log("Moved source document to personal sandbox.");
   }

   output = "<script>history.back();</script>";
}



output;

Here are my questions :

- Shouldn't "currentStore.lookupRoot().owner" return the owner's GUID? Right now, it returns the user name.

- Is there a better way to make sure to get the user's sandbox (and not the preview repository or the staging sandbox) instead of "storeName.lastIndexOf(storeSuffix) == storeSuffixPosition"?

- I tried to use "storeOwnerUserName == currentUserName" as a test but this would aways fail, even if both were set to the same value, say "admin". Do you have any idea why. Look a the logging traces to see that…

- is there a nice way to recursively create the parent repositories of the source node (in a "mkdir -p" fashion) before copying the node to the sandbox?

- I'm not sure how to use the cross-repository copy function. The "document.copy(currentStore.lookupRoot());" in the code doesn't work (the function seems to exetute, but I don't find anything "My Sandbox") and I have tried many other combination that resulted in an Alfresco stack trace for "method not found". Can you give me the proper way to call this method?

Thanks!

kevinr
Star Contributor
Star Contributor
I'll try and answer your Javascript related questions:

>- Shouldn't "currentStore.lookupRoot().owner" return the owner's GUID? Right now, it returns the user name.

99% of the time we store the username when dealing with an authority as the username/groupname is a unique identifier. You can easily lookup the person GUID for that user using the JavaScript People API:
http://wiki.alfresco.com/wiki/JavaScript_API#People_API

>- Is there a better way to make sure to get the user's sandbox (and not the preview repository or the staging sandbox) instead of "storeName.lastIndexOf(storeSuffix) == storeSuffixPosition"?

Not right now. We have added a bunch of helpers for this in the equivalent Template AVM API but they did not make it into the JavaScript API for 2.1. They will be in the next release to make this easier.

>- I tried to use "storeOwnerUserName == currentUserName" as a test but this would aways fail, even if both were set to the same value, say "admin". Do you have any idea why. Look a the logging traces to see that…

Assuming they are both valid Javascript 'string' objects then it should work. I'm not sure why you are using the  new String(…)  syntax everywhere - you don't need to do conversion by hand as the JavaScript engine will convert between Java String and Javascript string objects automatically for you. If you stick to using the values returned from the properties (which are valid JavaScript 'string' objects) then the problem will probably go away.

>- is there a nice way to recursively create the parent repositories of the source node (in a "mkdir -p" fashion) before copying the node to the sandbox?

No there is not. You could write a function for this and then use the script import features to include that util function into all your scripts.

>- I'm not sure how to use the cross-repository copy function. The "document.copy(currentStore.lookupRoot());" in the code doesn't work (the function seems to exetute, but I don't find anything "My Sandbox") and I have tried many other combination that resulted in an Alfresco stack trace for "method not found". Can you give me the proper way to call this method?

The Cross-repo copy is performed via a special helper object. I've corrected the docs to mention that:
http://wiki.alfresco.com/wiki/JavaScript_API#Cross_Repository_Copy
So you would do something like this:
crossRepoCopy.copy(document, currentStore.lookupRoot(), document.name);

Hope this helps,

Kevin