Workflow Content handling - java

I am using Liferay 6.1.1 CE.
I've created a multilevel kaleo workflow (i.e. with two levels of approvals), by writing a definition in a xml file (leaveapproval.xml) and loading it to the server. It works fine as I have tested this workflow in Blogs.
So now, I wants to submit the content of the workflow to a web service after completing the second level approval.
How can i handle the content of the workflow?
Is it possible?
<?xml version="1.0"?>
<workflow-definition
xmlns="urn:liferay.com:liferay-workflow_6.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:liferay.com:liferay-workflow_6.1.0 http://www.liferay.com/dtd/liferay-workflow-definition_6_1_0.xsd">
<name>LEAVE IN ACTION USER ACTION</name>
<description>A sample multilevel approver can approve a workflow content.</description>
<version>1</version>
<state>
<name>created</name>
<metadata>
<![CDATA[
{"xy":[36,51]}
]]>
</metadata>
<initial>true</initial>
<transitions>
<transition>
<name>review</name>
<target>review</target>
<default>true</default>
</transition>
</transitions>
</state>
<task>
<name>review</name>
<metadata>
<![CDATA[
{"xy":[168,36]}
]]>
</metadata>
<actions>
<notification>
<name>Review Notification</name>
<template>You have a new submission waiting for review in the workflow.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
<notification>
<name>Review Completion Notification</name>
<template>
Your submission has been reviewed and the reviewer has applied the following ${taskComments}.</template>
<template-language>freemarker</template-language>
<notification-type>email</notification-type>
<recipients>
<user />
</recipients>
<execution-type>onExit</execution-type>
</notification>
</actions>
<assignments>
<roles>
<role>
<role-type>regular</role-type>
<name>Portal Head</name>
</role>
<role>
<role-type>regular</role-type>
<name>Portal Content Reviewer</name>
</role>
</roles>
</assignments>
<transitions>
<transition>
<name>approve</name>
<target>recommended</target>
</transition>
<transition>
<name>reject</name>
<target>update</target>
<default>false</default>
</transition>
</transitions>
</task>
<task>
<name>recommended</name>
<metadata>
<![CDATA[{"xy":[168,36]}]]>
</metadata>
<actions>
<notification>
<name>Review Notification</name>
<template>You have a new submission waiting for your review in the workflow.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
<notification>
<name>Review Completion Notification</name>
<template>
Your submission has been reviewed and the reviewer has applied the following ${taskComments}.</template>
<template-language>freemarker</template-language>
<notification-type>email</notification-type>
<recipients>
<user />
</recipients>
<execution-type>onExit</execution-type>
</notification>
</actions>
<assignments>
<user>
<user-id>13379</user-id>
</user>
</assignments>
<transitions>
<transition>
<name>approve</name>
<target>approved</target>
</transition>
<transition>
<name>reject</name>
<target>update</target>
<default>false</default>
</transition>
</transitions>
</task>
<task>
<name>update</name>
<metadata>
<![CDATA[
{"transitions":{"resubmit":{"bendpoints":[[303,140]]}},"xy":[328,199]}
]]>
</metadata>
<actions>
<action>
<name>reject</name>
<script>
<![CDATA[
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("denied"),
workflowContext);
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("pending"),
workflowContext);
]]>
</script>
<script-language>javascript</script-language>
<execution-type>onAssignment</execution-type>
</action>
<notification>
<name>Creator Modification Notification</name>
<template>Your submission was rejected by a reviewer, please modify and resubmit.</template>
<template-language>text</template-language>
<notification-type>email</notification-type>
<execution-type>onAssignment</execution-type>
</notification>
</actions>
<assignments>
<user />
</assignments>
<transitions>
<transition>
<name>resubmit</name>
<target>review</target>
</transition>
</transitions>
</task>
<state>
<name>approved</name>
<metadata>
<![CDATA[
{"xy":[380,51]}
]]>
</metadata>
<actions>
<action>
<name>approve</name>
<script>
<![CDATA[Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus (Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("approved"), workflowContext);]]>
</script>
<script-language>javascript</script-language>
<execution-type>onEntry</execution-type>
</action>
</actions>
</state>
</workflow-definition>
Help me..

