Clients
-------

Java Client
~~~~~~~~~~~
The Artificer implementation provides a full-featured Java client library that can be
used to integrate with S-RAMP compliant servers.  This section of the guide describes how to use
this library.


Basic Usage
^^^^^^^^^^^
The Artificer client is a simple Java based client library and can be included in a Maven project
by including the following pom.xml dependency:

----
    <dependency>
      <groupId>org.artificer</groupId>
      <artifactId>artificer-client</artifactId>
      <version>${artificer.client.version}</version>
    </dependency>
----

Once the library is included in your project, you can use the client by instantiating the 
*ArtificerAtomApiClient* class.  Note that the client class supports pluggable authentication
mechanisms, although BASIC auth is a simple matter of including the username and password
upon construction of the client. 

Please refer to the javadoc of that class for details, but here are some usage examples to 
help you get started (code simplified for readability):

.'Upload an XSD document to Artificer'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);
String artifactFileName = getXSDArtifactName();
InputStream is = getXSDArtifactContentStream();
ArtifactType type = ArtifactType.XsdDocument();
BaseArtifactType artifact = client.uploadArtifact(ArtifactType.XsdDocument(), is, artifactFileName);
----

.'Create a custom artifact in Artificer (meta-data only, no file content)'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);
ExtendedArtifactType artifact = new ExtendedArtifactType();
artifact.setArtifactType(BaseArtifactEnum.EXTENDED_ARTIFACT_TYPE);
artifact.setExtendedType("MyArtifactType");
artifact.setName("My Test Artifact #1");
artifact.setDescription("Description of my test artifact.");
BaseArtifactType createdArtifact = client.createArtifact(artifact);
----

.'Retrieve full meta-data for an XSD artifact by its UUID'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);
String uuid = getArtifactUUID();
BaseArtifactType metaData = client.getArtifactMetaData(ArtifactType.XsdDocument(), uuid);
----

.'Retrieve artifact content'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);
String uuid = getArtifactUUID();
InputStream content = client.getArtifactContent(ArtifactType.XsdDocument(), uuid);
----

.'Query the Artificer repository (by artifact name)'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);
String artifactName = getArtifactName();
QueryResultSet rset = client.buildQuery("/s-ramp/xsd/XsdDocument[@name = ?]")
        .parameter(artifactName)
        .count(10)
        .query();
----

.'Query the Artificer repository using a stored query'
----
ArtificerAtomApiClient client = new ArtificerAtomApiClient(urlToArtificer);

StoredQuery storedQuery = new StoredQuery();
storedQuery.setQueryName("FooQuery");
storedQuery.setQueryExpression("/s-ramp/ext/FooType");
storedQuery.getPropertyName().add("importantProperty1");
storedQuery.getPropertyName().add("importantProperty2");
client.createStoredQuery(storedQuery);

QueryResultSet rset = client.queryWithStoredQuery(storedQuery.getQueryName());
----


Extended Feature: Ontologies
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Although the S-RAMP specification is silent on how the API should support the
management of ontologies, the Artificer implementation provides an extension
to the Atom based REST API to support this.  Using any of the client's ontology
related methods will work when communicating with the Artificer implementation of
S-RAMP, but will likely fail when communicating with any other S-RAMP server.

The client supports adding, updating, and getting (both individual and a full list)
ontologies from the Artificer repository.


Extended Feature: Auditing
^^^^^^^^^^^^^^^^^^^^^^^^^^
The Artificer implementation also offers an extension to the Atom based
REST API to get and set auditing information for artifacts in the repository.


Important Notes
^^^^^^^^^^^^^^^

WildFly and EAP
+++++++++++++++

When using the Java client from within a webapp running on WildFly or EAP, the 'artificer-client' Maven dependency
carries transitive dependencies that conflict with modules on the app server.  At this time, the worst known offender
is 'jaxb-impl' (causes a PropertyException related to RESTEasy's use of 'NamespacePrefixMapper').  It's vital to do the
following in your webapp's POM.

Exclude 'jaxb-impl' from the 'artificer-client' dependency:
----
<dependency>
  <groupId>org.artificer</groupId>
  <artifactId>artificer-client</artifactId>
  <version>[version]</version>
  
  <exclusions>
    <exclusion>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
    </exclusion>
  </exclusions>
</dependency>
----

Include the 'com.sun.xml.bind' module in your 'maven-war-plugin' 'manifestEntries':
----
<plugin>
  <artifactId>maven-war-plugin</artifactId>
  <version>2.3</version>
  <configuration>
    <archive>
      <manifestEntries>
        <Dependencies>com.sun.xml.bind,...</Dependencies>
      </manifestEntries>
    </archive>
  </configuration>
</plugin>
----


EJB Client
~~~~~~~~~~

The logic and actions that back all of the REST services are available for direct use through EJB, for both local server
and remote client use.  This should be the top choice for client interactivity where performance is a major
consideration, as it removes the typical REST bottlenecks.

To use it, you'll need to add the following dependencies:

----
<dependency>
  <groupId>org.artificer</groupId>
  <artifactId>artificer-server-api</artifactId>
  <version>[ARTIFICER VERSION]</version>
</dependency>
<dependency>
  <groupId>org.wildfly</groupId>
  <artifactId>wildfly-ejb-client-bom</artifactId>
  <version>8.2.0.Final</version>
  <type>pom</type>
  <scope>runtime</scope>
</dependency>
----

There are a couple of things to note with the dependencies.  1.) We're "cheating" and using the 'wildfly-ejb-client-bom'
to pull in quite a bit.  With out it, you'll need the EJB API, JTA API, etc.  2.) xercesImpl is currently required
during runtime, mostly due to XMLGregorianCalendarImpl use during (un)marshalling.

