/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform 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. * * The Whole Platform 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 the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.lang.reusables.visitors; import static org.whole.lang.reusables.reflect.ReusablesEntityDescriptorEnum.PathExpression_ord; import static org.whole.lang.reusables.reflect.ReusablesEntityDescriptorEnum.Reusable; import static org.whole.lang.reusables.reflect.ReusablesEntityDescriptorEnum.Reusable_ord; import static org.whole.lang.reusables.reflect.ReusablesEntityDescriptorEnum.Reusables; import org.whole.lang.bindings.IBindingManager; import org.whole.lang.commons.factories.CommonsEntityAdapterFactory; import org.whole.lang.exceptions.WholeIllegalArgumentException; import org.whole.lang.iterators.IEntityIterator; import org.whole.lang.iterators.IteratorFactory; import org.whole.lang.matchers.Matcher; import org.whole.lang.model.IEntity; import org.whole.lang.model.adapters.IEntityAdapter; import org.whole.lang.operations.DynamicCompilerOperation; import org.whole.lang.resources.CompoundResourceRegistry; import org.whole.lang.resources.IResource; import org.whole.lang.resources.IResourceRegistry; import org.whole.lang.resources.ResourceRegistry; import org.whole.lang.reusables.factories.ReusablesEntityFactory; import org.whole.lang.reusables.model.Adapt; import org.whole.lang.reusables.model.IReusablesEntity; import org.whole.lang.reusables.model.Include; import org.whole.lang.reusables.model.Model; import org.whole.lang.reusables.model.Registry; import org.whole.lang.reusables.model.Reusable; import org.whole.lang.reusables.model.Reuse; import org.whole.lang.reusables.model.Sync; import org.whole.lang.reusables.operations.EvaluateCloneOperation; import org.whole.lang.reusables.reflect.ReusablesEntityDescriptorEnum; import org.whole.lang.util.BehaviorUtils; import org.whole.lang.util.EntityUtils; import org.whole.lang.util.ResourceUtils; /** * @author Enrico Persiani */ public class ReusablesInterpreterVisitor extends AbstractReusablesSemanticsVisitor { @Override public void setResultIterator(IEntityIterator<?> iterator) { if (iterator != null) iterator.setBindings(getBindings()); super.setResultIterator(iterator); } protected EvaluateCloneOperation evaluateCloneOperation; protected EvaluateCloneOperation getEvaluateCloneOperation() { if (evaluateCloneOperation == null) { evaluateCloneOperation = new EvaluateCloneOperation(getOperation(), entity -> Matcher.matchAnyImpl(entity, ReusablesEntityDescriptorEnum.Adapt, ReusablesEntityDescriptorEnum.Resource, ReusablesEntityDescriptorEnum.Include, ReusablesEntityDescriptorEnum.Reuse, ReusablesEntityDescriptorEnum.Sync)); } return evaluateCloneOperation; } protected boolean isEvaluateCloneOperation() { return getBindings().wIsSet("evaluateCloneOperation"); } protected void evaluateAndClone(IEntity entity, IBindingManager bm) { bm.setResult(getEvaluateCloneOperation().clone(entity)); } protected void evaluateAndClone(IEntity entity) { evaluateAndClone(entity, getBindings()); } @Override public boolean visitAdapter(IEntityAdapter entity) { setResult(null); switch (entity.wGetEntityDescriptor().getOrdinal()) { case Reusable_ord: if (isEvaluateCloneOperation()) evaluateAndClone(entity.wGetAdaptee(false)); else return super.visitAdapter(entity); return false; case PathExpression_ord: // setResultIterator(DynamicCompilerOperation.compile(entity.wGetAdaptee(false), getBindings()).getResultIterator()); try { getBindings().wEnterScope(); getBindings().wDef("self", entity.wGetAdaptee(false)); setResultIterator(BehaviorUtils.lazyEvaluate(entity.wGetAdaptee(false), 0, getBindings())); } finally { getBindings().wExitScope(); } return false; default: return super.visitAdapter(entity); } } @Override public void visit(IReusablesEntity entity) { switch (entity.wGetEntityDescriptor().getOrdinal()) { case ReusablesEntityDescriptorEnum.Load_ord: case ReusablesEntityDescriptorEnum.Save_ord: case ReusablesEntityDescriptorEnum.Classpath_ord: case ReusablesEntityDescriptorEnum.FileSystem_ord: case ReusablesEntityDescriptorEnum.Workspace_ord: case ReusablesEntityDescriptorEnum.URL_ord: case ReusablesEntityDescriptorEnum.File_ord: case ReusablesEntityDescriptorEnum.PathSegments_ord: case ReusablesEntityDescriptorEnum.PathWithExtension_ord: case ReusablesEntityDescriptorEnum.PathName_ord: case ReusablesEntityDescriptorEnum.PersistenceId_ord: case ReusablesEntityDescriptorEnum.URI_ord: case ReusablesEntityDescriptorEnum.Contents_ord: case ReusablesEntityDescriptorEnum.Folder_ord: DynamicCompilerOperation.compile(entity, getBindings()); return; } if (isEvaluateCloneOperation()) evaluateAndClone(entity); } @Override public void visit(Adapt entity) { Reusable reusable = entity.getAdapted(); IEntityIterator<?> contentIterator = null; IEntityIterator<?> adapterIterator = null; if (EntityUtils.isResolver(reusable)) { contentIterator = IteratorFactory.constantIterator(entity.getOriginal(), false); if (EntityUtils.isNotResolver(entity.getAdapter())) { entity.getAdapter().accept(this); adapterIterator = getResultIterator(); } } if (contentIterator == null) contentIterator = IteratorFactory.constantIterator(reusable, false); boolean updateAdapted = EntityUtils.isResolver(entity.getAdapted()); IEntityIterator<?> evaluateIterator = IteratorFactory.singleValuedRunnableIterator( (selfEntity, bm, arguments) -> { try { getBindings().wEnterScope(); getBindings().wDefValue("evaluateCloneOperation", true); evaluateAndClone(selfEntity, bm); } finally { getBindings().wExitScope(); } if (updateAdapted) { Reusable adapted = EntityUtils.clone(bm.getResult()).wGetAdapter(Reusable); if (EntityUtils.isResolver(entity.getAdapted())) entity.setAdapted(adapted); else { if (!Matcher.matchImpl(Reusables, entity.getAdapted())) entity.setAdapted(ReusablesEntityFactory.instance.createReusables(EntityUtils.clone(entity.getAdapted()))); entity.getAdapted().wAdd(adapted); } } } ); IEntityIterator<? extends IEntity> expandIterator = adapterIterator != null ? IteratorFactory.composeIterator(evaluateIterator, adapterIterator, contentIterator) : IteratorFactory.composeIterator(evaluateIterator, contentIterator); for (IEntity result : expandIterator) { stagedVisit(result.wGetAdaptee(false)); setResult(result); } } @Override public void visit(Include entity) { IEntityIterator<?> contentIterator = readResource(entity.getResource()); IEntityIterator<?> evaluateIterator = IteratorFactory.singleValuedRunnableIterator( (selfEntity, bm, arguments) -> evaluateAndClone(selfEntity, bm)); setResultIterator(IteratorFactory.composeIterator(evaluateIterator, contentIterator)); } @Override public void visit(Reuse entity) { Reusable reusable = entity.getAdapted(); Reusable original = CommonsEntityAdapterFactory.createResolver(Reusable); IEntityIterator<?> contentIterator = null; IEntityIterator<?> adapterIterator = null; if (EntityUtils.isResolver(reusable)) { try { getBindings().wEnterScope(); getBindings().wDefValue("evaluateCloneOperation", true); reusable = entity.getOriginal(); if (EntityUtils.isResolver(reusable)) { contentIterator = readResource(entity.getResource()); contentIterator.setBindings(getBindings()); contentIterator.reset(entity); if (contentIterator.hasNext()) original = EntityUtils.clone(contentIterator.next()).wGetAdapter(Reusable); if (contentIterator.hasNext()) { original = ReusablesEntityFactory.instance.createReusables(original); do { original.wAdd(EntityUtils.clone(contentIterator.next()).wGetAdapter(Reusable)); } while (contentIterator.hasNext()); } entity.setOriginal(original); } if (EntityUtils.isNotResolver(entity.getAdapter())) { entity.getAdapter().accept(this); adapterIterator = getResultIterator(); } } finally { getBindings().wExitScope(); } } if (contentIterator == null) contentIterator = IteratorFactory.constantIterator(reusable, false); boolean updateAdapted = EntityUtils.isResolver(entity.getAdapted()); IEntityIterator<?> evaluateIterator = IteratorFactory.singleValuedRunnableIterator( (selfEntity, bm, arguments) -> { try { getBindings().wEnterScope(); getBindings().wDefValue("evaluateCloneOperation", true); evaluateAndClone(selfEntity, bm); } finally { getBindings().wExitScope(); } if (updateAdapted) { Reusable adapted = EntityUtils.clone(bm.getResult()).wGetAdapter(Reusable); if (EntityUtils.isResolver(entity.getAdapted())) entity.setAdapted(adapted); else { if (!Matcher.matchImpl(Reusables, entity.getAdapted())) entity.setAdapted(ReusablesEntityFactory.instance.createReusables(EntityUtils.clone(entity.getAdapted()))); entity.getAdapted().wAdd(adapted); } } } ); setResultIterator(adapterIterator != null ? IteratorFactory.composeIterator(evaluateIterator, adapterIterator, contentIterator) : IteratorFactory.composeIterator(evaluateIterator, contentIterator)); } @Override public void visit(Sync entity) { Reusable reusable = entity.getVariant(); if (EntityUtils.isResolver(reusable)) visit((Reuse) entity); else { setResultIterator(IteratorFactory.constantComposeIterator(reusable, IteratorFactory.singleValuedRunnableIterator( (selfEntity, bm, arguments) -> evaluateAndClone(selfEntity, bm) ))); } } @Override public void visit(Registry entity) { entity.getRegistryUri().accept(this); String registryId = getResult().wStringValue(); if (!ResourceRegistry.hasRegistry(registryId)) throw new WholeIllegalArgumentException("Undefined registry "+registryId).withSourceEntity(entity).withBindings(getBindings()); IResourceRegistry<IResource> registry = ResourceRegistry.getRegistry(registryId); entity.getUri().accept(this); String uri = getResult().wStringValue(); String contextUri = getBindings().wIsSet("contextURI") ? getBindings().wStringValue("contextURI") : null; if (ResourceUtils.hasFragmentPart(uri) && registry instanceof CompoundResourceRegistry) { CompoundResourceRegistry<IResource> compoundRegistry = (CompoundResourceRegistry<IResource>) registry; setResult(compoundRegistry.getFunctionModel(uri, true, contextUri)); } else setResult(registry.getResourceModel(uri, true, contextUri)); } @Override public void visit(Model entity) { entity.getContent().accept(this); } }