For running anything programmatically on a certain workflow step, you generally just need a <script> tag, just like you're doing to update the statuses.
So, in your approved <state>, you'd probably want to add another <action> tag, this one to handle the web service call (and let the other action remain the way it is).
The language you'd use for the script will depend on what you're comfortable with. I'd use groovy, since it handles plain java code pretty well, and that's what I know.
Here's what it might look like (only including that last <state> tag):
<state>
<name>approved</name>
<metadata>
<![CDATA[
{"xy":[380,51]}
]]>
</metadata>
<actions>
<action>
<name>approve</name>
<script>
<![CDATA[
Packages.com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil.updateStatus(
Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.toStatus("approved"),
workflowContext);
]]>
</script>
<script-language>javascript</script-language>
<execution-type>onEntry</execution-type>
</action>
<action>
<name>submit-web-service</name>
<script>
<![CDATA[
import java.io.*
import java.net.*
URL url = new URL(
"www.my-web-service.com/api/whatever?theParam=" +
${theRelevantContextVariable});
URLConnection urlConnection = url.openConnection();
// if necessary to read response data:
// BufferedReader bufferedReader = new BufferedReader(
// new InputStreamReader(urlConnection.getInputStream()));
// String something = bufferedReader.readLine();
// etc.
]]>
</script>
<script-language>groovy</script-language>
<execution-type>onEntry</execution-type>
</action>
</actions>
</state>
You may need a POST request instead, in which case you'd implement the web service call differently. But in any case you'd write the web service code in an action tag. Something like this should work.

Related

Consuming WCF service in Java does not generate an interface

We have a pretty big WCF service that we use for quite some time, but up until now we've been connecting to it only via c#. Now we have a need to connect to it from Java.
I found out quickly that if I use Eclipse and go to new/other/Web Service Client I can put the WSDL link there to auto generate the code.
Doing that straight away did not produce much though. I obtained two files, one of which had empty body.
This is my first issue with this auto generation tool - it creates something, but I don't see any log of what it succeeded and what failed in creating.
I searched and found out that i had to change the bindings to basicHttpBinding, and make sure that httpGetEnabled is set to "true". After this change, auto generation in Java produces a lot of code, i get the data contract schemas and so on. And I get 4 files under the 'org.tempuri' namespace:
BasicHttpBinding_IMyServiceStub.java
IMyServiceProxy.java
MyService.java
MyServiceLocator.java
However looking at some tutorials, it seems I should get a fifth one, IMyService.java - which I did not get. And, I do have errors in the generated code pointing out that indeed IMyService cannot be resolved, as its being used in a few places, but its definition was not auto-generated.
Since I have no logs of what has failed during auto generation, I'm kind of lost what to look for as a culprit.
Does anyone have any experience on either:
a) locating logs for auto generation that would tell me what went
wrong
b) directly know what causes the Interface class not to be generated?
I'm suspecting i have to change something more in webconfig file on the server. A second guess is that perhaps we use some c# construct not recognised by java...or something.
Anyway, completly lost here, as there is no feedback of what went wrong.
Here is a webconfig file from the IIS server.
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="XXX" connectionString="XXX" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation targetFramework="4.0"/>
<customErrors mode="Off"/>
<httpRuntime executionTimeout="5400" requestValidationMode="2.0"/>
<identity impersonate="false"/>
</system.web>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="bindingNetTcp" closeTimeout="01:00:00" openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00">
<binaryMessageEncoding maxSessionSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binaryMessageEncoding>
<tcpTransport maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
</binding>
<binding name="bindingHttps" closeTimeout="01:00:00" openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00">
<binaryMessageEncoding maxReadPoolSize="2147483647" maxWritePoolSize="2147483647" maxSessionSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binaryMessageEncoding>
<httpsTransport manualAddressing="false" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" allowCookies="true" authenticationScheme="Anonymous" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" keepAliveEnabled="true" maxBufferSize="2147483647" proxyAuthenticationScheme="Anonymous" realm="" transferMode="StreamedResponse" unsafeConnectionNtlmAuthentication="false" useDefaultWebProxy="true"/>
</binding>
<binding name="bindingHttp" closeTimeout="01:00:00" openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00">
<binaryMessageEncoding maxReadPoolSize="2147483647" maxWritePoolSize="2147483647" maxSessionSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binaryMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" allowCookies="true" authenticationScheme="Anonymous" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" keepAliveEnabled="true" maxBufferSize="2147483647" proxyAuthenticationScheme="Anonymous" realm="" transferMode="StreamedResponse" unsafeConnectionNtlmAuthentication="false" useDefaultWebProxy="true"/>
</binding>
</customBinding>
<netTcpBinding>
<binding name="NetTcpBinding_IGodService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="Windows"/>
</security>
</binding>
<binding name="NetTcpBinding_IGodService1" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="Windows"/>
</security>
</binding>
<binding name="CustomBinding_IDQMServer">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="XXX.XXX" behaviorConfiguration="XXXBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://example.com:4502/xxx/xxx/"/>
<add baseAddress="http://example.com/xxx/xxx/"/>
</baseAddresses>
</host>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="" binding="customBinding" bindingConfiguration="bindingHttps" contract="xxx.Ixxx"/>
<endpoint address="" binding="basicHttpBinding" contract="xxx.Ixxx"/>
<endpoint address="" binding="customBinding" bindingConfiguration="bindingNetTcp" contract="xxx.Ixxx"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="xxxBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceThrottling maxConcurrentCalls="2500" maxConcurrentInstances="2147483647" maxConcurrentSessions="2147483647"/>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="SrvBehavior">
<clientCredentials>
<clientCertificate findValue="xxx" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<defaultDocument>
<files>
<add value="xxx.svc"/>
</files>
</defaultDocument>
</system.webServer>
</configuration>
Please note that im using basicHttpBinding there, previously it was "bindingHttp" like the https one, but it didnt work at all.
EDIT: As pointed out in the comment section, we're using Lists in the service quite a lot, an example of the c# wcf interface:
public class ListResults<T>//our own custom return class
{
public List<T> Result { get; set; }
public long? ID { get; set; }
public int? Error { get; set; }
}
[SecurityOperationBehavior]
[OperationContract]
ListResults<SomeDataType> SomeListFunction(string param1, long? param2, bool? param3);

