Java tutorial
/** * Copyright (C) 2010-2012 Brookhaven National Laboratory * Copyright (C) 2010-2012 Helmholtz-Zentrum Berlin fr Materialien und Energie GmbH * All rights reserved. Use is subject to license terms. */ package gov.bnl.channelfinder.api; import gov.bnl.channelfinder.api.Channel.Builder; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.swing.text.html.parser.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.base.Joiner; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.UniformInterfaceException; 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.api.client.filter.HTTPBasicAuthFilter; import com.sun.jersey.client.urlconnection.HTTPSProperties; import com.sun.jersey.core.util.MultivaluedMapImpl; /** * A Client object to query the channelfinder service for channels based on * channel names and/or properties and tags associated with channels. * * @author shroffk * */ public class ChannelFinderClientImpl implements ChannelFinderClient { private final WebResource service; private final ExecutorService executor; private static final String resourceChannels = "resources/channels"; private static final String resourceProperties = "resources/properties"; private static final String resourceTags = "resources/tags"; /** * A Builder class to help create the client to the Channelfinder Service * * @author shroffk * */ public static class CFCBuilder { // required private URI uri = null; // optional private boolean withHTTPAuthentication = false; private HTTPBasicAuthFilter httpBasicAuthFilter = null; private ClientConfig clientConfig = null; private TrustManager[] trustManager = new TrustManager[] { new DummyX509TrustManager() };; @SuppressWarnings("unused") private SSLContext sslContext = null; private String protocol = null; private String username = null; private String password = null; private ExecutorService executor = Executors.newSingleThreadExecutor(); private CFProperties properties = new CFProperties(); private static final String serviceURL = "http://localhost:8080/ChannelFinder"; //$NON-NLS-1$ private CFCBuilder() { this.uri = URI.create(this.properties.getPreferenceValue("channelfinder.serviceURL", serviceURL)); //$NON-NLS-1$ this.protocol = this.uri.getScheme(); } private CFCBuilder(URI uri) { this.uri = uri; this.protocol = this.uri.getScheme(); } /** * Creates a {@link CFCBuilder} for a CF client to Default URL in the * channelfinder.properties. * * @return {@link CFCBuilder} */ public static CFCBuilder serviceURL() { return new CFCBuilder(); } /** * Creates a {@link CFCBuilder} for a CF client to URI <tt>uri</tt>. * * @param uri * @return {@link CFCBuilder} */ public static CFCBuilder serviceURL(String uri) { return new CFCBuilder(URI.create(uri)); } /** * Creates a {@link CFCBuilder} for a CF client to {@link URI} * <tt>uri</tt>. * * @param uri * @return {@link CFCBuilder} */ public static CFCBuilder serviceURL(URI uri) { return new CFCBuilder(uri); } /** * Enable of Disable the HTTP authentication on the client connection. * * @param withHTTPAuthentication * @return {@link CFCBuilder} */ public CFCBuilder withHTTPAuthentication(boolean withHTTPAuthentication) { this.withHTTPAuthentication = withHTTPAuthentication; return this; } /** * Set the username to be used for HTTP Authentication. * * @param username * @return {@link CFCBuilder} */ public CFCBuilder username(String username) { this.username = username; return this; } /** * Set the password to be used for the HTTP Authentication. * * @param password * @return {@link CFCBuilder} */ public CFCBuilder password(String password) { this.password = password; return this; } /** * set the {@link ClientConfig} to be used while creating the * channelfinder client connection. * * @param clientConfig * @return {@link CFCBuilder} */ public CFCBuilder withClientConfig(ClientConfig clientConfig) { this.clientConfig = clientConfig; return this; } @SuppressWarnings("unused") private CFCBuilder withSSLContext(SSLContext sslContext) { this.sslContext = sslContext; return this; } /** * Set the trustManager that should be used for authentication. * * @param trustManager * @return {@link CFCBuilder} */ public CFCBuilder withTrustManager(TrustManager[] trustManager) { this.trustManager = trustManager; return this; } /** * Provide your own executor on which the queries are to be made. <br> * By default a single threaded executor is used. * * @param executor * @return {@link CFCBuilder} */ public CFCBuilder withExecutor(ExecutorService executor) { this.executor = executor; return this; } /** * Will actually create a {@link ChannelFinderClientImpl} object using * the configuration informoation in this builder. * * @return {@link ChannelFinderClientImpl} */ public ChannelFinderClient create() throws ChannelFinderException { if (this.protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$ this.clientConfig = new DefaultClientConfig(); } else if (this.protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$ if (this.clientConfig == null) { SSLContext sslContext = null; try { sslContext = SSLContext.getInstance("SSL"); //$NON-NLS-1$ sslContext.init(null, this.trustManager, null); } catch (NoSuchAlgorithmException e) { throw new ChannelFinderException(e.getMessage()); } catch (KeyManagementException e) { throw new ChannelFinderException(e.getMessage()); } this.clientConfig = new DefaultClientConfig(); this.clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }, sslContext)); } } if (this.withHTTPAuthentication) { this.httpBasicAuthFilter = new HTTPBasicAuthFilter( ifNullReturnPreferenceValue(this.username, "channelfinder.username", "username"), ifNullReturnPreferenceValue(this.password, "channelfinder.password", "password")); } return new ChannelFinderClientImpl(this.uri, this.clientConfig, this.httpBasicAuthFilter, this.executor); } private String ifNullReturnPreferenceValue(String value, String key, String Default) { if (value == null) { return this.properties.getPreferenceValue(key, Default); } else { return value; } } } ChannelFinderClientImpl(URI uri, ClientConfig config, HTTPBasicAuthFilter httpBasicAuthFilter, ExecutorService executor) { Client client = Client.create(config); if (httpBasicAuthFilter != null) { client.addFilter(httpBasicAuthFilter); } client.addFilter(new RawLoggingFilter(Logger.getLogger(RawLoggingFilter.class.getName()))); client.setFollowRedirects(true); service = client.resource(UriBuilder.fromUri(uri).build()); this.executor = executor; } /** * Get a list of names of all the properties currently present on the * channelfinder service. * * @return list of names of all existing {@link Property}s. */ public Collection<String> getAllProperties() { return wrappedSubmit(new Callable<Collection<String>>() { @Override public Collection<String> call() throws Exception { Collection<String> allProperties = new HashSet<String>(); ObjectMapper mapper = new ObjectMapper(); List<XmlProperty> xmlproperties = new ArrayList<XmlProperty>(); try { xmlproperties = mapper.readValue( service.path(resourceProperties).accept(MediaType.APPLICATION_JSON).get(String.class), new TypeReference<List<XmlProperty>>() { }); } catch (JsonParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (XmlProperty xmlproperty : xmlproperties) { allProperties.add(xmlproperty.getName()); } return allProperties; } }); } /** * Get a list of names of all the tags currently present on the * channelfinder service. * * @return a list of names of all the existing {@link Tag}s. */ public Collection<String> getAllTags() { return wrappedSubmit(new Callable<Collection<String>>() { @Override public Collection<String> call() throws Exception { Collection<String> allTags = new HashSet<String>(); ObjectMapper mapper = new ObjectMapper(); List<XmlTag> xmltags = new ArrayList<XmlTag>(); try { xmltags = mapper.readValue( service.path(resourceTags).accept(MediaType.APPLICATION_JSON).get(String.class), new TypeReference<List<XmlTag>>() { }); } catch (JsonParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (XmlTag xmltag : xmltags) { allTags.add(xmltag.getName()); } return allTags; } }); } @Deprecated public static void resetPreferences() { try { Preferences.userNodeForPackage(ChannelFinderClientImpl.class).clear(); } catch (BackingStoreException e) { e.printStackTrace(); } } /** * Returns a channel that exactly matches the channelName * <tt>channelName</tt>. * * @param channelName * - name of the required channel. * @return {@link Channel} with name <tt>channelName</tt> or null * @throws ChannelFinderException */ public Channel getChannel(String channelName) throws ChannelFinderException { try { return wrappedSubmit(new FindByChannelName(channelName)); } catch (ChannelFinderException e) { if (e.getStatus().equals(ClientResponse.Status.NOT_FOUND)) { return null; } else { throw e; } } } private class FindByChannelName implements Callable<Channel> { private final String channelName; FindByChannelName(String channelName) { super(); this.channelName = channelName; } @Override public Channel call() throws UniformInterfaceException { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); try { return new Channel(mapper.readValue(service.path(resourceChannels).path(channelName) .get(ClientResponse.class).getEntityInputStream(), XmlChannel.class)); } catch (JsonParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } } /** * Destructively set a single channel <tt>channel</tt>, if the channel * already exists it will be replaced with the given channel. * * @param channel * the channel to be added * @throws ChannelFinderException */ public void set(Channel.Builder channel) throws ChannelFinderException { wrappedSubmit(new SetChannel(channel.toXml())); } private class SetChannel implements Runnable { private XmlChannel pxmlChannel = new XmlChannel(); public SetChannel(XmlChannel xmlChannel) { super(); this.pxmlChannel = xmlChannel; } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceChannels).path(this.pxmlChannel.getName()).type(MediaType.APPLICATION_JSON) .put(mapper.writeValueAsString(this.pxmlChannel)); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Destructively set a set of channels, if any channels already exists it is * replaced. * * @param channels * set of channels to be added * @throws ChannelFinderException */ public void set(Collection<Builder> channels) throws ChannelFinderException { wrappedSubmit(new SetChannels(ChannelUtil.toCollectionXmlChannels(channels))); } private class SetChannels implements Runnable { private List<XmlChannel> pxmlchannels = null; public SetChannels(List<XmlChannel> xmlchannels) { super(); this.pxmlchannels = xmlchannels; } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); OutputStream out = new ByteArrayOutputStream(); try { mapper.writeValue(out, this.pxmlchannels); final byte[] data = ((ByteArrayOutputStream) out).toByteArray(); String test = new String(data); service.path(resourceChannels).type(MediaType.APPLICATION_JSON).put(test); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Destructively set a Tag <tt>tag</tt> with no associated channels to the * database. * * @param tag * - the tag to be set. */ public void set(Tag.Builder tag) { wrappedSubmit(new SetTag(tag.toXml())); } /** * Destructively set tag <tt>tag</tt> to channel <tt>channelName</tt> and * remove the tag from all other channels. * * @param tag * - the tag to be set. * @param channelName * - the channel to which the tag should be set on. * @throws ChannelFinderException */ public void set(Tag.Builder tag, String channelName) throws ChannelFinderException { Collection<String> channelNames = new ArrayList<String>(); channelNames.add(channelName); wrappedSubmit(new SetTag(tag.toXml(), channelNames)); } /** * Set tag <tt>tag</tt> on the set of channels {channels} and remove it from * all others. * * @param tag * - the tag to be set. * @param channelNames * - the list of channels to which this tag will be added and * removed from all others. * @throws ChannelFinderException */ public void set(Tag.Builder tag, Collection<String> channelNames) throws ChannelFinderException { wrappedSubmit(new SetTag(tag.toXml(), channelNames)); } public void set(Tag.Builder tag, Map<String, String> channelTagMap) { wrappedSubmit(new SetTag(tag.toXml(), channelTagMap)); } private class SetTag implements Runnable { private XmlTag pxmlTag; public SetTag(XmlTag xmlTag) { super(); this.pxmlTag = xmlTag; } SetTag(XmlTag xmlTag, Map<String, String> channelTagMap) { super(); this.pxmlTag = xmlTag; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (Entry<String, String> e : channelTagMap.entrySet()) { XmlChannel xmlChannel = new XmlChannel(e.getKey()); // need a copy to avoid a cycle xmlChannel.addXmlProperty( new XmlProperty(this.pxmlTag.getName(), this.pxmlTag.getOwner(), e.getValue())); channels.add(xmlChannel); } this.pxmlTag.setChannels(channels); } SetTag(XmlTag xmlTag, Collection<String> channelNames) { super(); this.pxmlTag = xmlTag; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (String channelName : channelNames) { XmlChannel xmlChannel = new XmlChannel(channelName); xmlChannel.addXmlTag(new XmlTag(this.pxmlTag.getName(), this.pxmlTag.getOwner())); channels.add(xmlChannel); } this.pxmlTag.setChannels(channels); } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceTags).path(this.pxmlTag.getName()).type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON).put(mapper.writeValueAsString(this.pxmlTag)); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Destructively set a new property <tt>property</tt>. * * @param prop * - the property to be set. */ public void set(Property.Builder prop) throws ChannelFinderException { wrappedSubmit(new SetProperty(prop.toXml())); } /** * Destructively set property <tt>prop</tt> and add it to the channel * <tt>channelName</tt> and remove it from all others. * * @param prop * - property to be set. * @param channelName * - the channel to which this property must be added. */ public void set(Property.Builder prop, String channelName) { Collection<String> ch = new ArrayList<String>(); ch.add(channelName); wrappedSubmit(new SetProperty(prop.toXml(), ch)); } /** * Destructively set property <tt>prop</tt> and add it to the channels * <tt>channelNames</tt> removing it from all other channels. By default all * channels will contain the property with the same value specified in the * <tt>prop</tt>.<br> * to individually set the value for each channel use channelPropertyMap. * * @param prop * - the property to be set. * @param channelNames * - the channels to which this property should be added and * removed from all others. */ public void set(Property.Builder prop, Collection<String> channelNames) { wrappedSubmit(new SetProperty(prop.toXml(), channelNames)); } /** * Destructively set the property <tt>prop</tt> and add it to the channels * specified in the <tt>channelPropertyMap</tt>, where the map key is the * channel name and the associated value is the property value to be used * for that channel. * * @param prop * - the property to be set. * @param channelPropertyMap * - map with channel names and property values */ public void set(Property.Builder prop, Map<String, String> channelPropertyMap) { wrappedSubmit(new SetProperty(prop.toXml(), channelPropertyMap)); } private class SetProperty implements Runnable { private XmlProperty pxmlProperty; SetProperty(XmlProperty prop) { this.pxmlProperty = prop; } SetProperty(XmlProperty prop, Map<String, String> channelPropertyMap) { super(); this.pxmlProperty = prop; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (Entry<String, String> e : channelPropertyMap.entrySet()) { XmlChannel xmlChannel = new XmlChannel(e.getKey()); // need a copy to avoid a cycle xmlChannel.addXmlProperty( new XmlProperty(this.pxmlProperty.getName(), this.pxmlProperty.getOwner(), e.getValue())); channels.add(xmlChannel); } this.pxmlProperty.setChannels(channels); } SetProperty(XmlProperty prop, Collection<String> channelNames) { super(); this.pxmlProperty = prop; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (String channelName : channelNames) { XmlChannel xmlChannel = new XmlChannel(channelName); // need a copy to avoid a linking cycle xmlChannel.addXmlProperty(new XmlProperty(this.pxmlProperty.getName(), this.pxmlProperty.getOwner(), this.pxmlProperty.getValue())); channels.add(xmlChannel); } this.pxmlProperty.setChannels(channels); } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceProperties).path(this.pxmlProperty.getName()).type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON).put(mapper.writeValueAsString(this.pxmlProperty)); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Update existing channel with <tt>channel</tt>. * * @param channel * @throws ChannelFinderException */ public void update(Channel.Builder channel) throws ChannelFinderException { wrappedSubmit(new UpdateChannel(channel.toXml())); } private class UpdateChannel implements Runnable { private XmlChannel channel; UpdateChannel(XmlChannel channel) { super(); this.channel = channel; } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceChannels).path(this.channel.getName()).type(MediaType.APPLICATION_JSON) .post(mapper.writeValueAsString(this.channel)); } catch (UniformInterfaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Update Tag <tt>tag </tt> by adding it to Channel with name * <tt>channelName</tt>, without affecting the other instances of this tag. * * @param tag * the tag to be added * @param channelName * Name of the channel to which the tag is to be added * @throws ChannelFinderException */ public void update(Tag.Builder tag, String channelName) throws ChannelFinderException { wrappedSubmit(new UpdateTag(tag.toXml(), channelName)); } /** * * Update the Tag <tt>tag</tt> by adding it to the set of the channels with * names <tt>channelNames</tt>, without affecting the other instances of * this tag. * * @param tag * - the tag that needs to be updated. * @param channelNames * - list of channels to which this tag should be added. * @throws ChannelFinderException */ public void update(Tag.Builder tag, Collection<String> channelNames) throws ChannelFinderException { wrappedSubmit(new UpdateTag(tag.toXml(), channelNames)); } private class UpdateTag implements Runnable { private XmlTag pxmlTag; @SuppressWarnings("unused") UpdateTag(XmlTag xmlTag) { super(); this.pxmlTag = xmlTag; } UpdateTag(XmlTag xmlTag, String ChannelName) { super(); this.pxmlTag = xmlTag; List<XmlChannel> channels = new ArrayList<XmlChannel>(); channels.add(new XmlChannel(ChannelName)); this.pxmlTag.setChannels(channels); } UpdateTag(XmlTag xmlTag, Collection<String> channelNames) { super(); this.pxmlTag = xmlTag; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (String channelName : channelNames) { channels.add(new XmlChannel(channelName, "")); } xmlTag.setChannels(channels); } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceTags).path(this.pxmlTag.getName()).type(MediaType.APPLICATION_JSON) .put(mapper.writeValueAsString(this.pxmlTag)); } catch (UniformInterfaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Update Property <tt>property</tt> by adding it to the channel * <tt>channelName</tt>, without affecting the other channels. * * @param property * - the property to be updated * @param channelName * - the channel to which this property should be added or * updated. * @throws ChannelFinderException */ public void update(Property.Builder property, String channelName) throws ChannelFinderException { wrappedSubmit(new UpdateChannelProperty(property.toXml(), channelName)); } private class UpdateChannelProperty implements Runnable { private final String channelName; private XmlProperty pxmlProperty; UpdateChannelProperty(XmlProperty xmlProperty, String channelName) { super(); this.pxmlProperty = xmlProperty; this.channelName = channelName; XmlChannel xmlChannel = new XmlChannel(this.channelName); List<XmlChannel> channels = new ArrayList<XmlChannel>(); channels.add(xmlChannel); // need a defensive copy to avoid A cycle xmlChannel.addXmlProperty( new XmlProperty(xmlProperty.getName(), xmlProperty.getOwner(), xmlProperty.getValue())); xmlProperty.setChannels(channels); } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceProperties).path(this.pxmlProperty.getName()).type(MediaType.APPLICATION_JSON) .put(mapper.writeValueAsString(this.pxmlProperty)); } catch (UniformInterfaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * * * @param property * @param channelNames * @throws ChannelFinderException */ public void update(Property.Builder property, Collection<String> channelNames) throws ChannelFinderException { wrappedSubmit(new UpdateProperty(property.toXml(), channelNames)); } /** * * * @param property * @param channelPropValueMap * @throws ChannelFinderException */ public void update(Property.Builder property, Map<String, String> channelPropValueMap) throws ChannelFinderException { wrappedSubmit(new UpdateProperty(property.toXml(), channelPropValueMap)); } private class UpdateProperty implements Runnable { private XmlProperty pxmlProperty; @SuppressWarnings("unused") UpdateProperty(XmlProperty xmlProperty) { super(); this.pxmlProperty = xmlProperty; } UpdateProperty(XmlProperty xmlProperty, Collection<String> channelNames) { super(); this.pxmlProperty = xmlProperty; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (String channelName : channelNames) { XmlChannel xmlChannel = new XmlChannel(channelName); // need a defensive copy to avoid A cycle xmlChannel.addXmlProperty( new XmlProperty(xmlProperty.getName(), xmlProperty.getOwner(), xmlProperty.getValue())); channels.add(xmlChannel); } xmlProperty.setChannels(channels); } UpdateProperty(XmlProperty xmlProperty, Map<String, String> channelPropValueMap) { super(); this.pxmlProperty = xmlProperty; List<XmlChannel> channels = new ArrayList<XmlChannel>(); for (Entry<String, String> e : channelPropValueMap.entrySet()) { XmlChannel xmlChannel = new XmlChannel(e.getKey()); // need a defensive copy to avoid A cycle xmlChannel.addXmlProperty( new XmlProperty(xmlProperty.getName(), xmlProperty.getOwner(), e.getValue())); channels.add(xmlChannel); } xmlProperty.setChannels(channels); } @Override public void run() { ObjectMapper mapper = new ObjectMapper(); try { service.path(resourceProperties).path(this.pxmlProperty.getName()).type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON).post(mapper.writeValueAsString(this.pxmlProperty)); } catch (UniformInterfaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Search for channels who's name match the pattern <tt>pattern</tt>.<br> * The pattern can contain wildcard char * or ?.<br> * * @param pattern * - the search pattern for the channel names * @return A Collection of channels who's name match the pattern * <tt>pattern</tt> * @throws ChannelFinderException */ public Collection<Channel> findByName(String pattern) throws ChannelFinderException { // return wrappedSubmit(new FindByParam("~name", pattern)); Map<String, String> searchMap = new HashMap<String, String>(); searchMap.put("~name", pattern); return wrappedSubmit(new FindByMap(searchMap)); } /** * Search for channels with tags who's name match the pattern * <tt>pattern</tt>.<br> * The pattern can contain wildcard char * or ?.<br> * * @param pattern * - the search pattern for the tag names * @return A Collection of channels which contain tags who's name match the * pattern <tt>pattern</tt> * @throws ChannelFinderException */ public Collection<Channel> findByTag(String pattern) throws ChannelFinderException { // return wrappedSubmit(new FindByParam("~tag", pattern)); Map<String, String> searchMap = new HashMap<String, String>(); searchMap.put("~tag", pattern); return wrappedSubmit(new FindByMap(searchMap)); } /** * Search for channels with properties who's Value match the pattern * <tt>pattern</tt>.<br> * The pattern can contain wildcard char * or ?.<br> * * @param property * - the name of the property. * @param pattern * - the seatch pattern for the property value. * @return A collection of channels containing the property with name * <tt>propertyName</tt> who's value matches the pattern * <tt> pattern</tt>. * @throws ChannelFinderException */ public Collection<Channel> findByProperty(String property, String... pattern) throws ChannelFinderException { Map<String, String> propertyPatterns = new HashMap<String, String>(); if (pattern.length > 0) { propertyPatterns.put(property, Joiner.on(",").join(pattern)); //$NON-NLS-1$ } else { propertyPatterns.put(property, "*"); //$NON-NLS-1$ } return wrappedSubmit(new FindByMap(propertyPatterns)); } /** * Query for channels based on the Query string <tt>query</tt> example: * find("SR* Cell=1,2 Tags=GolderOrbit,myTag)<br> * * this will return all channels with names starting with SR AND have * property Cell=1 OR 2 AND have tags goldenOrbit AND myTag.<br> * * IMP: each criteria is logically AND'ed while multiple values for * Properties are OR'ed.<br> * * @param query * @return Collection of channels which satisfy the search criteria. * @throws ChannelFinderException */ public Collection<Channel> find(String query) throws ChannelFinderException { return wrappedSubmit(new FindByMap(buildSearchMap(query))); } /** * Query for channels based on the multiple criteria specified in the map. * Map.put("~name", "*")<br> * Map.put("~tag", "tag1")<br> * Map.put("Cell", "1,2,3") * * this will return all channels with name=any name AND tag=tag1 AND * property Cell = 1 OR 2 OR 3. * * @param map * @return Collection of channels which satisfy the search map. * @throws ChannelFinderException */ public Collection<Channel> find(Map<String, String> map) throws ChannelFinderException { return wrappedSubmit(new FindByMap(map)); } /** * uery for channels based on the multiple criteria specified in the map. * Map.put("~name", "*")<br> * Map.put("~tag", "tag1")<br> * Map.put("Cell", "1")<br> * Map.put("Cell", "2")<br> * Map.put("Cell", "3")<br> * * this will return all channels with name=any name AND tag=tag1 AND * property Cell = 1 OR 2 OR 3. * * @param map * - multivalued map of all search criteria * @return Collection of channels which satisfy the search map. * @throws ChannelFinderException */ public Collection<Channel> find(MultivaluedMap<String, String> map) throws ChannelFinderException { return wrappedSubmit(new FindByMap(map)); } private class FindByMap implements Callable<Collection<Channel>> { private MultivaluedMapImpl map; FindByMap(Map<String, String> map) { MultivaluedMapImpl mMap = new MultivaluedMapImpl(); for (Entry<String, String> entry : map.entrySet()) { String key = entry.getKey(); for (String value : Arrays.asList(entry.getValue().split(","))) { mMap.add(key, value.trim()); } } this.map = mMap; } FindByMap(MultivaluedMap<String, String> map) { this.map = new MultivaluedMapImpl(); this.map.putAll(map); } @Override public Collection<Channel> call() throws Exception { Collection<Channel> channels = new HashSet<Channel>(); List<XmlChannel> xmlchannels = new ArrayList<XmlChannel>(); ObjectMapper mapper = new ObjectMapper(); try { xmlchannels = mapper .readValue( service.path(resourceChannels).queryParams(this.map) .accept(MediaType.APPLICATION_JSON).get(String.class), new TypeReference<List<XmlChannel>>() { }); } catch (JsonParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (XmlChannel xmlchannel : xmlchannels) { channels.add(new Channel(xmlchannel)); } return Collections.unmodifiableCollection(channels); } } public static MultivaluedMap<String, String> buildSearchMap(String searchPattern) { MultivaluedMap<String, String> map = new MultivaluedMapImpl(); searchPattern = searchPattern.replaceAll(", ", ","); String[] words = searchPattern.split("\\s"); if (words.length <= 0) { throw new IllegalArgumentException(); } else { for (int index = 0; index < words.length; index++) { if (!words[index].contains("=")) { // this is a name value if (words[index] != null) map.add("~name", words[index]); } else { // this is a property or tag String[] keyValue = words[index].split("="); String key = null; String valuePattern; try { key = keyValue[0]; valuePattern = keyValue[1]; if (key.equalsIgnoreCase("Tags")) { key = "~tag"; } for (String value : valuePattern.replace("||", ",").split(",")) { map.add(key, value); } } catch (ArrayIndexOutOfBoundsException e) { if (e.getMessage().equals(String.valueOf(0))) { throw new IllegalArgumentException( "= must be preceeded by a propertyName or keyword Tags."); } else if (e.getMessage().equals(String.valueOf(1))) throw new IllegalArgumentException("key: '" + key + "' is specified with no pattern."); } } } } return map; } /** * Completely Delete {tag} with name = tagName from all channels and the * channelfinder service. * * @param tagName * - name of tag to be deleted. * @throws ChannelFinderException */ public void deleteTag(String tagName) throws ChannelFinderException { wrappedSubmit(new DeleteElement(resourceTags, tagName)); } /** * Completely Delete property with name = propertyName from all channels and * the channelfinder service. * * @param propertyName * - name of property to be deleted. * @throws ChannelFinderException */ public void deleteProperty(String propertyName) throws ChannelFinderException { wrappedSubmit(new DeleteElement(resourceProperties, propertyName)); } /** * Delete the channel identified by <tt>channel</tt> * * @param channelName * channel to be removed * @throws ChannelFinderException */ public void deleteChannel(String channelName) throws ChannelFinderException { wrappedSubmit(new DeleteElement(resourceChannels, //$NON-NLS-1$ channelName)); } private class DeleteElement implements Runnable { private final String elementType; private final String elementName; DeleteElement(String elementType, String elementName) { super(); this.elementType = elementType; this.elementName = elementName; } @Override public void run() { service.path(elementType).path(elementName).delete(); } } /** * Delete the set of channels identified by <tt>channels</tt> * * @param channels * @throws ChannelFinderException */ @Deprecated public void delete(Collection<Channel.Builder> channels) throws ChannelFinderException { for (Channel.Builder channel : channels) { deleteChannel(channel.build().getName()); } } /** * Delete tag <tt>tag</tt> from the channel with the name * <tt>channelName</tt> * * @param tag * - the tag to be deleted. * @param channelName * - the channel from which to delete the tag <tt>tag</tt> * @throws ChannelFinderException */ public void delete(Tag.Builder tag, String channelName) throws ChannelFinderException { wrappedSubmit(new DeleteElementfromChannel(resourceTags, tag //$NON-NLS-1$ .toXml().getName(), channelName)); } /** * Remove the tag <tt>tag </tt> from all the channels <tt>channelNames</tt> * * @param tag * - the tag to be deleted. * @param channelNames * - the channels from which to delete the tag <tt>tag</tt> * @throws ChannelFinderException */ public void delete(Tag.Builder tag, Collection<String> channelNames) throws ChannelFinderException { // TODO optimize using the /tags/<name> payload with list of channels for (String channelName : channelNames) { delete(tag, channelName); } } /** * Remove property <tt>property</tt> from the channel with name * <tt>channelName</tt> * * @param property * - the property to be deleted. * @param channelName * - the channel from which to delete the property * <tt>property</tt> * @throws ChannelFinderException */ public void delete(Property.Builder property, String channelName) throws ChannelFinderException { wrappedSubmit(new DeleteElementfromChannel(resourceProperties, property.build().getName(), channelName)); } /** * Remove the property <tt>property</tt> from the set of channels * <tt>channelNames</tt> * * @param property * - the property to be deleted. * @param channelNames * - the channels from which to delete the property * <tt>property</tt> * @throws ChannelFinderException */ public void delete(Property.Builder property, Collection<String> channelNames) throws ChannelFinderException { for (String channel : channelNames) { delete(property, channel); } } private class DeleteElementfromChannel implements Runnable { private final String elementType; private final String elementName; private final String channelName; DeleteElementfromChannel(String elementType, String elementName, String channelName) { super(); this.elementType = elementType; this.elementName = elementName; this.channelName = channelName; } @Override public void run() { service.path(this.elementType).path(this.elementName).path(this.channelName) .accept(MediaType.APPLICATION_JSON).delete(); } } /** * close */ public void close() { this.executor.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!this.executor.awaitTermination(60, TimeUnit.SECONDS)) { this.executor.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!this.executor.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); //$NON-NLS-1$ } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted this.executor.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } private <T> T wrappedSubmit(Callable<T> callable) { try { return this.executor.submit(callable).get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { if (e.getCause() != null && e.getCause() instanceof UniformInterfaceException) { throw new ChannelFinderException((UniformInterfaceException) e.getCause()); } throw new RuntimeException(e); } } private void wrappedSubmit(Runnable runnable) { try { this.executor.submit(runnable).get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { if (e.getCause() != null && e.getCause() instanceof UniformInterfaceException) { throw new ChannelFinderException((UniformInterfaceException) e.getCause()); } throw new RuntimeException(e); } } public Collection<Channel> getAllChannels() { ObjectMapper mapper = new ObjectMapper(); List<XmlChannel> xmlchannels = new ArrayList<XmlChannel>(); try { xmlchannels = mapper.readValue( service.path(resourceChannels).accept(MediaType.APPLICATION_JSON).get(String.class), new TypeReference<List<XmlChannel>>() { }); } catch (JsonParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientHandlerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Collection<Channel> set = new HashSet<Channel>(); for (XmlChannel channel : xmlchannels) { set.add(new Channel(channel)); } return set; } }