lunes, 5 de mayo de 2014

... FSW documentation

Hi,
I have started to write down the documentation I'm creating in my github.
Documentation is written in asciidoc format, so github plugin for asciidoc makes it easily readable from there, and displays much nicely than in blogger, for which I should provide a template (css), but I do not time.

If you follow the project you will be updated with latest information, tips and tricks I collect.

I hope somebody finds it useful.

By the way, some of the tips and tricks from JUnit in SwitchYard has been incorporated into the official docs for next release :-D

... Configuration in SwitchYard

Configuration (Properties)

SwitchYard supports configuration properties, that can be injected into configuration or into service implementations:

Switchyard model configuration

SwitchYard allow you to replace any attribute or element value in switchyard.xml with a property from the runtime environment. The syntax for a replaced token is "${varname}" where "varname" is your property name. The configuration layer in SwitchYard is configured with instances of PropertyResolver, which are used to resolve the value of a property based on its name.

Property resolution order

Property values are resolved from the following locations:
  • System properties passed by -D option of Java VM like "-Dproperty.name=property.value"
  • System environment variables, referenced with an "env." prefix, for example: env.PATH
  • Unit test properties
  • JBoss AS7 properties, including access into the SecurityVault
  • Domain properties in switchyard.xml
  • SCA property definitions in the composite or component
The priority in resolving a property is from top to bottom, so a property defined as a System property will always take precedence over a property defined at domain or composite, and a property at domain level will olways take precedence over a property defined at component level.

Injecting properties into Service Implementation

Implementation properties allow you to inject one or more property values into a service implementation. This is based on the property support in the SCA assembly spec. Since the property is injected into service implementation logic, the injection mechanism itself is unique to each implementation type. The details for each implementation type follow:
  • Java: injected using @Property into a CDI bean
  • Camel: wired into Camel properties component and accessible in a Camel route using Camel’s own varName property notation
  • BPEL: mapped into process variables via an <assign> with using resolveProperty() XPath custom function
  • BPMN 2: inserted into process variables by data input associations
  • Drools: available in a global map

Injecting properties in Java Bean implementations

Implementation properties represent environmental properties that you have defined in the SwitchYard application descriptor (switchyard.xml) for your bean implementation. Implementation properties in SwitchYard are the properties that you can configure on a specific service implementation. That is, you can make the property value available to service logic executing inside an implementation container. Here is an example:
<sca:component name="SimpleServiceBean">
      <bean:implementation.bean class="com.example.switchyard.switchyard_example.SimpleServiceBean"/>
      <sca:service name="SimpleService">
        <sca:interface.java interface="com.example.switchyard.switchyard_example.SimpleService">
          <properties>
            <property name="userName" value="${user.name}"/>
          </properties>
        </sca:interface.java>
      </sca:service>
</sca:component>
To access the Implementation Properties, add an @Property annotation to your bean class identifying the property you want to inject:
@Service(SimpleService.class)
public class SimpleServiceBean implements SimpleService {

  @Property(name="userName")
  private String name;

  @Override
  public String sayHello(String message) {
        return "Hello " + name + ", I got a message: " + message;
    }

}

Injecting Implementation Properties in Camel Routes

SwitchYard integrates with the Properties Component in Camel to make system and application properties available inside your route definitions. You can inject properties into your camel route using {{propertyname}} expression, where propertyName is the name of the property. For example, the following camel route expects the user.name property to be injected in the last <Log> statement:
<route xmlns="http://camel.apache.org/schema/spring" id="CamelTestRoute">
    <log message="ItemId [${body}]"/>
    <to uri="switchyard://WarehouseService?operationName=hasItem"/>
    <log message="Title Name [${body}]"/>
    <log message="Properties [{{user.name}}]"/>
</route>

Injecting Implementation Properties in BPEL

You can inject properties into your BPEL process definition with using SwitchYardPropertyFunction.resolveProperty() XPath custom function.
This bpel:copy section copies "Greeting" property value into the ReplySayHelloVar variable:
.....
<bpel:copy>
     <bpel:from xmlns:property="java:org.switchyard.component.bpel.riftsaw.SwitchYardPropertyFunction"
                expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0">
         <![CDATA[concat(property:resolveProperty('Greeting'), $ReceiveSayHelloVar.parameters/tns:input)]]>
     </bpel:from>
     <bpel:to part="parameters" variable="ReplySayHelloVar">
         <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[tns:result]]></bpel:query>
     </bpel:to>
</bpel:copy>

Injecting Implementation Properties in BPMN 2

TODO:

Injecting Implementation Properties in Drools

TODO:

Invocation properties

While it is a best practice to write your service logic to the data that is defined in the contract (the input and output message types), there can be situations where you need to access contextual information like message headers such as received file name in your implementation. To facilitate this, the Bean component allows you to access the SwitchYard Exchange Context instance associated with a given Bean Service Operation invocation. Invocation properties represent the contextual information (like message headers) in your bean implementation.

Accessing Invocation Properties

To enable access to the invocation properties, add a Context property to your bean and annotate it with the CDI @Inject annotation:
@Service(SimpleService.class)
public class SimpleServiceBean implements SimpleService {

@Inject
private Context context;

public String sayHello(String message) {
        System.out.println("*** Funky Context Property Value: " + context.getPropertyValue("funkyContextProperty"));
        return "Hi there!!";
    }
}
Here, the Context interface allows your bean logic to get and set properties in the context.
You can invoke the Context instance only within the scope of one of the Service Operation methods. If you invoke it outside this scope, it results in an UnsupportedOperationException error.