How can I implements Message Inspectors?

I want to build a soap Client .NET to contact Java web service. The problem is in the response because there is no compatibility from Java and .NET for the signature.
So I want to disable the validation response from .NET, for this, I have find this articles on MSDN
https://msdn.microsoft.com/en-us/library/aa717047.aspx
I can read that it possibile to insert a method that intercept the response and I can bypass the check. But I'm not able to do this.
I have write import in my project these class:
SchemaValidationBehavior
SchemaValidationBehaviorExtensionElement
SchemaValidationMessageInspector
This is my app.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyNewService">
<security defaultAlgorithmSuite="Basic128" authenticationMode="MutualCertificate" requireDerivedKeys="false" securityHeaderLayout="Lax" includeTimestamp="true" messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" requireSignatureConfirmation="false">
<localClientSettings detectReplays="true"/>
<localServiceSettings detectReplays="true"/>
</security>
<textMessageEncoding messageVersion="Soap11WSAddressing10"/>
<httpsTransport/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://edottotest.sanita.regione.rsr.rupar.puglia.it/nsisr/PianoAssistenzialeResidenzialeService" binding="customBinding" bindingConfiguration="MyNewService" contract="PianoAssistenzialeResidenzialeService.PianoAssistenzialeResidenziale" name="PianoAssistenzialeResidenzialePort" >
<identity>
<dns value="HEALTHNETBR"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
I think the problem is on this file.

Form validation in Struts2

