1 /*******************************************************************************
2 * Copyright (c) 2012-2013 University of Stuttgart.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * and the Apache License 2.0 which both accompany this distribution,
6 * and are available at http://www.eclipse.org/legal/epl-v10.html
7 * and http://www.apache.org/licenses/LICENSE-2.0
10 * Oliver Kopp - initial API and implementation
11 *******************************************************************************/
12 package org.eclipse.winery.repository.client;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.net.HttpURLConnection;
17 import java.net.InetSocketAddress;
18 import java.net.Proxy;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.LinkedList;
25 import java.util.List;
27 import java.util.SortedSet;
28 import java.util.TreeSet;
30 import javax.ws.rs.core.MediaType;
31 import javax.ws.rs.core.MultivaluedMap;
32 import javax.xml.XMLConstants;
33 import javax.xml.bind.JAXBContext;
34 import javax.xml.bind.JAXBException;
35 import javax.xml.bind.Marshaller;
36 import javax.xml.bind.Unmarshaller;
37 import javax.xml.namespace.QName;
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.DocumentBuilderFactory;
40 import javax.xml.parsers.ParserConfigurationException;
41 import javax.xml.validation.Schema;
42 import javax.xml.validation.SchemaFactory;
44 import org.eclipse.winery.common.Util;
45 import org.eclipse.winery.common.beans.NamespaceIdOptionalName;
46 import org.eclipse.winery.common.constants.MimeTypes;
47 import org.eclipse.winery.common.ids.GenericId;
48 import org.eclipse.winery.common.ids.IdUtil;
49 import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
50 import org.eclipse.winery.common.interfaces.QNameAlreadyExistsException;
51 import org.eclipse.winery.common.interfaces.QNameWithName;
52 import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
53 import org.eclipse.winery.model.tosca.TDefinitions;
54 import org.eclipse.winery.model.tosca.TEntityType;
55 import org.eclipse.winery.model.tosca.TExtensibleElements;
56 import org.eclipse.winery.model.tosca.TTopologyTemplate;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.w3c.dom.Document;
60 import org.xml.sax.SAXException;
62 import com.fasterxml.jackson.core.type.TypeReference;
63 import com.fasterxml.jackson.databind.ObjectMapper;
64 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
65 import com.sun.jersey.api.client.Client;
66 import com.sun.jersey.api.client.ClientResponse;
67 import com.sun.jersey.api.client.WebResource;
68 import com.sun.jersey.api.client.config.ClientConfig;
69 import com.sun.jersey.api.client.config.DefaultClientConfig;
70 import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
71 import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
72 import com.sun.jersey.core.util.MultivaluedMapImpl;
74 public final class WineryRepositoryClient implements IWineryRepositoryClient {
76 private static final Logger logger = LoggerFactory.getLogger(WineryRepositoryClient.class);
78 // switch off validation, currently causes more trouble than it brings
79 private static final boolean VALIDATING = false;
81 private final Collection<String> knownURIs = new HashSet<String>();
82 private final Collection<WebResource> repositoryResources = new HashSet<WebResource>();
83 private final Client client;
84 private final ObjectMapper mapper = new ObjectMapper();
86 private final Map<Class<? extends TEntityType>, Map<QName, TEntityType>> entityTypeDataCache;
88 private final Map<GenericId, String> nameCache;
89 private static final int MAX_NAME_CACHE_SIZE = 1000;
91 private String primaryRepository = null;
92 private WebResource primaryWebResource = null;
94 // thread-safe JAXB as inspired by https://jaxb.java.net/guide/Performance_and_thread_safety.html
95 // The other possibility: Each subclass sets JAXBContext.newInstance(theSubClass.class); in its static {} part.
96 // This seems to be more complicated than listing all subclasses in initContext
97 public final static JAXBContext context = WineryRepositoryClient.initContext();
99 // schema aware document builder
100 private final DocumentBuilder toscaDocumentBuilder;
103 // taken from http://stackoverflow.com/a/15253142/873282
104 private static class ConnectionFactory implements HttpURLConnectionFactory {
109 private void initializeProxy() {
110 this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888));
114 public HttpURLConnection getHttpURLConnection(URL url) throws IOException {
115 this.initializeProxy();
116 return (HttpURLConnection) url.openConnection(this.proxy);
122 * Creates the client without the use of any proxy
124 public WineryRepositoryClient() {
129 * @param useProxy if a debugging proxy should be used
131 * @throws IllegalStateException if DOM parser could not be created
133 public WineryRepositoryClient(boolean useProxy) {
134 ClientConfig clientConfig = new DefaultClientConfig();
135 clientConfig.getClasses().add(JacksonJsonProvider.class);
137 URLConnectionClientHandler ch = new URLConnectionClientHandler(new ConnectionFactory());
138 this.client = new Client(ch, clientConfig);
140 this.client = Client.create(clientConfig);
143 this.entityTypeDataCache = new HashMap<>();
144 this.nameCache = new HashMap<>();
146 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
147 factory.setNamespaceAware(true);
148 if (WineryRepositoryClient.VALIDATING) {
149 factory.setValidating(true);
150 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
152 URL resource = this.getClass().getResource("/TOSCA-v1.0.xsd");
154 schema = schemaFactory.newSchema(resource);
155 } catch (SAXException e) {
156 throw new IllegalStateException("Schema could not be initalized", e);
158 factory.setSchema(schema);
161 this.toscaDocumentBuilder = factory.newDocumentBuilder();
162 } catch (ParserConfigurationException e) {
163 throw new IllegalStateException("document builder could not be initalized", e);
166 TODO: include this somehow - in the case of VALIDATING
168 Does not work with TTopolgoyTemplate as this is not allowed in the root of an XML document
169 this.toscaDocumentBuilder.setErrorHandler(new ErrorHandler() {
172 public void warning(SAXParseException arg0) throws SAXException {
177 public void fatalError(SAXParseException arg0) throws SAXException {
182 public void error(SAXParseException arg0) throws SAXException {
189 private static JAXBContext initContext() {
190 // code copied+adapted from JAXBSupport
194 // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282
196 context = JAXBContext.newInstance(
198 WinerysPropertiesDefinition.class);
200 } catch (JAXBException e) {
201 WineryRepositoryClient.logger.error("Could not initialize JAXBContext", e);
202 throw new IllegalStateException(e);
208 * Creates a marshaller
210 * @throws IllegalStateException if marshaller could not be instantiated
212 private static Marshaller createMarshaller() {
213 // code copied+adapted from JAXBSupport
216 m = WineryRepositoryClient.context.createMarshaller();
217 // pretty printed output is required as the XML is sent 1:1 to the browser for editing
218 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
219 // not possible here: m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper);
220 } catch (JAXBException e) {
221 WineryRepositoryClient.logger.error("Could not instantiate marshaller", e);
222 throw new IllegalStateException(e);
228 * Creates a unmarshaller
230 * @throws IllegalStateException if unmarshaller could not be instantiated
232 private static Unmarshaller createUnmarshaller() {
235 um = WineryRepositoryClient.context.createUnmarshaller();
236 } catch (JAXBException e) {
237 WineryRepositoryClient.logger.error("Could not instantiate unmarshaller", e);
238 throw new IllegalStateException(e);
243 /*** methods directly from IWineryRepositoryClient ***/
249 public void addRepository(String uri) {
250 if (this.knownURIs.add(uri)) {
251 // URI is not already known, add a new resource
252 WebResource wr = this.client.resource(uri);
253 this.repositoryResources.add(wr);
254 if (this.primaryRepository == null) {
255 this.primaryRepository = uri;
256 this.primaryWebResource = wr;
265 public String getPrimaryRepository() {
266 return this.primaryRepository;
273 public void setPrimaryRepository(String uri) {
274 this.addRepository(uri);
275 // now we are sure that a web resource for the uri exists
276 this.primaryRepository = uri;
277 // Update the reference to the primaryWebResource
278 // The appropriate resource has been created via
279 // this.addRepository(uri);
280 for (WebResource wr : this.repositoryResources) {
281 if (wr.getURI().equals(uri)) {
282 this.primaryWebResource = wr;
286 assert (this.primaryWebResource != null);
289 /*** methods directly from IWineryRepository ***/
295 public SortedSet<String> getNamespaces() {
296 SortedSet<String> res = new TreeSet<String>();
297 for (WebResource wr : this.repositoryResources) {
298 WebResource namespacesResource = wr.path("admin").path("namespaces");
300 // this could be parsed using JAXB
301 // (http://jersey.java.net/nonav/documentation/latest/json.html),
302 // but we are short in time, so we do a quick hack
303 String nsList = namespacesResource.accept(MediaType.APPLICATION_JSON).get(String.class);
304 WineryRepositoryClient.logger.trace(nsList);
305 List<String> nsListList;
307 nsListList = this.mapper.readValue(nsList, new TypeReference<List<String>>() {
309 } catch (Exception e) {
310 WineryRepositoryClient.logger.error(e.getMessage(), e);
313 res.addAll(nsListList);
319 * Base method for getQNameListOfAllTypes and getAllTypes.
321 private <T extends TExtensibleElements> Map<WebResource, List<NamespaceIdOptionalName>> getWRtoNamespaceAndIdListMapOfAllTypes(String path) {
322 Map<WebResource, List<NamespaceIdOptionalName>> res = new HashMap<WebResource, List<NamespaceIdOptionalName>>();
323 for (WebResource wr : this.repositoryResources) {
324 WebResource componentListResource = wr.path(path);
326 // this could be parsed using JAXB
327 // (http://jersey.java.net/nonav/documentation/latest/json.html),
328 // but we are short in time, so we do a quick hack
329 // The result also contains the optional name
330 String idList = componentListResource.accept(MediaType.APPLICATION_JSON).get(String.class);
331 WineryRepositoryClient.logger.trace(idList);
332 List<NamespaceIdOptionalName> nsAndIdList;
334 nsAndIdList = this.mapper.readValue(idList, new TypeReference<List<NamespaceIdOptionalName>>() {
336 } catch (Exception e) {
337 WineryRepositoryClient.logger.error(e.getMessage(), e);
340 res.put(wr, nsAndIdList);
349 public String getName(GenericId id) {
350 if (this.nameCache.containsKey(id)) {
351 return this.nameCache.get(id);
355 for (WebResource wr : this.repositoryResources) {
356 String pathFragment = IdUtil.getURLPathFragment(id);
357 WebResource resource = wr.path(pathFragment).path("name");
358 ClientResponse response = resource.accept(MediaType.TEXT_PLAIN_TYPE).get(ClientResponse.class);
359 if (response.getClientResponseStatus() == ClientResponse.Status.OK) {
360 name = response.getEntity(String.class);
361 // break loop as the first match is the final result
365 // if all resources did not return "OK", "null" is returned
368 if (this.nameCache.size() > WineryRepositoryClient.MAX_NAME_CACHE_SIZE) {
369 // if cache grew too large, clear it.
370 this.nameCache.clear();
372 this.nameCache.put(id, name);
382 public <T extends TEntityType> List<QName> getQNameListOfAllTypes(Class<T> className) {
383 String path = Util.getURLpathFragmentForCollection(className);
384 Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path);
385 Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes.values();
386 List<QName> res = new ArrayList<QName>(namespaceAndIdListCollection.size());
387 for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) {
388 for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) {
389 QName qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId());
397 * Fetches java objects at a given URL
399 * @param path the path to use. E.g., "nodetypes" for node types, ...
400 * @param className the class of the expected return type. May be
401 * TDefinitions or TEntityType. TDefinitions the mode is that the
402 * import statement are recursively resolved and added to the
403 * returned Defintitions elment
405 // we convert an object to T if it T is definitions
406 // does not work without compiler error
407 @SuppressWarnings("unchecked")
408 private <T extends TExtensibleElements> Collection<T> getAllTypes(String path, Class<T> className) {
409 Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path);
410 // now we now all QNames. We have to fetch the full content now
412 Collection<T> res = new LinkedList<T>();
413 for (WebResource wr : wRtoNamespaceAndIdListMapOfAllTypes.keySet()) {
414 WebResource componentListResource = wr.path(path);
416 // go through all ids and fetch detailed information on each
419 for (NamespaceIdOptionalName nsAndId : wRtoNamespaceAndIdListMapOfAllTypes.get(wr)) {
420 TDefinitions definitions = WineryRepositoryClient.getDefinitions(componentListResource, nsAndId.getNamespace(), nsAndId.getId());
421 if (definitions == null) {
428 if (TDefinitions.class.equals(className)) {
429 // mode: complete definitions
430 result = (T) definitions;
432 // mode: only the nested element
433 // convention: first element in list is the element we look for
434 if (definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) {
436 WineryRepositoryClient.logger.error("Type {}/{} was found, but did not return any data", nsAndId.getNamespace(), nsAndId.getId());
438 WineryRepositoryClient.logger.trace("Probably found valid data for {}/{}", nsAndId.getNamespace(), nsAndId.getId());
439 result = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
441 this.cache((TEntityType) result, new QName(nsAndId.getNamespace(), nsAndId.getId()));
445 // TODO: if multiple repositories are used, the new element
446 // should be put "sorted" into the list. This could be done by
447 // add(parsedResult, index), where index is calculated by
448 // incrementing index as long as the current element is smaller
449 // than the element to insert.
450 if (result != null) {
459 * Caches the TEntityType data of a QName to avoid multiple get requests
463 private void cache(TEntityType et, QName qName) {
464 Map<QName, TEntityType> map;
465 if ((map = this.entityTypeDataCache.get(et.getClass())) == null) {
466 map = new HashMap<>();
467 this.entityTypeDataCache.put(et.getClass(), map);
469 // quick hack to keep cache size small
470 if (map.size() > 1000) {
477 private static WebResource getTopologyTemplateWebResource(WebResource base, QName serviceTemplate) {
478 String nsEncoded = Util.DoubleURLencode(serviceTemplate.getNamespaceURI());
479 String idEncoded = Util.DoubleURLencode(serviceTemplate.getLocalPart());
480 WebResource res = base.path("servicetemplates").path(nsEncoded).path(idEncoded).path("topologytemplate");
488 public Collection<QNameWithName> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) {
489 // inspired by getQNameListOfAllTypes
490 String path = Util.getRootPathFragment(clazz);
491 Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path);
492 Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes.values();
493 List<QNameWithName> res = new ArrayList<QNameWithName>(namespaceAndIdListCollection.size());
495 for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) {
496 for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) {
497 QNameWithName qn = new QNameWithName();
498 qn.qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId());
499 qn.name = namespaceAndId.getName();
510 public <T extends TEntityType> Collection<T> getAllTypes(Class<T> c) {
511 String urlPathFragment = Util.getURLpathFragmentForCollection(c);
512 Collection<T> allTypes = this.getAllTypes(urlPathFragment, c);
517 @SuppressWarnings("unchecked")
518 public <T extends TEntityType> T getType(QName qname, Class<T> type) {
520 if (this.entityTypeDataCache.containsKey(type)) {
521 Map<QName, TEntityType> map = this.entityTypeDataCache.get(type);
522 if (map.containsKey(qname)) {
523 res = (T) map.get(qname);
528 // not yet seen, try to fetch resource
530 for (WebResource wr : this.repositoryResources) {
531 String path = Util.getURLpathFragmentForCollection(type);
533 TDefinitions definitions = WineryRepositoryClient.getDefinitions(wr, path, qname.getNamespaceURI(), qname.getLocalPart());
535 if (definitions == null) {
536 // in case of an error, just try the next one
540 res = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
541 this.cache(res, qname);
550 * Tries to retrieve a TDefinitions from the given resource / encoded(ns) /
553 * @return null if 404 or other error
555 private static TDefinitions getDefinitions(WebResource wr, String path, String ns, String localPart) {
556 WebResource componentListResource = wr.path(path);
557 return WineryRepositoryClient.getDefinitions(componentListResource, ns, localPart);
561 * Tries to retrieve a TDefinitions from the given resource / encoded(ns) /
564 * @return null if 404 or other error
566 private static TDefinitions getDefinitions(WebResource componentListResource, String ns, String localPart) {
567 // we need double encoding as the client decodes the URL once
568 String nsEncoded = Util.DoubleURLencode(ns);
569 String idEncoded = Util.DoubleURLencode(localPart);
571 WebResource instanceResource = componentListResource.path(nsEncoded).path(idEncoded);
573 // TODO: org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsWithAssociatedThings() could be used to do the resolving at the server
575 ClientResponse response = instanceResource.accept(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS).get(ClientResponse.class);
576 if (response.getStatus() != 200) {
581 TDefinitions definitions;
583 Unmarshaller um = WineryRepositoryClient.createUnmarshaller();
584 definitions = (TDefinitions) um.unmarshal(response.getEntityInputStream());
585 } catch (JAXBException e) {
586 WineryRepositoryClient.logger.error("Could not umarshal TDefinitions", e);
597 public <T extends TEntityType> Collection<TDefinitions> getAllTypesWithAssociatedElements(Class<T> c) {
598 String urlPathFragment = Util.getURLpathFragmentForCollection(c);
599 Collection<TDefinitions> allTypes = this.getAllTypes(urlPathFragment, TDefinitions.class);
605 * @param stream the stream to parse
606 * @return null if document is invalid
608 private Document parseAndValidateTOSCAXML(InputStream stream) {
611 document = this.toscaDocumentBuilder.parse(stream);
612 } catch (SAXException | IOException e) {
613 WineryRepositoryClient.logger.debug("Could not parse TOSCA file", e);
623 public TTopologyTemplate getTopologyTemplate(QName serviceTemplate) {
624 // we try all repositories until the first hit
625 for (WebResource wr : this.repositoryResources) {
626 WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(wr, serviceTemplate);
627 ClientResponse response = r.accept(MediaType.TEXT_XML).get(ClientResponse.class);
628 if (response.getClientResponseStatus() == ClientResponse.Status.OK) {
629 TTopologyTemplate topologyTemplate;
630 Document doc = this.parseAndValidateTOSCAXML(response.getEntityInputStream());
636 topologyTemplate = WineryRepositoryClient.createUnmarshaller().unmarshal(doc.getDocumentElement(), TTopologyTemplate.class).getValue();
637 } catch (JAXBException e) {
638 WineryRepositoryClient.logger.debug("Could not parse topology, returning null", e);
641 // first hit: immediately stop and return result
642 return topologyTemplate;
653 public void setTopologyTemplate(QName serviceTemplate, TTopologyTemplate topologyTemplate) throws Exception {
654 WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(this.primaryWebResource, serviceTemplate);
655 String xmlAsString = Util.getXMLAsString(TTopologyTemplate.class, topologyTemplate);
656 ClientResponse response = r.type(MediaType.TEXT_XML).put(ClientResponse.class, xmlAsString);
657 WineryRepositoryClient.logger.debug(response.toString());
658 int status = response.getStatus();
659 if ((status < 200) || (status >= 300)) {
660 throw new Exception(response.toString());
668 public QName getArtifactTypeQNameForExtension(String extension) {
669 // we try all repositories until the first hit
670 for (WebResource wr : this.repositoryResources) {
671 WebResource artifactTypesResource = wr.path("artifacttypes").queryParam("extension", extension);
672 ClientResponse response = artifactTypesResource.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);
673 if (response.getClientResponseStatus() == ClientResponse.Status.OK) {
674 QName res = QName.valueOf(response.getEntity(String.class));
684 * Does NOT check for global QName uniqueness, only in the scope of all
688 public void createArtifactTemplate(QName qname, QName artifactType) throws QNameAlreadyExistsException {
689 WebResource artifactTemplates = this.primaryWebResource.path("artifacttemplates");
690 MultivaluedMap<String, String> map = new MultivaluedMapImpl();
691 map.putSingle("namespace", qname.getNamespaceURI());
692 map.putSingle("name", qname.getLocalPart());
693 map.putSingle("type", artifactType.toString());
694 ClientResponse response = artifactTemplates.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, map);
695 if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) {
696 // TODO: pass ClientResponse.Status somehow
697 // TODO: more fine grained checking for error message. Not all
698 // failures are that the QName already exists
699 WineryRepositoryClient.logger.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString()));
700 throw new QNameAlreadyExistsException();
702 // no further return is made
709 public void createComponent(QName qname, Class<? extends TOSCAComponentId> idClass) throws QNameAlreadyExistsException {
710 WebResource resource = this.primaryWebResource.path(Util.getRootPathFragment(idClass));
711 MultivaluedMap<String, String> map = new MultivaluedMapImpl();
712 map.putSingle("namespace", qname.getNamespaceURI());
713 map.putSingle("name", qname.getLocalPart());
714 ClientResponse response = resource.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, map);
715 if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) {
716 // TODO: pass ClientResponse.Status somehow
717 // TODO: more fine grained checking for error message. Not all failures are that the QName already exists
718 WineryRepositoryClient.logger.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString()));
719 throw new QNameAlreadyExistsException();
721 // no further return is made
725 public void forceDelete(GenericId id) throws IOException {
726 String pathFragment = IdUtil.getURLPathFragment(id);
727 for (WebResource wr : this.repositoryResources) {
728 ClientResponse response = wr.path(pathFragment).delete(ClientResponse.class);
729 if ((response.getClientResponseStatus() != ClientResponse.Status.NO_CONTENT) || (response.getClientResponseStatus() != ClientResponse.Status.NOT_FOUND)) {
730 WineryRepositoryClient.logger.debug(String.format("Error %d when deleting id %s from URI %s", response.getStatus(), id.toString(), wr.getURI().toString()));
736 public boolean primaryRepositoryAvailable() {
737 if (this.primaryWebResource == null) {
741 ClientResponse response = this.primaryWebResource.get(ClientResponse.class);
742 boolean res = (response.getClientResponseStatus() == ClientResponse.Status.OK);