/* * Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved. * * This file is part of the Jspresso framework. * * Jspresso is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jspresso is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Jspresso. If not, see <http://www.gnu.org/licenses/>. */ package org.jspresso.framework.model.descriptor.basic; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.jspresso.framework.model.component.IComponent; import org.jspresso.framework.model.component.IQueryComponent; import org.jspresso.framework.model.component.query.ComparableQueryStructure; import org.jspresso.framework.model.component.query.EnumQueryStructure; import org.jspresso.framework.model.descriptor.IComponentDescriptor; import org.jspresso.framework.model.descriptor.IComponentDescriptorProvider; import org.jspresso.framework.model.descriptor.IPropertyDescriptor; import org.jspresso.framework.model.descriptor.IQueryComponentDescriptor; import org.jspresso.framework.model.descriptor.IReferencePropertyDescriptor; import org.jspresso.framework.model.descriptor.query.ComparableQueryStructureDescriptor; import org.jspresso.framework.model.descriptor.query.EnumQueryStructureDescriptor; import org.jspresso.framework.model.entity.IEntity; import org.jspresso.framework.util.accessor.IAccessorFactory; /** * An implementation used for query components. * * @param <E> * the concrete type of components. * @author Vincent Vandenschrick * @internal */ public class RefQueryComponentDescriptor<E> extends AbstractComponentDescriptor<E> implements IQueryComponentDescriptor { private static final Logger LOG = LoggerFactory.getLogger(BasicQueryComponentDescriptorFactory.class); private Class<? extends E> componentContract; private IComponentDescriptorProvider<? extends IComponent> queryComponentsDescriptorProvider; private final Map<Class<? extends IComponent>, IComponentDescriptor<? extends IComponent>> registry; private IAccessorFactory accessorFactory; /** * Constructs a new {@code BasicQueryComponentDescriptor} instance. * * @param componentDescriptorProvider * the provider for delegate entity descriptor. * @param componentContract * the actual query component contract. * @param registry * the shared registry to store / retrieve referenced query descriptors. * @param accessorFactory * the accessor factory */ @SuppressWarnings("unchecked") protected RefQueryComponentDescriptor(IComponentDescriptorProvider<? extends IComponent> componentDescriptorProvider, Class<? extends E> componentContract, Map<Class<? extends IComponent>, IComponentDescriptor<? extends IComponent>> registry, IAccessorFactory accessorFactory) { super(IQueryComponent.class.getName()); this.registry = registry; this.registry.put((Class<IComponent>) componentContract, (IComponentDescriptor<IComponent>) this); this.queryComponentsDescriptorProvider = componentDescriptorProvider; this.accessorFactory = accessorFactory; this.componentContract = componentContract; if (getI18nNameKey() == null && componentContract != null) { setI18nNameKey(componentContract.getName()); } Collection<IPropertyDescriptor> propertyDescriptors = new ArrayList<>(); for (IPropertyDescriptor propertyDescriptor : getQueriedComponentsDescriptor().getPropertyDescriptors()) { propertyDescriptors.add(propertyDescriptor.createQueryDescriptor()); } propertyDescriptors.addAll(getExtraPropertyDescriptors()); setPropertyDescriptors(propertyDescriptors); } /** * Performs delayed configuration. */ protected void finishConfiguration() { setDescription(getQueriedComponentsDescriptor().getDescription()); setIcon(getQueriedComponentsDescriptor().getIcon()); List<String> qProperties = new ArrayList<>(); for (String queryableProperty : queryComponentsDescriptorProvider.getQueryableProperties()) { IPropertyDescriptor propertyDescriptor = getPropertyDescriptor(queryableProperty); if (propertyDescriptor instanceof ComparableQueryStructureDescriptor) { for (String nestedRenderedProperty : ((ComparableQueryStructureDescriptor) propertyDescriptor) .getRenderedProperties()) { qProperties.add(propertyDescriptor.getName() + "." + nestedRenderedProperty); } } else { qProperties.add(propertyDescriptor.getName()); } } setRenderedProperties(qProperties); setQueryableProperties(queryComponentsDescriptorProvider.getQueryableProperties()); setToStringProperty(getQueriedComponentsDescriptor().getToStringProperty()); setToHtmlProperty(getQueriedComponentsDescriptor().getToHtmlProperty()); setAutoCompleteProperty(getQueriedComponentsDescriptor().getAutoCompleteProperty()); setUnclonedProperties(getQueriedComponentsDescriptor().getUnclonedProperties()); setPageSize(getQueriedComponentsDescriptor().getPageSize()); setOrderingProperties(getQueriedComponentsDescriptor().getOrderingProperties()); } /** * Allows subclasses to specify extra property descriptors. * * @return none. */ protected Collection<IPropertyDescriptor> getExtraPropertyDescriptors() { return Collections.emptyList(); } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected IPropertyDescriptor refinePropertyDescriptor(IPropertyDescriptor propertyDescriptor) { // Only refine properties that belong to the original entity if (propertyDescriptor == null || getQueriedComponentsDescriptor().getPropertyDescriptor( propertyDescriptor.getName()) == null) { return propertyDescriptor; } IPropertyDescriptor refinedPropertyDescriptor; if (propertyDescriptor instanceof AbstractEnumerationPropertyDescriptor && ((AbstractEnumerationPropertyDescriptor) propertyDescriptor).isQueryMultiselect()) { refinedPropertyDescriptor = new EnumQueryStructureDescriptor( (AbstractEnumerationPropertyDescriptor) propertyDescriptor); } else if (propertyDescriptor instanceof BasicPropertyDescriptor && isPropertyFilterComparable( propertyDescriptor)) { refinedPropertyDescriptor = new ComparableQueryStructureDescriptor( ((BasicPropertyDescriptor) propertyDescriptor).createQueryDescriptor(), accessorFactory); ((ComparableQueryStructureDescriptor) refinedPropertyDescriptor).setMandatory(false); } else if ((propertyDescriptor instanceof IReferencePropertyDescriptor<?>)) { IComponentDescriptor<? extends IComponent> referencedDescriptor; referencedDescriptor = ((IReferencePropertyDescriptor<IComponent>) propertyDescriptor).getReferencedDescriptor(); Class<? extends IComponent> referencedType; try { referencedType = referencedDescriptor.getComponentContract(); } catch (RuntimeException ex) { LOG.debug("An exception occurred while trying to load the class {}. This might be normal during compilation.", referencedDescriptor.getName(), ex); referencedType = null; } if (referencedType != null) { if (propertyDescriptor instanceof BasicReferencePropertyDescriptor<?> && !(ComparableQueryStructure.class .isAssignableFrom(referencedType)) && !(EnumQueryStructure.class.isAssignableFrom(referencedType)) && !(referencedDescriptor instanceof RefQueryComponentDescriptor<?>)) { BasicReferencePropertyDescriptor<IComponent> basicRefPropDesc = ( (BasicReferencePropertyDescriptor<IComponent>) propertyDescriptor); // List<String> savedRenderedProperties = basicRefPropDesc // .getRenderedProperties(); basicRefPropDesc.setReferencedDescriptor(createOrGetRefQueryDescriptor(referencedDescriptor, referencedType)); // basicRefPropDesc.setRenderedProperties(savedRenderedProperties); } } refinedPropertyDescriptor = propertyDescriptor; } else { refinedPropertyDescriptor = propertyDescriptor; } return refinedPropertyDescriptor; } private IComponentDescriptor<? extends IComponent> createOrGetRefQueryDescriptor( IComponentDescriptor<? extends IComponent> referencedDescriptor, Class<? extends IComponent> referencedType) { IComponentDescriptor<? extends IComponent> refQueryDescriptor; synchronized (registry) { refQueryDescriptor = registry.get(referencedType); if (refQueryDescriptor == null) { refQueryDescriptor = new RefQueryComponentDescriptor<>(referencedDescriptor, referencedType, registry, accessorFactory); ((RefQueryComponentDescriptor<?>) refQueryDescriptor).finishConfiguration(); } } return refQueryDescriptor; } /** * {@inheritDoc} */ @Override public Class<? extends E> getComponentContract() { return componentContract; } /** * {@inheritDoc} */ @Override public boolean isEntity() { return IEntity.class.isAssignableFrom(getComponentContract()); } /** * {@inheritDoc} */ @Override public boolean isPurelyAbstract() { return false; } /** * Whether we need to create a comparable query structure for this property. * * @param propertyDescriptor * the property descriptor to test. * @return true if we need to create a comparable query structure for this * property. */ protected boolean isPropertyFilterComparable(IPropertyDescriptor propertyDescriptor) { return propertyDescriptor.isFilterComparable(); } /** * Gets the queriedComponentsDescriptor. * * @return the queriedComponentsDescriptor. */ @Override public IComponentDescriptor<? extends IComponent> getQueriedComponentsDescriptor() { return queryComponentsDescriptorProvider.getComponentDescriptor(); } }