Page contains form which looks like below.
1) If I insert to form validate="true", then after page load this form submit request to mail action (at this point validation xml was not created yet).
2) After validation xml was created (in the same pakage with action), then action which control request to this page returns 404 page.
Did I miss something?
<s:form action="mail" method="post">
<s:textfield name="name" key="Your name" size="20" />
<div style="clear: both;margin-top:10px"></div>
<s:textarea label="Comment" name="comment" cols="65" rows="5"/>
<s:submit method="mail" key="Send" align="left"
style="width:100px; height:35px; margin-top:20px"/>
</s:form>
validation xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="name">
<field-validator type="required">
<message>Please enter a user name</message>
</field-validator>
</field>
<field name="comment">
<field-validator type="required">
<message>Please enter your message</message>
</field-validator>
</field>
</validators>
If I do not add validation then all is working as it should.
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.custom.i18n.resources" value="ApplicationResources" />
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="Exception">/error404.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Throwable" result="Exception" />
</global-exception-mappings>
<!-- loads page -->
<action name="main"
class="com.user.action.LoginAction" method="main">
<result name="success">/main.jsp</result>
</action>
<!-- mail action -->
<action name="mail" class="com.user.action.LoginAction" method="mail" >
<result name="success">/main.jsp</result>
</action>
</package>
</struts>
INPUT is one of the predefined results made available by Struts2;
Basically, if your Action sends parameters that are incorrect (conversion errors, like if you send a "abc" to an Integer Action variable), or that don't pass the validation, the Workflow Interceptor return the INPUT result and follow the path specified in the struts configuration for that Action.
Your problem is that you have not defined any INPUT result for your Actions, while you always should.
You can also set a global input result as a fallback, but be careful with that... generally, the page you want to go in case of an INPUT is the same from where the request has been sent.
In case of an INPUT result, your Action method (eg. execute()) is not executed, so if you load common data in that method, like select boxes content, it won't be available anymore.
Read this answers to fully understand what this implies and how to make it work:
How do we repopulate controls when validation fails
Detailed Workflow of the INPUT result processing

CXF WADL2Java does not produce the right input parameters

I went through the documentation, which helped me figure out several issues I had, but not the following two problems:
1) I have got a get(GET) method: get(#Context Request request, #PathParam("isbn")String isbn)
How do I formulate the WADL for it so that I get the #Context in the produced Java code?
2) I have got a update (PUT) method: update(#PathParam("isbn") String isbn, BookState st)
How do I formuate the WADL to get the BookState in the produced Java code?
Here is my current WADL, which does not do it:
<resource path="/{isbn}">
....
<method name="GET" id="get" >
<request />
<response>
<representation mediaType="application/xml" element="prefix1:book" />
</response>
</method>
<method name="PUT" id="update" >
<request>
<representation mediaType="application/xml" element="prefix1:book" />
</request>
<response>
<representation mediaType="application/octet-stream" />
</response>
</method>
</resource>

Problem raising event in scxml

I'm having a problem with the following scxml code:
<?xml version="1.0" encoding="utf-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="global">
...
<state id="global" initial="init">
...
<state id="state2">
<onentry>
<if cond="mydata.skip">
<if cond="_event.name=='ev.prev'">
<raise event="ev.prev" />
<else/>
<raise event="ev.next" />
</if>
</if>
</onentry>
<transition event="ev.next" target="end" />
<transition event="ev.prev" target="state1" />
</state>
...
</state>
</scxml>
It works ok but when I have added the onentry element the proccessor says the following:
[WARN] Ignoring element <raise> in namespace "http://www.w3.org/2005/07/scxml" at null:2:882 and digester match "scxml/state/state/onentry/if/if/raise"
[WARN] Ignoring element <raise> in namespace "http://www.w3.org/2005/07/scxml" at null:2:912 and digester match "scxml/state/state/onentry/if/if/else/raise"
It seems that raise is not understood. I've tried to change 'raise' element with the 'send' one and I've gotten a similar log warning. Can anyone tell me what may be wrong?
Thanks.
UPDATE
I've tried to change the schema avoiding the embedding of the if elements like this:
<?xml version="1.0" encoding="utf-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="global">
...
<state id="global" initial="init">
...
<state id="state2">
<onentry>
<if cond="mydata.skip and _event.name=='ev.prev'">
<raise event="ev.prev" />
<else if cond="mydata.skip and _event.name=='ev.next'"/>
<raise event="ev.next" />
</if>
</onentry>
<transition event="ev.next" target="end" />
<transition event="ev.prev" target="state1" />
</state>
...
</state>
</scxml>
but it gives the following error too:
[WARN] Ignoring element <raise> in namespace "http://www.w3.org/2005/07/scxml" at null:2:1057 and digester match "scxml/state/state/onentry/if/raise"
I couldn't make the raise event work either. But according to the standard:
http://www.w3.org/TR/scxml/#raise
you can also use a send event. So I tried that, and I could make that work.
<state id="testID">
<onentry>
<send event="'test.onentry'" />
</onentry>
<transition event="test.transition" target="testID2"></transition>
</state>
That sent the event test.onentry as expected. But note the single quotes inside the double quotes in there!

Categories

Resources