/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.labs64.netlicensing.domain; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.labs64.netlicensing.domain.entity.Country; import com.labs64.netlicensing.domain.entity.License; import com.labs64.netlicensing.domain.entity.LicenseTemplate; import com.labs64.netlicensing.domain.entity.Licensee; import com.labs64.netlicensing.domain.entity.PaymentMethod; import com.labs64.netlicensing.domain.entity.Product; import com.labs64.netlicensing.domain.entity.ProductModule; import com.labs64.netlicensing.domain.entity.Token; import com.labs64.netlicensing.domain.entity.Transaction; import com.labs64.netlicensing.domain.vo.LicenseTypeProperties; import com.labs64.netlicensing.domain.vo.LicensingModelProperties; import com.labs64.netlicensing.domain.vo.Page; import com.labs64.netlicensing.domain.vo.PageImpl; import com.labs64.netlicensing.domain.vo.ValidationResult; import com.labs64.netlicensing.exception.ConversionException; import com.labs64.netlicensing.exception.NetLicensingException; import com.labs64.netlicensing.exception.WrongResponseFormatException; import com.labs64.netlicensing.schema.context.Item; import com.labs64.netlicensing.schema.context.Netlicensing; import com.labs64.netlicensing.schema.converter.Converter; import com.labs64.netlicensing.schema.converter.ItemToCountryConverter; import com.labs64.netlicensing.schema.converter.ItemToLicenseConverter; import com.labs64.netlicensing.schema.converter.ItemToLicenseTemplateConverter; import com.labs64.netlicensing.schema.converter.ItemToLicenseTypePropertiesConverter; import com.labs64.netlicensing.schema.converter.ItemToLicenseeConverter; import com.labs64.netlicensing.schema.converter.ItemToLicensingModelPropertiesConverter; import com.labs64.netlicensing.schema.converter.ItemToPaymentMethodConverter; import com.labs64.netlicensing.schema.converter.ItemToProductConverter; import com.labs64.netlicensing.schema.converter.ItemToProductModuleConverter; import com.labs64.netlicensing.schema.converter.ItemToTokenConverter; import com.labs64.netlicensing.schema.converter.ItemToTransactionConverter; import com.labs64.netlicensing.schema.converter.ItemsToValidationResultConverter; import com.labs64.netlicensing.util.Visitable; import com.labs64.netlicensing.util.Visitor; /** * Factory that contains static methods for creating entities */ public class EntityFactory { private static final Map<Class<?>, Class<?>> entityToConverterMap = new HashMap<Class<?>, Class<?>>(); static { entityToConverterMap.put(License.class, ItemToLicenseConverter.class); entityToConverterMap.put(Licensee.class, ItemToLicenseeConverter.class); entityToConverterMap.put(LicenseTemplate.class, ItemToLicenseTemplateConverter.class); entityToConverterMap.put(PaymentMethod.class, ItemToPaymentMethodConverter.class); entityToConverterMap.put(Product.class, ItemToProductConverter.class); entityToConverterMap.put(ProductModule.class, ItemToProductModuleConverter.class); entityToConverterMap.put(Token.class, ItemToTokenConverter.class); entityToConverterMap.put(Transaction.class, ItemToTransactionConverter.class); entityToConverterMap.put(Country.class, ItemToCountryConverter.class); entityToConverterMap.put(LicensingModelProperties.class, ItemToLicensingModelPropertiesConverter.class); entityToConverterMap.put(LicenseTypeProperties.class, ItemToLicenseTypePropertiesConverter.class); } private Map<Class<?>, Converter<Item, ?>> convertersCache; private Map<Class<?>, Converter<Item, ?>> getConvertersCache() { if (convertersCache == null) { convertersCache = new HashMap<>(); } return convertersCache; } /** * Creates entity of specific class from service response * * @param netlicensing * service XML response * @param entityClass * entity class * @return entity class instance created from service response * @throws com.labs64.netlicensing.exception.NetLicensingException */ @SuppressWarnings("unchecked") public <T> T create(final Netlicensing netlicensing, final Class<T> entityClass) throws NetLicensingException { if (entityClass == ValidationResult.class) { return (T) new ItemsToValidationResultConverter().convert(netlicensing.getItems()); } else { final Item item = findSuitableItemOfType(netlicensing, entityClass); return converterFor(entityClass).convert(item); } } public class LinkedEntitiesPopulator extends Visitor { private final List<Object> linkedEntities; public LinkedEntitiesPopulator(final List<Object> linkedEntities) { this.linkedEntities = linkedEntities; } public void visit(final Product product) throws Exception { final List<ProductModule> linkedProductModules = new ArrayList<>(); for (final Iterator<Object> iter = linkedEntities.iterator(); iter.hasNext();) { final Object linkedEntity = iter.next(); if (ProductModule.class.isAssignableFrom(linkedEntity.getClass())) { final ProductModule linkedProductModule = (ProductModule) linkedEntity; if (product.getNumber().equals(linkedProductModule.getProduct().getNumber())) { iter.remove(); linkedProductModules.add(linkedProductModule); linkedProductModule.setProduct(product); } } else if (Licensee.class.isAssignableFrom(linkedEntity.getClass())) { final Licensee linkedLecensee = (Licensee) linkedEntity; if (product.getNumber().equals(linkedLecensee.getProduct().getNumber())) { iter.remove(); linkedLecensee.setProduct(product); } } } for (final ProductModule linkedProductModule : linkedProductModules) { if (Visitable.class.isAssignableFrom(linkedProductModule.getClass())) { ((Visitable) linkedProductModule).accept(this); } } } public void visit(final ProductModule productModule) throws Exception { final List<LicenseTemplate> linkedLicenseTemplates = new ArrayList<>(); for (final Iterator<Object> iter = linkedEntities.iterator(); iter.hasNext();) { final Object linkedEntity = iter.next(); if (LicenseTemplate.class.isAssignableFrom(linkedEntity.getClass())) { final LicenseTemplate linkedLicenseTemplate = (LicenseTemplate) linkedEntity; if (productModule.getNumber().equals(linkedLicenseTemplate.getProductModule().getNumber())) { iter.remove(); linkedLicenseTemplates.add(linkedLicenseTemplate); linkedLicenseTemplate.setProductModule(productModule); } } } for (final LicenseTemplate linkedLicenseTemplate : linkedLicenseTemplates) { if (Visitable.class.isAssignableFrom(linkedLicenseTemplate.getClass())) { ((Visitable) linkedLicenseTemplate).accept(this); } } } public void visit(final LicenseTemplate licenseTemplate) throws Exception { for (final Iterator<Object> iter = linkedEntities.iterator(); iter.hasNext();) { final Object linkedEntity = iter.next(); if (License.class.isAssignableFrom(linkedEntity.getClass())) { final License linkedLicense = (License) linkedEntity; if (licenseTemplate.getNumber().equals(linkedLicense.getLicenseTemplate().getNumber())) { iter.remove(); linkedLicense.setLicenseTemplate(licenseTemplate); } } } } } /** * Creates page of entities of specified class from service response * * @param netlicensing * service XML response * @param entityClass * entity class * @return page of entities created from service response * @throws com.labs64.netlicensing.exception.NetLicensingException */ public <T> Page<T> createPage(final Netlicensing netlicensing, final Class<T> entityClass) throws NetLicensingException { if (netlicensing.getItems() != null) { final List<T> entities = new ArrayList<T>(); final List<Object> linkedEntities = new ArrayList<Object>(); for (final Item item : netlicensing.getItems().getItem()) { final Class<?> itemEntityClass = getEntityClassByItemType(item); if (entityClass.isAssignableFrom(itemEntityClass)) { entities.add(converterFor(entityClass).convert(item)); } else { linkedEntities.add(converterFor(itemEntityClass).convert(item)); } } if (!linkedEntities.isEmpty()) { for (final T entity : entities) { if (Visitable.class.isAssignableFrom(entity.getClass())) { try { ((Visitable) entity).accept(new LinkedEntitiesPopulator(linkedEntities)); } catch (final Exception e) { throw new ConversionException("Error processing linked entities", e); } } } } return PageImpl.createInstance(entities, netlicensing.getItems().getPagenumber(), netlicensing.getItems().getItemsnumber(), netlicensing.getItems().getTotalpages(), netlicensing.getItems().getTotalitems(), netlicensing.getItems().getHasnext()); } else { throw new WrongResponseFormatException("Service response is not a page response"); } } /** * Returns converter that is able to convert an {@link Item} object to an entity of specified class * * @param entityClass * entity class * @return {@link Converter} suitable for the given entity class */ @SuppressWarnings("unchecked") private <T> Converter<Item, T> converterFor(final Class<T> entityClass) { Converter<Item, T> converter = null; try { converter = (Converter<Item, T>) getConvertersCache().get(entityClass); } catch (final ClassCastException e) { throw new RuntimeException("Wrong converter type found for entity class " + entityClass.getCanonicalName()); } if (converter == null) { final Class<?> converterClass = entityToConverterMap.get(entityClass); if (converterClass == null) { throw new IllegalArgumentException("No converter is found for entity of class " + entityClass.getCanonicalName()); } try { converter = (Converter<Item, T>) converterClass.newInstance(); getConvertersCache().put(entityClass, converter); } catch (final InstantiationException e) { throw new RuntimeException("Can not instantiate converter of class " + converterClass.getCanonicalName()); } catch (final IllegalAccessException e) { throw new RuntimeException("Can not instantiate converter of class " + converterClass.getCanonicalName()); } } return converter; } /** * Finds and returns from {@link Netlicensing} object suitable item of specified type * * @param netlicensing * {@link Netlicensing} response object * @param type * class type to be matched * @return suitable item of specified type * @throws WrongResponseFormatException */ private Item findSuitableItemOfType(final Netlicensing netlicensing, final Class<?> type) throws WrongResponseFormatException { if (netlicensing.getItems() != null) { for (final Item item : netlicensing.getItems().getItem()) { if (isItemOfType(item, type)) { return item; } } } throw new WrongResponseFormatException("Service response doesn't contain item of type " + type.getCanonicalName()); } /** * Check whether the {@link Item} object is of provided type. * * @param item * {@link Item} object * @param type * class type to be matched * @return true if item is the XML item of class "type" */ private boolean isItemOfType(final Item item, final Class<?> type) { return type.getSimpleName().equals(item.getType()) || type.getSimpleName().equals(item.getType() + "Properties"); } /** * Gets the entity class by response item type. * * @param item * the item * @return the entity class, if match is found * @throws WrongResponseFormatException * if match is not found */ private Class<?> getEntityClassByItemType(final Item item) throws WrongResponseFormatException { final String itemType = item.getType(); final String itemTypeProps = itemType.concat("Properties"); for (final Class<?> entityClass : entityToConverterMap.keySet()) { if (entityClass.getSimpleName().equals(itemType) || entityClass.getSimpleName().equals(itemTypeProps)) { return entityClass; } } throw new WrongResponseFormatException("Service response contains unexpected item type " + itemType); } }