package org.erlide.engine.internal;
import java.lang.reflect.Constructor;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.Platform;
import org.erlide.engine.IErlangEngine;
import org.erlide.engine.InjectionException;
import org.erlide.engine.internal.model.BeamLocator;
import org.erlide.engine.internal.model.ErlModel;
import org.erlide.engine.internal.model.erlang.ModelFindUtil;
import org.erlide.engine.internal.model.erlang.ModelInternalUtils;
import org.erlide.engine.internal.model.root.ProjectConfiguratorFactory;
import org.erlide.engine.internal.services.cleanup.ErlTidyCleanupProvider;
import org.erlide.engine.internal.services.codeassist.ErlangCompletionService;
import org.erlide.engine.internal.services.codeassist.ErlideContextAssist;
import org.erlide.engine.internal.services.edoc.ErlideEdocExport;
import org.erlide.engine.internal.services.parsing.ErlParser;
import org.erlide.engine.internal.services.parsing.ErlideParser;
import org.erlide.engine.internal.services.parsing.ErlideScanner;
import org.erlide.engine.internal.services.parsing.ScannerProvider;
import org.erlide.engine.internal.services.proclist.ErlideProclist;
import org.erlide.engine.internal.services.search.ErlangXref;
import org.erlide.engine.internal.services.search.ErlideDoc;
import org.erlide.engine.internal.services.search.ErlideOpen;
import org.erlide.engine.internal.services.search.ErlideSearchServer;
import org.erlide.engine.internal.services.search.ModelSearcher;
import org.erlide.engine.internal.services.text.ErlideIndent;
import org.erlide.engine.model.OtpRpcFactory;
import org.erlide.engine.model.root.IBeamLocator;
import org.erlide.engine.model.root.IErlModel;
import org.erlide.engine.model.root.IErlModule;
import org.erlide.engine.model.root.IErlProject;
import org.erlide.engine.model.root.IProjectConfiguratorFactory;
import org.erlide.engine.services.ErlangService;
import org.erlide.engine.services.GenericService;
import org.erlide.engine.services.SystemInfoService;
import org.erlide.engine.services.cleanup.CleanupProvider;
import org.erlide.engine.services.codeassist.CompletionService;
import org.erlide.engine.services.codeassist.ContextAssistService;
import org.erlide.engine.services.edoc.EdocExportService;
import org.erlide.engine.services.parsing.NullScannerService;
import org.erlide.engine.services.parsing.ParserService;
import org.erlide.engine.services.parsing.ScannerProviderService;
import org.erlide.engine.services.parsing.SimpleParserService;
import org.erlide.engine.services.parsing.SimpleScannerService;
import org.erlide.engine.services.proclist.ProclistService;
import org.erlide.engine.services.search.ModelFindService;
import org.erlide.engine.services.search.ModelSearcherService;
import org.erlide.engine.services.search.ModelUtilService;
import org.erlide.engine.services.search.OpenService;
import org.erlide.engine.services.search.OtpDocService;
import org.erlide.engine.services.search.SearchServerService;
import org.erlide.engine.services.search.XrefService;
import org.erlide.engine.services.text.IndentService;
import org.erlide.runtime.rpc.IOtpRpc;
import org.erlide.runtime.rpc.RpcException;
import org.erlide.util.ErlLogger;
import org.osgi.framework.Bundle;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.google.common.collect.Maps;
public class DefaultErlangEngine implements IErlangEngine, IExecutableExtension {
private final Map<Class<? extends ErlangService>, Class<? extends ErlangService>> implementations = Maps
.newHashMap();
@SuppressWarnings("unchecked")
@Override
public <T extends ErlangService> T getService(final Class<T> type) {
try {
final Class<? extends ErlangService> clazz = implementations.get(type);
if (clazz == null) {
throw new InjectionException(
"ErlangService implementation not found for " + type.getName());
}
final Constructor<?> constructor = clazz.getConstructors()[0];
final Class<?>[] parameterTypes = constructor.getParameterTypes();
final Object[] initargs = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
final Class<?> paramType = parameterTypes[i];
initargs[i] = injectParameter(paramType);
}
return (T) constructor.newInstance(initargs);
} catch (final Exception e) {
throw new InjectionException(
"Could not instantiate service " + type.getName(), e);
}
}
private Object injectParameter(final Class<?> paramType) {
if (IOtpRpc.class == paramType) {
return backend;
}
if (IErlModel.class == paramType) {
return getModel();
}
if (String.class == paramType) {
return getStateDir();
}
throw new InjectionException(
"Constructor parameters are not injectable (ErlangService): "
+ paramType.getName());
}
public DefaultErlangEngine() {
// TODO how to inject runtime and other start params?
// TODO use extension points?
implementations.put(XrefService.class, ErlangXref.class);
implementations.put(IndentService.class, ErlideIndent.class);
implementations.put(OtpDocService.class, ErlideDoc.class);
implementations.put(IBeamLocator.class, BeamLocator.class);
implementations.put(OpenService.class, ErlideOpen.class);
implementations.put(SystemInfoService.class, SystemInfo.class);
}
private IOtpRpc backend;
private volatile ErlModel erlangModel;
@Override
public IErlModel getModel() {
if (erlangModel == null) {
erlangModel = new ErlModel();
}
if (!erlangModel.isOpen()) {
try {
erlangModel.open(null);
} catch (final CoreException e) {
ErlLogger.error(e);
}
}
return erlangModel;
}
private volatile String stateDir;
@Override
public String getStateDir() {
if (stateDir == null) {
final Bundle modelPlugin = Platform.getBundle(ModelPlugin.PLUGIN_ID);
stateDir = Platform.getStateLocation(modelPlugin).toPortableString();
}
return stateDir;
}
@Override
public ContextAssistService getContextAssistService() {
return new ErlideContextAssist(backend);
}
@Override
public SearchServerService getSearchServerService() {
return new ErlideSearchServer(backend);
}
@Override
public ModelUtilService getModelUtilService() {
return new ModelInternalUtils(backend);
}
@Override
public ModelFindService getModelFindService() {
return new ModelFindUtil(backend);
}
/**
* <p>
* Construct a {@link CleanUpProvider} appropriate for a particular IResource.
* </p>
*/
@Override
public CleanupProvider getCleanupProvider() {
return new ErlTidyCleanupProvider(backend);
}
@Override
public ParserService getParserService() {
return new ErlParser(backend);
}
@Override
public ScannerProviderService getScannerProviderService() {
return new ScannerProvider(backend);
}
@Override
public EdocExportService getEdocExportService() {
return new ErlideEdocExport(backend);
}
@Override
public ProclistService getProclistService() {
return new ErlideProclist();
}
@Override
public SimpleScannerService getSimpleScannerService() {
if (backend == null) {
return new NullScannerService();
}
return new ErlideScanner(backend);
}
@Override
public SimpleParserService getSimpleParserService() {
return new ErlideParser(backend);
}
@Override
public ModelSearcherService getModelSearcherService() {
return new ModelSearcher();
}
@Override
public IProjectConfiguratorFactory getProjectConfiguratorFactory() {
return ProjectConfiguratorFactory.getDefault();
}
@Override
public CompletionService getCompletionService(final IErlProject project,
final IErlModule module, final String elementBefore) {
return new ErlangCompletionService(project, module, elementBefore);
}
@Override
public boolean isAvailable() {
return backend != null;
}
@Override
public GenericService getGenericService() {
return new GenericService() {
@Override
public OtpErlangObject call(final String module, final String fun,
final int offset, final int length, final String text) {
try {
final OtpErlangObject r1 = backend.call(module, fun, "sii", text,
offset, length);
return r1;
} catch (final RpcException e) {
return new OtpErlangString("");
}
}
};
}
@Override
public void setInitializationData(final IConfigurationElement config,
final String propertyName, final Object data) throws CoreException {
backend = OtpRpcFactory.getOtpRpc();
}
}