Java tutorial
/** * Mule Zuora Cloud Connector * * 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.txt file. */ /** * This file was automatically generated by the Mule Development Kit */ package org.mule.modules.zuora; import java.beans.PropertyDescriptor; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.*; import javax.xml.datatype.XMLGregorianCalendar; import com.zuora.api.*; import org.apache.commons.io.IOUtils; import org.mule.api.ConnectionException; import org.mule.api.ConnectionExceptionCode; import org.mule.api.MuleContext; import org.mule.api.MuleException; import org.mule.api.annotations.*; import org.mule.api.annotations.display.Password; import org.mule.api.annotations.display.Placement; import org.mule.api.annotations.licensing.RequiresEnterpriseLicense; 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.api.context.MuleContextAware; import org.mule.common.metadata.*; import org.mule.common.metadata.builder.DefaultMetaDataBuilder; import org.mule.common.metadata.builder.PojoMetaDataBuilder; import org.mule.common.metadata.datatype.DataType; import org.mule.common.query.DefaultOperatorVisitor; import org.mule.common.query.DsqlQueryVisitor; import org.mule.common.query.DsqlQuery; import org.mule.modules.zuora.zobject.ZObjectType; import org.mule.modules.zuora.zuora.api.CxfZuoraClient; import org.mule.modules.zuora.zuora.api.RestZuoraClient; import org.mule.modules.zuora.zuora.api.RestZuoraClientImpl; import org.mule.modules.zuora.zuora.api.SessionTimedOutException; import org.mule.modules.zuora.zuora.api.ZuoraClient; import org.mule.modules.zuora.zuora.api.ZuoraException; import org.mule.streaming.PagingConfiguration; import org.mule.streaming.ProviderAwarePagingDelegate; import com.zuora.api.object.ZObject; import com.zuora.api.object.ZuoraBeanMap; import org.springframework.beans.BeanUtils; /** * Zuora is the leader in online recurring billing and payment solutions for SaaS and subscription businesses. * <p/> * This connector provides full access to the Z-Commerce platform API. * * @author MuleSoft, Inc. */ @Connector(name = "zuora", friendlyName = "Zuora", minMuleVersion = "3.5") @RequiresEnterpriseLicense public class ZuoraModule implements MuleContextAware { private static final String API_URL = "/apps/services/a/48.0"; private static final String REST_API_URL = "/apps/api/"; /** * The client to use. Mainly for mocking purposes */ @Configurable @Optional private ZuoraClient<Exception> client; // Not configurable, just used to get batch exports. //NOTE: If more processors need this, we might build a Facade to hide it along with the SOAP client private RestZuoraClient restClient; /** * Target URI to connect to */ @Configurable @Default("https://apisandbox.zuora.com") @Optional @Placement(group = "Connection") private String endpoint; private String username; private String password; private MuleContext muleContext; @MetaDataKeyRetriever public List<MetaDataKey> getMetadataKeys() { List<MetaDataKey> keys = new ArrayList<MetaDataKey>(); Class<?> c = ZObjectType.class; Field[] flds = c.getDeclaredFields(); for (Field f : flds) { if (f.isEnumConstant()) { Object value = null; try { value = f.get(c); } catch (IllegalAccessException e) { throw new RuntimeException("Error while retrieving keys.", e); } keys.add(createKey(((ZObjectType) value).getZObjectClass())); } } return keys; } private MetaDataKey createKey(Class<?> cls) { return new DefaultMetaDataKey(cls.getSimpleName(), cls.getSimpleName()); } @MetaDataRetriever public MetaData getMetadata(MetaDataKey key) throws Exception { Class<?> cls = getClassForType(key.getId()); PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(cls); Map<String, MetaDataModel> fieldMap = new HashMap<String, MetaDataModel>(); for (PropertyDescriptor pd : pds) { if (pd.getReadMethod() != null && pd.getWriteMethod() != null) { fieldMap.put(pd.getName(), getFieldMetadata(pd.getPropertyType())); } } DefaultDefinedMapMetaDataModel mapModel = new DefaultDefinedMapMetaDataModel(fieldMap, key.getId()); return new DefaultMetaData(mapModel); } private MetaDataModel getFieldMetadata(Class<?> propertyType) { DataType dataType; if (String.class.equals(propertyType)) { dataType = DataType.STRING; } else if (Number.class.isAssignableFrom(propertyType)) { dataType = DataType.NUMBER; } else if (XMLGregorianCalendar.class.equals(propertyType)) { dataType = DataType.DATE_TIME; } else { return new DefaultPojoMetaDataModel(propertyType); } return new DefaultSimpleMetaDataModel(dataType); } private Class<?> getClassForType(String type) throws ClassNotFoundException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class<?> cls = cl.loadClass("com.zuora.api.object." + type); return cls; } /** * Connects to Zuora * * @param username Username to identify the user * @param password Password to authenticate the username */ @Connect public synchronized void connect(@ConnectionKey String username, @Password String password) throws ConnectionException { try { client = new CxfZuoraClient(username, password, this.endpoint + API_URL); restClient = new RestZuoraClientImpl(this.endpoint + REST_API_URL); this.username = username; this.password = password; //Dummy call to make sure credentials are ok. getUserInfo(); } catch (UnexpectedErrorFault e) { throw new ConnectionException(ConnectionExceptionCode.UNKNOWN, e.getFaultInfo().getFaultCode().value(), e.getFaultInfo().getFaultMessage()); } catch (LoginFault e) { if (e.getFaultInfo().getFaultCode() == ErrorCode.INVALID_LOGIN) { throw new ConnectionException(ConnectionExceptionCode.INCORRECT_CREDENTIALS, e.getFaultInfo().getFaultCode().value(), e.getFaultInfo().getFaultMessage()); } else { throw new ConnectionException(ConnectionExceptionCode.UNKNOWN, e.getFaultInfo().getFaultCode().value(), e.getFaultInfo().getFaultMessage()); } } catch (Exception e) { throw new ConnectionException(ConnectionExceptionCode.UNKNOWN, ConnectionExceptionCode.UNKNOWN.toString(), e.getMessage()); } } @ValidateConnection public boolean isConnected() { return client != null; } /** * Destroys the session */ @Disconnect public synchronized void disconnect() { client = null; } @ConnectionIdentifier public String getSessionId() { return client.getSessionId(); } /** * Batch creation of ZObjects associated to Subscriptions * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:subscribe} * * @param subscriptions the list of subscriptions to perform * @return a subscription results list, one for each subscription * * @throws Exception If subscription fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<SubscribeResult> subscribe( @Default("#[payload]") List<com.zuora.api.SubscribeRequest> subscriptions) throws Exception { return client.subscribe(subscriptions); } /** * Batch creation of ZObjects * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:create} * * @param zobjects the zobjects to create * @param type the type of zobject passed * @return a list of {@link SaveResult}, one for each ZObject * * @throws Exception If creation fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<SaveResult> create(@MetaDataKeyParam String type, @Optional @Default("#[payload]") List<Map<String, Object>> zobjects) throws Exception { return client.create(toPojos(type, zobjects)); } private List<ZObject> toPojos(String type, List<Map<String, Object>> zobjects) { ArrayList<ZObject> pojos = new ArrayList<ZObject>(); for (Map<String, Object> o : zobjects) { ZObject zobject = toPojo(type, o); pojos.add(zobject); } return pojos; } @SuppressWarnings("unchecked") private ZObject toPojo(String type, Map<String, Object> o) { ZObject zobject; if (o instanceof ZuoraBeanMap) { zobject = (ZObject) ((ZuoraBeanMap) o).getBean(); } else { try { Class<?> cls = getClassForType(type); zobject = (ZObject) cls.newInstance(); ZuoraBeanMap zuoraBeanMap = new ZuoraBeanMap(zobject); zuoraBeanMap.putAll(o); } catch (Exception e) { throw new RuntimeException(e); } } return zobject; } /** * Batch creation of invoices for accounts * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:generate} * * @param zobjects the zobjects to generate, as a list of string-object maps . * Zuora attribute names, unlike java beans, are CamelCase. * @param type the type of zobject passed * @return a list of {@link SaveResult}, one for each ZObject * * @throws Exception if generation fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<SaveResult> generate(@MetaDataKeyParam String type, @Optional @Default("#[payload]") List<Map<String, Object>> zobjects) throws Exception { return client.generate(toPojos(type, zobjects)); } /** * Batch update of ZObjects * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:update} * * @param zobjects the zobjects to update, as a list of string-object maps . * Zuora attribute names, unlike java beans, are CamelCase. * @param type the type of zobject passed * @return a list of {@link SaveResult}, one for each ZObject * * @throws Exception If update fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<SaveResult> update(@MetaDataKeyParam String type, @Optional @Default("#[payload]") List<Map<String, Object>> zobjects) throws Exception { return client.update(toPojos(type, zobjects)); } /** * Batch delete of ZObjects * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:delete} * * @param type the type of ZObjects to delete * @param ids the list of ids to delete * @return a list of {@link DeleteResult}, one for each id * * @throws Exception if deletion fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<DeleteResult> delete(@MetaDataKeyParam String type, List<String> ids) throws Exception { return client.delete(type, ids); } /** * Lazily retrieves ZObject that match a given query, * written in Zuora native query language * <p/> * If you expect more than 2000 results to be returned, remember that you have * to enable queryMore for your zuora account (as documented: * http://knowledgecenter.zuora.com/D_Using_the_Zuora_API/C_API_Reference/E_API_Calls/queryMore()) * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:find} * * @param query the query, using the SQL-Like Zuora Query Language * @param pagingConfiguration . * @return a {@link ZObject} iterable. {@link ZObject} returned by this operation * may be instances of either static ZObject - like Account or Amendment -, if the object is a non-customizable Zuora entity, * or {@link ZObject}, if the object is a customizable Zuora entity * @throws Exception if find fails */ @SuppressWarnings("unchecked") @Paged @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public ProviderAwarePagingDelegate<Map<String, Object>, ZuoraModule> find( @org.mule.api.annotations.Query final String query, final PagingConfiguration pagingConfiguration) { return new ProviderAwarePagingDelegate<Map<String, Object>, ZuoraModule>() { private int pageNumber = 0; private boolean isDone; private String queryLocator; private int count = -1; @Override public List<Map<String, Object>> getPage(ZuoraModule provider) { try { QueryResult result = null; if (this.pageNumber == 0) { result = provider.getClient().query(query); pageNumber++; count = result.getSize(); isDone = result.getDone(); queryLocator = result.getQueryLocator(); } else if (!isDone) { result = provider.getClient().queryMore(queryLocator); pageNumber++; isDone = result.getDone(); queryLocator = result.getQueryLocator(); } else { return Collections.emptyList(); } List<Map<String, Object>> maps = new ArrayList<Map<String, Object>>(); for (ZObject o : result.getRecords()) { if (o != null) { maps.add(new ZuoraBeanMap(o)); } } return maps; } catch (Exception e) { e.printStackTrace(); } return Collections.emptyList(); } @Override public void close() throws MuleException { } @Override public int getTotalResults(ZuoraModule provider) throws Exception { return 0; } }; } @QueryTranslator public String toNativeQuery(DsqlQuery query) { ZuoraQueryVisitor visitor = new ZuoraQueryVisitor(); query.accept(visitor); return visitor.dsqlQuery(); } /** * Answers user information * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:get-user-info} * * @return a {@link User} * @throws Exception if request fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public User getUserInfo() throws Exception { return client.getUserInfo(); } /** * Amends subscriptions * <p/> * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:amend} * * @param amendaments the list of amendments to perform * @return a list of {@link AmendResult}, one for each amendment * @throws Exception if amend fails */ @Processor @InvalidateConnectionOn(exception = SessionTimedOutException.class) public List<AmendResult> amend(@Default("#[payload]") List<com.zuora.api.AmendRequest> amendaments) throws Exception { return client.amend(amendaments); } /** * Retrieve an exported file from Zuora and return an InputStream to it * * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:get-export-file-stream} * * @param exportId id of the Zuora exported file to retrieve * @return an InputStream to read from the exported file * @throws IOException if can't access the exported file * @throws ZuoraException if the exported file doesn't exist */ @Processor public InputStream getExportFileStream(final String exportId) throws IOException { return getRestClient().getExportedFileStream(this.username, this.password, exportId); } /** * Retrieve an exported file from Zuora, and return its content as a String * * {@sample.xml ../../../doc/mule-module-zuora.xml.sample zuora:get-export-file-content} * * @param exportId id of the Zuora exported file to retrieve * @return the file's content as a String * @throws IOException if can't access the exported file * @throws ZuoraException if the exported file doesn't exist */ @Processor public String getExportFileContent(final String exportId) throws IOException { final InputStream exportedFileStream = getExportFileStream(exportId); final String content = IOUtils.toString(exportedFileStream, "UTF-8"); exportedFileStream.close(); return content; } public void setEndpoint(String endpoint) { this.endpoint = endpoint; } public String getEndpoint() { return endpoint; } public void setClient(ZuoraClient<Exception> client) { this.client = client; } public ZuoraClient<Exception> getClient() { return client; } public void setRestClient(RestZuoraClient client) { this.restClient = client; } private RestZuoraClient getRestClient() { return this.restClient; } @Override public void setMuleContext(final MuleContext context) { this.muleContext = context; } MuleContext getMuleContext() { return this.muleContext; } public static class ZuoraQueryVisitor extends DsqlQueryVisitor { @Override public org.mule.common.query.expression.OperatorVisitor operatorVisitor() { return new ZuoraOperatorVisitor(); } } public static class ZuoraOperatorVisitor extends DefaultOperatorVisitor { @Override public java.lang.String notEqualsOperator() { return " != "; } @Override public String lessOperator() { return " < "; } @Override public java.lang.String lessOrEqualsOperator() { return " <= "; } } }