org.sourcepit.tpmp.resolver.tycho.TychoSourceIUResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.sourcepit.tpmp.resolver.tycho.TychoSourceIUResolver.java

Source

/*
 * Copyright 2014 Bernd Vogt and others.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.sourcepit.tpmp.resolver.tycho;

import static org.sourcepit.common.utils.lang.Exceptions.pipe;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.sisu.equinox.EquinoxServiceFactory;
import org.eclipse.tycho.artifacts.TargetPlatform;
import org.eclipse.tycho.osgi.adapters.MavenLoggerAdapter;
import org.eclipse.tycho.p2.resolver.facade.P2ResolutionResult;
import org.eclipse.tycho.p2.resolver.facade.P2ResolutionResult.Entry;
import org.eclipse.tycho.p2.resolver.facade.P2Resolver;
import org.eclipse.tycho.p2.resolver.facade.P2ResolverFactory;
import org.sourcepit.common.manifest.osgi.BundleManifest;
import org.sourcepit.common.manifest.osgi.BundleSymbolicName;
import org.sourcepit.common.manifest.osgi.Version;
import org.sourcepit.common.manifest.osgi.resource.BundleManifestResourceImpl;
import org.sourcepit.tpmp.resolver.TargetPlatformResolutionHandler;

import com.google.common.base.Optional;

@Named
public class TychoSourceIUResolver {
    @Inject
    private MavenProjectFacade projectFacade;

    @Inject
    private EquinoxServiceFactory equinox;

    @Inject
    private Logger logger;

    public void resolveSources(MavenSession session, final TargetPlatform targetPlatform,
            Collection<String> sourceTargetBundles, TargetPlatformResolutionHandler handler) {
        final Set<String> sourceTargets = new HashSet<String>(sourceTargetBundles);
        if (sourceTargets.isEmpty()) {
            return;
        }

        final Map<String, MavenProject> projectsMap = projectFacade.createVidToProjectMap(session);

        final P2Resolver resolver = createResolver();

        final ClassLoader classLoader = targetPlatform.getClass().getClassLoader();

        final P2TargetPlatformDAO tpDAO = new P2TargetPlatformDAO(classLoader);
        final InstallableUnitDAO iuDAO = tpDAO.getInstallableUnitDAO();

        for (final Object unit : tpDAO.getInstallableUnits(targetPlatform)) {
            if (sourceTargets.isEmpty()) {
                return;
            }

            if (hasSourceCapability(iuDAO, unit)) {
                final String symbolicName = iuDAO.getId(unit);
                final String version = iuDAO.getVersion(unit).toString();

                final BundleManifest manifest = getManifest(iuDAO, unit);

                String[] targetIdAndVersion = getTargetIdAndVersion(manifest);
                if (targetIdAndVersion == null) {
                    targetIdAndVersion = getTargetIdAndVersion(symbolicName, version);
                }

                if (targetIdAndVersion != null) {
                    final String targetKey = targetIdAndVersion[0] + "_" + targetIdAndVersion[1];
                    if (sourceTargets.remove(targetKey)) {
                        final P2ResolutionResult result = resolve(targetPlatform, resolver, symbolicName, version);
                        for (Entry entry : result.getArtifacts()) {
                            final Optional<MavenProject> mavenProject = projectFacade.getMavenProject(projectsMap,
                                    targetIdAndVersion[0], targetIdAndVersion[1]);

                            final File location = projectFacade.getLocation(entry, mavenProject);
                            if (location != null && location.exists()) {
                                handler.handlePlugin(entry.getId(), entry.getVersion(), location, false,
                                        mavenProject.orNull());
                            }
                        }
                    }
                }
            }
        }
    }

    private static P2ResolutionResult resolve(final TargetPlatform targetPlatform, final P2Resolver resolver,
            final String symbolicName, String version) {
        final String strictVersion = "[" + version + "," + version + "]";
        return resolver.resolveInstallableUnit(targetPlatform, symbolicName, strictVersion);
    }

    private P2Resolver createResolver() {
        final P2ResolverFactory factory = equinox.getService(P2ResolverFactory.class);
        final P2Resolver resolver = factory.createResolver(new MavenLoggerAdapter(logger, false));
        return resolver;
    }

    private String[] getTargetIdAndVersion(String symbolicName, String version) {
        String targetId = null;
        if (symbolicName.endsWith(".source")) {
            targetId = symbolicName.substring(0, symbolicName.length() - ".source".length());
        }
        if (targetId == null || version == null) {
            return null;
        }
        return new String[] { targetId, version };
    }

    private String[] getTargetIdAndVersion(BundleManifest manifest) {
        String targetId = null;
        String version = null;

        final BundleSymbolicName bundleSymbolicName = manifest.getBundleSymbolicName();
        final Version bundleVersion = manifest.getBundleVersion();
        if (bundleSymbolicName != null && bundleVersion != null) {
            String symbolicName = bundleSymbolicName.getSymbolicName();
            String value = manifest.getHeaderValue("Eclipse-SourceBundle");
            if (value == null) {
                if (symbolicName.endsWith(".source")) {
                    targetId = symbolicName.substring(0, symbolicName.length() - ".source".length());
                }
                version = bundleVersion.toFullString();
            } else {
                String[] segments = value.split(";");
                targetId = segments[0];
                for (int i = 1; i < segments.length; i++) {
                    String segment = segments[i];
                    if (segment.startsWith("version=")) {
                        segment = segment.substring("version=".length());
                        if (segment.startsWith("\"")) {
                            segment = segment.substring(1);
                        }
                        if (segment.endsWith("\"")) {
                            segment = segment.substring(0, segment.length() - 1);
                        }
                        version = segment;
                        break;
                    }
                }
            }
        }

        if (targetId == null || version == null) {
            return null;
        }
        return new String[] { targetId, version };
    }

    private static BundleManifest getManifest(InstallableUnitDAO iuDao, Object unit) {
        final TouchpointDataDAO tdDAO = iuDao.getTouchpointDataDAO();
        final TouchpointInstructionDAO tiDAO = tdDAO.getTouchpointInstructionDAO();
        for (Object point : iuDao.getTouchpointData(unit)) {
            Object instruction = tdDAO.getInstruction(point, "manifest");
            if (instruction != null) {
                String manifest = tiDAO.getBody(instruction);

                Resource resource = new BundleManifestResourceImpl();
                try {
                    resource.load(new ByteArrayInputStream(manifest.getBytes("UTF-8")), null);
                } catch (IOException e) {
                    throw pipe(e);
                }
                return (BundleManifest) resource.getContents().get(0);
            }
        }
        return null;
    }

    private static boolean hasSourceCapability(InstallableUnitDAO iuDao, Object unit) {
        for (Object capabilty : iuDao.getProvidedCapabilities(unit)) {
            if (capabilty.toString().startsWith("org.eclipse.equinox.p2.eclipse.type/source/")) {
                return true;
            }
        }
        return false;
    }

    private abstract static class AbstractDAO {
        private final String className;

        protected final ClassLoader classLoader;

        private Class<?> clazz;

        protected AbstractDAO(ClassLoader classLoader, String className) {
            this.classLoader = classLoader;
            this.className = className;
        }

        protected Class<?> getClazz() {
            if (clazz == null) {
                try {
                    clazz = classLoader.loadClass(className);
                } catch (ClassNotFoundException e) {
                    throw new IllegalStateException(e);
                }
            }
            return clazz;
        }

        protected Method getMethod(String methodName, Class<?>... argTypes) {
            return getMethod(getClazz(), methodName, argTypes);
        }

        private static Method getMethod(Class<?> clazz, String methodName, Class<?>... argTypes) {
            try {
                return clazz.getDeclaredMethod(methodName, argTypes);
            } catch (NoSuchMethodException e) {
                for (Class<?> interfaze : clazz.getInterfaces()) {
                    final Method method = getMethod(interfaze, methodName, argTypes);
                    if (method != null) {
                        return method;
                    }
                }
                final Class<?> superclass = clazz.getSuperclass();
                if (superclass != null) {
                    final Method method = getMethod(superclass, methodName, argTypes);
                    if (method != null) {
                        return method;
                    }
                }
                return null;
            }
        }

        @SuppressWarnings("unchecked")
        protected static <T> T invoke(Method method, Object target, Object... args) {
            try {
                return (T) method.invoke(target, args);
            } catch (IllegalAccessException e) {
                throw pipe(e);
            } catch (InvocationTargetException e) {
                final Throwable t = e.getTargetException();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                }
                if (t instanceof Error) {
                    throw (Error) t;
                }
                if (t instanceof Exception) {
                    throw pipe((Exception) t);
                }
                throw new IllegalStateException(t);
            }
        }
    }

    private static class P2TargetPlatformDAO extends AbstractDAO {
        private InstallableUnitDAO iuDAO;

        private Method getInstallableUnits;

        public P2TargetPlatformDAO(ClassLoader classLoader) {
            super(classLoader, "org.eclipse.tycho.p2.target.P2TargetPlatform");
        }

        public InstallableUnitDAO getInstallableUnitDAO() {
            if (iuDAO == null) {
                iuDAO = new InstallableUnitDAO(classLoader);
            }
            return iuDAO;
        }

        public Collection<?> getInstallableUnits(Object targetPlatform) {
            if (getInstallableUnits == null) {
                getInstallableUnits = getMethod("getInstallableUnits");
            }
            return invoke(getInstallableUnits, targetPlatform);
        }
    }

    static class InstallableUnitDAO extends AbstractDAO {
        private TouchpointDataDAO tdDAO;

        private Method getId;
        private Method getVersion;
        private Method getProvidedCapabilities;
        private Method getTouchpointData;
        private Method setProperty;

        public InstallableUnitDAO(ClassLoader classLoader) {
            super(classLoader, "org.eclipse.equinox.internal.p2.metadata.InstallableUnit");
        }

        public TouchpointDataDAO getTouchpointDataDAO() {
            if (tdDAO == null) {
                tdDAO = new TouchpointDataDAO(classLoader);
            }
            return tdDAO;
        }

        public String getId(Object unit) {
            if (getId == null) {
                getId = getMethod("getId");
            }
            return invoke(getId, unit);
        }

        public Object getVersion(Object unit) {
            if (getVersion == null) {
                getVersion = getMethod("getVersion");
            }
            return invoke(getVersion, unit);
        }

        public Collection<?> getProvidedCapabilities(Object installableUnit) {
            if (getProvidedCapabilities == null) {
                getProvidedCapabilities = getMethod("getProvidedCapabilities");
            }
            return invoke(getProvidedCapabilities, installableUnit);
        }

        public Collection<?> getTouchpointData(Object unit) {
            if (getTouchpointData == null) {
                getTouchpointData = getMethod("getTouchpointData");
            }
            return invoke(getTouchpointData, unit);
        }

        public String setProperty(Object unit, String key, String value) {
            if (setProperty == null) {
                setProperty = getMethod("setProperty", String.class, String.class);
            }
            return invoke(setProperty, unit, key, value);
        }
    }

    private static class TouchpointDataDAO extends AbstractDAO {
        private TouchpointInstructionDAO tiDAO;
        private Method getInstruction;

        protected TouchpointDataDAO(ClassLoader classLoader) {
            super(classLoader, "org.eclipse.equinox.p2.metadata.ITouchpointData");
        }

        public TouchpointInstructionDAO getTouchpointInstructionDAO() {
            if (tiDAO == null) {
                tiDAO = new TouchpointInstructionDAO(classLoader);
            }
            return tiDAO;
        }

        public Object getInstruction(Object touchpointData, String key) {
            if (getInstruction == null) {
                getInstruction = getMethod("getInstruction", String.class);
            }
            return invoke(getInstruction, touchpointData, key);
        }
    }

    private static class TouchpointInstructionDAO extends AbstractDAO {
        private Method getBody;

        protected TouchpointInstructionDAO(ClassLoader classLoader) {
            super(classLoader, "org.eclipse.equinox.p2.metadata.ITouchpointInstruction");
        }

        public String getBody(Object instruction) {
            if (getBody == null) {
                getBody = getMethod("getBody");
            }
            return invoke(getBody, instruction);
        }
    }
}