Java tutorial
/** * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.md file. */ /** * This file was automatically generated by the Mule Development Kit */ package org.mule.modules.servicesource; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.mule.api.ConnectionException; import org.mule.api.ConnectionExceptionCode; import org.mule.api.MuleException; import org.mule.api.annotations.Configurable; import org.mule.api.annotations.Connect; import org.mule.api.annotations.ConnectionIdentifier; import org.mule.api.annotations.Connector; import org.mule.api.annotations.Disconnect; import org.mule.api.annotations.InvalidateConnectionOn; import org.mule.api.annotations.MetaDataKeyRetriever; import org.mule.api.annotations.MetaDataRetriever; import org.mule.api.annotations.Processor; import org.mule.api.annotations.ReconnectOn; import org.mule.api.annotations.ValidateConnection; import org.mule.api.annotations.display.Password; import org.mule.api.annotations.licensing.RequiresEnterpriseLicense; import org.mule.api.annotations.lifecycle.Start; import org.mule.api.annotations.param.ConnectionKey; import org.mule.api.annotations.param.Default; import org.mule.api.annotations.param.MetaDataKeyParam; import org.mule.api.annotations.param.Optional; import org.mule.common.metadata.DefaultMetaDataKey; import org.mule.common.metadata.MetaData; import org.mule.common.metadata.MetaDataKey; import org.mule.commons.jersey.JerseyUtil; import org.mule.commons.jersey.provider.GsonProvider; import org.mule.modules.servicesource.jersey.BasicAuthHeadersBehaviour; import org.mule.modules.servicesource.jersey.HeadersBehaviour; import org.mule.modules.servicesource.jersey.ServiceSourceResponseHandler; import org.mule.modules.servicesource.metadata.MetadataExtractor; import org.mule.modules.servicesource.metadata.RelationsTransformer; import org.mule.modules.servicesource.model.Address; import org.mule.modules.servicesource.model.ApiResponse; import org.mule.modules.servicesource.model.Note; import org.mule.modules.servicesource.model.PropertyDescriptor; import org.mule.modules.servicesource.model.RelationTarget; import org.mule.modules.servicesource.model.Relationship; import org.mule.modules.servicesource.model.ServiceSourceEntity; import org.mule.modules.servicesource.model.analysis.AnalysisObject; import org.mule.modules.servicesource.model.asset.Asset; import org.mule.modules.servicesource.model.booking.Booking; import org.mule.modules.servicesource.model.contact.Contact; import org.mule.modules.servicesource.model.dataload.DataLoad; import org.mule.modules.servicesource.model.dataload.DataLoadCompleteRequest; import org.mule.modules.servicesource.model.forecast.Forecast; import org.mule.modules.servicesource.model.lookup.Lookup; import org.mule.modules.servicesource.model.lookup.LookupConfig; import org.mule.modules.servicesource.model.lookup.LookupRequest; import org.mule.modules.servicesource.model.offer.Offer; import org.mule.modules.servicesource.model.opportunity.Opportunity; import org.mule.modules.servicesource.model.product.Product; import org.mule.modules.servicesource.model.quote.Quote; import org.mule.modules.servicesource.model.search.ExportParameters; import org.mule.modules.servicesource.model.task.Task; import java.util.UUID; import com.google.gson.stream.JsonReader; import com.google.gson.stream.MalformedJsonException; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; import com.sun.jersey.api.client.GenericType; 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.api.json.JSONConfiguration; import com.sun.jersey.core.impl.provider.entity.FormMultivaluedMapProvider; import com.sun.jersey.core.impl.provider.entity.FormProvider; import com.sun.jersey.core.impl.provider.entity.InputStreamProvider; import com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider; import com.sun.jersey.multipart.impl.MultiPartWriter; /** * ServiceSource Cloud Connector. The ServiceSource Connector will allow to use the ServiceSource REST API. Almost every operation that can be done via the API can be done through * this connector. * * @author mariano.gonzalez@mulesoft.com */ @Connector(name = "servicesource", schemaVersion = "1.0", friendlyName = "ServiceSource", description = "ServiceSource", minMuleVersion = "3.5") public class ServiceSourceConnector { private static final Logger logger = Logger.getLogger(ServiceSourceConnector.class); /** * The relative URL where the main API calls are made. */ @Configurable @Default("/rest/api/") private String apiUrl; /** * The relative URL where the analysis API calls are made */ @Configurable @Default("/analysis/api/") private String analysisUrl; /** * The relative url of the endpoint that handles login */ @Configurable @Default("/login.json") private String loginUrl; /** * The read timeout interval, in milliseconds */ @Configurable @Default("0") private Integer readTimeout; /** * The connect timeout interval, in milliseconds */ @Configurable @Default("0") private Integer connectTimeout; /** * Defines if the connector should use basic authentication instead of the cookie based authentication. */ @Configurable @Default("false") private Boolean useBasicAuth; /** * URL of the ServiceSource server API */ private String server; /** * Name of the tenant */ private String tenantName; /** * Application username */ private String username; /** * Application password */ private String password; /** * Jersey Client */ private Client client; /** * CSRF Token */ private String csrfToken; private List<Map<String, Object>> modelsMetadata; private NewCookie coockie; private ConnectionIdentifierWrapper connId; private JerseyUtil apiClient; private WebResource apiResource; private WebResource analysisResource; /* * TODO: Make this actualy be a cache. Implement eviction and size policies */ private Map<LookupRequest, String> lookupKeyCache = new HashMap<LookupRequest, String>(); /** * This method initiates the ServiceSource client and gson * * @throws MuleException */ @Start public void init() throws MuleException { ClientConfig clientConfig = new DefaultClientConfig(); clientConfig.getClasses().add(MultiPartWriter.class); clientConfig.getClasses().add(MimeMultipartProvider.class); clientConfig.getClasses().add(InputStreamProvider.class); clientConfig.getClasses().add(FormProvider.class); clientConfig.getClasses().add(FormMultivaluedMapProvider.class); clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); clientConfig.getSingletons().add(new GsonProvider(GsonFactory.getGson())); this.client = Client.create(clientConfig); this.client.setReadTimeout(this.readTimeout); this.client.setConnectTimeout(this.connectTimeout); } /** * Connect * * @param username * Application username * @param password * Application password * @param server * URL of the SRPS server API * @param tenantName * Name of the tenant * @throws ConnectionException . */ @Connect public void connect(@ConnectionKey String username, @Password String password, String server, String tenantName) throws ConnectionException { if (useBasicAuth) { setUpBasicAuth(username, password, server, tenantName); } else { setUpCookieBasedAuth(username, password, server, tenantName); } this.setUsername(username); this.setPassword(password); this.setServer(server); this.setTenantName(tenantName); this.apiResource = this.buildWebResource("https", this.server, this.apiUrl, this.tenantName); this.analysisResource = this.buildWebResource("https", this.server, this.analysisUrl, this.tenantName); } private void setUpBasicAuth(String username, String password, String server, String tenantName) { this.connId = new ConnectionIdentifierWrapper(UUID.randomUUID().toString()); this.apiClient = JerseyUtil.builder().addRequestBehaviour(new BasicAuthHeadersBehaviour(username, password)) .setResponseHandler(new ServiceSourceResponseHandler()).build(); this.client.addFilter(new HTTPBasicAuthFilter(username, password)); } private void setUpCookieBasedAuth(String username, String password, String server, String tenantName) throws ConnectionException { Map<String, String> loginCredentials = new HashMap<String, String>(); loginCredentials.put("username", username); loginCredentials.put("password", password); WebResource loginResource = this.buildWebResource("https", server, this.loginUrl, null); ClientResponse response = loginResource.accept(MediaType.APPLICATION_JSON_TYPE) .entity(loginCredentials, MediaType.APPLICATION_JSON_TYPE).post(ClientResponse.class); Status status = response.getClientResponseStatus(); if (status == Status.OK) { String entity = response.getEntity(String.class); ApiResponse<?> apiResponse = GsonFactory.getGson().fromJson(entity, ApiResponse.class); if (apiResponse.isSuccess()) { this.setCsrfToken(response.getHeaders().get("x-csrf-token").get(0)); this.coockie = response.getCookies().get(0); this.connId = new ConnectionIdentifierWrapper(this.coockie.getValue()); this.apiClient = JerseyUtil.builder().addRequestBehaviour(new HeadersBehaviour(this.coockie)) .setResponseHandler(new ServiceSourceResponseHandler()).build(); } else { throw new ConnectionException(ConnectionExceptionCode.UNKNOWN, entity, "ServiceSource rejected login"); } } else if (status == Status.UNAUTHORIZED) { throw new ConnectionException(ConnectionExceptionCode.INCORRECT_CREDENTIALS, null, null); } else { throw new ConnectionException(ConnectionExceptionCode.CANNOT_REACH, null, null); } } /** * Disconnect */ @Disconnect public void disconnect() { this.coockie = null; this.apiClient = null; this.connId = null; } /** * Are we connected */ @ValidateConnection public boolean isConnected() { // return this.coockie != null; return this.connId != null && this.connId.getValue() != null; } /** * Connection Identifier */ @ConnectionIdentifier public String connectionId() { // return this.coockie.getValue(); return this.connId.getValue(); } private WebResource buildWebResource(String protocol, String server, String url, String tenantName) { try { WebResource resource = this.client.resource(new URI(protocol, server, url, null, null)); if (!StringUtils.isBlank(tenantName)) { resource = resource.path(tenantName); } return resource; } catch (URISyntaxException e) { throw new ServiceSourceException(e); } } @MetaDataKeyRetriever public List<MetaDataKey> getMetaDataKeys() throws Exception { ServiceSourceCollection[] collections = ServiceSourceCollection.values(); List<MetaDataKey> keys = new ArrayList<MetaDataKey>(collections.length); for (ServiceSourceCollection collection : collections) { keys.add(new DefaultMetaDataKey(collection.getCollectionName(), collection.name())); } return keys; } @MetaDataRetriever public MetaData getMetaData(MetaDataKey key) throws Exception { ServiceSourceCollection collection = ServiceSourceCollection.getByCollectionName(key.getId()); List<Map<String, Object>> metadata = this.getModelsMetadata(); MetadataExtractor extractor = new MetadataExtractor(); for (Map<String, Object> model : metadata) { if (collection.getEntityName().equals(model.get("name"))) { return extractor.extractMetadata(model, collection); } } return extractor.extractStaticMetadata(collection); } @SuppressWarnings("unchecked") public List<Map<String, Object>> getModelsMetadata() { if (this.modelsMetadata == null) { String json = this.apiClient.get(this.apiResource.path("metadata").path("models::export"), String.class); this.modelsMetadata = GsonFactory.getGson().fromJson(json, ApiResponse.class).getRecords(); } return this.modelsMetadata; } /** * * Consumes the lookups config API looking for a lookup for the given connection on the given propertyPath. If found, then the name of a lookup matching the displayName is * returned * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:lookup-key} * * @param collectionName * the name of collection that the lookup referes to * @param propertyPath * the property path of the lookup vlaue * @param displayName * the displayName being looked up * @return a String if the value was found, null otherwise */ @Processor public String lookupKey(String collectionName, String propertyPath, String displayName) { ServiceSourceCollection collection = ServiceSourceCollection.getByCollectionName(collectionName); if (collection == null) { throw new IllegalArgumentException(collectionName + " is not a known collection"); } LookupRequest request = new LookupRequest(collection, propertyPath, displayName); if (this.lookupKeyCache.containsKey(request)) { return this.lookupKeyCache.get(request); } List<LookupConfig> configs = this.apiClient.get( this.apiResource.path(ServiceSourceCollection.LookupConfig.getCollectionName()), new GenericType<List<LookupConfig>>() { }); for (LookupConfig config : configs) { if (collection.getEntityName().equals(config.getModel()) && propertyPath.equals(config.getPropertyPath())) { ServiceSourceCollection sourceCollection = ServiceSourceCollection .getByCollectionName(config.getSrcCollection()); List<ServiceSourceEntity> lookups = this.search(sourceCollection, config.getFilter(), false, null, 100); for (ServiceSourceEntity l : lookups) { Lookup lookup = (Lookup) l; if (lookup.getDisplayName().equals(displayName)) { String retVal = lookup.getName(); this.lookupKeyCache.put(request, retVal); return retVal; } } } } this.lookupKeyCache.put(request, null); return null; } /** * It retrieves the id that should be used in a data load call. Based on a data load config name that the user provides. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:get-data-load-config-id} * * @param displayName * the data load config name for which you want to get the id * @return the id related to the config name */ @Processor public String getDataLoadConfigId(String displayName) { WebResource.Builder resource = this.apiResource.path("app.dataload.configs::find").getRequestBuilder(); Map<String, Object> filters = new HashMap<String, Object>(); filters.put("displayName", displayName); Map<String, Map<String, Object>> request = new HashMap<String, Map<String, Object>>(); request.put("filter", filters); resource = resource.entity(request); Map<String, Object> dataLoadConfig = this.apiClient.post(resource, new GenericType<Map<String, Object>>() { }); Map<String, Object> data = (Map<String, Object>) dataLoadConfig.get("data"); List<Map<String, Object>> config = (List<Map<String, Object>>) data.get("app.dataload.config"); return (String) config.get(0).get("_id"); } /** * This method provides search capabilities by specifying filters through a map. The advantage of using this processor over query is that you can now use a map to visually add * the filters and you don't risk exceeding the max length of the query params since the filters are sent as a post. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:search} * * @param collection * The collection to query * @param filters * map that includes filters * @param streaming * wheter or not to do streaming * @param columns * an optional list of columns to return. Use this to only return the fields you're interested while reducing network traffic * @param limit * the max number of results to return. If you want to have no limit then pass -1 * @return A List of objects that matched the criteria. The actual type of those objects depends on the provided collection but will be a subclass of * {@link ServiceSourceEntity} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) @SuppressWarnings("unchecked") public List<ServiceSourceEntity> search(ServiceSourceCollection collection, @Optional Map<String, Object> filters, @Default("false") boolean streaming, @Optional List<String> columns, @Default("100") int limit) { Map<String, Object> entity = new HashMap<String, Object>(); if (filters != null) { entity.put("filter", filters); } Map<String, Object> params = new HashMap<String, Object>(); params.put("limit", limit); if (streaming || !CollectionUtils.isEmpty(columns)) { params.put("stream", streaming); params.put("columns", columns); } entity.put("params", params); WebResource.Builder builder = this.apiResource.path(collection.getCollectionName() + "::find") .entity(entity); if (streaming) { return (List<ServiceSourceEntity>) this.readStream(this.apiClient.post(builder, InputStream.class), collection.getType()); } else { return this.apiClient.post(builder, new GenericType<List<ServiceSourceEntity>>() { }); } } /** * Export a collection. You can optionally specify the columns you want to export and whether or not to use streaming * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:export} * * @param streaming * wether or not use streaming * @param collection * The collection to query * @param columns * list of string specifying the columns to return * * @return A List of objects that matched the criteria. The actual type of those objects depends on the provided collection but will be a subclass of * {@link ServiceSourceEntity} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public List<ServiceSourceEntity> export(ServiceSourceCollection collection, @Default("false") boolean streaming, @Optional List<String> columns) { ExportParameters params = new ExportParameters(); params.setStreaming(streaming); params.setColumns(columns); Map<String, ExportParameters> entity = new HashMap<String, ExportParameters>(); entity.put("params", params); return this.apiClient.post(this.apiResource.path(collection.getCollectionName() + "::find").entity(entity), new GenericType<List<ServiceSourceEntity>>() { }); } /** * This method allows searching on the analysis API. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:analysis-search} * * @param collection * the collection to query * @param filters * map that includes filters * * @return the actual type of the return value depends on the provided collection, but it will be an implementation of {@link AnalysisObject} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public AnalysisObject analysisSearch(AnalysisCollection collection, @Optional Map<String, Object> filters) { WebResource.Builder resource = this.analysisResource.path(collection.getCollectionName()) .getRequestBuilder(); if (filters != null) { Map<String, Map<String, Object>> request = new HashMap<String, Map<String, Object>>(); request.put("filter", filters); resource = resource.entity(request); } return this.apiClient.post(resource, collection.getType()); } /** * This method provides basic search capabilities through a collection by providing a mongo formatted query. Take in count that the query is sent as a query param so per http * protocol limitations there's a limit on the amount of characters that it can have. * * To post large filters use search instead. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:query} * * @param collection * The collection to query * @param query * a mongo formatted query * * @return A List of objects that matched the query. The actual type of those objects depends on the provided collection but will be a subclass of {@link ServiceSourceEntity} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public List<ServiceSourceEntity> query(ServiceSourceCollection collection, String query) { return this.apiClient.get(this.apiResource.path(collection.getCollectionName()).queryParam("query", query), new GenericType<List<ServiceSourceEntity>>() { }); } /** * Creates new contact * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-contact} * * @param contact * A {@link Contact} * @return a {@link Contact} representing the newly created contact */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Contact createContact(@Default("#[payload]") Contact contact) { return (Contact) create(ServiceSourceCollection.Contacts, contact); } /** * Creates a new note * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-contact} * * @param note * A {@link Note} * @return a {@link Contact} representing the newly created note */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Note createNote(@Default("#[payload]") Note note) { return (Note) create(ServiceSourceCollection.Notes, note); } /** * Creates new address * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-address} * * @param address * A {@link Address} * @return a {@link Address} representing the newly created address */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Address createAddress(@Default("#[payload]") Address address) { return (Address) create(ServiceSourceCollection.Addresses, address); } /** * Creates new offer * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-offer} * * @param offer * A {@link Offer} * @return a {@link Offer} representing the newly created offer */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Offer createOffer(@Default("#[payload]") Offer offer) { return (Offer) create(ServiceSourceCollection.Offers, offer); } /** * Creates a new opportunity * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-opportunity} * * @param opportunity * A {@link Opportunity} * @return a {@link Opportunity} representing the newly created opportunity */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Opportunity createOpportunity(@Default("#[payload]") Opportunity opportunity) { return (Opportunity) create(ServiceSourceCollection.Opportunities, opportunity); } /** * Creates a new forecast * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-forecast} * * @param forecast * A {@link Forecast} * @return a {@link Forecast} representing the newly created contact */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Forecast createForecast(@Default("#[payload]") Forecast forecast) { return (Forecast) create(ServiceSourceCollection.Forecasts, forecast); } /** * Creates a new lookup * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-lookup} * * @param lookup * A {@link Lookup} * @return a {@link Lookup} representing the newly created lookup */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Lookup createLookup(@Default("#[payload]") Lookup lookup) { return (Lookup) create(ServiceSourceCollection.Lookups, lookup); } /** * Creates a new Asset * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-asset} * * @param asset * A {@link org.mule.module.servicesource.model.Asset} * @return a {@link org.mule.module.servicesource.model.Asset} representing the newly created Asset */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Asset createAsset(@Default("#[payload]") Asset asset) { return (Asset) create(ServiceSourceCollection.Assets, asset); } /** * Creates a new Booking * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-booking} * * @param booking * A {@link org.mule.module.servicesource.model.Booking} * @return a {@link org.mule.module.servicesource.model.Booking} representing the newly created Booking */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Booking createBooking(@Default("#[payload]") Booking booking) { return (Booking) create(ServiceSourceCollection.Bookings, booking); } /** * Creates a new Product * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-product} * * @param product * A {@link org.mule.module.servicesource.model.Product} * @return a {@link org.mule.module.servicesource.model.Product} representing the newly created Product */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Product createProduct(@Default("#[payload]") Product product) { return (Product) create(ServiceSourceCollection.Products, product); } /** * Creates a new Quote * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-quote} * * @param quote * A {@link org.mule.module.servicesource.model.Quote} * @return a {@link org.mule.module.servicesource.model.Quote} representing the newly created Quote */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Quote createQuote(@Default("#[payload]") Quote quote) { return (Quote) create(ServiceSourceCollection.Quotes, quote); } /** * Creates a new Task * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create-task} * * @param task * A {@link org.mule.module.servicesource.model.Task} * @return a {@link org.mule.module.servicesource.model.Task} representing the newly created task */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Task createTask(@Default("#[payload]") Task task) { return (Task) create(ServiceSourceCollection.Tasks, task); } /** * Fetches the contact identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-contact} * * @param objectId * Id of the object to read. * @return an instance of {@link Contact} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Contact readContact(String objectId) { return (Contact) read(ServiceSourceCollection.Contacts, objectId); } /** * Fetches the note identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-note} * * @param objectId * Id of the object to read. * @return an instance of {@link Note} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Note readNote(String objectId) { return (Note) read(ServiceSourceCollection.Notes, objectId); } /** * Fetches the address identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-address} * * @param objectId * Id of the object to read. * @return an instance of {@link Address} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Address readAddress(String objectId) { return (Address) read(ServiceSourceCollection.Addresses, objectId); } /** * Fetches the opportunity identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-opportunity} * * @param objectId * Id of the object to read. * @return an instance of {@link Opportunity} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Opportunity readOpportunity(String objectId) { return (Opportunity) read(ServiceSourceCollection.Opportunities, objectId); } /** * Fetches the offer identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-offer} * * @param objectId * Id of the object to read. * @return an instance of {@link Offer} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Offer readOffer(String objectId) { return (Offer) read(ServiceSourceCollection.Offers, objectId); } /** * Fetches the forecast identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-forecast} * * @param objectId * Id of the object to read. * @return an instance of {@link Forecast} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Forecast readForecast(String objectId) { return (Forecast) read(ServiceSourceCollection.Forecasts, objectId); } /** * Fetches the Asset identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-asset} * * @param objectId * Id of the object to read. * @return an instance of {@link org.mule.module.servicesource.model.forecast.Asset} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Asset readAsset(String objectId) { return (Asset) read(ServiceSourceCollection.Assets, objectId); } /** * Fetches the Booking identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-booking} * * @param objectId * Id of the object to read. * @return an instance of {@link org.mule.module.servicesource.model.forecast.Booking} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Booking readBooking(String objectId) { return (Booking) read(ServiceSourceCollection.Bookings, objectId); } /** * Fetches the Product identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-product} * * @param objectId * Id of the object to read. * @return an instance of {@link org.mule.module.servicesource.model.forecast.Product} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Product readProduct(String objectId) { return (Product) read(ServiceSourceCollection.Products, objectId); } /** * Fetches the Quote identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-quote} * * @param objectId * Id of the object to read. * @return an instance of {@link org.mule.module.servicesource.model.forecast.Quote} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Quote readQuote(String objectId) { return (Quote) read(ServiceSourceCollection.Quotes, objectId); } /** * Fetches the Task identified by the object id. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read-task} * * @param objectId * Id of the object to read. * @return an instance of {@link org.mule.module.servicesource.model.forecast.Task} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Task readTask(String objectId) { return (Task) read(ServiceSourceCollection.Tasks, objectId); } /** * Updates a given note * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-note} * * @param objectId * Id of the no to update. * @param note * the new state of the note as an instance of {@link Note} * @return The updated note as an instance of {@link Note}. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Note updateNote(String objectId, @Default("#[payload]") Note note) { return (Note) update(ServiceSourceCollection.Notes, objectId, note); } /** * Updates a given contact * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-contact} * * @param objectId * Id of the object to update. * @param contact * the new state of the contact as an instance of {@link Contact} * @return The updated contact as an instance of {@link Contact} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Contact updateContact(String objectId, @Default("#[payload]") Contact contact) { return (Contact) update(ServiceSourceCollection.Contacts, objectId, contact); } /** * Updates an address * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-address} * * @param objectId * Id of the object to update. * @param address * the new state of the note as an instance of {@link Address} * @return The updated address as an instance of {@link Address}. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Address updateAddress(String objectId, @Default("#[payload]") Address address) { return (Address) update(ServiceSourceCollection.Addresses, objectId, address); } /** * Updates an opportunity * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-opportunity} * * @param objectId * Id of the object to update. * @param opportunity * the new state of the note as an instance of {@link Opportunity} * @return The updated opportunity as an instance of {@link Opportunity} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Opportunity updateOpportunity(String objectId, @Default("#[payload]") Opportunity opportunity) { return (Opportunity) update(ServiceSourceCollection.Addresses, objectId, opportunity); } /** * Updates an offer * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-offer} * * @param objectId * Id of the object to update. * @param offer * the new state of the offer as an instance of {@link Offer} * @return The updated offer as an instance of {@link Offer} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Offer updateOffer(String objectId, @Default("#[payload]") Offer offer) { return (Offer) update(ServiceSourceCollection.Offers, objectId, offer); } /** * Updates a forecast * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-forecast} * * @param objectId * Id of the object to update. * @param forecast * the new state of the forecast as an instance of {@link Forecast} * @return The updated forecast as an instance of {@link Forecast} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Forecast updateForecast(String objectId, @Default("#[payload]") Forecast forecast) { return (Forecast) update(ServiceSourceCollection.Forecasts, objectId, forecast); } /** * Updates an Asset * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-asset} * * @param objectId * Id of the object to update. * @param asset * the new state of the asset as an instance of {@link Asset} * @return The updated asset as an instance of {@link Asset} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Asset updateAsset(String objectId, @Default("#[payload]") Asset asset) { return (Asset) update(ServiceSourceCollection.Assets, objectId, asset); } /** * Updates a Booking * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-booking} * * @param objectId * Id of the object to update. * @param booking * the new state of the booking as an instance of {@link Booking} * @return The updated booking as an instance of {@link Booking} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Booking updateBooking(String objectId, @Default("#[payload]") Booking booking) { return (Booking) update(ServiceSourceCollection.Bookings, objectId, booking); } /** * Updates a Product * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-product} * * @param objectId * Id of the object to update. * @param product * the new state of the product as an instance of {@link Product} * @return The updated product as an instance of {@link Product} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Product updateProduct(String objectId, @Default("#[payload]") Product product) { return (Product) update(ServiceSourceCollection.Products, objectId, product); } /** * Updates a Quote * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-quote} * * @param objectId * Id of the object to update. * @param quote * the new state of the quote as an instance of {@link Quote} * @return The updated quote as an instance of {@link Quote} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Quote updateQuote(String objectId, @Default("#[payload]") Quote quote) { return (Quote) update(ServiceSourceCollection.Quotes, objectId, quote); } /** * Updates a Task * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update-task} * * @param objectId * Id of the object to update. * @param task * the new state of the task as an instance of {@link Task} * @return The updated task as an instance of {@link Task} */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public Task updateTask(String objectId, @Default("#[payload]") Task task) { return (Task) update(ServiceSourceCollection.Tasks, objectId, task); } /** * Removes the object from the collection, permitting reference checks. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:delete} * * @param collection * The name of the collection * @param objectId * Id of the object to delete. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public void delete(ServiceSourceCollection collection, String objectId) { this.apiClient.delete(this.apiResource.path(collection.getCollectionName()).path(objectId), String.class); } /** * Invoke Static Method Executes a static method on the collection. These methods can perform actions across multiple objects. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:invoke-static-method} * * @param collection * The name of the collection * @param method * The static method to be invoked. * @param parameters * The parameters for the specified method. * @return a list of maps representing the output object */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public List<Map<String, String>> invokeStaticMethod(ServiceSourceCollection collection, String method, @Default("#[payload]") Map<String, Object> parameters) { WebResource.Builder resource = this.apiResource.path(collection.getEntityName() + "::" + method) .getRequestBuilder(); if (parameters != null) { Map<String, Map<String, Object>> args = new HashMap<String, Map<String, Object>>(); args.put("input", parameters); resource = resource.entity(args); } return this.apiClient.post(resource, new GenericType<List<Map<String, String>>>() { }); } /** * Executes a method on the object of a collection. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:invoke-object-method} * * @param collection * the collection the object belongs to * @param objectId * Id of the object. * @param method * The object method to be invoked. * @param parameters * The parameters for the specified method. * @return a list of maps representing the output of the invokation */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public List<Map<String, String>> invokeObjectMethod(ServiceSourceCollection collection, String objectId, String method, @Default("#[payload]") Map<String, Object> parameters) { WebResource.Builder resource = this.apiResource.path(collection.getEntityName()) .path(objectId + "::" + method).getRequestBuilder(); if (parameters != null) { Map<String, Map<String, Object>> args = new HashMap<String, Map<String, Object>>(); args.put("input", parameters); resource = resource.entity(args); } return this.apiClient.post(resource, new GenericType<List<Map<String, String>>>() { }); } /** * Starts a Data Load by creating an entry in the data load collection. The returned data load object contains an id field and the content of this field must be used in the * load and done API call URLs. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:start-data-load} * * @param jobName * the name of the data load job you want to start * @param displayName * a friendly name for the generated job * @param dataLoadConfigId * the id of the data load configuration that this job references to * @return another instance of {@link DataLoad} which represents the created DataLoad object. It also includes the id you need to provide later on. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public DataLoad startDataLoad(String jobName, String dataLoadConfigId, String displayName) { DataLoad dataLoad = new DataLoad(); dataLoad.setName(jobName); dataLoad.setDisplayName(displayName); List<Relationship> relations = new ArrayList<Relationship>(1); dataLoad.setRelationships(relations); Relationship r = new Relationship(); PropertyDescriptor relation = new PropertyDescriptor(); relation.setName("dataloadConfig"); RelationTarget target = new RelationTarget(); target.setKey(dataLoadConfigId); target.setType("app.dataload.config"); r.setRelation(relation); r.setTarget(target); relations.add(r); List<DataLoad> response = this.apiClient.post(this.apiResource.path("dataload").entity(dataLoad), new GenericType<List<DataLoad>>() { }); if (CollectionUtils.isEmpty(response)) { throw new ServiceSourceException("no dataload instance was returned"); } else { return response.get(0); } } /** * Pushes data through the load API. The ID of the data load job must be included as input. Each invocation of the load API provides data for a single collection and parallel * calls can be made to push data to multiple collections. The object content can be deduced from the data dictionary, metadata API or by fetching a pre-existing object using * the object fetch API. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:load-data} * * @param objects * a list with instances of {@link ServiceSourceEntity} all belonging to the same collection * @param collection * a member of the {@link ServiceSourceCollection} enum representing the collection that owns the entities * @param dataLoadJobId * The id of the data load job. * @param incremental * If true performs an incremental load and the data may already exist and should be updated if it does rather than just added * @return a list with instances of {@link ServiceSourceEntity} which represent the inserted objects */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public List<ServiceSourceEntity> loadData(@Default("#[payload]") List<ServiceSourceEntity> objects, ServiceSourceCollection collection, String dataLoadJobId, @Default("false") boolean incremental) { WebResource resource = this.apiResource.path("dataload").path(dataLoadJobId + "::load"); if (incremental) { resource = resource.queryParam("incremental", "true"); } Map<String, List<ServiceSourceEntity>> entity = new HashMap<String, List<ServiceSourceEntity>>(); entity.put(collection.getCollectionName(), objects); return this.apiClient.post(resource.entity(entity), new GenericType<List<ServiceSourceEntity>>() { }); } /** * Pushes data through the load API. The ID of the data load job must be included as input. Each invocation of the load API provides data for a single collection and parallel * calls can be made to push data to multiple collections. The object content can be deduced from the data dictionary, metadata API or by fetching a pre-existing object using * the object fetch API. * * Unlike its load-data counterpart, this version of the processor takes maps instead of pojos and includes support for DataSense. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:dynamic-load-data} * * @param objects * a list with instances of {@link ServiceSourceEntity} all belonging to the same collection * @param collection * a member of the {@link ServiceSourceCollection} enum representing the collection that owns the entities * @param dataLoadJobId * The id of the data load job. * @param incremental * If true performs an incremental load and the data may already exist and should be updated if it does rather than just added * @param staging * If true tells Renew OnDemand that the incoming data needs to be staged in Renew, this will allow for post processing of data to complete before any new data is * exposed to the users */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public void dynamicLoadData(@MetaDataKeyParam String collection, @Default("#[payload]") List<Map<String, Object>> objects, String dataLoadJobId, @Default("false") boolean incremental, @Default("false") boolean staging) { RelationsTransformer.adaptMetaModelToApi(objects); WebResource resource = this.apiResource.path("dataload").path(dataLoadJobId + "::load"); if (incremental) { resource = resource.queryParam("incremental", "true"); } if (staging) { resource = resource.queryParam("staging", "true"); } Map<String, List<Map<String, Object>>> entity = new HashMap<String, List<Map<String, Object>>>(); entity.put(collection, objects); this.apiClient.post(resource.entity(entity), String.class); } /** * This processor must be invoked to indicate that the data load job has completed. This call must be made after all the in-progress load calls complete. The done API can * optionally contain summary statistics about the loaded data organized by input source. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:complete-data-load} * * @param request * an instance of {@link DataLoadCompleteRequest} with the comple data load request data * @param dataLoadJobId * The id of the data load job. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public void completeDataLoad(@Default("#[payload]") DataLoadCompleteRequest request, String dataLoadJobId) { this.apiClient.post(this.apiResource.path("dataload").path(dataLoadJobId + "::done").entity(request), String.class); } /** * This processor must be invoked to indicate that the data load job has to be proccesed. This processor should only be use when you started a data load job as Stagin job. This * will allow for post processing of data to complete before any new data is exposed to the users. * * The process API can optionally contain summary statistics about the loaded data organized by input source. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:process-data-load} * * @param request * an instance of {@link DataLoadCompleteRequest} with the comple data load request data * @param dataLoadJobId * The id of the data load job. */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public void processDataLoad(@Default("#[payload]") DataLoadCompleteRequest request, String dataLoadJobId) { this.apiClient.post(this.apiResource.path("dataload").path(dataLoadJobId + "::process").entity(request), String.class); } /** * Generic method to create entities in dynamic collections * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:create} * * @param collection * a member of the {@link ServiceSourceCollection} enum representing the collection that owns the entity * @param entity * a subclass instance of {@link ServiceSourceEntity} * @return a subclass instance of {@link ServiceSourceEntity} with the created entity */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public ServiceSourceEntity create(ServiceSourceCollection collection, @Default("#[payload]") ServiceSourceEntity entity) { List<ServiceSourceEntity> response = this.apiClient.post( this.apiResource.path(collection.getCollectionName()), new GenericType<List<ServiceSourceEntity>>() { }); if (response.isEmpty()) { throw new ServiceSourceException("CREATE operation did not return an instance of " + collection); } else { return response.get(0); } } /** * Generic method to create entities dynamicly using DataSense. This method used a Map to represent entities instead of pojos. * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:dynamic-create} * * @param collection * a String representation of a ServiceSource collection. For example: app.offers * @param entity * a Map representing the entity * @return a Map with a representation of the created entity */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) @SuppressWarnings("unchecked") public Map<String, Object> dynamicCreate(@MetaDataKeyParam String collection, @Default("#[payload]") Map<String, Object> entity) { RelationsTransformer.adaptMetaModelToApi(entity); Map<String, Object> response = this.apiClient.post(this.apiResource.path(collection).entity(entity), new GenericType<Map<String, Object>>() { }); Map<String, Object> data = (Map<String, Object>) response.get("data"); if (data != null) { return ((List<Map<String, Object>>) data.get("core.contact")).get(0); } throw new ServiceSourceException("CREATE operation did not return data. Response was: " + collection); } /** * Generic method to read entities from dynamic collections * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:read} * * @param collection * a member of the {@link ServiceSourceCollection} enum representing the collection that owns the entity * @param objectId * the id of the entity you want to get * @return a subclass instance of {@link ServiceSourceEntity} with the created entity */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public ServiceSourceEntity read(ServiceSourceCollection collection, String objectId) { List<ServiceSourceEntity> response = this.apiClient.get( this.apiResource.path(collection.getCollectionName()).path(objectId), new GenericType<List<ServiceSourceEntity>>() { }); return response.isEmpty() ? null : response.get(0); } /** * Generic method to update entities from dynamic collections * * {@sample.xml ../../../doc/servicesource-connector.xml.sample servicesource:update} * * @param collection * a member of the {@link ServiceSourceCollection} enum representing the collection that owns the entity * @param objectId * the id of the entity you want to get * @param entity * a subclass instance of {@link ServiceSourceEntity} with the entitie's new state * @return a subclass instance of {@link ServiceSourceEntity} with the created entity */ @Processor @ReconnectOn(exceptions = NotAuthenticatedException.class) public ServiceSourceEntity update(ServiceSourceCollection collection, String objectId, @Default("#[payload]") ServiceSourceEntity entity) { List<ServiceSourceEntity> response = this.apiClient.post( this.apiResource.path(collection.getCollectionName()).path(objectId).entity(entity), new GenericType<List<ServiceSourceEntity>>() { }); if (response.isEmpty()) { throw new ServiceSourceException("UPDATE operation did not return an instance of " + collection); } else { return response.get(0); } } public String getServer() { return server; } public void setServer(String server) { if (server.startsWith("https://")) { server = server.substring(("https://").length()); } if (server.endsWith("/")) { server = server.substring(0, server.length() - 1); } this.server = server; } private <T> List<T> readStream(InputStream stream, Class<T> type) { JsonReader reader = null; try { reader = new JsonReader(new InputStreamReader(stream)); List<T> result = new ArrayList<T>(); try { reader.beginArray(); } catch (MalformedJsonException e) { // this means that the input came empty return result; } while (reader.hasNext()) { result.add(GsonFactory.getGson().<T>fromJson(reader, type)); } reader.endArray(); return result; } catch (IOException e) { throw new ServiceSourceException("Error consuming stream", e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { logger.error("Error closing stream reader", e); } } IOUtils.closeQuietly(stream); } } public String getApiUrl() { return apiUrl; } public void setApiUrl(String apiUrl) { this.apiUrl = apiUrl; } public String getLoginUrl() { return loginUrl; } public void setLoginUrl(String loginUrl) { this.loginUrl = loginUrl; } public String getTenantName() { return tenantName; } public void setTenantName(String tenantName) { this.tenantName = tenantName; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getCsrfToken() { return csrfToken; } public void setCsrfToken(String csrfToken) { this.csrfToken = csrfToken; } public String getAnalysisUrl() { return analysisUrl; } public void setAnalysisUrl(String analysisUrl) { this.analysisUrl = analysisUrl; } public Integer getReadTimeout() { return readTimeout; } public void setReadTimeout(Integer readTimeout) { this.readTimeout = readTimeout; } public Integer getConnectTimeout() { return connectTimeout; } public void setConnectTimeout(Integer connectTimeout) { this.connectTimeout = connectTimeout; } public Boolean getUseBasicAuth() { return useBasicAuth; } public void setUseBasicAuth(Boolean useBasicAuth) { this.useBasicAuth = useBasicAuth; } }