http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java new file mode 100644 index 0000000..fd0285d --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java @@ -0,0 +1,220 @@ +package io.github.taverna_extras.component.registry.local; +/* + * 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 static org.apache.commons.io.FileUtils.deleteDirectory; +import static org.apache.commons.io.FileUtils.writeStringToFile; +import static org.apache.log4j.Logger.getLogger; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.util.Set; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Family; +import io.github.taverna_extras.component.api.License; +import io.github.taverna_extras.component.api.SharingPolicy; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.api.profile.Profile; +import io.github.taverna_extras.component.profile.ComponentProfileImpl; +import io.github.taverna_extras.component.registry.ComponentRegistry; +import io.github.taverna_extras.component.registry.ComponentUtil; +import io.github.taverna_extras.component.utils.SystemUtils; + +/** + * A component registry implemented using the local file system. Note that the + * components it contains are <i>not</i> shareable. + * + * @author alanrw + */ +class LocalComponentRegistry extends ComponentRegistry { + private static final Logger logger = getLogger(LocalComponentRegistry.class); + static final String ENC = "utf-8"; + private ComponentUtil util; + private SystemUtils system; + private File baseDir; + + public LocalComponentRegistry(File registryDir, ComponentUtil util, + SystemUtils system) throws ComponentException { + super(registryDir); + baseDir = registryDir; + this.util = util; + this.system = system; + } + + @Override + public Family internalCreateComponentFamily(String name, + Profile componentProfile, String description, License license, + SharingPolicy sharingPolicy) throws ComponentException { + File newFamilyDir = new File(getComponentFamiliesDir(), name); + newFamilyDir.mkdirs(); + File profileFile = new File(newFamilyDir, "profile"); + try { + writeStringToFile(profileFile, componentProfile.getName(), ENC); + } catch (IOException e) { + throw new ComponentException("Could not write out profile", e); + } + File descriptionFile = new File(newFamilyDir, "description"); + try { + writeStringToFile(descriptionFile, description, ENC); + } catch (IOException e) { + throw new ComponentException("Could not write out description", e); + } + return new LocalComponentFamily(this, newFamilyDir, util, system); + } + + @Override + protected void populateFamilyCache() throws ComponentException { + File familiesDir = getComponentFamiliesDir(); + for (File subFile : familiesDir.listFiles()) { + if (!subFile.isDirectory()) + continue; + LocalComponentFamily newFamily = new LocalComponentFamily(this, + subFile, util, system); + familyCache.put(newFamily.getName(), newFamily); + } + } + + @Override + protected void populateProfileCache() throws ComponentException { + File profilesDir = getComponentProfilesDir(); + for (File subFile : profilesDir.listFiles()) + if (subFile.isFile() && (!subFile.isHidden()) + && subFile.getName().endsWith(".xml")) + try { + profileCache.add(new LocalComponentProfile(subFile)); + } catch (MalformedURLException e) { + logger.error("Unable to read profile", e); + } + } + + @Override + protected void internalRemoveComponentFamily(Family componentFamily) + throws ComponentException { + try { + deleteDirectory(new File(getComponentFamiliesDir(), + componentFamily.getName())); + } catch (IOException e) { + throw new ComponentException("Unable to delete component family", e); + } + } + + private File getBaseDir() { + baseDir.mkdirs(); + return baseDir; + } + + private File getComponentFamiliesDir() { + File componentFamiliesDir = new File(getBaseDir(), "componentFamilies"); + componentFamiliesDir.mkdirs(); + return componentFamiliesDir; + } + + private File getComponentProfilesDir() { + File componentProfilesDir = new File(getBaseDir(), "componentProfiles"); + componentProfilesDir.mkdirs(); + return componentProfilesDir; + } + + @Override + public Profile internalAddComponentProfile(Profile componentProfile, + License license, SharingPolicy sharingPolicy) + throws ComponentException { + String name = componentProfile.getName().replaceAll("\\W+", "") + + ".xml"; + String inputString = componentProfile.getXML(); + File outputFile = new File(getComponentProfilesDir(), name); + try { + writeStringToFile(outputFile, inputString); + } catch (IOException e) { + throw new ComponentException("Unable to save profile", e); + } + + try { + return new LocalComponentProfile(outputFile); + } catch (MalformedURLException e) { + throw new ComponentException("Unable to create profile", e); + } + } + + @Override + public int hashCode() { + return 31 + ((baseDir == null) ? 0 : baseDir.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LocalComponentRegistry other = (LocalComponentRegistry) obj; + if (baseDir == null) + return (other.baseDir == null); + return baseDir.equals(other.baseDir); + } + + @Override + public void populatePermissionCache() { + return; + } + + @Override + public void populateLicenseCache() { + return; + } + + @Override + public License getPreferredLicense() { + return null; + } + + @Override + public Set<Version.ID> searchForComponents(String prefixString, String text) + throws ComponentException { + throw new ComponentException("Local registries cannot be searched yet"); + } + + @Override + public String getRegistryTypeName() { + return "File System"; + } + + class LocalComponentProfile extends ComponentProfileImpl { + URI uri; + + LocalComponentProfile(File file) throws MalformedURLException, + ComponentException { + super(LocalComponentRegistry.this, file.toURI(), util + .getBaseProfileLocator()); + uri = file.toURI(); + } + + @Override + public String toString() { + return "Local Component Profile[" + uri + "]"; + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java new file mode 100644 index 0000000..f2625d1 --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java @@ -0,0 +1,62 @@ +package io.github.taverna_extras.component.registry.local; +/* + * 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.File; +import java.net.URL; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; + +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Registry; +import io.github.taverna_extras.component.registry.ComponentUtil; +import io.github.taverna_extras.component.utils.SystemUtils; +import org.springframework.beans.factory.annotation.Required; + +public class LocalComponentRegistryFactory { + private final Map<File, Registry> registries = new HashMap<>(); + private ComponentUtil util; + private SystemUtils system; + + @Required + public void setComponentUtil(ComponentUtil util) { + this.util = util; + } + + @Required + public void setSystemUtils(SystemUtils system) { + this.system = system; + } + + public synchronized Registry getComponentRegistry(File registryDir) + throws ComponentException { + if (!registries.containsKey(registryDir)) + registries.put(registryDir, new LocalComponentRegistry(registryDir, + util, system)); + return registries.get(registryDir); + } + + public Registry getComponentRegistry(URL componentRegistryBase) + throws ComponentException { + @SuppressWarnings("deprecation") + String hackedPath = URLDecoder.decode(componentRegistryBase.getPath()); + return getComponentRegistry(new File(hackedPath)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java new file mode 100644 index 0000000..976aa8b --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java @@ -0,0 +1,108 @@ +package io.github.taverna_extras.component.registry.local; +/* + * 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 static java.lang.Integer.parseInt; +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.apache.log4j.Logger.getLogger; +import static io.github.taverna_extras.component.registry.local.LocalComponent.COMPONENT_FILENAME; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.registry.ComponentVersion; +import io.github.taverna_extras.component.utils.SystemUtils; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +/** + * @author alanrw + * + */ +class LocalComponentVersion extends ComponentVersion { + private static Logger logger = getLogger(LocalComponentVersion.class); + + private final File componentVersionDir; + private SystemUtils system; + + protected LocalComponentVersion(LocalComponent component, + File componentVersionDir, SystemUtils system) { + super(component); + this.componentVersionDir = componentVersionDir; + this.system = system; + } + + @Override + protected final String internalGetDescription() { + File descriptionFile = new File(componentVersionDir, "description"); + try { + if (descriptionFile.isFile()) + return readFileToString(descriptionFile); + } catch (IOException e) { + logger.error("failed to get description from " + descriptionFile, e); + } + return ""; + } + + @Override + protected final Integer internalGetVersionNumber() { + return parseInt(componentVersionDir.getName()); + } + + @Override + protected final WorkflowBundle internalGetImplementation() + throws ComponentException { + File filename = new File(componentVersionDir, COMPONENT_FILENAME); + try { + return system.getBundle(filename); + } catch (Exception e) { + logger.error( + "failed to get component realization from " + filename, e); + throw new ComponentException("Unable to open dataflow", e); + } + } + + @Override + public int hashCode() { + return 31 + ((componentVersionDir == null) ? 0 : componentVersionDir + .hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LocalComponentVersion other = (LocalComponentVersion) obj; + if (componentVersionDir == null) + return (other.componentVersionDir == null); + return componentVersionDir.equals(other.componentVersionDir); + } + + @Override + public URL getHelpURL() { + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java new file mode 100644 index 0000000..87b99b1 --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java @@ -0,0 +1,654 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static java.lang.Math.min; +import static java.lang.String.format; +import static java.lang.System.getProperty; +import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.net.HttpURLConnection.HTTP_NO_CONTENT; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; +import static java.net.URLEncoder.encode; +import static javax.xml.bind.DatatypeConverter.printBase64Binary; +import static org.apache.commons.io.IOUtils.copy; +import static org.apache.log4j.Logger.getLogger; +import static io.github.taverna_extras.component.registry.ClientVersion.VERSION; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.registry.standard.Client.MyExperimentConnector.ServerResponse; +import io.github.taverna_extras.component.registry.standard.annotations.Unused; +import org.apache.taverna.security.credentialmanager.CMException; +import org.apache.taverna.security.credentialmanager.CredentialManager; +import org.apache.taverna.security.credentialmanager.UsernamePassword; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +class Client { + private static final String API_VERIFICATION_RESOURCE = "/component-profiles.xml"; + private static final String WHOAMI = "/whoami.xml"; + private static final String PLUGIN_USER_AGENT = "Taverna2-Component-plugin/" + + VERSION + " Java/" + getProperty("java.version"); + private static final int MESSAGE_TRIM_LENGTH = 512; + private static final Logger logger = getLogger(Client.class); + private final MyExperimentConnector http; + private final URL registryBase; + private final JAXBContext jaxbContext; + private final CredentialManager cm; + + Client(JAXBContext context, URL repository, CredentialManager cm) + throws ComponentException { + this(context, repository, true, cm); + } + + Client(JAXBContext context, URL repository, boolean tryLogIn, + CredentialManager cm) throws ComponentException { + this.cm = cm; + this.registryBase = repository; + this.jaxbContext = context; + this.http = new MyExperimentConnector(tryLogIn); + logger.info("instantiated client connection engine to " + repository); + } + + public boolean verify() { + try { + String url = url(API_VERIFICATION_RESOURCE); + logger.info("API verification: HEAD for " + url); + return http.HEAD(url).getCode() == HTTP_OK; + } catch (Exception e) { + logger.info("failed to connect to " + registryBase, e); + return false; + } + } + + private String url(String uri, String... arguments) + throws MalformedURLException, UnsupportedEncodingException { + StringBuilder uriBuilder = new StringBuilder(uri); + for (String queryElement : arguments) { + String[] bits = queryElement.split("=", 2); + uriBuilder.append(uriBuilder.indexOf("?") < 0 ? "?" : "&") + .append(bits[0]).append('=') + .append(encode(bits[1], "UTF-8")); + } + return new URL(registryBase, uriBuilder.toString()).toString(); + } + + private Marshaller getMarshaller() throws JAXBException { + return jaxbContext.createMarshaller(); + } + + /** + * Does an HTTP GET against the configured repository. + * + * @param clazz + * The JAXB-annotated class that the result is supposed to be + * instantiated into. + * @param uri + * The path part of the URI within the repository. + * @param query + * The strings to put into the query part. Each should be in + * <tt>key=value</tt> form. + * @return The deserialized response object. + * @throws ComponentException + * If anything goes wrong. + */ + public <T> T get(Class<T> clazz, String uri, String... query) + throws ComponentException { + try { + int redirectCounter = 0; + + String url = url(uri, query); + ServerResponse response; + do { + if (redirectCounter++ > 5) + throw new ComponentException("too many redirects!"); + logger.info("GET of " + url); + response = http.GET(url); + if (response.isFailure()) + throw new ComponentException( + "Unable to perform request (%d): %s", + response.getCode(), response.getError()); + } while ((url = response.getLocation()) != null); + return response.getResponse(clazz); + + } catch (ComponentException e) { + throw e; + } catch (MalformedURLException e) { + throw new ComponentException("Problem constructing resource URL", e); + } catch (JAXBException e) { + throw new ComponentException("Problem when unmarshalling response", + e); + } catch (Exception e) { + throw new ComponentException("Problem when sending request", e); + } + } + + /** + * Does an HTTP POST against the configured repository. + * + * @param clazz + * The JAXB-annotated class that the result is supposed to be + * instantiated into. + * @param elem + * The JAXB element to post to the resource. + * @param uri + * The path part of the URI within the repository. + * @param query + * The strings to put into the query part. Each should be in + * <tt>key=value</tt> form. + * @return The deserialized response object. + * @throws ComponentException + * If anything goes wrong. + */ + public <T> T post(Class<T> clazz, JAXBElement<?> elem, String uri, + String... query) throws ComponentException { + try { + + String url = url(uri, query); + logger.info("POST to " + url); + StringWriter sw = new StringWriter(); + getMarshaller().marshal(elem, sw); + if (logger.isDebugEnabled()) + logger.info("About to post XML document:\n" + sw); + ServerResponse response = http.POST(url, sw); + if (response.isFailure()) + throw new ComponentException( + "Unable to perform request (%d): %s", + response.getCode(), response.getError()); + if (response.getLocation() != null) + return get(clazz, response.getLocation()); + return response.getResponse(clazz); + + } catch (ComponentException e) { + throw e; + } catch (MalformedURLException e) { + throw new ComponentException("Problem constructing resource URL", e); + } catch (JAXBException e) { + throw new ComponentException("Problem when marshalling request", e); + } catch (Exception e) { + throw new ComponentException("Problem when sending request", e); + } + } + + /** + * Does an HTTP PUT against the configured repository. + * + * @param clazz + * The JAXB-annotated class that the result is supposed to be + * instantiated into. + * @param elem + * The JAXB element to post to the resource. + * @param uri + * The path part of the URI within the repository. + * @param query + * The strings to put into the query part. Each should be in + * <tt>key=value</tt> form. + * @return The deserialized response object. + * @throws ComponentException + * If anything goes wrong. + */ + @Unused + public <T> T put(Class<T> clazz, JAXBElement<?> elem, String uri, + String... query) throws ComponentException { + try { + + String url = url(uri, query); + logger.info("PUT to " + url); + StringWriter sw = new StringWriter(); + getMarshaller().marshal(elem, sw); + if (logger.isDebugEnabled()) + logger.info("About to put XML document:\n" + sw); + ServerResponse response = http.PUT(url, sw); + if (response.isFailure()) + throw new ComponentException( + "Unable to perform request (%d): %s", + response.getCode(), response.getError()); + if (response.getLocation() != null) + return get(clazz, response.getLocation()); + return response.getResponse(clazz); + + } catch (ComponentException e) { + throw e; + } catch (MalformedURLException e) { + throw new ComponentException("Problem constructing resource URL", e); + } catch (JAXBException e) { + throw new ComponentException("Problem when marshalling request", e); + } catch (Exception e) { + throw new ComponentException("Problem when sending request", e); + } + } + + /** + * Does an HTTP DELETE against the configured repository. + * + * @param uri + * The path part of the URI within the repository. + * @param query + * The strings to put into the query part. Each should be in + * <tt>key=value</tt> form. + * @throws ComponentException + * If anything goes wrong. + */ + public void delete(String uri, String... query) throws ComponentException { + ServerResponse response; + try { + + String url = url(uri, query); + logger.info("DELETE of " + url); + response = http.DELETE(url); + + } catch (MalformedURLException e) { + throw new ComponentException("Problem constructing resource URL", e); + } catch (Exception e) { + throw new ComponentException("Unable to perform request", e); + } + if (response.isFailure()) + throw new ComponentException("Unable to perform request (%d): %s", + response.getCode(), response.getError()); + } + + private String getCredentials(String urlString, boolean mandatory) + throws CMException, UnsupportedEncodingException { + final URI serviceURI = URI.create(urlString); + + if (mandatory || cm.hasUsernamePasswordForService(serviceURI)) { + UsernamePassword userAndPass = cm.getUsernameAndPasswordForService( + serviceURI, true, null); + // Check for user didn't log in... + if (userAndPass == null) + return null; + return printBase64Binary(format("%s:%s", userAndPass.getUsername(), + userAndPass.getPasswordAsString()).getBytes("UTF-8")); + } + return null; + } + + private void clearCredentials(String baseURL) throws CMException { + for (URI uri : cm.getServiceURIsForAllUsernameAndPasswordPairs()) + if (uri.toString().startsWith(baseURL)) + cm.deleteUsernameAndPasswordForService(uri); + } + + private static Document getDocumentFromStream(InputStream inputStream) + throws SAXException, IOException, ParserConfigurationException { + DocumentBuilder db = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + Document doc; + try (InputStream is = new BufferedInputStream(inputStream)) { + if (!logger.isDebugEnabled()) + doc = db.parse(is); + else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + copy(is, baos); + String response = baos.toString("UTF-8"); + logger.info("response message follows\n" + + response.substring(0, + min(MESSAGE_TRIM_LENGTH, response.length()))); + doc = db.parse(new ByteArrayInputStream(baos.toByteArray())); + } + } + return doc; + } + + class MyExperimentConnector { + // authentication settings (and the current user) + private String authString = null; + + private void tryLogIn(boolean mandatory) throws ComponentException { + // check if the stored credentials are valid + ServerResponse response = null; + try { + String userPass = getCredentials(registryBase.toString(), + mandatory); + if (userPass == null) + logger.debug("no credentials available for " + registryBase); + else { + // set the system to the "logged in" state from INI file properties + authString = userPass; + response = GET(registryBase.toString() + WHOAMI); + } + } catch (Exception e) { + authString = null; + logger.debug("failed when verifying login credentials", e); + } + + if (response == null || response.getCode() != HTTP_OK) + try { + if (response != null) + throw new ComponentException("failed to log in: " + + response.getError()); + } finally { + try { + authString = null; + clearCredentials(registryBase.toString()); + } catch (Exception e) { + logger.debug("failed to clear credentials", e); + } + } + if (authString != null) + logger.debug("logged in to repository successfully"); + } + + MyExperimentConnector(boolean tryLogIn) throws ComponentException { + if (tryLogIn) + tryLogIn(false); + } + + // getter for the current status + private boolean isLoggedIn() { + return authString != null; + } + + private HttpURLConnection connect(String method, String strURL) + throws MalformedURLException, IOException { + HttpURLConnection conn = (HttpURLConnection) new URL(strURL) + .openConnection(); + conn.setRequestMethod(method); + if (method.equals("POST") || method.equals("PUT")) + conn.setDoOutput(true); + conn.setRequestProperty("User-Agent", PLUGIN_USER_AGENT); + if (authString != null) + conn.setRequestProperty("Authorization", "Basic " + authString); + return conn; + } + + private boolean elevate() throws ComponentException { + tryLogIn(true); + return isLoggedIn(); + } + + /** + * Generic method to execute GET requests to myExperiment server. + * + * @param url + * The URL on myExperiment to issue GET request to. + * @return An object containing XML Document with server's response body + * and a response code. Response body XML document might be null + * if there was an error or the user wasn't authorised to + * perform a certain action. Response code will always be set. + * @throws Exception + */ + public ServerResponse GET(String url) throws Exception { + if (!isLoggedIn()) + logger.warn("not logged in"); + return receiveServerResponse(connect("GET", url), url, true, false); + } + + /** + * Generic method to execute GET requests to myExperiment server. + * + * @param url + * The URL on myExperiment to issue GET request to. + * @return An object containing XML Document with server's response body + * and a response code. Response body XML document might be null + * if there was an error or the user wasn't authorised to + * perform a certain action. Response code will always be set. + * @throws Exception + */ + public ServerResponse HEAD(String url) throws Exception { + if (!isLoggedIn()) + logger.warn("not logged in"); + return receiveServerResponse(connect("HEAD", url), url, false, true); + } + + /** + * Generic method to execute GET requests to myExperiment server. + * + * @param url + * The URL on myExperiment to POST to. + * @param xmlDataBody + * Body of the XML data to be POSTed to strURL. + * @return An object containing XML Document with server's response body + * and a response code. Response body XML document might be null + * if there was an error or the user wasn't authorised to + * perform a certain action. Response code will always be set. + * @throws Exception + */ + public ServerResponse POST(String url, Object xmlDataBody) + throws Exception { + if (!isLoggedIn() && !elevate()) + return null; + + HttpURLConnection conn = connect("POST", url); + sendXmlBody(xmlDataBody, conn); + return receiveServerResponse(conn, url, false, false); + } + + /** + * Generic method to execute DELETE requests to myExperiment server. + * This is only to be called when a user is logged in. + * + * @param url + * The URL on myExperiment to direct DELETE request to. + * @return An object containing XML Document with server's response body + * and a response code. Response body XML document might be null + * if there was an error or the user wasn't authorised to + * perform a certain action. Response code will always be set. + * @throws Exception + */ + public ServerResponse DELETE(String url) throws Exception { + if (!isLoggedIn() && !elevate()) + return null; + return receiveServerResponse(connect("DELETE", url), url, true, + false); + } + + @Unused + public ServerResponse PUT(String url, Object xmlDataBody) + throws Exception { + if (!isLoggedIn() && !elevate()) + return null; + + HttpURLConnection conn = connect("PUT", url); + sendXmlBody(xmlDataBody, conn); + return receiveServerResponse(conn, url, false, false); + } + + /** + * Factoring out of how to write a body. + * + * @param xmlDataBody + * What to write (an {@link InputStream}, a {@link Reader} or + * an object that will have it's {@link Object#toString() + * toString()} method called. + * @param conn + * Where to write it to. + * @throws IOException + * If anything goes wrong. The <code>conn</code> will be + * disconnected in the case of a failure. + */ + private void sendXmlBody(Object xmlDataBody, HttpURLConnection conn) + throws IOException { + try { + conn.setRequestProperty("Content-Type", "application/xml"); + if (xmlDataBody instanceof InputStream) + copy((InputStream) xmlDataBody, conn.getOutputStream()); + else + try (OutputStreamWriter out = new OutputStreamWriter( + conn.getOutputStream())) { + if (xmlDataBody instanceof Reader) + copy((Reader) xmlDataBody, out); + else + out.write(xmlDataBody.toString()); + } + } catch (IOException e) { + conn.disconnect(); + throw e; + } + } + + /** + * A common method for retrieving myExperiment server's response for all + * types of requests. + * + * @param conn + * Instance of the established URL connection to poll for + * server's response. + * @param url + * The URL on myExperiment with which the connection is + * established. + * @param isGETrequest + * Flag for identifying type of the request. True when the + * current connection executes GET request; false when it + * executes a POST request. + * @return An object containing XML Document with server's response body + * and a response code. Response body XML document might be null + * if there was an error or the user wasn't authorised to + * perform a certain action. Response code will always be set. + */ + private ServerResponse receiveServerResponse(HttpURLConnection conn, + String url, boolean isGETrequest, boolean isHEADrequest) + throws Exception { + try { + switch (conn.getResponseCode()) { + case HTTP_OK: + /* + * data retrieval was successful - parse the response XML + * and return it along with response code + */ + if (isHEADrequest) + return new ServerResponse(conn.getResponseCode(), null, + null); + return new ServerResponse(conn.getResponseCode(), null, + getDocumentFromStream(conn.getInputStream())); + case HTTP_NO_CONTENT: + return new ServerResponse(HTTP_OK, null, null); + + case HttpURLConnection.HTTP_CREATED: + case HttpURLConnection.HTTP_MOVED_PERM: + case HttpURLConnection.HTTP_MOVED_TEMP: + case HttpURLConnection.HTTP_SEE_OTHER: + case HttpURLConnection.HTTP_USE_PROXY: + return new ServerResponse(conn.getResponseCode(), + conn.getHeaderField("Location"), null); + + case HTTP_BAD_REQUEST: + case HTTP_FORBIDDEN: + /* + * this was a bad XML request - need full XML response to + * retrieve the error message from it; Java throws + * IOException if getInputStream() is used when non HTTP_OK + * response code was received - hence can use + * getErrorStream() straight away to fetch the error + * document + */ + return new ServerResponse(conn.getResponseCode(), null, + getDocumentFromStream(conn.getErrorStream())); + + case HTTP_UNAUTHORIZED: + // this content is not authorised for current user + logger.warn("non-authorised request to " + url + "\n" + + IOUtils.toString(conn.getErrorStream())); + return new ServerResponse(conn.getResponseCode(), null, + null); + + case HTTP_NOT_FOUND: + if (isHEADrequest) + return new ServerResponse(conn.getResponseCode(), null, + null); + throw new FileNotFoundException("no such resource: " + url); + default: + // unexpected response code - raise an exception + throw new IOException( + format("Received unexpected HTTP response code (%d) while %s %s", + conn.getResponseCode(), + (isGETrequest ? "fetching data at" + : "posting data to"), url)); + } + } finally { + conn.disconnect(); + } + } + + class ServerResponse { + private final int responseCode; + private final String responseLocation; + private final Document responseBody; + + ServerResponse(int responseCode, String responseLocation, + Document responseBody) { + this.responseCode = responseCode; + this.responseBody = responseBody; + this.responseLocation = responseLocation; + } + + public int getCode() { + return responseCode; + } + + public boolean isFailure() { + return responseCode >= HTTP_BAD_REQUEST; + } + + public String getLocation() { + return responseLocation; + } + + public <T> T getResponse(Class<T> clazz) throws JAXBException { + return jaxbContext.createUnmarshaller() + .unmarshal(responseBody.getDocumentElement(), clazz) + .getValue(); + } + + /** + * Returns contents of the "reason" field of the error message. + */ + public String getError() { + if (responseBody != null) { + Node reasonElement = responseBody.getDocumentElement() + .getElementsByTagName("reason").item(0); + if (reasonElement != null) { + String reason = reasonElement.getTextContent(); + if (!reason.isEmpty()) + return reason; + } + } + return format("unknown reason (%d)", responseCode); + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java new file mode 100644 index 0000000..44de963 --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java @@ -0,0 +1,239 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static java.lang.String.format; +import static io.github.taverna_extras.component.registry.standard.NewComponentRegistry.logger; +import static io.github.taverna_extras.component.registry.standard.Policy.getPolicy; +import static io.github.taverna_extras.component.utils.SystemUtils.getElementString; +import static io.github.taverna_extras.component.utils.SystemUtils.getValue; + +import java.lang.ref.SoftReference; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.IllegalFormatException; + +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Family; +import io.github.taverna_extras.component.api.License; +import io.github.taverna_extras.component.api.Registry; +import io.github.taverna_extras.component.api.SharingPolicy; +import io.github.taverna_extras.component.registry.Component; +import io.github.taverna_extras.component.registry.ComponentVersion; +import io.github.taverna_extras.component.registry.api.ComponentType; +import io.github.taverna_extras.component.registry.api.Description; +import io.github.taverna_extras.component.utils.SystemUtils; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +class NewComponent extends Component { + static final String ELEMENTS = "title,description"; + static final String EXTRA = "license-type,permissions"; + + private final SystemUtils system; + final NewComponentRegistry registry; + final NewComponentFamily family; + private final String id; + private final String title; + private final String description; + private final String resource; + + NewComponent(NewComponentRegistry registry, NewComponentFamily family, + Description cd, SystemUtils system) throws ComponentException { + super(cd.getUri()); + this.system = system; + this.registry = registry; + this.family = family; + id = cd.getId().trim(); + title = getElementString(cd, "title"); + description = getElementString(cd, "description"); + resource = cd.getResource(); + } + + NewComponent(NewComponentRegistry registry, NewComponentFamily family, + ComponentType ct, SystemUtils system) { + super(ct.getUri()); + this.system = system; + this.registry = registry; + this.family = family; + id = ct.getId().trim(); + title = ct.getTitle().trim(); + description = ct.getDescription().trim(); + resource = ct.getResource(); + } + + public ComponentType getCurrent(String elements) throws ComponentException { + return registry.getComponentById(id, null, elements); + } + + @Override + protected String internalGetName() { + return title; + } + + @Override + protected String internalGetDescription() { + return description; + } + + @Override + protected void populateComponentVersionMap() { + try { + for (Description d : getCurrent("versions").getVersions() + .getWorkflow()) + versionMap.put(d.getVersion(), new Version(d.getVersion(), + getValue(d))); + } catch (ComponentException e) { + logger.warn("failed to retrieve version list: " + e.getMessage()); + } + } + + @Override + protected Version internalAddVersionBasedOn(WorkflowBundle bundle, + String revisionComment) throws ComponentException { + /* + * Only fetch the license and sharing policy now; user might have + * updated them on the site and we want to duplicate. + */ + ComponentType ct = getCurrent(EXTRA); + License license = registry.getLicense(getValue(ct.getLicenseType()) + .trim()); + SharingPolicy sharingPolicy = getPolicy(ct.getPermissions()); + + return (Version) registry.createComponentVersionFrom(this, title, + revisionComment, bundle, license, sharingPolicy); + } + + public String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (o instanceof NewComponent) { + NewComponent other = (NewComponent) o; + return registry.equals(other.registry) && id.equals(other.id); + } + return false; + } + + public String getResourceLocation() { + return resource; + } + + private static final int BASEHASH = NewComponent.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ registry.hashCode() ^ id.hashCode(); + } + + class Version extends ComponentVersion { + private int version; + private String description; + private String location; + private SoftReference<WorkflowBundle> bundleRef; + + private static final String htmlPageTemplate = "%1$s/workflows/%2$s/versions/%3$s.html"; + + protected Version(Integer version, String description, WorkflowBundle bundle) { + super(NewComponent.this); + this.version = version; + this.description = description; + this.bundleRef = new SoftReference<>(bundle); + } + + protected Version(Integer version, String description) { + super(NewComponent.this); + this.version = version; + this.description = description; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Version) { + Version other = (Version) o; + return version == other.version + && NewComponent.this.equals(other.getComponent()); + } + return false; + } + + @Override + public int hashCode() { + return NewComponent.this.hashCode() ^ (version << 16) + ^ (version >> 16); + } + + @Override + protected Integer internalGetVersionNumber() { + return version; + } + + @Override + protected String internalGetDescription() { + return description; + } + + private String getLocationUri() throws ComponentException { + if (location == null) + location = registry.getComponentById(id, version, + "content-uri").getContentUri(); + return location; + } + + @Override + protected synchronized WorkflowBundle internalGetImplementation() + throws ComponentException { + if (bundleRef == null || bundleRef.get() == null) { + String contentUri = getLocationUri(); + try { + WorkflowBundle result = system.getBundleFromUri(contentUri + + "?version=" + version); + bundleRef = new SoftReference<>(result); + return result; + } catch (Exception e) { + throw new ComponentException("Unable to open dataflow", e); + } + } + return bundleRef.get(); + } + + @Override + public URL getHelpURL() { + try { + return new URL(format(htmlPageTemplate, + registry.getRegistryBaseString(), getId(), version)); + } catch (IllegalFormatException | MalformedURLException e) { + logger.error(e); + return null; + } + } + } + + @Override + public Registry getRegistry() { + return registry; + } + + @Override + public Family getFamily() { + return family; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java new file mode 100644 index 0000000..1c16b1e --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java @@ -0,0 +1,151 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static io.github.taverna_extras.component.utils.SystemUtils.getElementString; + +import java.util.List; + +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.api.profile.Profile; +import io.github.taverna_extras.component.registry.ComponentFamily; +import io.github.taverna_extras.component.registry.ComponentUtil; +import io.github.taverna_extras.component.registry.api.ComponentFamilyType; +import io.github.taverna_extras.component.registry.api.Description; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; + +/** + * A family of components in the new-interface registry. + * + * @author Donal Fellows + */ +class NewComponentFamily extends ComponentFamily { + static final String ELEMENTS = "title,description"; + + private final NewComponentRegistry registry; + private final NewComponentProfile profile; + private final String id; + private final String name; + private final String description; + private final String uri; + private final String resource; + + NewComponentFamily(NewComponentRegistry componentRegistry, + NewComponentProfile profile, Description familyDesc, + ComponentUtil util) throws ComponentException { + super(componentRegistry, util); + uri = familyDesc.getUri(); + registry = componentRegistry; + this.profile = profile; + id = familyDesc.getId().trim(); + name = getElementString(familyDesc, "title"); + description = getElementString(familyDesc, "description"); + resource = familyDesc.getResource(); + } + + public NewComponentFamily(NewComponentRegistry componentRegistry, + NewComponentProfile profile, ComponentFamilyType cft, + ComponentUtil util) { + super(componentRegistry, util); + uri = cft.getUri(); + registry = componentRegistry; + this.profile = profile; + id = cft.getId(); + name = cft.getTitle(); + description = cft.getDescription(); + resource = cft.getResource(); + } + + @Override + protected String internalGetName() { + return name; + } + + @Override + protected String internalGetDescription() { + return description; + } + + @Override + protected Profile internalGetComponentProfile() throws ComponentException { + return profile; + } + + public List<Component> getMemberComponents() throws ComponentException { + return registry.listComponents(this); + } + + @Override + protected void populateComponentCache() throws ComponentException { + for (Component c : getMemberComponents()) { + NewComponent component = (NewComponent) c; + componentCache.put(component.getName(), component); + } + } + + @Override + protected Version internalCreateComponentBasedOn(String componentName, + String description, WorkflowBundle bundle) throws ComponentException { + if (componentName == null) + componentName = registry.annUtils.getTitle(bundle, "Untitled"); + if (description == null) + componentName = registry.annUtils.getDescription(bundle, + "Undescribed"); + return registry.createComponentFrom(this, componentName, description, + bundle, registry.getPreferredLicense(), + registry.getDefaultSharingPolicy()); + } + + @Override + protected void internalRemoveComponent(Component component) + throws ComponentException { + registry.deleteComponent((NewComponent) component); + } + + String getId() { + return id; + } + + public String getUri() { + return uri; + } + + @Override + public boolean equals(Object o) { + if (o instanceof NewComponentFamily) { + NewComponentFamily other = (NewComponentFamily) o; + return registry.equals(other.registry) && id.equals(other.id); + } + return false; + } + + private static final int BASEHASH = NewComponentFamily.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ registry.hashCode() ^ id.hashCode(); + } + + public String getResourceLocation() { + return resource; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java new file mode 100644 index 0000000..5e08b4b --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java @@ -0,0 +1,76 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 io.github.taverna_extras.component.api.License; +import io.github.taverna_extras.component.registry.api.LicenseType; + +class NewComponentLicense implements License { + private NewComponentRegistry registry; + private String id; + private String title; + private String description; + private String abbreviation; + + static final String ELEMENTS = "title,description,unique-name"; + + NewComponentLicense(NewComponentRegistry newComponentRegistry, + LicenseType lt) { + registry = newComponentRegistry; + id = lt.getId(); + title = lt.getTitle(); + description = lt.getDescription(); + abbreviation = lt.getUniqueName(); + } + + String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof NewComponentLicense)) + return false; + NewComponentLicense other = (NewComponentLicense) o; + return registry.equals(other.registry) && id.equals(other.id); + } + + private static final int BASEHASH = NewComponentLicense.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ registry.hashCode() ^ id.hashCode(); + } + + @Override + public String getName() { + return title; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getAbbreviation() { + return abbreviation; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java new file mode 100644 index 0000000..372c853 --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java @@ -0,0 +1,121 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static io.github.taverna_extras.component.utils.SystemUtils.getElementString; + +import java.net.MalformedURLException; +import java.net.URL; + +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.profile.BaseProfileLocator; +import io.github.taverna_extras.component.profile.ComponentProfileImpl; +import io.github.taverna_extras.component.registry.api.ComponentProfileType; +import io.github.taverna_extras.component.registry.api.Description; + +/** + * Profiles managed by the new-interface component registry. + * + * @author Donal Fellows + */ +class NewComponentProfile extends ComponentProfileImpl { + private static final String LOCATION = "content-uri"; + static final String ELEMENTS = LOCATION; + + private final NewComponentRegistry registry; + private String id; + private String location; + private String resource; + private final String uri; + + private static URL contentUrl(ComponentProfileType cpt) + throws ComponentException { + try { + return new URL(cpt.getContentUri()); + } catch (MalformedURLException e) { + throw new ComponentException("bad profile location", e); + } + } + + private static URL getLocationURL(Description cpd) throws ComponentException { + try { + return new URL(getElementString(cpd, LOCATION)); + } catch (MalformedURLException e) { + throw new ComponentException("bad profile location", e); + } + } + + NewComponentProfile(NewComponentRegistry registry, + ComponentProfileType profile, BaseProfileLocator base) + throws ComponentException { + super(registry, contentUrl(profile), base); + this.registry = registry; + uri = profile.getUri(); + id = profile.getId(); + location = profile.getContentUri(); + resource = profile.getResource(); + } + + NewComponentProfile(NewComponentRegistry registry, Description cpd, + BaseProfileLocator base) throws ComponentException { + super(registry, getLocationURL(cpd), base); + this.registry = registry; + uri = cpd.getUri(); + id = cpd.getId(); + location = getElementString(cpd, LOCATION); + resource = cpd.getResource(); + } + + public String getLocation() { + return location; + } + + public String getID() { + return id; + } + + public String getUri() { + return uri; + } + + @Override + public boolean equals(Object o) { + if (o instanceof NewComponentProfile) { + NewComponentProfile other = (NewComponentProfile) o; + return registry.equals(other.registry) && id.equals(other.id); + } + return false; + } + + private static final int BASEHASH = NewComponentProfile.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ registry.hashCode() ^ id.hashCode(); + } + + @Override + public String toString() { + return "Remote Component Profile[" + location + "]"; + } + + public String getResourceLocation() { + return resource; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java new file mode 100644 index 0000000..00a549e --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java @@ -0,0 +1,485 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static org.apache.log4j.Logger.getLogger; +import static io.github.taverna_extras.component.registry.standard.Policy.PRIVATE; +import static io.github.taverna_extras.component.utils.SystemUtils.getElementString; + +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Family; +import io.github.taverna_extras.component.api.License; +import io.github.taverna_extras.component.api.SharingPolicy; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.api.Version.ID; +import io.github.taverna_extras.component.api.profile.Profile; +import io.github.taverna_extras.component.registry.ComponentRegistry; +import io.github.taverna_extras.component.registry.ComponentUtil; +import io.github.taverna_extras.component.registry.ComponentVersionIdentification; +import io.github.taverna_extras.component.registry.api.ComponentDescriptionList; +import io.github.taverna_extras.component.registry.api.ComponentFamilyList; +import io.github.taverna_extras.component.registry.api.ComponentFamilyType; +import io.github.taverna_extras.component.registry.api.ComponentProfileList; +import io.github.taverna_extras.component.registry.api.ComponentProfileType; +import io.github.taverna_extras.component.registry.api.ComponentType; +import io.github.taverna_extras.component.registry.api.Content; +import io.github.taverna_extras.component.registry.api.Description; +import io.github.taverna_extras.component.registry.api.LicenseList; +import io.github.taverna_extras.component.registry.api.LicenseType; +import io.github.taverna_extras.component.registry.api.ObjectFactory; +import io.github.taverna_extras.component.registry.api.Permissions; +import io.github.taverna_extras.component.registry.api.PolicyList; +import io.github.taverna_extras.component.utils.AnnotationUtils; +import io.github.taverna_extras.component.utils.SystemUtils; + +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.security.credentialmanager.CredentialManager; + +class NewComponentRegistry extends ComponentRegistry { + private static final String PROFILE_MIME_TYPE = "application/vnd.taverna.component-profile+xml"; + private static final String T2FLOW_MIME_TYPE = "application/vnd.taverna.t2flow+xml"; + static final Logger logger = getLogger(NewComponentRegistry.class); + static final JAXBContext jaxbContext; + static final Charset utf8; + private static final ObjectFactory objectFactory = new ObjectFactory(); + + // service URIs + private static final String COMPONENT_SERVICE = "/component.xml"; + private static final String COMPONENT_FAMILY_SERVICE = "/component-family.xml"; + private static final String COMPONENT_PROFILE_SERVICE = "/component-profile.xml"; + private static final String COMPONENT_LIST = "/components.xml"; + private static final String COMPONENT_FAMILY_LIST = "/component-families.xml"; + private static final String COMPONENT_PROFILE_LIST = "/component-profiles.xml"; + private static final String WORKFLOW_SERVICE = "/workflow.xml"; + private static final String PACK_SERVICE = "/pack.xml"; + private static final String FILE_SERVICE = "/file.xml"; + private static final String LICENSE_LIST = "/licenses.xml"; + private static final String POLICY_LIST = "/policies.xml"; + + static { + JAXBContext c = null; + Charset cs = null; + try { + c = JAXBContext.newInstance(ComponentDescriptionList.class, + ComponentFamilyList.class, ComponentProfileList.class, + ComponentType.class, ComponentFamilyType.class, + ComponentProfileType.class, PolicyList.class, + LicenseList.class); + cs = Charset.forName("UTF-8"); + } catch (JAXBException e) { + throw new Error("failed to build context", e); + } catch (UnsupportedCharsetException e) { + throw new Error("failed to find charset", e); + } finally { + jaxbContext = c; + utf8 = cs; + } + } + + Client client; + private final CredentialManager cm; + private final ComponentUtil util; + private final SystemUtils system; + final AnnotationUtils annUtils; + + protected NewComponentRegistry(CredentialManager cm, URL registryBase, + ComponentUtil util, SystemUtils system, AnnotationUtils annUtils) throws ComponentException { + super(registryBase); + this.cm = cm; + this.util = util; + this.system = system; + this.annUtils = annUtils; + } + + private void checkClientCreated() throws ComponentException { + try { + if (client == null) + client = new Client(jaxbContext, super.getRegistryBase(), cm); + } catch (Exception e) { + throw new ComponentException("Unable to access registry", e); + } + } + + private List<Description> listComponentFamilies(String profileUri) + throws ComponentException { + checkClientCreated(); + return client.get(ComponentFamilyList.class, COMPONENT_FAMILY_LIST, + "component-profile=" + profileUri, + "elements=" + NewComponentFamily.ELEMENTS).getPack(); + } + + ComponentType getComponentById(String id, Integer version, String elements) + throws ComponentException { + checkClientCreated(); + + if (version != null) { + return client.get(ComponentType.class, WORKFLOW_SERVICE, + "id=" + id, "version=" + version, "elements=" + elements); + } + return client.get(ComponentType.class, WORKFLOW_SERVICE, "id=" + id, + "elements=" + elements); + } + + @SuppressWarnings("unused") + private ComponentFamilyType getComponentFamilyById(String id, + String elements) throws ComponentException { + checkClientCreated(); + + return client.get(ComponentFamilyType.class, PACK_SERVICE, "id=" + id, + "elements=" + elements); + } + + private ComponentProfileType getComponentProfileById(String id, + String elements) throws ComponentException { + checkClientCreated(); + + return client.get(ComponentProfileType.class, FILE_SERVICE, "id=" + id, + "elements=" + elements); + } + + @Override + protected void populateFamilyCache() throws ComponentException { + for (Profile pr : getComponentProfiles()) { + NewComponentProfile p = (NewComponentProfile) pr; + for (Description cfd : listComponentFamilies(p + .getResourceLocation())) + familyCache.put(getElementString(cfd, "title"), + new NewComponentFamily(this, p, cfd, util)); + } + } + + @Override + protected Family internalCreateComponentFamily(String familyName, + Profile componentProfile, String description, License license, + SharingPolicy sharingPolicy) throws ComponentException { + NewComponentProfile profile = (NewComponentProfile) componentProfile; + + checkClientCreated(); + + return new NewComponentFamily(this, profile, client.post( + ComponentFamilyType.class, + objectFactory.createPack(makeComponentFamilyCreateRequest( + profile, familyName, description, license, + sharingPolicy)), COMPONENT_FAMILY_SERVICE, "elements=" + + NewComponentFamily.ELEMENTS), util); + } + + @Override + protected void internalRemoveComponentFamily(Family componentFamily) + throws ComponentException { + NewComponentFamily ncf = (NewComponentFamily) componentFamily; + checkClientCreated(); + + client.delete(WORKFLOW_SERVICE, "id=" + ncf.getId()); + } + + @Override + protected void populateProfileCache() throws ComponentException { + checkClientCreated(); + + for (Description cpd : client.get(ComponentProfileList.class, + COMPONENT_PROFILE_LIST, + "elements=" + NewComponentProfile.ELEMENTS).getFile()) + if (cpd.getUri() != null && !cpd.getUri().isEmpty()) + profileCache.add(new NewComponentProfile(this, cpd, util + .getBaseProfileLocator())); + } + + @Override + protected Profile internalAddComponentProfile(Profile componentProfile, + License license, SharingPolicy sharingPolicy) + throws ComponentException { + if (componentProfile == null) + throw new ComponentException("component profile must not be null"); + try { + if (componentProfile instanceof NewComponentProfile) { + NewComponentProfile profile = (NewComponentProfile) componentProfile; + if (profile.getComponentRegistry().equals(this)) + return new NewComponentProfile(this, + getComponentProfileById(profile.getId(), + NewComponentProfile.ELEMENTS), + util.getBaseProfileLocator()); + } + } catch (ComponentException e) { + // Do nothing but fall through + } + checkClientCreated(); + + return new NewComponentProfile(this, client.post( + ComponentProfileType.class, objectFactory + .createFile(makeComponentProfileCreateRequest( + componentProfile.getName(), + componentProfile.getDescription(), + componentProfile.getXML(), license, + sharingPolicy)), COMPONENT_PROFILE_SERVICE, + "elements=" + NewComponentProfile.ELEMENTS), + util.getBaseProfileLocator()); + } + + public Permissions getPermissions(SharingPolicy userSharingPolicy) { + if (userSharingPolicy == null) + userSharingPolicy = getDefaultSharingPolicy(); + return ((Policy) userSharingPolicy).getPermissionsElement(); + } + + private ComponentProfileType makeComponentProfileCreateRequest( + String title, String description, String content, License license, + SharingPolicy sharingPolicy) throws ComponentException { + ComponentProfileType profile = new ComponentProfileType(); + + profile.setFilename(title + ".xml"); + profile.setTitle(title); + profile.setTitle(description); + profile.setContentType(PROFILE_MIME_TYPE); + profile.setContent(new Content()); + profile.getContent().setEncoding("base64"); + profile.getContent().setType("binary"); + profile.getContent().setValue(content.getBytes(utf8)); + if (license == null) + license = getPreferredLicense(); + profile.setLicenseType(new Description()); + profile.getLicenseType().getContent().add(license.getAbbreviation()); + profile.setPermissions(getPermissions(sharingPolicy)); + + return profile; + } + + private ComponentFamilyType makeComponentFamilyCreateRequest( + NewComponentProfile profile, String familyName, String description, + License license, SharingPolicy sharingPolicy) + throws ComponentException { + ComponentFamilyType familyDoc = new ComponentFamilyType(); + + familyDoc.setComponentProfile(profile.getResourceLocation()); + familyDoc.setDescription(description); + familyDoc.setTitle(familyName); + if (license == null) + license = getPreferredLicense(); + familyDoc.setLicenseType(new Description()); + familyDoc.getLicenseType().getContent().add(license.getAbbreviation()); + familyDoc.setPermissions(getPermissions(sharingPolicy)); + + return familyDoc; + } + + private ComponentType makeComponentVersionCreateRequest(String title, + String description, WorkflowBundle content, NewComponentFamily family, + License license, SharingPolicy sharingPolicy) + throws ComponentException { + ComponentType comp = new ComponentType(); + + comp.setTitle(title); + comp.setDescription(description); + if (family != null) + comp.setComponentFamily(family.getResourceLocation()); + comp.setContentType(T2FLOW_MIME_TYPE); + comp.setContent(new Content()); + comp.getContent().setEncoding("base64"); + comp.getContent().setType("binary"); + comp.getContent().setValue(system.serializeBundle(content)); + if (license == null) + license = getPreferredLicense(); + if (license != null) { + comp.setLicenseType(new Description()); + comp.getLicenseType().getContent().add(license.getAbbreviation()); + } + comp.setPermissions(getPermissions(sharingPolicy)); + + return comp; + } + + private static final boolean DO_LIST_POLICIES = false; + + private List<Description> listPolicies() throws ComponentException { + checkClientCreated(); + return client.get(PolicyList.class, POLICY_LIST, "type=group") + .getPolicy(); + } + + @Override + protected void populatePermissionCache() { + permissionCache.add(Policy.PUBLIC); + permissionCache.add(Policy.PRIVATE); + try { + if (DO_LIST_POLICIES) + for (Description d : listPolicies()) + permissionCache.add(new Policy.Group(d.getId())); + } catch (ComponentException e) { + logger.warn("failed to fetch sharing policies", e); + } + } + + private List<LicenseType> listLicenses() throws ComponentException { + checkClientCreated(); + + return client.get(LicenseList.class, LICENSE_LIST, + "elements=" + NewComponentLicense.ELEMENTS).getLicense(); + } + + @Override + protected void populateLicenseCache() { + try { + for (LicenseType lt : listLicenses()) + licenseCache.add(new NewComponentLicense(this, lt)); + } catch (ComponentException e) { + logger.warn("failed to fetch licenses", e); + } + } + + @Override + public License getPreferredLicense() throws ComponentException { + return getLicenseByAbbreviation(getNameOfPreferredLicense()); + } + + public String getNameOfPreferredLicense() { + return "by-nd"; + } + + public SharingPolicy getDefaultSharingPolicy() { + return PRIVATE; + } + + private List<Description> listComponents(String query, String prefixes) + throws ComponentException { + checkClientCreated(); + + return client.get(ComponentDescriptionList.class, COMPONENT_LIST, + "query=" + query, "prefixes=" + prefixes, + "elements=" + NewComponent.ELEMENTS).getWorkflow(); + } + + @Override + public Set<ID> searchForComponents(String prefixes, String text) + throws ComponentException { + HashSet<ID> versions = new HashSet<>(); + for (Description cd : listComponents(text, prefixes)) { + NewComponent nc = null; + for (Family f : getComponentFamilies()) { + nc = (NewComponent) ((NewComponentFamily) f) + .getComponent(getElementString(cd, "title")); + if (nc != null) + break; + } + if (nc != null) + versions.add(new ComponentVersionIdentification( + getRegistryBase(), nc.getFamily().getName(), nc + .getName(), cd.getVersion())); + else + logger.warn("could not construct component for " + cd.getUri()); + } + return versions; + } + + private List<Description> listComponents(String familyUri) + throws ComponentException { + checkClientCreated(); + + return client.get(ComponentDescriptionList.class, COMPONENT_LIST, + "component-family=" + familyUri, + "elements=" + NewComponent.ELEMENTS).getWorkflow(); + } + + protected List<Component> listComponents(NewComponentFamily family) + throws ComponentException { + List<Component> result = new ArrayList<>(); + for (Description cd : listComponents(family.getResourceLocation())) + result.add(new NewComponent(this, family, cd, system)); + return result; + } + + protected void deleteComponent(NewComponent component) + throws ComponentException { + checkClientCreated(); + + client.delete(WORKFLOW_SERVICE, "id=" + component.getId()); + } + + protected Version createComponentFrom(NewComponentFamily family, + String componentName, String description, + WorkflowBundle implementation, License license, + SharingPolicy sharingPolicy) throws ComponentException { + checkClientCreated(); + + ComponentType ct = client.post(ComponentType.class, objectFactory + .createWorkflow(makeComponentVersionCreateRequest( + componentName, description, implementation, family, + license, sharingPolicy)), COMPONENT_SERVICE, + "elements=" + NewComponent.ELEMENTS); + NewComponent nc = new NewComponent(this, family, ct, system); + return nc.new Version(ct.getVersion(), description, implementation); + } + + protected Version createComponentVersionFrom(NewComponent component, + String componentName, String description, + WorkflowBundle implementation, License license, + SharingPolicy sharingPolicy) throws ComponentException { + checkClientCreated(); + + ComponentType ct = client.post(ComponentType.class, objectFactory + .createWorkflow(makeComponentVersionCreateRequest( + componentName, description, implementation, + component.family, license, sharingPolicy)), + COMPONENT_SERVICE, "id=" + component.getId(), "elements=" + + NewComponent.ELEMENTS); + return component.new Version(ct.getVersion(), description, + implementation); + } + + public License getLicense(String name) throws ComponentException { + for (License l : getLicenses()) + if (l.getAbbreviation().equals(name)) + return l; + return null; + } + + @Override + public boolean equals(Object o) { + // Careful! Java's URL equality IS BROKEN! + if (o != null && o instanceof NewComponentRegistry) { + NewComponentRegistry other = (NewComponentRegistry) o; + return getRegistryBaseString() + .equals(other.getRegistryBaseString()); + } + return false; + } + + private static final int BASEHASH = NewComponentRegistry.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ getRegistryBaseString().hashCode(); + } + + @Override + public String getRegistryTypeName() { + return "Component API"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java new file mode 100644 index 0000000..43dc37d --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java @@ -0,0 +1,83 @@ +package io.github.taverna_extras.component.registry.standard; +/* + * 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 static io.github.taverna_extras.component.registry.standard.NewComponentRegistry.jaxbContext; +import static io.github.taverna_extras.component.registry.standard.NewComponentRegistry.logger; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.registry.ComponentRegistry; +import io.github.taverna_extras.component.registry.ComponentUtil; +import io.github.taverna_extras.component.utils.AnnotationUtils; +import io.github.taverna_extras.component.utils.SystemUtils; +import org.apache.taverna.security.credentialmanager.CredentialManager; +import org.springframework.beans.factory.annotation.Required; + +public class NewComponentRegistryFactory { + private final Map<String, NewComponentRegistry> componentRegistries = new HashMap<>(); + private CredentialManager cm; + private ComponentUtil util; + private SystemUtils system; + private AnnotationUtils annUtils; + + @Required + public void setCredentialManager(CredentialManager cm) { + this.cm = cm; + } + + @Required + public void setComponentUtil(ComponentUtil util) { + this.util = util; + } + + @Required + public void setSystemUtils(SystemUtils system) { + this.system = system; + } + + @Required + public void setAnnotationUtils(AnnotationUtils annUtils) { + this.annUtils = annUtils; + } + + public synchronized ComponentRegistry getComponentRegistry(URL registryBase) + throws ComponentException { + if (!componentRegistries.containsKey(registryBase.toExternalForm())) { + logger.debug("constructing registry instance for " + registryBase); + componentRegistries.put(registryBase.toExternalForm(), + new NewComponentRegistry(cm, registryBase, util, system, + annUtils)); + } + return componentRegistries.get(registryBase.toExternalForm()); + } + + public boolean verifyBase(URL registryBase) { + try { + return new Client(jaxbContext, registryBase, false, cm).verify(); + } catch (Exception e) { + logger.info("failed to construct connection client to " + + registryBase, e); + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java new file mode 100644 index 0000000..3b521af --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java @@ -0,0 +1,136 @@ +package io.github.taverna_extras.component.registry.standard; + +import static java.lang.System.identityHashCode; +import static io.github.taverna_extras.component.registry.api.Privilege.DOWNLOAD; +import static io.github.taverna_extras.component.registry.api.Privilege.VIEW; + +import io.github.taverna_extras.component.api.SharingPolicy; +import io.github.taverna_extras.component.registry.api.Permissions; +import io.github.taverna_extras.component.registry.api.Permissions.Permission; + +abstract class Policy implements SharingPolicy { + public static final SharingPolicy PUBLIC = new Public(); + public static final SharingPolicy PRIVATE = new Private(); + + Policy() { + } + + public abstract Permissions getPermissionsElement(); + + public static SharingPolicy getPolicy(Permissions perm) { + if (perm == null) + return PRIVATE; + if (perm.getGroupPolicyId() != null) + return new Group(perm.getGroupPolicyId()); + for (Permission p : perm.getPermission()) + if (p.getId() != null) + return new Group(p.getId().toString(), perm); + return PUBLIC; + } + + @Override + public boolean equals(Object o) { + if (o == null || !(o instanceof Policy)) + return false; + return equals((Policy) o); + } + + @Override + public abstract int hashCode(); + + protected abstract boolean equals(Policy p); + + static class Public extends Policy { + @Override + public String getName() { + return "Public"; + } + + @Override + public Permissions getPermissionsElement() { + Permission.Privilege privView = new Permission.Privilege(); + privView.setType(VIEW); + Permission.Privilege privDownload = new Permission.Privilege(); + privDownload.setType(DOWNLOAD); + Permission perm = new Permission(); + perm.setCategory("public"); + perm.getPrivilege().add(privView); + perm.getPrivilege().add(privDownload); + Permissions result = new Permissions(); + result.getPermission().add(perm); + return result; + } + + @Override + protected boolean equals(Policy p) { + return p instanceof Public; + } + + @Override + public int hashCode() { + return identityHashCode(PUBLIC); + } + } + + static class Private extends Policy { + @Override + public String getName() { + return "Private"; + } + + @Override + public Permissions getPermissionsElement() { + return null; + } + + @Override + protected boolean equals(Policy p) { + return p instanceof Private; + } + + @Override + public int hashCode() { + return identityHashCode(PRIVATE); + } + } + + static class Group extends Policy { + private String id; + private Permissions p; + + public Group(String id) { + this.id = id; + } + + public Group(String id, Permissions p) { + this.id = id; + this.p = p; + } + + @Override + public String getName() { + return "Group(" + id + ")"; + } + + @Override + public Permissions getPermissionsElement() { + if (p != null) + return p; + Permissions result = new Permissions(); + result.setGroupPolicyId(id); + return result; + } + + @Override + protected boolean equals(Policy p) { + return (p instanceof Group) && id.equals(((Group) p).id); + } + + private static final int BASEHASH = Group.class.hashCode(); + + @Override + public int hashCode() { + return BASEHASH ^ id.hashCode(); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java new file mode 100644 index 0000000..e6a709b --- /dev/null +++ b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java @@ -0,0 +1,43 @@ +package io.github.taverna_extras.component.registry.standard.annotations; +/* + * 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 static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.CLASS; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Marks a constructor, field, method or parameter as unused. Unused members + * exist for the purpose of documentation or completeness. + * + * @author Donal Fellows + */ +@Documented +@Target({ CONSTRUCTOR, FIELD, METHOD, PARAMETER, TYPE }) +@Retention(CLASS) +public @interface Unused { + +}
