/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.coconut.resource.sokan.generators;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.reuseware.coconut.compositionprogram.DerivedCompositionProgram;
import org.reuseware.coconut.compositionprogram.util.CompositionInterfaceComputerUtil;
import org.reuseware.coconut.compositionprogram.util.CompositionProgramExtractorUtil;
import org.reuseware.coconut.fracol.FragmentCollaboration;
import org.reuseware.coconut.fragment.Fragment;
import org.reuseware.coconut.fragment.FragmentFactory;
import org.reuseware.coconut.resource.ReuseResources;
import org.reuseware.coconut.resource.sokan.IndexConstants;
import org.reuseware.coconut.resource.sokan.util.SokanReuseResourceUtil;
import org.reuseware.coconut.resource.util.ReuseResourcesUtil;
import org.reuseware.coconut.reuseextension.ComponentModelSpecification;
import org.reuseware.coconut.reuseextension.ReuseExtension;
import org.reuseware.coconut.reuseextension.RootElementContext;
import org.reuseware.coconut.reuseextension.evaluator.EvaluatorUtil;
import org.reuseware.coconut.reuseextensionactivator.Argument;
import org.reuseware.coconut.reuseextensionactivator.ReuseExtensionActivator;
import org.reuseware.sokan.Constraint;
import org.reuseware.sokan.FacetedRequest;
import org.reuseware.sokan.ID;
import org.reuseware.sokan.IndexMetaData;
import org.reuseware.sokan.IndexRow;
import org.reuseware.sokan.index.DependencyMap;
import org.reuseware.sokan.index.indexer.CalledIndexer;
import org.reuseware.sokan.index.util.FacetUtil;
import org.reuseware.sokan.index.util.IndexUtil;
import org.reuseware.sokan.index.util.ResourceUtil;
/**
* This called indexer (generator) generates the composition
* interface of the fragment it indexes. For this it prepares the
* fragment with the reuse extension activators that are in
* its scope. Then it calls CompositionInterfaceComputerUtil.compute().
* <p>
* This indexer caches the generated composition interface model in
* the field: <i>org.reuseware.coconut.resource.sokan.fragment</i>.
*/
public class FragmentCompositionInterfaceGenerator implements CalledIndexer {
/**
* @param artifactURI the URI
* @param metaData the meta data to fill
* @param resourceSet the resource set to use
*/
public void createIndex(URI artifactURI, IndexMetaData metaData,
ResourceSet resourceSet) {
Resource fragmentResource = null;
try {
fragmentResource = resourceSet.getResource(artifactURI, true);
} catch (Exception e) {
//ok
}
if (fragmentResource == null) {
return;
}
EList<String> ufi = ResourceUtil.idFrom(artifactURI).getSegments();
List<ReuseExtensionActivator> rexActivatorList =
SokanReuseResourceUtil.findReuseExtensionActivators(ufi, resourceSet);
// == COMPOSITION INTERFACE
computeAndCacheCompositionInterface(
ufi, fragmentResource, rexActivatorList, resourceSet, metaData);
// the composition programs need to be reloaded in the resource set to find the updated fragment models
unloadCompositionPrograms(artifactURI, resourceSet);
//reload for re-validation
reloadReuseExtension(fragmentResource, resourceSet);
reloadReuseExtensionActivator(fragmentResource, resourceSet);
}
private void computeAndCacheCompositionInterface(
List<String> ufi,
Resource fragmentResource,
List<ReuseExtensionActivator> rexActivatorList,
ResourceSet resourceSet,
IndexMetaData metaData) {
Fragment fragment = null;
//physical or composed?
List<Constraint> constraints = FacetUtil.buildConstraints(
IndexConstants.COLUMN_COMPOSED_FRAGMENT,
ResourceUtil.idString(ufi));
FacetedRequest request = FacetUtil.buildFacetedRequest(constraints);
List<IndexRow> response = IndexUtil.INSTANCE.getIndex(request);
if (response.isEmpty()) {
fragment = FragmentFactory.eINSTANCE.createPhysicalFragment();
} else {
fragment = FragmentFactory.eINSTANCE.createComposedFragment();
}
//load
fragment.getUFI().addAll(ufi);
fragment.getContents().addAll(fragmentResource.getContents());
//find reuse extension activators
for (ReuseExtensionActivator rexActivator : rexActivatorList) {
if (rexActivator.getReuseExtension() instanceof ComponentModelSpecification) {
if (influencesFragment(rexActivator, fragment)) {
fragment.getComponentModelActivators().add(rexActivator);
}
}
}
//compute composition interface (post processors might need diagrams)
if (!fragment.getContents().isEmpty()) {
for (URI fragmentDiagramURI : ReuseResources.INSTANCE.getDiagramURIs(ufi)) {
Resource fragmentDiagramResource = null;
try {
fragmentDiagramResource = resourceSet.getResource(fragmentDiagramURI, true);
} catch (Exception e) {
//ok
}
if (fragmentDiagramResource != null) {
fragment.getDiagrams().addAll(fragmentDiagramResource.getContents());
}
}
}
CompositionInterfaceComputerUtil.compute(fragment);
//index (cache)
Resource tempXMIResource = resourceSet.createResource(URI.createURI("temp:/temp.xmi"));
tempXMIResource.getContents().add(fragment);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
tempXMIResource.save(outputStream, resourceSet.getLoadOptions());
metaData.putSingle(IndexConstants.COLUMN_FRAGMENT, outputStream.toString("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
resourceSet.getResources().remove(tempXMIResource);
// are there external computers registered?
//TODO #1656: test this
DerivedCompositionProgram derivedCp = CompositionProgramExtractorUtil.extract(fragment);
if (derivedCp != null && derivedCp.getUCPI() != null && !derivedCp.getUCPI().isEmpty()) {
URI derivedCpURI = SokanReuseResourceUtil.getDerivedCompositionProgramURI(
derivedCp.getUCPI(), fragment.getUFI(), null);
Resource resource = createResourceForDerivedCompositionProgram(
derivedCp, derivedCpURI, resourceSet);
ReuseResourcesUtil.completeCompositionProgram(resource);
}
}
private boolean influencesFragment(ReuseExtensionActivator rexActivator,
Fragment fragment) {
ReuseExtension rex = rexActivator.getReuseExtension();
if (rex instanceof ComponentModelSpecification) {
for (EObject root : fragment.getContents()) {
for (RootElementContext rootElementContext : rex.getRootElementContexts()) {
if (rootElementContext.getEBoundClass().isInstance(root)) {
Map<String, String> args = new LinkedHashMap<String, String>();
for (Argument arg : rexActivator.getArguments()) {
args.put(arg.getParameter(), arg.getValue());
}
if (EvaluatorUtil.eval(
fragment.getUFI(),
root,
rootElementContext.getIsExpression(),
args)) {
return true;
}
}
}
}
}
return false;
}
private Resource createResourceForDerivedCompositionProgram(
DerivedCompositionProgram derivedCompositionProgram,
URI derivedCpURI, ResourceSet resourceSet) {
Resource derivedCpResource = null;
try {
derivedCpResource = resourceSet.getResource(derivedCpURI, true);
} catch (Exception e) {
//ok
}
if (derivedCpResource == null) {
derivedCpResource = resourceSet.createResource(derivedCpURI);
}
DerivedCompositionProgram derivedCP = derivedCompositionProgram;
derivedCpResource.getContents().clear();
derivedCpResource.getContents().add(derivedCP);
derivedCpResource.setModified(true);
return derivedCpResource;
}
private void unloadCompositionPrograms(URI artifactURI, ResourceSet resourceSet) {
for (List<String> ucpi : ReuseResources.INSTANCE.getInfluencedComposingCompositionProgramIDsFragment(
ResourceUtil.idFrom(artifactURI).getSegments())) {
URI cpURI = ResourceUtil.uriFrom(ResourceUtil.idFrom(ucpi));
if (cpURI != null) {
unload(cpURI, resourceSet);
}
}
}
private void reloadReuseExtension(Resource resource, ResourceSet resourceSet) {
if (resource.getContents().isEmpty()) {
return;
}
if (!(resource.getContents().get(0) instanceof FragmentCollaboration)) {
return;
}
URI fracolURI = resource.getURI();
List<Constraint> constraints = FacetUtil.buildConstraints(
IndexConstants.COLUMN_CM_IMPLEMENTED_FRAGMENT_COLLABORATION,
ResourceUtil.idString(ResourceUtil.idFrom(fracolURI)));
FacetedRequest request = FacetUtil.buildFacetedRequest(constraints);
List<IndexRow> response = IndexUtil.INSTANCE.getIndex(request);
for (IndexRow row : response) {
URI rexURI = ResourceUtil.uriFrom(row.getPhyURI());
if (rexURI != null) {
reload(rexURI, resourceSet);
}
}
constraints = FacetUtil.buildConstraints(
IndexConstants.COLUMN_CL_IMPLEMENTED_FRAGMENT_COLLABORATION,
ResourceUtil.idString(ResourceUtil.idFrom(fracolURI)));
request = FacetUtil.buildFacetedRequest(constraints);
response = IndexUtil.INSTANCE.getIndex(request);
for (IndexRow row : response) {
URI rexURI = ResourceUtil.uriFrom(row.getPhyURI());
if (rexURI != null) {
reload(rexURI, resourceSet);
}
}
}
private void reloadReuseExtensionActivator(Resource resource, ResourceSet resourceSet) {
if (resource.getContents().isEmpty()) {
return;
}
if (!(resource.getContents().get(0) instanceof ReuseExtension)) {
return;
}
URI rexURI = resource.getURI();
List<Constraint> constraints = FacetUtil.buildConstraints(
IndexConstants.COLUMN_CM_ACTIVATED_REUSE_EXTENSION,
ResourceUtil.idString(ResourceUtil.idFrom(rexURI)));
FacetedRequest request = FacetUtil.buildFacetedRequest(constraints);
List<IndexRow> response = IndexUtil.INSTANCE.getIndex(request);
for (IndexRow row : response) {
URI rexActivatorURI = ResourceUtil.uriFrom(row.getPhyURI());
if (rexActivatorURI != null) {
reload(rexActivatorURI, resourceSet);
}
}
constraints = FacetUtil.buildConstraints(
IndexConstants.COLUMN_CL_ACTIVATED_REUSE_EXTENSION,
ResourceUtil.idString(ResourceUtil.idFrom(rexURI)));
request = FacetUtil.buildFacetedRequest(constraints);
response = IndexUtil.INSTANCE.getIndex(request);
for (IndexRow row : response) {
URI rexActivatorURI = ResourceUtil.uriFrom(row.getPhyURI());
if (rexActivatorURI != null) {
reload(rexActivatorURI, resourceSet);
}
}
}
private void unload(URI cpURI, ResourceSet resourceSet) {
Resource cpResource = resourceSet.getResource(cpURI, false);
if (cpResource != null) {
cpResource.unload();
}
}
private void reload(URI resourceURI, ResourceSet resourceSet) {
Resource cpResource = resourceSet.getResource(resourceURI, false);
if (cpResource != null) {
cpResource.unload();
}
try {
resourceSet.getResource(resourceURI, true);
} catch (Exception e) {
//ok
}
}
/**
* This implementation does nothing.
*
* @param artifactID the artifact's ID
* @param depMap the dependency map to fill
*/
public void getDependent(ID artifactID, DependencyMap depMap) { }
}