blob: f1537fb971f7fe3b852ee4287c990f60039266e6 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* 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:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
*/
package org.eclipse.osbp.xtext.functionlibrarydsl.provider;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.eclipse.osbp.ui.api.functionlibrary.IFunctionLibraryGroup;
import org.eclipse.osbp.ui.api.functionlibrary.IFunctionLibraryPackage;
import org.eclipse.osbp.ui.api.functionlibrary.IFunctionLibraryService;
import org.eclipse.osbp.ui.api.statemachine.IStateMachine;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This service provides access to the function library.
*/
@Component(immediate = true)
public class FunctionLibraryService implements IFunctionLibraryService {
private final Logger LOGGER = LoggerFactory
.getLogger(FunctionLibraryService.class);
private Set<ServiceReference<IFunctionLibraryPackage>> functionLibraryPackages = new HashSet<>();
private Set<Bundle> bundles = new HashSet<>();
@SuppressWarnings("unused")
private ComponentContext context;
@Activate
protected void activate(ComponentContext context) {
this.context = context;
}
@Deactivate
protected void deactivate(ComponentContext context) {
this.context = null;
functionLibraryPackages.clear();
bundles.clear();
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "removeFunctionLibraryPackage")
public synchronized void addFunctionLibraryPackage(
final ServiceReference<IFunctionLibraryPackage> ref) {
functionLibraryPackages.add(ref);
createBundleList();
LOGGER.debug("IFunctionLibraryPackage " + ref.getProperty("name")
+ " bound");
}
public synchronized void removeFunctionLibraryPackage(
final ServiceReference<IFunctionLibraryPackage> ref) {
functionLibraryPackages.remove(ref);
createBundleList();
LOGGER.debug("IFunctionLibraryPackage " + ref.getProperty("name")
+ " unbound");
}
private void createBundleList() {
if (LOGGER.isDebugEnabled())
LOGGER.debug("creating class loader list");
bundles.clear();
for (ServiceReference<IFunctionLibraryPackage> ref : functionLibraryPackages) {
try {
bundles.add(ref.getBundle());
} catch (Exception e) {
LOGGER.error("{}", e);
}
}
}
@SuppressWarnings("unchecked")
private Class<IFunctionLibraryGroup> getFunctionLibraryClass(
String className) {
for (Bundle bundle : bundles) {
try {
return (Class<IFunctionLibraryGroup>) bundle
.loadClass(className);
} catch (ClassNotFoundException e) {
LOGGER.error("{}", e);
}
}
return null;
}
private Object callFunctionLibrary(
Class<IFunctionLibraryGroup> functionLibGroupClass,
String methodName, Object fieldValue, Locale locale,
Object... params) {
if (functionLibGroupClass != null) {
try {
IFunctionLibraryGroup functionLibGroup = functionLibGroupClass
.newInstance();
for (Method method : functionLibGroupClass.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
try {
// both locale and fieldValue are set
if (locale != null && fieldValue != null) {
if (params.length > 0) {
return method.invoke(functionLibGroup,
fieldValue, locale, params);
}
return method.invoke(functionLibGroup,
fieldValue, locale);
}
// both locale and fieldValue are UNSET
else if (locale == null && fieldValue == null) {
return method.invoke(functionLibGroup);
}
// either locale or fieldValue is set, the other is
// unset
// only fieldValue is set
else if (fieldValue != null) {
return method.invoke(functionLibGroup,
fieldValue);
}
// only locale is set (last possible condition)
else {
return method.invoke(functionLibGroup, locale);
}
} catch (IllegalArgumentException e) {
LOGGER.error("{}", e);
} catch (InvocationTargetException e) {
LOGGER.error("{}", e);
}
}
}
} catch (InstantiationException e) {
LOGGER.error("{}", e);
} catch (IllegalAccessException e) {
LOGGER.error("{}", e);
}
}
return null;
}
public Object callFunctionLibrary(String className, String methodName,
Object fieldValue, Locale locale, Object... params) {
return callFunctionLibrary(getFunctionLibraryClass(className),
methodName, fieldValue, locale, params);
}
public Object callFunctionLibrary(String className, String methodName,
Object fieldValue) {
return callFunctionLibrary(getFunctionLibraryClass(className),
methodName, fieldValue, null);
}
public Object callFunctionLibrary(String className, String methodName,
Locale locale) {
return callFunctionLibrary(getFunctionLibraryClass(className),
methodName, null, locale);
}
public Object callFunctionLibrary(String className, String methodName) {
return callFunctionLibrary(className, methodName, null);
}
public boolean guard(IStateMachine statemachine, String className,
String methodName) {
Class<?> clz = getFunctionLibraryClass(className);
try {
BeanInfo info = Introspector.getBeanInfo(clz);
for (MethodDescriptor methodDesc : info.getMethodDescriptors()) {
Method method = methodDesc.getMethod();
Class[] parameterTypes = method.getParameterTypes();
if (methodName.equals(method.getName())) {
if(parameterTypes.length == 1) {
if(IStateMachine.class.isAssignableFrom(parameterTypes[0])) {
if(boolean.class.isAssignableFrom(method.getReturnType())) {
return (Boolean) method.invoke(clz, statemachine);
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have a return type Boolean. Found "+method.getReturnType().getCanonicalName()+" instead.");
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have a parameter of type IStateMachine. Found "+parameterTypes[0].getCanonicalName()+" instead.");
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have exactly 1 parameter. Found "+parameterTypes.length+" parameters instead.");
}
}
}
LOGGER.error("method "+methodName+" was not found in class "+className);
} catch (IntrospectionException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("{}", e);
}
return false;
}
public boolean operation(IStateMachine statemachine, String className,
String methodName, Object... params) {
Class<?> clz = getFunctionLibraryClass(className);
try {
BeanInfo info = Introspector.getBeanInfo(clz);
for (MethodDescriptor methodDesc : info.getMethodDescriptors()) {
Method method = methodDesc.getMethod();
Class[] parameterTypes = method.getParameterTypes();
if (methodName.equals(method.getName())) {
if(parameterTypes.length >= 1) {
if(IStateMachine.class.isAssignableFrom(parameterTypes[0])) {
if(boolean.class.isAssignableFrom(method.getReturnType())) {
if(parameterTypes.length == 1) {
return (Boolean) method.invoke(clz, statemachine);
} else {
return (Boolean) method.invoke(clz, statemachine, params);
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have a return type Boolean. Found "+method.getReturnType().getCanonicalName()+" instead.");
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have as first parameter type IStateMachine. Found "+parameterTypes[0].getCanonicalName()+" instead.");
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have at least one parameter. Found "+parameterTypes.length+" parameters instead.");
}
}
}
LOGGER.error("method "+methodName+" was not found in class "+className);
} catch (IntrospectionException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("{}", e);
}
return false;
}
@Override
public Object function(IStateMachine statemachine, String className,
String methodName, Object... params) {
Class<?> clz = getFunctionLibraryClass(className);
try {
BeanInfo info = Introspector.getBeanInfo(clz);
for (MethodDescriptor methodDesc : info.getMethodDescriptors()) {
Method method = methodDesc.getMethod();
Class[] parameterTypes = method.getParameterTypes();
if (methodName.equals(method.getName())) {
if(parameterTypes.length >= 1) {
if(IStateMachine.class.isAssignableFrom(parameterTypes[0])) {
if(parameterTypes.length == 1) {
return method.invoke(clz, statemachine);
} else {
return method.invoke(clz, statemachine, params);
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have as first parameter type IStateMachine. Found "+parameterTypes[0].getCanonicalName()+" instead.");
}
} else {
LOGGER.error("method "+methodName+" in class "+className+" must have at least one parameter. Found "+parameterTypes.length+" parameters instead.");
}
}
}
LOGGER.error("method "+methodName+" was not found in class "+className);
} catch (IntrospectionException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("{}", e);
}
return null;
}
}