Domain properties

See package: org.switchyard.common.property
PropertyResolvers: PropertiesPropertyResolver TestPropertyResolver SystemAndTestPropertyResolver CompoundPropertyResolver MapPropertyResolver
Creating our custom propertyResolver and registering it in switchyard.xml in switchyard as propertyResolver. https://github.com/jboss-switchyard/core/blob/master/config/src/main/java/org/switchyard/config/DOMConfiguration.java#L685

Tips and tricks

Define default value for a property

When we define a property, we can provide a default value, so if the property is not defined by the user it will get this default value. To define this default value, just append to the property name the default value, separated by a colon (:).
${server.port:8080}

Where to define environment properties

As component properties

Properties can be defined as component property. This way of defining properties is not dynamic, but every properties defined here, can be overriden by properties defined in a "prioritized" scope.
<sy:switchyard ...>
  <sca:composite ...>
    <sca:component ...>
      ...
      <sca:property value="test" name="MY_PROPERTY"/>
    </sca:component>
    <sca:service...>
      ...
    </sca:service>
    <sca:reference ...>
      ...
    </sca:reference>

  </sca:composite>
  ...
</sy:switchyard>

As composite properties

Properties can be defined as composite property. This way of defining properties is not dynamic, but every properties defined here, can be overriden by properties defined in a "prioritized" scope.
<sy:switchyard ...>
  <sca:composite ...>
    <sca:component ...>
      ...
    </sca:component>
    <sca:service...>
      ...
    </sca:service>
    <sca:reference ...>
      <sca:interface.java .../>
      <file:binding.file name="FileBinding">
        <file:directory>/tmp</file:directory>
        <file:fileName>${MY_FILENAME}</file:fileName>
        <file:produce/>
      </file:binding.file>
    </sca:reference>
    <sca:property value="test.txt" name="MY_FILENAME"/>
  </sca:composite>
  ...
</sy:switchyard>

As domain properties

Properties can be defined as composite property. This way of defining properties is not dynamic, but every properties defined here, can be overriden by properties defined in a "prioritized" scope.
<sy:switchyard ...>
  <sca:composite ...>
    <sca:component ...>
      ...
    </sca:component>
    <sca:service...>
      ...
    </sca:service>
    <sca:reference ...>
      ...
    </sca:reference>
  </sca:composite>
  ...
  <sca:domain>
    <sca:property value="test.txt" name="MY_FILENAME"/>
  </sca:domain>
 </sy:switchyard>

In a static module (or dynamic)

Right now, it seems that defining properties in static module does not work. They do not get picked up by the property resolvers. Properties can be externalized from the SwitchYard application it self by defining them outside the switchyard.xml file. One place could be a module. For this to work, you need to define your module:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<module xmlns="urn:jboss:module:1.0" name="com.examples.switchyard.properties">
    <properties>
        <property name="ftp_server.host" value="localhost"/>
        <property name="ftp_server.port" value="22"/>
    </properties>
</module>
And use these properties in your SwitchYard application:
<ftp:binding.sftp>
    <ftp:host>${ftp_server.host}</ftp:host>
    <ftp:port>${ftp_server.port}</ftp:port>
   ....
</ftp:binding.sftp>

As OS environment properties

Properties can be loaded from OS environment properties. Every environment property is accesible by prefixing it with env.
So a property defined like (in bash):
export MY_PROPERTY=test
Can be used in your SwitchYard application:
<ftp:binding.sftp>
    <ftp:host>${env.MY_PROPERTY}</ftp:host>
   ....
</ftp:binding.sftp>

As Application Server properties from AS configuration

Application server has the ability to define properties directly in it’s configuration (either by file or with the console) and this configuration will be dynamically updated, and persisted. See: https://community.jboss.org/wiki/JBossAS7SystemProperties
Adding the following configuration to the definition of the server definition:
<server name="xyz.home" xmlns="urn:jboss:domain:1.0">
    <extensions>
        <extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.clustering.jgroups"/>
        <extension module="org.jboss.as.connector"/>
        ....
    </extensions>
    <system-properties>
        <property name="MY_PROPERTY" value="test"/>
    </system-properties>
This properties will be used in the same way:
<ftp:binding.sftp>
    <ftp:host>${MY_PROPERTY}</ftp:host>
   ....
</ftp:binding.sftp>

As Application Server properties from file

You can pass a properties file as an argument to JBoss AS startup script, and it will load all the properties in the file and make then accesible, so we can start the AS like:
$./standalone.sh -P file:///data/production.properties
And this properties will be accesible, as in any other example above.
Provided alternatives are
-P=<url>
Load system properties from the given URL.
-P <url>
Load system properties from the given URL.
--properties=<url>
Load system properties from the given URL.

Load all properties from a file

It is not possible to load all the properties available in a file, so a JIRA has been created.
   <sca:properties file="ftp.properties"/>

Loading properties for test

In tests, properties can be added and resolved at the top level. There is a PropertyMixIn that eases working with properties:
   private PropertyMixIn pmi;

   ...
   pmi.set("test.property.name", "test");
   pmi.set("test.property.name", Integer.valueOf(100));
   ...
   pmi.get("test.property.name");
   ...
If you need, underlying access to the PropertyResolver for tests, where a MixIn is not applicable (Not Running With SwitchYardRunner), and to avoid having to set command line parameters, there is a TestPropertyResolver.INSTANCE that can be used in tests.
To put a property do:
TestPropertyResolver.INSTANCE.getMap().put("name","value");
This property will be set, and retrieved by any service when resolving that property.