package com.evrythng.java.wrapper.service; import com.evrythng.commons.domain.SortOrder; import com.evrythng.java.wrapper.ApiManager; import com.evrythng.java.wrapper.core.EvrythngApiBuilder.Builder; import com.evrythng.java.wrapper.core.EvrythngServiceBase; import com.evrythng.java.wrapper.exception.EvrythngClientException; import com.evrythng.java.wrapper.mapping.ActionDeserializer; import com.evrythng.java.wrapper.mapping.EvrythngJacksonModule; import com.evrythng.thng.resource.model.store.BooleanProperty; import com.evrythng.thng.resource.model.store.Location; import com.evrythng.thng.resource.model.store.NumberProperty; import com.evrythng.thng.resource.model.store.Property; import com.evrythng.thng.resource.model.store.Redirector; import com.evrythng.thng.resource.model.store.StringProperty; import com.evrythng.thng.resource.model.store.Thng; import com.evrythng.thng.resource.model.store.action.Action; import com.evrythng.thng.resource.model.store.action.CustomAction; import com.fasterxml.jackson.core.type.TypeReference; import org.pcollections.PVector; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Service wrapper for the {@code /thngs} endpoint of the EVRYTHNG Engine API. */ public class ThngService extends EvrythngServiceBase { public static final String PATH_THNGS = "/thngs"; public static final String PATH_THNG = PATH_THNGS + "/%s"; public static final String PATH_THNG_PROPERTIES = PATH_THNG + "/properties"; public static final String PATH_THNG_PROPERTY = PATH_THNG_PROPERTIES + "/%s"; public static final String PATH_THNG_LOCATION = PATH_THNG + "/location"; public static final String PATH_THNG_REDIRECTOR = PATH_THNG + "/redirector"; public static final String PATH_THNG_REDIRECTOR_QR = PATH_THNG_REDIRECTOR + "/qr"; public static final String PATH_THNG_ACTIONS = PATH_THNG + "/actions"; public static final String PATH_THNG_ALL_ACTIONS = PATH_THNG_ACTIONS + "/all"; public static final String PATH_THNG_ALL_ACTION = PATH_THNG_ALL_ACTIONS + "/%s"; public static final String PATH_THNG_TYPED_ACTIONS = PATH_THNG_ACTIONS + "/%s"; public static final String PATH_THNG_TYPED_ACTION = PATH_THNG_TYPED_ACTIONS + "/%s"; private static final TypeReference<List<Action>> ACTIONS_TYPE_REFERENCE = new TypeReference<List<Action>>() {}; protected ActionDeserializer deserializer; public ThngService(final ApiManager apiManager, final EvrythngJacksonModule evrythngJacksonModule) { super(apiManager); deserializer = evrythngJacksonModule.getActionDeserializer(); } /* ***** Thng ***** */ /** * Creates a new {@link Thng}. * <p> * POST {@value #PATH_THNGS} * * @param thng {@link Thng} instance * @return a pre-configured {@link Builder} */ public Builder<Thng> thngCreator(final Thng thng) throws EvrythngClientException { return post(PATH_THNGS, thng, new TypeReference<Thng>() { }); } /** * Retrieves {@link Thng}s, whether all, by filter, or by ids, in an iterative way. * @return A remote iterator that keeps returning a page, with size specified by the {@link Builder#perPage(int)} method, until all matching resources are returned. * @throws EvrythngClientException in case server communication fails. */ public final Builder<Iterator<PVector<Thng>>> iterator() throws EvrythngClientException { return iterator(PATH_THNGS, new TypeReference<List<Thng>>() { }).sortOrder(SortOrder.descending()); } /* ***** /thngs/{id} ***** */ /** * Retrieves the referenced {@link Thng}. * <p> * GET {@value #PATH_THNG} * * @param thngId thng id * @return a pre-configured {@link Builder} */ public Builder<Thng> thngReader(final String thngId) throws EvrythngClientException { return get(String.format(PATH_THNG, thngId), new TypeReference<Thng>() { }); } /** * Updates the referenced {@link Thng}. * <p> * PUT {@value #PATH_THNG} * * @param thngId thng id * @param thng {@link Thng} instance * @return a pre-configured {@link Builder} */ public Builder<Thng> thngUpdater(final String thngId, final Thng thng) throws EvrythngClientException { return put(String.format(PATH_THNG, thngId), thng, new TypeReference<Thng>() { }); } /** * Batch update a list of {@link Thng}. Select the {@link Thng}s to update using query parameters ?ids or ?filter. * <p> * PUT {@value #PATH_THNGS} * * @param thng {@link Thng} instance * @return a pre-configured {@link Builder} */ public Builder<Long> thngsUpdater(final Thng thng) throws EvrythngClientException { return putMultiple(PATH_THNGS, thng); } /** * Deletes the referenced {@link Thng}. * <p> * DELETE {@value #PATH_THNG} * * @param thngId thng id * @return a pre-configured {@link Builder} */ public Builder<Boolean> thngDeleter(final String thngId) throws EvrythngClientException { return delete(String.format(PATH_THNG, thngId)); } /** * Bulk delete some thngs. Select the {@link Thng}s to delete using query parameters ?ids or ?filter. * <p> * DELETE {@value #PATH_THNGS} * * @return a pre-configured {@link Builder} */ public Builder<Long> thngsDeleter() throws EvrythngClientException { return deleteMultiple(PATH_THNGS); } /* ***** /thngs/{id}/properties ***** */ /** * Creates multiple {@link com.evrythng.thng.resource.model.store.StringProperty} resources on the referenced {@link Thng}. * <p> * PUT {@value #PATH_THNG_PROPERTIES} * * @param thngId thng id * @param properties list of {@link com.evrythng.thng.resource.model.store.StringProperty} instances * * @return a pre-configured {@link Builder} */ public Builder<List<Property<?>>> propertiesCreator(final String thngId, final List<Property<?>> properties) throws EvrythngClientException { return put(String.format(PATH_THNG_PROPERTIES, thngId), properties, new TypeReference<List<Property<?>>>() { }); } /** * Retrieves the last updated {@link com.evrythng.thng.resource.model.store.StringProperty} resources from the referenced {@link Thng}. * <p> * GET {@value #PATH_THNG_PROPERTIES} * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<List<Property<?>>> propertiesReader(final String thngId) throws EvrythngClientException { return get(String.format(PATH_THNG_PROPERTIES, thngId), new TypeReference<List<Property<?>>>() { }); } /** * Retrieves {@link Property} updates with specified key, for a {@link Thng}, in an iterative way. * @return A remote iterator that keeps returning a page, with size specified by the {@link Builder#perPage(int)} method, until all matching resources are returned. * @throws EvrythngClientException in case server communication fails. */ public final Builder<Iterator<PVector<Property<?>>>> propertiesIterator(final String thngId, final String key) throws EvrythngClientException { return iterator(String.format(PATH_THNG_PROPERTY, thngId, key), new TypeReference<List<Property<?>>>() { }).sortOrder(SortOrder.descending()); } /** * Deletes all {@link com.evrythng.thng.resource.model.store.StringProperty} resources from the referenced {@link Thng}. * <p> * DELETE {@value #PATH_THNG_PROPERTIES} * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<Boolean> propertiesDeleter(final String thngId) throws EvrythngClientException { return delete(String.format(PATH_THNG_PROPERTIES, thngId)); } /** * Retrieves the last values of the {@link com.evrythng.thng.resource.model.store.StringProperty} named {@code key} from the referenced {@link Thng}. * <p> * GET {@value #PATH_THNG_PROPERTY} * * @deprecated use {@link #propertiesIterator(String, String)} instead. * * @param thngId thng id * @param key key * * @return a pre-configured {@link Builder} */ @Deprecated public Builder<List<Property<?>>> propertyReader(final String thngId, final String key) throws EvrythngClientException { return get(String.format(PATH_THNG_PROPERTY, thngId, key), new TypeReference<List<Property<?>>>() { }); } /** * Updates the {@link com.evrythng.thng.resource.model.store.StringProperty} named {@code key} of the referenced {@link Thng}. * <p> * PUT {@value #PATH_THNG_PROPERTY} * * @param thngId thng id * @param key key * @param update property update * * @return a pre-configured {@link Builder} */ public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final Property<?> update) throws EvrythngClientException { return put(String.format(PATH_THNG_PROPERTY, thngId, key), Collections.singletonList(update), new TypeReference<List<Property<?>>>() { }); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final String value, final Long timestamp) throws EvrythngClientException { return put(String.format(PATH_THNG_PROPERTY, thngId, key), Collections.singletonList(new StringProperty(null, value, timestamp)), new TypeReference<List<Property<?>>>() { }); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final Number value, final Long timestamp) throws EvrythngClientException { return put(String.format(PATH_THNG_PROPERTY, thngId, key), Collections.singletonList(new NumberProperty(null, value.doubleValue(), timestamp)), new TypeReference<List<Property<?>>>() { }); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final Boolean value, final Long timestamp) throws EvrythngClientException { return put(String.format(PATH_THNG_PROPERTY, thngId, key), Collections.singletonList(new BooleanProperty(null, value, timestamp)), new TypeReference<List<Property<?>>>() { }); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final String value) throws EvrythngClientException { return propertyUpdater(thngId, key, value, null); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final Number value) throws EvrythngClientException { return propertyUpdater(thngId, key, value, null); } public Builder<List<Property<?>>> propertyUpdater(final String thngId, final String key, final Boolean value) throws EvrythngClientException { return propertyUpdater(thngId, key, value, null); } /** * Deletes the {@link com.evrythng.thng.resource.model.store.StringProperty} named {@code key} from the referenced {@link Thng}. * <p> * DELETE {@value #PATH_THNG_PROPERTY} * * @param thngId thng id * @param key key * * @return a pre-configured {@link Builder} */ public Builder<Boolean> propertyDeleter(final String thngId, final String key) throws EvrythngClientException { return delete(String.format(PATH_THNG_PROPERTY, thngId, key)); } /* ***** /thngs/{id}/location ***** */ /** * Retrieves the last {@link Location} resources from the referenced {@link Thng}. * <p> * GET {@value #PATH_THNG_LOCATION} * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<List<Location>> locationReader(final String thngId) throws EvrythngClientException { return get(String.format(PATH_THNG_LOCATION, thngId), new TypeReference<List<Location>>() { }); } /** * Updates the current {@link Location} of the referenced {@link Thng}. * <p> * PUT {@value #PATH_THNG_LOCATION} * * @param thngId thng id * @param location {@link Location} instance * @return a preconfigured {@link Builder} * @see #locationUpdater(String, List) */ public Builder<List<Location>> locationUpdater(final String thngId, final Location location) throws EvrythngClientException { return locationUpdater(thngId, Collections.singletonList(location)); } /** * Updates the referenced {@link Thng} with multiple {@link Location} resources. * <p> * PUT {@value #PATH_THNG_LOCATION} * * @param thngId thng id * @param locations list of {@link Location} * * @return a pre-configured {@link Builder} */ public Builder<List<Location>> locationUpdater(final String thngId, final List<Location> locations) throws EvrythngClientException { return put(String.format(PATH_THNG_LOCATION, thngId), locations, new TypeReference<List<Location>>() { }); } /** * Deletes the {@link Location} of the referenced {@link Thng}. * <p> * DELETE {@value #PATH_THNG_LOCATION} * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<Boolean> locationDeleter(final String thngId) throws EvrythngClientException { return delete(String.format(PATH_THNG_LOCATION, thngId)); } /* ***** /thngs/{id}/redirector ***** */ /** * Creates a redirector for the Thng. * * @param thngId thng id * @param redirection {@link Redirector} instance * * @return a pre-configured {@link Builder} */ public Builder<Redirector> redirectorCreator(final String thngId, final Redirector redirection) throws EvrythngClientException { return post(String.format(PATH_THNG_REDIRECTOR, thngId), redirection, new TypeReference<Redirector>() { }); } /** * Retrieves the redirector for the Thng. * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<Redirector> redirectorReader(final String thngId) throws EvrythngClientException { return get(String.format(PATH_THNG_REDIRECTOR, thngId), new TypeReference<Redirector>() { }); } /** * Deletes the redirector for the Thng. * * @param thngId thng id * * @return a pre-configured {@link Builder} */ public Builder<Boolean> redirectorDeleter(final String thngId) throws EvrythngClientException { return delete(String.format(PATH_THNG_REDIRECTOR, thngId)); } /** * Updates the redirector for the Thng. * * @param thngId thng id * @param redirection {@link Redirector} instance * * @return a pre-configured {@link Builder} */ public Builder<Redirector> redirectorUpdater(final String thngId, final Redirector redirection) throws EvrythngClientException { return put(String.format(PATH_THNG_REDIRECTOR, thngId), redirection, new TypeReference<Redirector>() { }); } /** * Creates an action. */ public <T extends Action> Builder<T> actionCreator(final String thngId, final T action) throws EvrythngClientException { return (Builder<T>) post(String.format(PATH_THNG_TYPED_ACTIONS, thngId, action.getType()), action, new TypeReference<Action>() { }); } /** * Creates an action using /thngs/../actions/all endpoint. */ public Builder<Action> actionAllCreator(final String thngId, final Action action) throws EvrythngClientException { return post(String.format(PATH_THNG_ALL_ACTIONS, thngId), action, new TypeReference<Action>() { }); } /** * Gets one action by actionId and type. */ @SuppressWarnings("unchecked") public <T extends Action> Builder<T> actionReader(final String thngId, final Class<T> actionClass, final String actionId) throws EvrythngClientException { String type = getType(actionClass); return (Builder<T>) get(String.format(PATH_THNG_TYPED_ACTION, thngId, type, actionId), new TypeReference<Action>() { }); } /** * Gets one action by actionId and type. */ public Builder<CustomAction> actionReader(final String thngId, final String customType, final String actionId) throws EvrythngClientException { checkCustomType(customType); return get(String.format(PATH_THNG_TYPED_ACTION, thngId, customType, actionId), new TypeReference<CustomAction>() { }); } /** * Gets one action by actionId. */ public Builder<Action> actionReader(final String thngId, final String actionId) throws EvrythngClientException { return get(String.format(PATH_THNG_ALL_ACTION, thngId, actionId), new TypeReference<Action>() { }); } /** * Gets all the actions. */ public Builder<List<Action>> actionsReader(final String thngId) throws EvrythngClientException { return get(String.format(PATH_THNG_ALL_ACTIONS, thngId), new TypeReference<List<Action>>() { }); } /** * Gets all the action of a type. */ @SuppressWarnings("unchecked") public <T extends Action> Builder<List<T>> actionsReader(final String thngId, final Class<T> actionClass) throws EvrythngClientException { String type = getType(actionClass); return (Builder<List<T>>) (Builder<?>) get(String.format(PATH_THNG_TYPED_ACTIONS, thngId, type), new TypeReference<List<Action>>() { }); } /** * Gets all the action of a type. */ public Builder<List<CustomAction>> actionsReader(final String thngId, final String customType) throws EvrythngClientException { checkCustomType(customType); return get(String.format(PATH_THNG_TYPED_ACTIONS, thngId, customType), new TypeReference<List<CustomAction>>() { }); } /** * Retrieves all actions of thng. * @param thngId thng id */ public Builder<Iterator<PVector<Action>>> actionsIterator(final String thngId) { return iterator(String.format(PATH_THNG_ALL_ACTIONS, thngId), ACTIONS_TYPE_REFERENCE).sortOrder(SortOrder.descending()); } /** * Retrieves all actions of thng of type. * @param thngId thng id. * @param actionTypeName action type. */ public Builder<Iterator<PVector<Action>>> actionsIterator(final String thngId, final String actionTypeName) { return iterator(String.format(PATH_THNG_TYPED_ACTIONS, thngId, actionTypeName), ACTIONS_TYPE_REFERENCE).sortOrder(SortOrder.descending()); } protected void checkCustomType(final String customType) { if (!customType.startsWith("_")) { throw new IllegalArgumentException("Custom types must start with '_' (underscore)."); } } public <T extends Action> String getType(final Class<T> actionClass) { String type = deserializer.getActionType(actionClass); if (type == null) { throw new IllegalArgumentException("The action type is not recognized."); } return type; } }