In order to deploy the DSC the most easy way is to have a Workbench installed. But there are also ways to deploy a DSC without having WorkBench by our side. In Java, we do so by the help of LC SDK jars, namely adobe-livecycle.jar and adobe-usermanagement-client.jar. Now, what if we want to deploy a DSC from a FLEX UI on a Livecycle Server, running somewhere remote, let say by the click of a button on an AIR App. But in Flex we can't use SDK jars, hence the creation of ServiceClientFacory is impossible.
Flex exposes remoting endpoint which can be used to communicate with LiveCycle via LCDS. The adobe-remoting-provider.swc whihc is used to facilitate the communication, can be found at the LiveCycle installed location, \\Adobe LiveCycle ES2\LiveCycle_ES_SDK\misc\DataServices\Client-Libraries.
The solution is to talk to DSC service named
"service.component_registry" directly, and thankfully LCDS provides
this facility.
This DSC named, "service.component_registry" is the core one,
that exposes out the operations concerned with the life of a DSC.
We'll go through the following steps to fulfill our task,
1. Create an AMFChannel and register
a the LC specific Remote Object with it.
2. Get the user's session id from
the LC server.
3. Pass DSC as a Document along with
the Session ID to the remote LC Server.
4. Get the DocumentReference in
regards to the location where the DSC is uploaded on the LC Server
machine.
5. Use the DocumentReference to
install the DSC onto LiveCycle Server.
6. Once we have the DSC
installed(the DSC is not yet started!!) the road is easy ahead.
:)
package {
private var _DSCComponent:Component;
public var selectedDSC:File;//the DSC to be deployed
public var LChostId:String;//host/ipaddress of LiveCycle Server
public var LCportId:String;//LiveCycle Server port
public var DSCDeployRemoteObject:RemoteObject;
public var DSCStartRemoteObject:RemoteObject;
public var DSCStopRemoteObject:RemoteObject;
public var DSCUninstallRemoteObject:RemoteObject;
//1. Initialize a Channel Set,
public function initializeChannelSet(ro:RemoteObject)
:ChannelSet {
var cs:ChannelSet= new ChannelSet();
// pass the server address to the channel
cs.addChannel(new AMFChannel(
"remoting-amf","http://"+LCHostId+":
"+LCPortId+"/remoting/messagebroker/amf"));
// pass the username and password.
// NOTE: only those users with Document Upload Permission and
// Role, will be allowed to participate.
ro.setCredentials("administrator", "password");
ro.channelSet = cs;
return cs;
}
//2. Create a Remote Object to get the user's session from
// the LC server.
public function deployDSC():void{
var cs:ChannelSet= new ChannelSet();
// create a remote object to fetch the auth token/sessionId
// of the user.
var authTokenService:RemoteObject;
// create a remote object to perform uploading and
// installing of DSC
DSCDeployRemoteObject =
new RemoteObject("system.component_registry");
DSCDeployRemoteObject.showBusyCursor = "true";
// this is the equivalent of the ComponentRegistry.install(...)
// attach a resultHandler and faultHandler to the method.
DSCDeployRemoteObject.installWithDocument.addEventListener(
"result",DSCDeployResultHandler);
DSCDeployRemoteObject.installWithDocument.addEventListener(
"fault",faultHandler);
cs = initializeChannelSet(DSCDeployRemoteObject);
//this set of operatons will get the session id post
// authentication of the File Upload request.
authTokenService = new
RemoteObject("LC.FileUploadAuthenticator");
//attach an event listener for when token received.
authTokenService.addEventListener("result",authTokenReceived);
//this is required to pass the authentication creadentials
//for the user whose session id/token will be returned.
authTokenService.channelSet = cs;
authTokenService.getFileUploadToken();
}
//3. Pass the DSC as a Document after receiving the token.
// the DSC once uploaded(not deployed yet) at the LC server,
// will respond back with the location url.
public function authTokenReceived(event:ResultEvent):void{
// store the token generated from the event.
var token:String = event.result as String;
try{
//now construct a proper file upload request
//alongwith the token generated form autheitcation.
var request:URLRequest =
DocumentReference.constructRequestForUpload(
"http://"+LCHostId+":"+LCPortId,token);
// selectedDSC is the File object of the DSC being referred.
selectedDSC.upload(request);
// attach an event listener for when the uploading of
// DSC at the LC server is complete.
selectedDSC.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,
completeDSCDeployHandler);
}catch (error:Error){ }
}
//4. The URL responded in the form of DocuemntReference
// from LC server, is the location where the DSC
// has been uploaded.
// Use the DocumentReference to install the DSC onto
// LiveCycle Server.
public function completeDSCDeployHandler(event:DataEvent):void{
// we have to explictly remove the listener once it's work is
// done, this is necessary when deploying multiple DSCs on
// different LC servers. Since this is a single thraded model,
// when deploying DSCs on multiple LC servers, one's listener
// can pretend to be the other one
// and create chaos on the server.
selectedDSC.removeEventListener(
DataEvent.UPLOAD_COMPLETE_DATA,
completeDSCDeployHandler);
var params:Object = new Object();
var docRef:DocumentReference = new DocumentReference();
// store the document reference
docRef.url = event.data as String;
docRef.referenceType = DocumentReference.REF_TYPE_URL;
// call the installWithDocument
// API of 'system.component_registry'
// passing it the document reference object.
DSCDeployRemoteObject.installWithDocument({"document":docRef});
}
// 5. Once the DSC is deployed, LC server responds back with an
// object for Component Interface.
public function DSCDeployResultHandler(event:ResultEvent):void{
DSCDeployRemoteObject.installWithDocument.removeEventListener(
"result",DSCDeployResultHandler);
// The Component object that the DSC responds back, is in the
// form of Object class. This Component object is now needed to
// perform all sorts of operation on the installed DSC.
// But Flex when sends this Component object back to LC server
// for performing various operations, it sends in the form of
// ObjectProxy class. Inorder for LC server to recognize it's
// own Component Interface, we need to create a Component.as
// class which will act as a proxy for the actual class.
_DSCComponent =
(new Component()).cast(event.result.component);
// optional,in case we want to hear for the DSC deployed event.
dispatchEvent(new Event('dscDeploy'));
}
// Start the DSC with the Component object got above.
public function startDSC(DSCComponent:Component):void{
_DSCComponent = DSCComponent;
DSCStartRemoteObject = new
RemoteObject("system.component_registry");
DSCStartRemoteObject.showBusyCursor = "true";
DSCStartRemoteObject.start.addEventListener(
ResultEvent.RESULT,DSCStartResultHandler);
DSCStartRemoteObject.start.addEventListener(
FaultEvent.FAULT,faultHandler);
initializeChannelSet(DSCStartRemoteObject);
// this is the equivalent of the ComponentRegistry.start(...)
DSCStartRemoteObject.start({"component":_DSCComponent});
}
// Called when the DSC is started on the LiveCycle Server.
public function DSCStartResultHandler(event:ResultEvent):void{
DSCStartRemoteObject.start.removeEventListener(
ResultEvent.RESULT,DSCStartResultHandler);
dispatchEvent(new Event('dscStart'));
}
// Stop the DSC with the Component object got above.
public function stopDSC(DSCComponent:Component):void{
_DSCComponent = DSCComponent;
DSCStopRemoteObject = new RemoteObject(
"system.component_registry");
DSCStopRemoteObject.showBusyCursor = "true";
DSCStopRemoteObject.stop.addEventListener(
"result",DSCStopResultHandler);
DSCStopRemoteObject.stop.addEventListener(
"fault",faultHandler);
initializeChannelSet(DSCStopRemoteObject);
// this is the equivalent of the ComponentRegistry.stop(...)
DSCStopRemoteObject.stop({"component":_DSCComponent});
}
// Called when the DSC is stopped on the LiveCycle Server.
public function DSCStopResultHandler(event:ResultEvent):void{
DSCStopRemoteObject.stop.removeEventListener(
"result",DSCStopResultHandler);
dispatchEvent(new Event('dscStop'));
}
// Uninstall the DSC with the Component object got above.
public function unInstallDSC(DSCComponent:Component):void{
_DSCComponent = DSCComponent;
DSCUninstallRemoteObject = new
RemoteObject("system.component_registry");
DSCUninstallRemoteObject.showBusyCursor = "true";
DSCUninstallRemoteObject.forceUninstall.addEventListener(
"result",DSCUninstallResultHandler);
DSCUninstallRemoteObject.forceUninstall.addEventListener(
"fault",faultHandler);
initializeChannelSet(DSCUninstallRemoteObject);
// this is the equivalent of
// ComponentRegistry.Uninstall(...)
DSCUninstallRemoteObject.uninstall(
{"component":_DSCComponent});
}
// Called when the DSC is uninstalled from the LiveCycle Server.
public function
DSCUninstallResultHandler(event:ResultEvent):void{
DSCUninstallRemoteObject.forceUninstall.removeEventListener(
"result",DSCUninstallResultHandler);
dispatchEvent(new Event('dscUnInstall'));
}
// A handler to catch any exceptions or errors during
// communicating Flex with LiveCycle Server.
public function faultHandler(event:FaultEvent):void{
dispatchEvent(new Event('dscFault'));
}
}
}
Component.as:
// We have to create an exact replica of the Component Interface that LiveCycle understands.
// Create a package with the same address.
package com.adobe.idp.dsc.registry.infomodel {
import mx.utils.ObjectProxy;
// an Interface from Flex can't map all Component Object's
// values to the interface on LC,
// so we seek the Implementation class of the same Interface.
// provide the qualified name of the implementation class
[RemoteClass(
alias="com.adobe.idp.dsc.registry.infomodel.impl.ComponentImpl")]
[Bindable]
public class Component {
// Here we provide the getters and setters
// from the Component Interface.
// After the DSC has been installed, the
// LiveCycle server sends back the
// Component object the Flex.
// This component object in debug mode can
// be easily traced for it'sproperties.
// These properties of Component object
// will define the getters and setters for this
// actionscript class.
}
}
+