Java tutorial
/** * */ package org.apache.taverna.scufl2.api.configurations; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.IOException; import java.net.URI; import org.apache.taverna.scufl2.api.activity.Activity; import org.apache.taverna.scufl2.api.common.AbstractNamed; import org.apache.taverna.scufl2.api.common.Child; import org.apache.taverna.scufl2.api.common.Configurable; import org.apache.taverna.scufl2.api.common.Typed; import org.apache.taverna.scufl2.api.common.Visitor; import org.apache.taverna.scufl2.api.common.WorkflowBean; import org.apache.taverna.scufl2.api.core.Processor; import org.apache.taverna.scufl2.api.core.Workflow; import org.apache.taverna.scufl2.api.port.Port; import org.apache.taverna.scufl2.api.profiles.Profile; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ValueNode; /** * Configuration of a {@link Configurable} workflow bean. * <p> * A configuration is activated by a {@link Profile}, and provides a link to the * {@link #getJson()} containing the properties to configure the bean, like an * {@link Activity}. * <p> * A configuration is of a certain (RDF) <strong>type</strong>, as defined by * {@link #getType()} - which determines which properties are required and * optional. For instance, the type * <code>http://ns.taverna.org.uk/2010/activity/wsdl/ConfigType</code> requires * the property * <code>http://ns.taverna.org.uk/2010/activity/wsdl/operation</code>. * <p> * These requirements are described in the {@link ConfigurationDefinition} that * matches the getConfigurableType() of the {@link Configurable} found by * {@link #getConfigures()}. Its * {@link ConfigurationDefinition#getPropertyResourceDefinition()} should in * {@link PropertyResourceDefinition#getTypeURI()} should match the * {@link #getType()} of this {@link Configuration}. * <p> * Note: {@link #getType()} (and the potentially misleading {@link #getType()}) * return the type of <b>this</b> Configuration, not the type of the * {@link Configurable} bean that it happens to configure. For instance, a * Configuration typed <code>http://example.com/WSDLConfiguration</code> might * configure an activity typed <code>http://example.com/WSDLActivity</code>, but * could also have configured an activity typed * <code>http://example.com/GlobusWSDLActivity</code>. * <p> * <strong>TODO: Where are the ConfigurationDefinitions found?</strong> * * @author Alan R Williams * @author Stian Soiland-Reyes * */ public class Configuration extends AbstractNamed implements Child<Profile>, Typed { private static final JsonNodeFactory JSON_NODE_FACTORY = JsonNodeFactory.instance; private Configurable configures; private Profile parent; private JsonNode json = JSON_NODE_FACTORY.objectNode(); private JsonNode jsonSchema; private URI type; /** * Constructs a <code>Configuration</code> with a random UUID as the name. */ public Configuration() { super(); } /** * Construct a <code>Configuration</code> with the specified name. * * @param name * the name of the <code>Configuration</code>. <strong>Must * not</strong> be <code>null</code> or an empty String. */ public Configuration(String name) { super(name); } @Override public boolean accept(Visitor visitor) { return visitor.visit(this); } /** * Return the {@link Configurable} workflow bean that is configured. * Typically an {@link Activity} or {@link Processor}, {@link Workflow} and * {@link Port} can be configured. * * @return the <code>Configurable</code> <code>WorkflowBean</code> that is * configured */ public Configurable getConfigures() { return configures; } @Override public Profile getParent() { return parent; } /** * Return the underlying JSON {@link JsonNode} which contains the properties * set by this configuration. * <p> * The JSON node is typically an {@link ObjectNode} or {@link ArrayNode}, * but could also be a {@link ValueNode}. The default node for a freshly * constructed Configuration is an {@link ObjectNode}. * @return the backing * {@link ObjectNode}. */ public JsonNode getJson() { return json; } /** * Return a string representation of the {@link #getJson()} configuration, * the string is valid JSON. * * @return */ public String getJsonAsString() { return json.toString(); } /** * Return the {@link #getJson()} configuration as an {@link ObjectNode}. * This is the default type for a new {@link Configuration}. * * @throws IllegalStateException * if the {@link #getJson()} is not an {@link ObjectNode} * * @return */ public ObjectNode getJsonAsObjectNode() { if (!json.isObject()) throw new IllegalStateException("JSON is not an ObjectNode, but " + json); return (ObjectNode) json; } /** * Return the type of the <code>Configuration</code>. * <p> * The URI will match the {@link PropertyResource#getTypeURI()}. * * @return the type of the <code>Configuration</code> */ @Override public URI getType() { return type; } /** * Set the {@link Configurable} {@link WorkflowBean} that is configured. * * @param configurable * the <code>Configurable</code> <code>WorkflowBean</code> that * is configured */ public void setConfigures(Configurable configurable) { configures = configurable; } @Override public void setParent(Profile parent) { if (this.parent != null && this.parent != parent) this.parent.getConfigurations().remove(this); this.parent = parent; if (parent != null) parent.getConfigurations().add(this); } /** * Set the underlying JSON {@link JsonNode} which contains the properties * set by this configuration. The JSON node is typically an * {@link ObjectNode} or {@link ArrayNode}, but could also be a * {@link ValueNode}. * <p> * If the provided ObjectNode is <code>null</code>, a new, blank * {@link ObjectNode} will be set. * * @param json * the underlying <code>JsonNode</code> which contains the * properties set by this configuration. */ public void setJson(JsonNode json) { if (json == null) this.json = JSON_NODE_FACTORY.objectNode(); this.json = json; } /** * Set the type of the <code>Configuration</code>. * <p> * This will also set {@link PropertyResource#setTypeURI(URI)}. * * @param type * the type of the <code>Configuration</code>. */ @Override public void setType(URI type) { this.type = type; } @Override protected void cloneInto(WorkflowBean clone, Cloning cloning) { super.cloneInto(clone, cloning); Configuration cloneConfig = (Configuration) clone; cloneConfig.setConfigures(cloning.cloneOrOriginal(getConfigures())); } public JsonNode getJsonSchema() { return jsonSchema; } public void setJsonSchema(JsonNode jsonSchema) { this.jsonSchema = jsonSchema; } public void setJsonSchema(String jsonString) { setJsonSchema(parseJson(jsonString)); } public void setJson(String jsonString) { setJson(parseJson(jsonString)); } protected JsonNode parseJson(String jsonString) { ObjectMapper mapper = new ObjectMapper(); try { JsonParser parser = mapper.getFactory().createParser(jsonString); return parser.readValueAs(JsonNode.class); } catch (IOException e) { throw new IllegalArgumentException("Not valid JSON string", e); } } }