/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3.
*
* This program 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 General Public License for more details, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.codesync.remote;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.flowerplatform.codesync.config.extension.FeatureAccessExtension;
import org.flowerplatform.communication.CommunicationPlugin;
import org.flowerplatform.communication.service.ServiceInvocationContext;
import org.flowerplatform.communication.stateful_service.RemoteInvocation;
import org.flowerplatform.editor.EditorPlugin;
import com.crispico.flower.mp.codesync.base.CodeSyncPlugin;
import com.crispico.flower.mp.model.codesync.AstCacheElement;
import com.crispico.flower.mp.model.codesync.CodeSyncElement;
import com.crispico.flower.mp.model.codesync.CodeSyncFactory;
import com.crispico.flower.mp.model.codesync.FeatureChange;
/**
* @author Mariana Gheorghe
*/
public class CodeSyncOperationsService {
public static final String ID = "codeSyncOperationsService";
public static CodeSyncOperationsService getInstance() {
return (CodeSyncOperationsService) CommunicationPlugin.getInstance()
.getServiceRegistry().getService(ID);
}
public CodeSyncElement create(String codeSyncType) {
CodeSyncElementDescriptor descriptor = CodeSyncPlugin.getInstance().getCodeSyncElementDescriptor(codeSyncType);
if (descriptor == null) {
throw new RuntimeException("Cannot find descriptor for codeSyncType = " + codeSyncType);
}
CodeSyncElement codeSyncElement = CodeSyncFactory.eINSTANCE.createCodeSyncElement();
codeSyncElement.setType(descriptor.getCodeSyncType());
// set the key feature to the default value
setFeatureValue(codeSyncElement, descriptor.getKeyFeature(), descriptor.getDefaultName());
return codeSyncElement;
}
public void add(CodeSyncElement parent, CodeSyncElement elementToAdd) {
elementToAdd.setAdded(true);
parent.getChildren().add(elementToAdd);
propagateParentSyncFalse(elementToAdd);
}
/**
* Delegates to registered {@link FeatureAccessExtension}s.
*/
public Object getFeatureValue(CodeSyncElement codeSyncElement, String feature) {
List<FeatureAccessExtension> converters =
CodeSyncPlugin.getInstance().getFeatureAccessExtensions();
for (FeatureAccessExtension converter : converters) {
if (converter.hasCodeSyncType(codeSyncElement.getType())) {
return converter.getValue(codeSyncElement, feature);
}
}
return null;
}
/**
* Returns the value of <code>feature</code> on the <code>codeSyncElement</code>, first from the
* list of {@link org.eclipse.emf.ecore.change.FeatureChange}s, if it exists.
*/
public Object getFeatureValue(CodeSyncElement codeSyncElement, EStructuralFeature feature) {
FeatureChange featureChange = codeSyncElement.getFeatureChanges().get(feature);
if (featureChange != null) {
return featureChange.getNewValue();
}
if (feature.getEContainingClass().isSuperTypeOf(codeSyncElement.eClass())) {
return codeSyncElement.eGet(feature);
} else {
AstCacheElement astElement = codeSyncElement.getAstCacheElement();
if (astElement != null) {
return astElement.eGet(feature);
}
}
return null;
}
public Object getOldFeatureValue(CodeSyncElement codeSyncElement, EStructuralFeature feature) {
FeatureChange featureChange = codeSyncElement.getFeatureChanges().get(feature);
if (featureChange != null) {
return featureChange.getOldValue();
} else {
return getFeatureValue(codeSyncElement, feature);
}
}
/**
* Delegates to registered {@link FeatureAccessExtension}s.
*/
public void setFeatureValue(CodeSyncElement codeSyncElement, String feature, Object newValue) {
List<FeatureAccessExtension> converters =
CodeSyncPlugin.getInstance().getFeatureAccessExtensions();
for (FeatureAccessExtension converter : converters) {
if (converter.hasCodeSyncType(codeSyncElement.getType())) {
converter.setValue(codeSyncElement, feature, newValue);
}
}
}
public void setFeatureValue(CodeSyncElement codeSyncElement, EStructuralFeature feature, Object newValue) {
Object oldValue = getOldFeatureValue(codeSyncElement, feature);
createAndAddFeatureChange(codeSyncElement, feature, oldValue, newValue);
}
/**
* Creates and adds a {@link FeatureChange} if the <code>oldValue</code> and <code>newValue</code> are different.
*
* Important: we first remove, and then add a new feature change to trigger a change description on the {@link CodeSyncElement},
* so the processors can update the views.
*
* @author Sebastian Solomon
*/
protected void createAndAddFeatureChange(CodeSyncElement element,
EStructuralFeature feature, Object oldValue, Object newValue) {
element.getFeatureChanges().removeKey(feature);
if (!safeEquals(newValue, oldValue)) {
FeatureChange featureChange = CodeSyncFactory.eINSTANCE
.createFeatureChange();
// first add the FC to the map
// so the feature will be available when setting old and new value
element.getFeatureChanges().put(feature, featureChange);
featureChange.setOldValue(oldValue);
featureChange.setNewValue(newValue);
if (element.isSynchronized()) {
element.setSynchronized(false);
propagateParentSyncFalse(element);
}
} else if (element.getFeatureChanges().size() == 0) {
propagateParentSyncTrue(element);
}
}
/**
* @author Sebastian Solomon
*/
protected void propagateParentSyncFalse(CodeSyncElement element) {
while (element.eContainer() != null) {
EObject parent = element.eContainer();
if (parent instanceof CodeSyncElement) {
element = (CodeSyncElement) parent;
if (element.isSynchronized()) {
element.setChildrenSynchronized(false);
}
} else
return;
}
}
/**
* @author Sebastian Solomon
*/
protected void propagateParentSyncTrue(CodeSyncElement element) {
if (!element.isAdded() && !element.isDeleted()
&& element.getFeatureChanges().size() == 0) {
element.setSynchronized(true); // orange
if (allChildrenGreen(element)) // if all childs green =>become green
element.setChildrenSynchronized(true);
// * walk whole parent hierarchy; set childrenSync = true if all
// children are sync,not newly added not deleted
while (element.eContainer() != null) {
if (element.eContainer() instanceof CodeSyncElement) {
element = (CodeSyncElement) element.eContainer();
if (allChildrenGreen(element)) {
element.setChildrenSynchronized(true);
} else
return; // if one child is notSync, return
}
}
}
}
/**
* @author Sebastian Solomon
*/
private boolean allChildrenGreen(CodeSyncElement element) {
for (CodeSyncElement cse : element.getChildren()) {
if (cse.isAdded() || cse.isDeleted() || !cse.isSynchronized()
|| !cse.isChildrenSynchronized())
return false;
}
return true;
}
protected boolean safeEquals(Object a, Object b) {
if (a == null) {
return b == null;
} else {
return a.equals(b);
}
}
public Object getKeyFeatureValue(CodeSyncElement element) {
CodeSyncElementDescriptor descriptor = CodeSyncPlugin.getInstance().getCodeSyncElementDescriptor(element.getType());
return getFeatureValue(element, descriptor.getKeyFeature());
}
public void setKeyFeatureValue(CodeSyncElement element, Object newValue) {
CodeSyncElementDescriptor descriptor = CodeSyncPlugin.getInstance().getCodeSyncElementDescriptor(element.getType());
String keyFeature = descriptor.getKeyFeature();
setFeatureValue(element, keyFeature, newValue);
}
public void markDeleted(CodeSyncElement element) {
// TODO
}
/**
* @author Sebastian Solomon
*/
protected void propagateOnChildDelete(CodeSyncElement cse) {
for (CodeSyncElement child : cse.getChildren()) {
child.setDeleted(true);
propagateOnChildDelete(child);
}
}
public boolean hasChildWithKeyFeatureValue(CodeSyncElement parent, String childCodeSyncType, String keyFeatureValue) {
for (CodeSyncElement child : parent.getChildren()) {
if (!childCodeSyncType.equals(child.getType())) {
continue;
}
if (keyFeatureValue.equals(getKeyFeatureValue(child))) {
return true;
}
}
return false;
}
public List<String> getFeatures(String codeSyncType) {
CodeSyncElementDescriptor descriptor = CodeSyncPlugin.getInstance().getCodeSyncElementDescriptor(codeSyncType);
return descriptor.getFeatures();
}
@RemoteInvocation
public void synchronize(ServiceInvocationContext context, String path, String technology) {
Object diagram;
try {
diagram = EditorPlugin.getInstance().getFileAccessController().getFile(path);
} catch (Exception e) {
throw new RuntimeException(path);
}
Object project = CodeSyncPlugin.getInstance().getProjectAccessController().getContainingProjectForFile(diagram);
Object srcDir = CodeSyncPlugin.getInstance().getProjectAccessController().getFolder(project, "js");
CodeSyncPlugin.getInstance().getCodeSyncAlgorithmRunner().runCodeSyncAlgorithm(project, srcDir, technology, context.getCommunicationChannel(), true);
}
@RemoteInvocation
public String regenerateDescriptors() {
return CodeSyncPlugin.getInstance().regenerateDescriptors();
}
}