Then, interacting with Artificer is as simple as:

----
ExtendedArtifactType artifact = new ExtendedArtifactType();
artifact.setArtifactType(BaseArtifactEnum.EXTENDED_ARTIFACT_TYPE);
artifact.setExtendedType("FooArtifactType");
artifact.setName("Foo");
artifact.setDescription("I'm a Foo");

try {
    Properties jndiProps = new Properties();
    jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
    jndiProps.put(Context.PROVIDER_URL,"http-remoting://localhost:8080");
    jndiProps.put("jboss.naming.client.ejb.context", true);
    Context context = new InitialContext(jndiProps);

    final ArtifactService artifactService =  (ArtifactService) context.lookup(
            "artificer-server/ArtifactService!" + ArtifactService.class.getName());
    artifactService.login("artificer", "artificer1!");
    artifactService.create(artifact);

    final QueryService queryService =  (QueryService) context.lookup(
            "artificer-server/QueryService!" + QueryService.class.getName());
    queryService.login("artificer", "artificer1!");
    ArtifactSet artifactSet = queryService.query("/s-ramp/ext/FooArtifactType");
    Iterator<BaseArtifactType> iterator = artifactSet.iterator();
    while (iterator.hasNext()) {
        BaseArtifactType artifactResult = iterator.next();
        System.out.println(artifactResult.getName());
    }
} catch (Exception e) {
    e.printStackTrace();
}
----

The complete list of services include the following.  Have a look at their javadocs -- the capabilities are fairly extensive.
* org.artificer.server.core.api.ArtifactService
* org.artificer.server.core.api.AuditService
* org.artificer.server.core.api.BatchService
* org.artificer.server.core.api.OntologyService
* org.artificer.server.core.api.QueryService

Note that you must call #login for each service, using the EJB/JMS username and password that you provided
during installation!


JMS Client
~~~~~~~~~~

Artificer publishes JMS messages to both topics and queues for several types of events.  The type of event
is designated by the JMSType header field.  All events carry the relevant object marshalled into a JSON payload.

Installation and Setup
^^^^^^^^^^^^^^^^^^^^^^

The 'artificer.properties' configuration file contains multiple properties relevant to the JMS setup:

----
# Artificer will automatically attempt to discover a JMS ConnectionFactory through the literal JNDI name
# "ConnectionFactory".  However, that name can be overridden here.
artificer.config.events.jms.connectionfactory = ConnectionFactory
# By default, Artificer publishes events through the "artificer/events/topic" JMS topic name (JNDI).  But, it will also publish
# to any other names listed here (comma-delimited).
artificer.config.events.jms.topics = artificer/events/topic
# In addition to the above topics, Artificer will also publish non-expiring events to any JMS queue names (JNDI)
# listed here (comma-delimited).
artificer.config.events.jms.queues =
----

Artificer supports two JMS environments:

* When Artificer is installed in WildFly/EAP by using our installation script, JMS is configured automatically.  The existing
HornetQ configuration is modified to add the default topic, described above, and all necessary credentials.
Users can add additional topics/queues to their framework, then add them to 'artificer.properties' (see above).
IMPORTANT: In order for HornetQ to work properly, the standalone-full profile must be used
('bin/standalone.sh -c standalone-full.xml')!  Without it, errors are guaranteed to occur during startup!
* For other EE platforms, Artificer will always attempt to discover a JMS 'ConnectionFactory' and all
configured topics/queues through JNDI.  If found, it will simply use that existing framework and setup.
Users can add additional topics/queues to their framework, then add them to 'artificer.properties' (see above).

Authorization
^^^^^^^^^^^^^

During installation, you were prompted for a password.  This set up a standard WildFly/EAP *admin* user (including the
*artificer* role used by the HornetQ configuration in standalone*.xml).  These credentials must be used when connecting
to the JMS topics/queues as a subscriber!

Artifact JMS Events
^^^^^^^^^^^^^^^^^^^

[width="50%",options="header"]
|=============================
|#Event#              |#JMSType Header#              |#Payload#
|Artifact Created     |artificer:artifactCreated     |Artifact JSON
|Artifact Updated     |artificer:artifactUpdated     |Old/New Artifacts JSON
|Artifact Deleted     |artificer:artifactDeleted     |Artifact JSON
|=============================

