/*******************************************************************************
* 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.compositionprogram.util;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.reuseware.coconut.compositionprogram.CompositionLink;
import org.reuseware.coconut.compositionprogram.CompositionProgram;
import org.reuseware.coconut.compositionprogram.CompositionprogramFactory;
import org.reuseware.coconut.compositionprogram.FragmentInstance;
import org.reuseware.coconut.compositionprogram.PortInstance;
import org.reuseware.coconut.fracol.Contribution;
import org.reuseware.coconut.fragment.AddressablePoint;
import org.reuseware.coconut.fragment.Fragment;
import org.reuseware.coconut.fragment.HeterogeneousPort;
import org.reuseware.coconut.fragment.Hook;
import org.reuseware.coconut.reuseextension.CompositionLanguageSyntaxSpecification;
import org.reuseware.coconut.reuseextension.FragmentRole2SyntaxBinding;
import org.reuseware.coconut.reuseextension.evaluator.EvaluatorUtil;
import org.reuseware.coconut.reuseextensionactivator.Argument;
import org.reuseware.coconut.reuseextensionactivator.ReuseExtensionActivator;
/**
* Utility methods for user friendly editing of composition programs.
*/
public final class CompositionProgramUtil {
private CompositionProgramUtil() { }
/**
* Activates the given {@link CompositionLanguageSyntaxSpecification}s for
* the given {@link CompositionProgram} by instantiating all default fragments
* specified in the syntaxes.
*
* @param compositionProgram the {@link CompositionProgram}.
* @param activatorList list of activators with {@link CompositionLanguageSyntaxSpecification}s.
*/
public static void activateCompositionLanguageSyntaxSpecifications(
CompositionProgram compositionProgram, List<ReuseExtensionActivator> activatorList) {
for (ReuseExtensionActivator activator : activatorList) {
if (activator.getReuseExtension() instanceof CompositionLanguageSyntaxSpecification) {
CompositionLanguageSyntaxSpecification clSyntax =
(CompositionLanguageSyntaxSpecification) activator.getReuseExtension();
Map<String, String> args = new LinkedHashMap<String, String>();
for (Argument arg : activator.getArguments()) {
args.put(arg.getParameter(), arg.getValue());
}
for (FragmentRole2SyntaxBinding binding : clSyntax.getFragmentRoleBindings()) {
if (binding.getUfiExpression() != null && binding.getNameExpression() != null) {
List<String> ufi = EvaluatorUtil.deriveID(
compositionProgram.getUCPI(), compositionProgram, binding.getUfiExpression(), args);
String name = EvaluatorUtil.derive(
compositionProgram.getUCPI(), compositionProgram, binding.getNameExpression(), args);
List<String> targetUfi = EvaluatorUtil.deriveID(
compositionProgram.getUCPI(), compositionProgram, binding.getTargetUfiExpression(), args);
String targetLocation = EvaluatorUtil.derive(
compositionProgram.getUCPI(), compositionProgram, binding.getTargetPhysicalLocationExpression(), args);
FragmentInstance fragmentInstance = CompositionprogramFactory.eINSTANCE
.createFragmentInstance();
fragmentInstance.getUFI().addAll(ufi);
fragmentInstance.setName(name);
if (targetUfi != null && !targetUfi.isEmpty()) {
fragmentInstance.getTargetUFI().addAll(targetUfi);
fragmentInstance.setTarget(true);
fragmentInstance.setTargetPhysicalLocation(targetLocation);
}
if (!containsFragmentInstance(compositionProgram, fragmentInstance)) {
compositionProgram.getFragmentInstances().add(fragmentInstance);
fragmentInstance.update();
}
}
}
}
}
}
private static boolean containsFragmentInstance(
CompositionProgram cp, FragmentInstance fi) {
for (FragmentInstance existingFI : cp.getFragmentInstances()) {
if (existingFI.getName().equals(fi.getName())) {
return true;
}
}
return false;
}
/**
* Creates a new instance of the given {@link Fragment} with an unique name in
* the given {@link CompositionProgram}.
*
* @param fragment the {@link Fragment} to instantiate.
* @param compositionProgram the {@link CompositionProgram} to instantiate the fragment in.
* @return the new {@link FragmentInstance}.
*/
public static FragmentInstance createFragmentInstance(
Fragment fragment, CompositionProgram compositionProgram) {
FragmentInstance fInstance =
CompositionprogramFactory.eINSTANCE.createFragmentInstance();
compositionProgram.getFragmentInstances().add(fInstance);
updateFragmentInstance(fragment, fInstance);
return fInstance;
}
/**
* Changes the given {@link FragmentInstance} to an instance of the
* given {@link Fragment}.
*
* @param fragment the {@link Fragment} that should be instantiated.
* @param fragmentInstance the {@link FragmentInstance} to update.
*/
public static void updateFragmentInstance(
Fragment fragment, FragmentInstance fragmentInstance) {
fragmentInstance.getUFI().clear();
fragmentInstance.getUFI().addAll(fragment.getUFI());
//find a name not used so far in the c.p.
String nameCand = fragment.getUFI().get(fragment.getUFI().size() - 1);
String name = nameCand;
int count = 2;
boolean found = false;
while (!found) {
found = true;
CompositionProgram compositionProgram = fragmentInstance.getCompositionProgram();
for (FragmentInstance existingFI : compositionProgram.getFragmentInstances()) {
if (name.equals(existingFI.getName())) {
name = nameCand + count;
count++;
found = false;
break;
}
}
}
fragmentInstance.setName(name);
fragmentInstance.setFragment(fragment);
fragmentInstance.update();
//set an initial targetUFI
EList<String> ufi = fragmentInstance.getUFI();
if (ufi.size() >= 1) {
EList<String> tufi = fragmentInstance.getTargetUFI();
tufi.clear();
tufi.addAll(ufi);
tufi.add(tufi.size() - 1, "composed");
}
}
/**
* Links all ports that can contribute to all receiving ports of existing target fragments in
* the composition programs that match.
*
* @param compositionProgram the {@link CompositionProgram} with receiving fragments.
* @param contributor new contributing {@link FragmentInstance}.
*/
public static void linkImplicitInterface(CompositionProgram compositionProgram,
FragmentInstance contributor) {
//check contributing ports of new fragment
for (PortInstance contributingPort : contributor.getPortInstances()) {
if (contributingPort.canContribute()) {
if (contributingPort.getSourceLinks().isEmpty()
&& contributingPort.getTargetLinks().isEmpty()) {
//find a proper receiver
for (FragmentInstance receivingFragment : compositionProgram.getFragmentInstances()) {
if (receivingFragment.isTarget()) {
//CompositionLink createdLink = null;
for (PortInstance receivingPort : receivingFragment.getPortInstances()) {
if (isImplicit(receivingPort)) {
//create a link and check if it is valid
CompositionLink link = CompositionprogramFactory.eINSTANCE.createCompositionLink();
link.setSource(contributingPort);
link.setTarget(receivingPort);
compositionProgram.getCompositionLinks().add(link);
//only declared contributions
if (link.compositionAssociation() instanceof Contribution) {
//does it match?
link.match();
if (!link.isValid()) {
link.setSource(null);
link.setTarget(null);
compositionProgram.getCompositionLinks().remove(link);
} else {
//createdLink = link;
break;
}
// there already a link? -> keep decide which to keep, or remove both (?)
/*if (createdLink != null) {
link.setSource(null);
link.setTarget(null);
cp.getCompositionLinks().remove(link);
break;
}*/
} else {
link.setSource(null);
link.setTarget(null);
compositionProgram.getCompositionLinks().remove(link);
}
}
}
}
}
}
}
}
}
/**
* Checks whether the port of the given {@link PortInstance} contains only hooks that
* refer to a structural feature (and not an element).
*
* @param portInstance {@link PortInstance} to check.
* @return true if implicit.
*/
private static boolean isImplicit(PortInstance portInstance) {
//is receiving at all?
if (portInstance == null) {
return false;
}
if (!portInstance.canReceive()) {
return false;
}
//ports are implicit if all their hooks refer to references and not element
for (HeterogeneousPort port : portInstance.allPorts()) {
for (AddressablePoint hook : port.getAddressablePoints()) {
if (hook instanceof Hook && hook.getVarTypedEStructuralFeature() == null) {
return false;
}
}
}
return true;
}
}