org.apache.felix.sigil.eclipse.ui.internal.classpath.SigilClassPathContainer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.felix.sigil.eclipse.ui.internal.classpath.SigilClassPathContainer.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.felix.sigil.eclipse.ui.internal.classpath;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.felix.sigil.eclipse.SigilCore;
import org.apache.felix.sigil.eclipse.job.ThreadProgressMonitor;
import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel;
import org.apache.felix.sigil.eclipse.ui.SigilUI;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;

/**
 * @author dave
 *
 */
public class SigilClassPathContainer implements IClasspathContainer {

    private static final String CLASSPATH = "classpath";
    private static final String EMPTY = "empty";

    private IClasspathEntry[] entries;

    private final ISigilProjectModel sigil;

    public SigilClassPathContainer(ISigilProjectModel sigil) {
        this.sigil = sigil;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.IClasspathContainer#getClasspathEntries()
     */
    public IClasspathEntry[] getClasspathEntries() {
        if (entries == null) {
            buildClassPathEntries();
        }

        return entries;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.IClasspathContainer#getDescription()
     */
    public String getDescription() {
        return "Bundle Context Classpath";
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.IClasspathContainer#getKind()
     */
    public int getKind() {
        return K_SYSTEM;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.core.IClasspathContainer#getPath()
     */
    public IPath getPath() {
        return new Path(SigilCore.CLASSPATH_CONTAINER_PATH);
    }

    /**
     * @return
     * @throws CoreException 
     * @throws CoreException 
     */
    private void buildClassPathEntries() {
        try {
            if (sigil.exists()) {
                entries = getCachedClassPath(sigil);

                if (entries == null) {
                    IProgressMonitor monitor = ThreadProgressMonitor.getProgressMonitor();
                    entries = sigil.findExternalClasspath(monitor).toArray(new IClasspathEntry[0]);

                    cacheClassPath(sigil, entries);
                }
            }
        } catch (CoreException e) {
            SigilCore.error("Failed to build classpath entries", e);
        } finally {
            if (entries == null) {
                entries = new IClasspathEntry[] {};
            }
        }
    }

    static IClasspathEntry[] getCachedClassPath(ISigilProjectModel project) {
        File f = getClassPathDir(project);
        if (f == null || !f.exists())
            return null;

        File[] entries = f.listFiles();
        if (entries == null || entries.length == 0)
            return null;

        ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(entries.length);
        for (File entry : entries) {
            if (EMPTY.equals(entry.getName())) {
                list.clear();
                break;
            } else {
                try {
                    list.add(readClassPath(project.getJavaModel(), entry));
                } catch (IOException e) {
                    SigilCore.warn("Failed to read classpath entry " + entry, e);
                }
            }
        }
        return list.toArray(new IClasspathEntry[list.size()]);
    }

    private static File getClassPathDir(ISigilProjectModel project) {
        IPath loc = project.getProject().getWorkingLocation(SigilUI.PLUGIN_ID);

        if (loc == null)
            return null;

        loc = loc.append(CLASSPATH);

        return new File(loc.toOSString());
    }

    static void cacheClassPath(ISigilProjectModel project, IClasspathEntry[] entries) {
        File f = getClassPathDir(project);

        if (f == null)
            return;

        if (!f.exists()) {
            if (!f.mkdirs()) {
                SigilCore.warn("Failed to create temp working directory " + f);
                return;
            }
        }

        try {
            if (entries.length == 0) {
                File empty = new File(f, EMPTY);
                empty.createNewFile();
            } else {
                int i = 0;
                for (IClasspathEntry e : entries) {
                    File entry = new File(f, Integer.toString(i++));
                    writeClassPath(project.getJavaModel(), entry, e);
                }
            }
        } catch (IOException e) {
            SigilCore.warn("Failed to read write classpath entries", e);
        }
    }

    /**
     * @param sigil
     */
    static void flushCachedClassPath(ISigilProjectModel project) {
        File f = getClassPathDir(project);

        if (f == null || !f.exists())
            return;

        File[] files = f.listFiles();
        if (files == null)
            return;

        for (File entry : files) {
            entry.delete();
        }
    }

    private static IClasspathEntry readClassPath(IJavaProject javaModel, File entry) throws IOException {
        FileInputStream in = new FileInputStream(entry);

        try {
            ByteArrayOutputStream buf = new ByteArrayOutputStream();

            byte[] b = new byte[1024];

            for (;;) {
                int r = in.read(b);
                if (r == -1)
                    break;
                buf.write(b, 0, r);
            }

            String enc = buf.toString();
            return javaModel.decodeClasspathEntry(enc);
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                SigilCore.warn("Failed to close stream to " + entry, e);
            }
        }
    }

    private static void writeClassPath(IJavaProject javaModel, File file, IClasspathEntry entry)
            throws IOException {
        String enc = javaModel.encodeClasspathEntry(entry);
        FileOutputStream out = new FileOutputStream(file);
        try {
            out.write(enc.getBytes());
            out.flush();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                SigilCore.warn("Failed to close stream to " + entry, e);
            }
        }
    }

}