These events carry the artifacts, marshalled into JSON, as payloads.  Note that these can be easily unmarshalled
back into the artificer-api module's Java bindings.  Here's a brief example using Jackson:

----
// The TextMessage is received through a typical JMS MessageListener.
TextMessage textMessage = ...;
ObjectMapper mapper = new ObjectMapper();
ExtendedArtifactType eventArtifact = mapper.readValue(textMessage.getText(), ExtendedArtifactType.class);
----

'Example Artifact Created JSON'
----
{
  "classifiedBy":[

  ],
  "relationship":[

  ],
  "property":[

  ],
  "artifactType":"EXTENDED_ARTIFACT_TYPE",
  "name":"Foo",
  "description":"created",
  "createdBy":"admin",
  "version":null,
  "uuid":"cd0d16c6-cee0-41fa-ad53-47d4e48947fb",
  "createdTimestamp":1411744515668,
  "lastModifiedTimestamp":1411744515668,
  "lastModifiedBy":"admin",
  "otherAttributes":{
    "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}derived":"false",
    "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}contentType":"application/xml"
  },
  "extendedType":"FooArtifactType"
}
----

artifactUpdated takes the payload a step further and includes both the original and the revised artifacts.

'Example Artifact Updated JSON'
----
{
  "updatedArtifact":{
    "@class":"org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ExtendedArtifactType",
    "classifiedBy":[

    ],
    "relationship":[

    ],
    "property":[

    ],
    "artifactType":"EXTENDED_ARTIFACT_TYPE",
    "name":"Foo",
    "description":"updated",
    "createdBy":"admin",
    "version":null,
    "uuid":"cd0d16c6-cee0-41fa-ad53-47d4e48947fb",
    "createdTimestamp":1411744515668,
    "lastModifiedTimestamp":1411744516142,
    "lastModifiedBy":"admin",
    "otherAttributes":{
      "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}derived":"false",
      "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}contentType":"application/xml"
    },
    "extendedType":"FooArtifactType"
  },
  "oldArtifact":{
    "@class":"org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ExtendedArtifactType",
    "classifiedBy":[

    ],
    "relationship":[

    ],
    "property":[

    ],
    "artifactType":"EXTENDED_ARTIFACT_TYPE",
    "name":"Foo",
    "description":"created",
    "createdBy":"admin",
    "version":null,
    "uuid":"cd0d16c6-cee0-41fa-ad53-47d4e48947fb",
    "createdTimestamp":1411744515668,
    "lastModifiedTimestamp":1411744515668,
    "lastModifiedBy":"admin",
    "otherAttributes":{
      "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}derived":"false",
      "{http://docs.oasis-open.org/s-ramp/ns/s-ramp-v1.0}contentType":"application/xml"
    },
    "extendedType":"FooArtifactType"
  }
}
----

Ontology JMS Events
^^^^^^^^^^^^^^^^^^^

[width="50%",options="header"]
|=============================
|#Event#              |#JMSType Header#              |#Payload#
|Ontology Created     |artificer:ontologyCreated     |Ontology JSON
|Ontology Updated     |artificer:ontologyUpdated     |Old/New Ontologies JSON
|Ontology Deleted     |artificer:ontologyDeleted     |Ontology JSON
|=============================

These events work similarly to Artifacts, but carry the ontology payload using the artificer-api module's
binding: RDF.

'Example Ontology Created JSON'
----
{
  "ontology":{
    "label":"Color",
    "comment":null,
    "id":"Color"
  },
  "clazz":[
    {
      "subClassOf":null,
      "label":"Red",
      "comment":null,
      "id":"Red"
    },
    {
      "subClassOf":null,
      "label":"Blue",
      "comment":null,
      "id":"Blue"
    }
  ],
  "otherAttributes":{
    "{http://www.w3.org/XML/1998/namespace}base":"foo"
  }
}
----

'Example Ontology Updated JSON'
----
{
  "updatedOntology":{
    "ontology":{
      "label":"ColorUpdated",
      "comment":null,
      "id":"Color"
    },
    "clazz":[
      {
        "subClassOf":null,
        "label":"Red",
        "comment":null,
        "id":"Red"
      },
      {
        "subClassOf":null,
        "label":"Blue",
        "comment":null,
        "id":"Blue"
      }
    ],
    "otherAttributes":{
      "{http://www.w3.org/XML/1998/namespace}base":"foo"
    }
  },
  "oldOntology":{
    "ontology":{
      "label":"Color",
      "comment":null,
      "id":"Color"
    },
    "clazz":[
      {
        "subClassOf":null,
        "label":"Red",
        "comment":null,
        "id":"Red"
      },
      {
        "subClassOf":null,
        "label":"Blue",
        "comment":null,
        "id":"Blue"
      }
    ],
    "otherAttributes":{
      "{http://www.w3.org/XML/1998/namespace}base":"foo"
    }
  }
}
----