Java tutorial
/******************************************************************************* * Copyright (c) 2012-2016 University of Stuttgart. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and the Apache License 2.0 which both accompany this distribution, * and are available at http://www.eclipse.org/legal/epl-v10.html * and http://www.apache.org/licenses/LICENSE-2.0 * * Contributors: * Oliver Kopp - initial API and implementation * Lukas Harzenetter, Nicole Keppler - forceDelete for Namespaces * Tino Stadelmaier, Philipp Meyer - rename id and/or Namespace *******************************************************************************/ package org.eclipse.winery.repository.client; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.eclipse.winery.common.Util; import org.eclipse.winery.common.beans.NamespaceIdOptionalName; import org.eclipse.winery.common.constants.MimeTypes; import org.eclipse.winery.common.ids.GenericId; import org.eclipse.winery.common.ids.IdUtil; import org.eclipse.winery.common.ids.Namespace; import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; import org.eclipse.winery.common.interfaces.QNameAlreadyExistsException; import org.eclipse.winery.common.interfaces.QNameWithName; import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; import org.eclipse.winery.model.tosca.TDefinitions; import org.eclipse.winery.model.tosca.TEntityType; import org.eclipse.winery.model.tosca.TExtensibleElements; import org.eclipse.winery.model.tosca.TTopologyTemplate; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory; import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; import com.sun.jersey.core.util.MultivaluedMapImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; public final class WineryRepositoryClient implements IWineryRepositoryClient { private static final Logger LOGGER = LoggerFactory.getLogger(WineryRepositoryClient.class); // switch off validation, currently causes more trouble than it brings private static final boolean VALIDATING = false; private final Collection<String> knownURIs = new HashSet<String>(); private final Collection<WebResource> repositoryResources = new HashSet<WebResource>(); private final Client client; private final ObjectMapper mapper = new ObjectMapper(); private final Map<Class<? extends TEntityType>, Map<QName, TEntityType>> entityTypeDataCache; private final Map<GenericId, String> nameCache; private static final int MAX_NAME_CACHE_SIZE = 1000; private String primaryRepository = null; private WebResource primaryWebResource = null; // thread-safe JAXB as inspired by https://jaxb.java.net/guide/Performance_and_thread_safety.html // The other possibility: Each subclass sets JAXBContext.newInstance(theSubClass.class); in its static {} part. // This seems to be more complicated than listing all subclasses in initContext public final static JAXBContext context = WineryRepositoryClient.initContext(); // schema aware document builder private final DocumentBuilder toscaDocumentBuilder; // taken from http://stackoverflow.com/a/15253142/873282 private static class ConnectionFactory implements HttpURLConnectionFactory { Proxy proxy; private void initializeProxy() { this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888)); } @Override public HttpURLConnection getHttpURLConnection(URL url) throws IOException { this.initializeProxy(); return (HttpURLConnection) url.openConnection(this.proxy); } } /** * Creates the client without the use of any proxy */ public WineryRepositoryClient() { this(false); } /** * @param useProxy if a debugging proxy should be used * * @throws IllegalStateException if DOM parser could not be created */ public WineryRepositoryClient(boolean useProxy) { ClientConfig clientConfig = new DefaultClientConfig(); clientConfig.getClasses().add(JacksonJsonProvider.class); if (useProxy) { URLConnectionClientHandler ch = new URLConnectionClientHandler(new ConnectionFactory()); this.client = new Client(ch, clientConfig); } else { this.client = Client.create(clientConfig); } this.entityTypeDataCache = new HashMap<>(); this.nameCache = new HashMap<>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); if (WineryRepositoryClient.VALIDATING) { factory.setValidating(true); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema; URL resource = this.getClass().getResource("/TOSCA-v1.0.xsd"); try { schema = schemaFactory.newSchema(resource); } catch (SAXException e) { throw new IllegalStateException("Schema could not be initalized", e); } factory.setSchema(schema); } try { this.toscaDocumentBuilder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new IllegalStateException("document builder could not be initalized", e); } /* TODO: include this somehow - in the case of VALIDATING Does not work with TTopolgoyTemplate as this is not allowed in the root of an XML document this.toscaDocumentBuilder.setErrorHandler(new ErrorHandler() { @Override public void warning(SAXParseException arg0) throws SAXException { throw arg0; } @Override public void fatalError(SAXParseException arg0) throws SAXException { throw arg0; } @Override public void error(SAXParseException arg0) throws SAXException { throw arg0; } }); */ } private static JAXBContext initContext() { // code copied+adapted from JAXBSupport JAXBContext context; try { // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282 // @formatter:off context = JAXBContext.newInstance(TDefinitions.class, WinerysPropertiesDefinition.class); // @formatter:on } catch (JAXBException e) { LOGGER.error("Could not initialize JAXBContext", e); throw new IllegalStateException(e); } return context; } /** * Creates a marshaller * * @throws IllegalStateException if marshaller could not be instantiated */ private static Marshaller createMarshaller() { // code copied+adapted from JAXBSupport Marshaller m; try { m = WineryRepositoryClient.context.createMarshaller(); // pretty printed output is required as the XML is sent 1:1 to the browser for editing m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // not possible here: m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper); } catch (JAXBException e) { LOGGER.error("Could not instantiate marshaller", e); throw new IllegalStateException(e); } return m; } /** * Creates a unmarshaller * * @throws IllegalStateException if unmarshaller could not be instantiated */ private static Unmarshaller createUnmarshaller() { Unmarshaller um; try { um = WineryRepositoryClient.context.createUnmarshaller(); } catch (JAXBException e) { LOGGER.error("Could not instantiate unmarshaller", e); throw new IllegalStateException(e); } return um; } /*** methods directly from IWineryRepositoryClient ***/ /** * {@inheritDoc} */ @Override public void addRepository(String uri) { if (this.knownURIs.add(uri)) { // URI is not already known, add a new resource WebResource wr = this.client.resource(uri); this.repositoryResources.add(wr); if (this.primaryRepository == null) { this.primaryRepository = uri; this.primaryWebResource = wr; } } } /** * {@inheritDoc} */ @Override public String getPrimaryRepository() { return this.primaryRepository; } /** * {@inheritDoc} */ @Override public void setPrimaryRepository(String uri) { this.addRepository(uri); // now we are sure that a web resource for the uri exists this.primaryRepository = uri; // Update the reference to the primaryWebResource // The appropriate resource has been created via // this.addRepository(uri); for (WebResource wr : this.repositoryResources) { if (wr.getURI().equals(uri)) { this.primaryWebResource = wr; break; } } assert (this.primaryWebResource != null); } /*** methods directly from IWineryRepository ***/ /** * {@inheritDoc} */ @Override public SortedSet<String> getNamespaces() { SortedSet<String> res = new TreeSet<String>(); for (WebResource wr : this.repositoryResources) { WebResource namespacesResource = wr.path("admin").path("namespaces"); // this could be parsed using JAXB // (http://jersey.java.net/nonav/documentation/latest/json.html), // but we are short in time, so we do a quick hack String nsList = namespacesResource.accept(MediaType.APPLICATION_JSON).get(String.class); LOGGER.trace(nsList); List<String> nsListList; try { nsListList = this.mapper.readValue(nsList, new TypeReference<List<String>>() { }); } catch (Exception e) { LOGGER.error(e.getMessage(), e); continue; } res.addAll(nsListList); } return res; } /** * Base method for getQNameListOfAllTypes and getAllTypes. */ private <T extends TExtensibleElements> Map<WebResource, List<NamespaceIdOptionalName>> getWRtoNamespaceAndIdListMapOfAllTypes( String path) { Map<WebResource, List<NamespaceIdOptionalName>> res = new HashMap<WebResource, List<NamespaceIdOptionalName>>(); for (WebResource wr : this.repositoryResources) { WebResource componentListResource = wr.path(path); // this could be parsed using JAXB // (http://jersey.java.net/nonav/documentation/latest/json.html), // but we are short in time, so we do a quick hack // The result also contains the optional name String idList = componentListResource.accept(MediaType.APPLICATION_JSON).get(String.class); LOGGER.trace(idList); List<NamespaceIdOptionalName> nsAndIdList; try { nsAndIdList = this.mapper.readValue(idList, new TypeReference<List<NamespaceIdOptionalName>>() { }); } catch (Exception e) { LOGGER.error(e.getMessage(), e); continue; } res.put(wr, nsAndIdList); } return res; } /** * {@inheritDoc} */ @Override public String getName(GenericId id) { if (this.nameCache.containsKey(id)) { return this.nameCache.get(id); } String name = null; for (WebResource wr : this.repositoryResources) { String pathFragment = IdUtil.getURLPathFragment(id); WebResource resource = wr.path(pathFragment).path("name"); ClientResponse response = resource.accept(MediaType.TEXT_PLAIN_TYPE).get(ClientResponse.class); if (response.getClientResponseStatus() == ClientResponse.Status.OK) { name = response.getEntity(String.class); // break loop as the first match is the final result break; } } // if all resources did not return "OK", "null" is returned if (name != null) { if (this.nameCache.size() > WineryRepositoryClient.MAX_NAME_CACHE_SIZE) { // if cache grew too large, clear it. this.nameCache.clear(); } this.nameCache.put(id, name); } return name; } /** * {@inheritDoc} */ @Override public <T extends TExtensibleElements> List<QName> getQNameListOfAllTypes(Class<T> className) { String path = Util.getURLpathFragmentForCollection(className); Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this .getWRtoNamespaceAndIdListMapOfAllTypes(path); Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes .values(); List<QName> res = new ArrayList<QName>(namespaceAndIdListCollection.size()); for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) { for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) { QName qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId()); res.add(qname); } } return res; } /** * Fetches java objects at a given URL * * @param path the path to use. E.g., "nodetypes" for node types, ... * @param className the class of the expected return type. May be * TDefinitions or TEntityType. TDefinitions the mode is that the * import statement are recursively resolved and added to the * returned Defintitions elment */ // we convert an object to T if it T is definitions // does not work without compiler error @SuppressWarnings("unchecked") private <T extends TExtensibleElements> Collection<T> getAllTypes(String path, Class<T> className) { Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this .getWRtoNamespaceAndIdListMapOfAllTypes(path); // now we now all QNames. We have to fetch the full content now Collection<T> res = new LinkedList<T>(); for (WebResource wr : wRtoNamespaceAndIdListMapOfAllTypes.keySet()) { WebResource componentListResource = wr.path(path); // go through all ids and fetch detailed information on each // type for (NamespaceIdOptionalName nsAndId : wRtoNamespaceAndIdListMapOfAllTypes.get(wr)) { TDefinitions definitions = WineryRepositoryClient.getDefinitions(componentListResource, nsAndId.getNamespace(), nsAndId.getId()); if (definitions == null) { // try next one continue; } T result; if (TDefinitions.class.equals(className)) { // mode: complete definitions result = (T) definitions; } else { // mode: only the nested element // convention: first element in list is the element we look for if (definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) { result = null; LOGGER.error("Type {}/{} was found, but did not return any data", nsAndId.getNamespace(), nsAndId.getId()); } else { LOGGER.trace("Probably found valid data for {}/{}", nsAndId.getNamespace(), nsAndId.getId()); result = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); // caching disabled as we also handle TServiceTemplates //this.cache((TEntityType) result, new QName(nsAndId.getNamespace(), nsAndId.getId())); } } // TODO: if multiple repositories are used, the new element // should be put "sorted" into the list. This could be done by // add(parsedResult, index), where index is calculated by // incrementing index as long as the current element is smaller // than the element to insert. if (result != null) { res.add(result); } } } return res; } /** * Caches the TEntityType data of a QName to avoid multiple get requests * * NOT thread safe */ private void cache(TEntityType et, QName qName) { Map<QName, TEntityType> map; if ((map = this.entityTypeDataCache.get(et.getClass())) == null) { map = new HashMap<>(); this.entityTypeDataCache.put(et.getClass(), map); } else { // quick hack to keep cache size small if (map.size() > 1000) { map.clear(); } } map.put(qName, et); } private static WebResource getTopologyTemplateWebResource(WebResource base, QName serviceTemplate) { String nsEncoded = Util.DoubleURLencode(serviceTemplate.getNamespaceURI()); String idEncoded = Util.DoubleURLencode(serviceTemplate.getLocalPart()); WebResource res = base.path("servicetemplates").path(nsEncoded).path(idEncoded).path("topologytemplate"); return res; } /** * {@inheritDoc} */ @Override public Collection<QNameWithName> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) { // inspired by getQNameListOfAllTypes String path = Util.getRootPathFragment(clazz); Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this .getWRtoNamespaceAndIdListMapOfAllTypes(path); Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes .values(); List<QNameWithName> res = new ArrayList<QNameWithName>(namespaceAndIdListCollection.size()); for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) { for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) { QNameWithName qn = new QNameWithName(); qn.qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId()); qn.name = namespaceAndId.getName(); res.add(qn); } } return res; } /** * {@inheritDoc} */ @Override public <T extends TExtensibleElements> Collection<T> getAllTypes(Class<T> c) { String urlPathFragment = Util.getURLpathFragmentForCollection(c); Collection<T> allTypes = this.getAllTypes(urlPathFragment, c); return allTypes; } @Override @SuppressWarnings("unchecked") public <T extends TEntityType> T getType(QName qname, Class<T> type) { T res = null; if (this.entityTypeDataCache.containsKey(type)) { Map<QName, TEntityType> map = this.entityTypeDataCache.get(type); if (map.containsKey(qname)) { res = (T) map.get(qname); } } if (res == null) { // not yet seen, try to fetch resource for (WebResource wr : this.repositoryResources) { String path = Util.getURLpathFragmentForCollection(type); TDefinitions definitions = WineryRepositoryClient.getDefinitions(wr, path, qname.getNamespaceURI(), qname.getLocalPart()); if (definitions == null) { // in case of an error, just try the next one continue; } res = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); this.cache(res, qname); break; } } return res; } /** * Tries to retrieve a TDefinitions from the given resource / encoded(ns) / * encoded(localPart) * * @return null if 404 or other error */ private static TDefinitions getDefinitions(WebResource wr, String path, String ns, String localPart) { WebResource componentListResource = wr.path(path); return WineryRepositoryClient.getDefinitions(componentListResource, ns, localPart); } /** * Tries to retrieve a TDefinitions from the given resource / encoded(ns) / * encoded(localPart) * * @return null if 404 or other error */ private static TDefinitions getDefinitions(WebResource componentListResource, String ns, String localPart) { // we need double encoding as the client decodes the URL once String nsEncoded = Util.DoubleURLencode(ns); String idEncoded = Util.DoubleURLencode(localPart); WebResource instanceResource = componentListResource.path(nsEncoded).path(idEncoded); // TODO: org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsWithAssociatedThings() could be used to do the resolving at the server ClientResponse response = instanceResource.accept(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS) .get(ClientResponse.class); if (response.getStatus() != 200) { // also handles 404 return null; } TDefinitions definitions; try { Unmarshaller um = WineryRepositoryClient.createUnmarshaller(); definitions = (TDefinitions) um.unmarshal(response.getEntityInputStream()); } catch (JAXBException e) { LOGGER.error("Could not umarshal TDefinitions", e); // try next service return null; } return definitions; } /** * {@inheritDoc} */ @Override public <T extends TEntityType> Collection<TDefinitions> getAllTypesWithAssociatedElements(Class<T> c) { String urlPathFragment = Util.getURLpathFragmentForCollection(c); Collection<TDefinitions> allTypes = this.getAllTypes(urlPathFragment, TDefinitions.class); return allTypes; } /** * * @param stream the stream to parse * @return null if document is invalid */ private Document parseAndValidateTOSCAXML(InputStream stream) { Document document; try { document = this.toscaDocumentBuilder.parse(stream); } catch (SAXException | IOException e) { LOGGER.debug("Could not parse TOSCA file", e); return null; } return document; } /** * {@inheritDoc} */ @Override public TTopologyTemplate getTopologyTemplate(QName serviceTemplate) { // we try all repositories until the first hit for (WebResource wr : this.repositoryResources) { WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(wr, serviceTemplate); ClientResponse response = r.accept(MediaType.TEXT_XML).get(ClientResponse.class); if (response.getClientResponseStatus() == ClientResponse.Status.OK) { TTopologyTemplate topologyTemplate; Document doc = this.parseAndValidateTOSCAXML(response.getEntityInputStream()); if (doc == null) { // no valid document return null; } try { topologyTemplate = WineryRepositoryClient.createUnmarshaller() .unmarshal(doc.getDocumentElement(), TTopologyTemplate.class).getValue(); } catch (JAXBException e) { LOGGER.debug("Could not parse topology, returning null", e); return null; } // first hit: immediately stop and return result return topologyTemplate; } } // nothing found return null; } /** * {@inheritDoc} */ @Override public void setTopologyTemplate(QName serviceTemplate, TTopologyTemplate topologyTemplate) throws Exception { WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(this.primaryWebResource, serviceTemplate); String xmlAsString = Util.getXMLAsString(TTopologyTemplate.class, topologyTemplate); ClientResponse response = r.type(MediaType.TEXT_XML).put(ClientResponse.class, xmlAsString); LOGGER.debug(response.toString()); int status = response.getStatus(); if ((status < 200) || (status >= 300)) { throw new Exception(response.toString()); } } /** * {@inheritDoc} */ @Override public QName getArtifactTypeQNameForExtension(String extension) { // we try all repositories until the first hit for (WebResource wr : this.repositoryResources) { WebResource artifactTypesResource = wr.path("artifacttypes").queryParam("extension", extension); ClientResponse response = artifactTypesResource.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class); if (response.getClientResponseStatus() == ClientResponse.Status.OK) { QName res = QName.valueOf(response.getEntity(String.class)); return res; } } return null; } /** * {@inheritDoc} * * Does NOT check for global QName uniqueness, only in the scope of all * artifact templates */ @Override public void createArtifactTemplate(QName qname, QName artifactType) throws QNameAlreadyExistsException { WebResource artifactTemplates = this.primaryWebResource.path("artifacttemplates"); MultivaluedMap<String, String> map = new MultivaluedMapImpl(); map.putSingle("namespace", qname.getNamespaceURI()); map.putSingle("name", qname.getLocalPart()); map.putSingle("type", artifactType.toString()); ClientResponse response = artifactTemplates.type(MediaType.APPLICATION_FORM_URLENCODED) .accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, map); if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) { // TODO: pass ClientResponse.Status somehow // TODO: more fine grained checking for error message. Not all // failures are that the QName already exists LOGGER.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString())); throw new QNameAlreadyExistsException(); } // no further return is made } /** * {@inheritDoc} */ @Override public void createComponent(QName qname, Class<? extends TOSCAComponentId> idClass) throws QNameAlreadyExistsException { WebResource resource = this.primaryWebResource.path(Util.getRootPathFragment(idClass)); MultivaluedMap<String, String> map = new MultivaluedMapImpl(); map.putSingle("namespace", qname.getNamespaceURI()); map.putSingle("name", qname.getLocalPart()); ClientResponse response = resource.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.TEXT_PLAIN) .post(ClientResponse.class, map); if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) { // TODO: pass ClientResponse.Status somehow // TODO: more fine grained checking for error message. Not all failures are that the QName already exists LOGGER.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString())); throw new QNameAlreadyExistsException(); } // no further return is made } @Override public void forceDelete(GenericId id) throws IOException { String pathFragment = IdUtil.getURLPathFragment(id); for (WebResource wr : this.repositoryResources) { ClientResponse response = wr.path(pathFragment).delete(ClientResponse.class); if ((response.getClientResponseStatus() != ClientResponse.Status.NO_CONTENT) || (response.getClientResponseStatus() != ClientResponse.Status.NOT_FOUND)) { LOGGER.debug(String.format("Error %d when deleting id %s from URI %s", response.getStatus(), id.toString(), wr.getURI().toString())); } } } private class NamespaceAndIdAsString { String namespace; String id; } /** * @param oldId the old id * @param newId the new id */ @Override public void rename(TOSCAComponentId oldId, TOSCAComponentId newId) throws IOException { String pathFragment = IdUtil.getURLPathFragment(oldId); NamespaceAndIdAsString namespaceAndIdAsString = new NamespaceAndIdAsString(); namespaceAndIdAsString.namespace = newId.getNamespace().getDecoded(); namespaceAndIdAsString.id = newId.getXmlId().getDecoded(); for (WebResource wr : this.repositoryResources) { // TODO: Check whether namespaceAndIdAsString is the correct data type expected at the resource ClientResponse response = wr.path(pathFragment).path("id").post(ClientResponse.class, namespaceAndIdAsString); if ((response.getClientResponseStatus() != ClientResponse.Status.NO_CONTENT) || (response.getClientResponseStatus() != ClientResponse.Status.NOT_FOUND)) { LOGGER.debug(String.format("Error %d when renaming TOSCAComponentId %s to %s at %s", response.getStatus(), oldId.toString(), newId.toString(), wr.getURI().toString())); } } } @Override public void forceDelete(Class<? extends TOSCAComponentId> toscaComponentIdClazz, Namespace namespace) throws IOException { throw new IllegalStateException("not yet implemented"); } @Override public boolean primaryRepositoryAvailable() { if (this.primaryWebResource == null) { return false; } ClientResponse response = this.primaryWebResource.get(ClientResponse.class); boolean res = (response.getClientResponseStatus() == ClientResponse.Status.OK); return res; } }