org.dspace.installer_edm.InstallerCrosswalk.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.installer_edm.InstallerCrosswalk.java

Source

/**
 *  Copyright 2013 Spanish Minister of Education, Culture and Sport
 *
 *  written by MasMedios
 *
 *  Licensed under the EUPL, Version 1.1 or  as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence");
 *
 *  You may not use this work  except in compliance with the License. You may obtain a copy of the License at:
 *
 *  http://ec.europa.eu/idabc/servlets/Docbb6d.pdf?id=31979
 *
 *  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.dspace.installer_edm;

import org.apache.commons.io.FileUtils;

import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

/**
 * @class InstallerCrosswalk
 *
 * Clase aadir un crosswalk al jar de la api de oai y configurar oaicat.properties para mostrarlo
 *
 *
 */
public abstract class InstallerCrosswalk extends InstallerEDMBase {

    /**
     * Nombre del formato
     */
    protected String crosswalkName;

    /**
     * Nombre completo de la clase
     */
    protected String canonicalCrosswalkName;

    /**
     * ruta del archivo XXXCrosswalk.java
     */
    protected String edmCrossWalk;

    /**
     * nombre del archivo XXXCrosswalk.java
     */
    protected String edmCrossWalkName;

    /**
     * nombre del archivo XXXCrosswalk.class
     */
    protected String edmCrossWalkClass;

    /**
     * archivo XXXCrosswalk.java
     */
    protected File edmCrossWalkFile;

    /**
     * contenido del archivo XXXCrosswalk.java
     */
    protected String edmCrossWalkContent;

    /**
     * ruta del archivo de la api de dspace para oai
     */
    protected String oaiApiJarName;

    /**
     * archivo de la api de dspace para oai
     */
    protected File oaiApiJarFile;

    /**
     * archivo jar de oaiApiJarWorkFile
     */
    protected JarFile oaiApiJarJarFile;

    /**
     * archivo de la apo de dspace para oai en el directorio de trabajo del instalador
     */
    protected File oaiApiJarWorkFile;

    /**
     * ruta del archivo oaicat.properties
     */
    protected String oaiCatPropertiesName;

    /**
     * archivo oaicat.properties
     */
    protected File oaiCatPropertiesFile;

    /**
     * archivo oaicat.properties en el directorio de trabajo del instalador
     */
    protected File oaiCatPropertiesWorkFile;

    /**
     * Constructor
     *
     * @param currentStepGlobal paso actual
     */
    public InstallerCrosswalk(int currentStepGlobal, String crosswalkName) {
        super(currentStepGlobal);
        this.crosswalkName = crosswalkName;
        this.canonicalCrosswalkName = "org.dspace.app.oai." + crosswalkName + "Crosswalk";
        this.edmCrossWalk = myInstallerDirPath + fileSeparator + "packages" + fileSeparator + crosswalkName
                + "Crosswalk.java";
        this.edmCrossWalkFile = new File(edmCrossWalk);
    }

    /**
     * Mtodo para ser llamado por las clases hijas para configuracin especfica
     */
    public abstract void configureCrosswalk();

    /**
     * Se comprueba que exista el archivo XXXCrosswalk.java y se pueda modificar
     * Se comprueba que exista el archivo de la api de oai de dspace y se pueda leer y se copia al directorio de trabajo del instalador
     *
     * Se abre el jar de la api de oai de dsapce y se comprueba si ya existe el archivo de la clase XXXCrosswalk.class y se pregunta si se sustituye.
     * Se configura, se escribe el java, se compila y se introduce en el jar de la api de oai de dspace.
     *
     * Se modifica oai.properties para aadir el crosswalk
     */
    public void configure() {
        try {
            // comprueba que exista el archivo EDMCrosswalk.java y se pueda modificar. Comprueba que exista el archivo de la api de oai de dspace y se pueda leer
            if (checkEdmCrowssWalk() && checkOaiApiJar()) {
                edmCrossWalkName = edmCrossWalkFile.getName();
                edmCrossWalkClass = "org/dspace/app/oai/" + edmCrossWalkName.replaceFirst("\\.java", ".class");

                // copia al directorio de trabajo del instalador
                oaiApiJarWorkFile = new File(myInstallerWorkDirPath + fileSeparator + oaiApiJarFile.getName());
                copyDspaceFile2Work(oaiApiJarFile, oaiApiJarWorkFile, "configure.edmcrosswalk.oaiapijar");
                oaiApiJarName = oaiApiJarWorkFile.getAbsolutePath();

                // abre el jar de la api de oai de dsapce
                oaiApiJarJarFile = new JarFile(oaiApiJarWorkFile);
                // comprueba si ya existe el archivo de la clase EDMCrosswalk.class
                ZipEntry edmOaiApiEdmCrossWalkZipentry = oaiApiJarJarFile.getEntry(edmCrossWalkClass);
                if (edmOaiApiEdmCrossWalkZipentry != null) {
                    // se pregunta si se sustituye
                    String response = null;
                    do {
                        installerEDMDisplay.showQuestion(currentStepGlobal, "configure.exists.class",
                                new String[] { edmCrossWalkClass, oaiApiJarFile.getAbsolutePath() });
                        response = br.readLine();
                        if (response == null)
                            continue;
                        response = response.trim();
                        if (!response.isEmpty() && response.equalsIgnoreCase(answerYes)) {
                            break;
                        } else
                            return;
                    } while (true);
                }
                installerEDMDisplay.showLn();
                installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.begin",
                        new String[] { edmCrossWalkName });
                installerEDMDisplay.showLn();
                // se lee el java y se recoge el contenido en edmCrossWalkContent
                readCrossWalk2String();
                configureCrosswalk();
                installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.compile");
                // compila
                if (compileEDMCrossWalk()) {
                    installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.updatejar",
                            new String[] { oaiApiJarWorkFile.getAbsolutePath() });
                    // se introduce en el jar de la api de oai de dspace
                    writeNewJar();
                    org.apache.commons.io.FileUtils
                            .deleteDirectory(new File(myInstallerWorkDirPath + fileSeparator + "org"));
                    oaiApiJarJarFile = new JarFile(oaiApiJarWorkFile);
                    edmOaiApiEdmCrossWalkZipentry = oaiApiJarJarFile.getEntry(edmCrossWalkClass);
                    if (edmOaiApiEdmCrossWalkZipentry != null) {
                        // modifica oai.properties para aadir el crosswalk
                        if (confOaiCatProperties()) {
                            installerEDMDisplay.showLn();
                            installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.ok",
                                    new String[] { oaiApiJarWorkFile.getName() });
                        } else
                            installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.nok");
                    } else
                        installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.nok");
                    oaiApiJarJarFile.close();
                } else
                    installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.nok");
            }
        } catch (IOException e) {
            showException(e);
            installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.nok");
        }
    }

    /**
     * Comprueba que el archivo XXXCrosswalk.java existe y se puede modificar, si no se pide la ruta
     *
     * @return si existe y se puede modificar
     * @throws IOException
     */
    protected boolean checkEdmCrowssWalk() throws IOException {
        if (!edmCrossWalkFile.exists() || !edmCrossWalkFile.isFile() || !edmCrossWalkFile.canWrite()) {
            installerEDMDisplay.showQuestion(currentStepGlobal, "checkEdmCrowssWalk.notexists",
                    new String[] { edmCrossWalk });
            installerEDMDisplay.showQuestion(currentStepGlobal, "checkEdmCrowssWalk.newclass");
            String response = null;
            do {
                response = br.readLine();
                if (response == null)
                    continue;
                response = response.trim();
                if (!response.isEmpty()) {
                    edmCrossWalkFile = new File(response);
                    return checkEdmCrowssWalk();
                } else
                    return false;
            } while (true);
        }
        return true;
    }

    /**
     * Comprueba que el archivo de la api de dspace para oai existe y se puede leer, si no se pide la ruta
     *
     * @return si existe y se pude leer
     * @throws IOException
     */
    protected boolean checkOaiApiJar() throws IOException {
        if (oaiApiJarFile == null || !oaiApiJarFile.exists() || !oaiApiJarFile.isFile()
                || !oaiApiJarFile.canRead()) {
            installerEDMDisplay.showQuestion(currentStepGlobal, "checkOaiApiJar.notexists",
                    new String[] { ((oaiApiJarName == null) ? "dspace-oai-api" : oaiApiJarName) });
            installerEDMDisplay.showQuestion(currentStepGlobal, "checkOaiApiJar.newjar");
            String response = null;
            do {
                response = br.readLine();
                if (response == null)
                    continue;
                response = response.trim();
                if (!response.isEmpty()) {
                    oaiApiJarFile = new File(response);
                    return checkOaiApiJar();
                } else
                    return false;
            } while (true);
        }
        return true;
    }

    /**
     * Recoge oaicat.properties de dspace o pide su ruta.
     * Lo copia al directorio de trabajo del instalador.
     * Modifica su contenido para aadir la propiedad del crosswalk: Crosswalks.edm=org.dspace.app.oai.EDMCrosswalk
     *
     * @return xito de la operacin
     * @throws IOException
     */
    protected boolean confOaiCatProperties() throws IOException {
        boolean status = false;
        // recoge oaicat.properties de dspace
        oaiCatPropertiesName = DspaceDir + fileSeparator + "config" + fileSeparator + "oaicat.properties";
        oaiCatPropertiesFile = new File(oaiCatPropertiesName);
        // pide su ruta
        String response = null;
        installerEDMDisplay.showLn();
        do {
            installerEDMDisplay.showQuestion(currentStepGlobal, "configure.edmcrosswalk.conf.oaicat",
                    new String[] { oaiCatPropertiesName });
            response = br.readLine();
            if (response == null)
                continue;
            response = response.trim();
            if (!response.isEmpty()) {
                oaiCatPropertiesFile = new File(response);
            }
            if (oaiCatPropertiesFile.exists() && oaiCatPropertiesFile.canRead())
                break;
        } while (true);
        // copia al directorio de trabajo del instalador
        oaiCatPropertiesWorkFile = new File(
                myInstallerWorkDirPath + fileSeparator + oaiCatPropertiesFile.getName());
        copyDspaceFile2Work(oaiCatPropertiesFile, oaiCatPropertiesWorkFile, "configure.edmcrosswalk.oaicat");

        // lee propiedades del archivo
        Properties properties = new Properties();
        URL url = oaiCatPropertiesWorkFile.toURI().toURL();
        InputStream is = url.openStream();
        properties.load(is);
        Writer out = null;
        try {
            String propCrossw = "Crosswalks." + crosswalkName.toLowerCase();
            // modifica su contenido para aadir la propiedad del crosswalk
            if (!properties.containsKey(propCrossw)) {
                out = new OutputStreamWriter(new FileOutputStream(oaiCatPropertiesWorkFile, true));
                out.write("\n\n# " + getTime() + " Appended by installerEDM to add the " + crosswalkName
                        + "Crosswalk\n");
                out.write(propCrossw + "=" + canonicalCrosswalkName + "\n");
            } else {
                installerEDMDisplay.showQuestion(currentStepGlobal, "confOaiCatProperties.exist",
                        new String[] { propCrossw, properties.getProperty(propCrossw), canonicalCrosswalkName });
            }
            status = true;
        } finally {
            if (is != null)
                is.close();
            if (out != null) {
                out.flush();
                out.close();
            }
        }
        return status;
    }

    /**
     * Compila el java en tiempo real
     *
     * @return xito de la operacin
     */
    protected boolean compileEDMCrossWalk() {
        boolean status = false;

        SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(canonicalCrosswalkName,
                edmCrossWalkContent);
        JavaFileObject javaFileObjects[] = new JavaFileObject[] { fileObject };

        Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);

        // libreras necesarias para linkar con el fuente a compilar
        String myInstallerPackagesDirPath = myInstallerDirPath + fileSeparator + "packages" + fileSeparator;
        StringBuilder jars = (fileSeparator.equals("\\"))
                ? new StringBuilder(myInstallerPackagesDirPath).append("dspace-api-1.7.2.jar;")
                        .append(myInstallerPackagesDirPath).append("jdom-1.0.jar;")
                        .append(myInstallerPackagesDirPath).append("oaicat-1.5.48.jar")
                : new StringBuilder(myInstallerPackagesDirPath).append("dspace-api-1.7.2.jar:")
                        .append(myInstallerPackagesDirPath).append("jdom-1.0.jar:")
                        .append(myInstallerPackagesDirPath).append("oaicat-1.5.48.jar");

        String[] compileOptions = new String[] { "-d", myInstallerWorkDirPath, "-source", "1.6", "-target", "1.6",
                "-cp", jars.toString() };
        Iterable<String> compilationOptionss = Arrays.asList(compileOptions);

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

        StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null);

        JavaCompiler.CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics,
                compilationOptionss, null, compilationUnits);

        status = compilerTask.call();

        if (!status) {
            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
                installerEDMDisplay
                        .showMessage("Error on line " + diagnostic.getLineNumber() + " in " + diagnostic);
            }
        }

        try {
            stdFileManager.close();
        } catch (IOException e) {
            showException(e);
        }
        return status;
    }

    /**
     * Lee el fuente del java para introducirlo en una cadena
     *
     * @throws java.io.FileNotFoundException
     */
    protected void readCrossWalk2String() throws FileNotFoundException {
        Scanner edmCrossWalkScanner = null;
        try {
            StringBuilder fileContents = new StringBuilder((int) edmCrossWalkFile.length());
            edmCrossWalkScanner = new Scanner(edmCrossWalkFile);
            String lineSeparator = System.getProperty("line.separator");
            while (edmCrossWalkScanner.hasNextLine()) {
                fileContents.append(edmCrossWalkScanner.nextLine()).append(lineSeparator);
            }
            edmCrossWalkContent = fileContents.toString();
        } finally {
            if (edmCrossWalkScanner != null)
                edmCrossWalkScanner.close();
        }
    }

    /**
     * Abre el jar para escribir el nuevo archivo class compilado, elresto de archivos los copia tal cual
     *
     * @throws IOException
     */
    protected void writeNewJar() throws IOException {
        // buffer para leer datos de los archivos
        final int BUFFER_SIZE = 1024;
        // directorio de trabajo
        File jarDir = new File(this.oaiApiJarJarFile.getName()).getParentFile();
        // nombre del jar
        String name = oaiApiJarWorkFile.getName();
        String extension = name.substring(name.lastIndexOf('.'));
        name = name.substring(0, name.lastIndexOf('.'));
        // archivo temporal del nuevo jar
        File newJarFile = File.createTempFile(name, extension, jarDir);
        newJarFile.deleteOnExit();
        // flujo de escritura del nuevo jar
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(newJarFile));

        // recorrer todos los archivos del jar menos el crosswalk para replicarlos
        try {
            Enumeration<JarEntry> entries = oaiApiJarJarFile.entries();
            while (entries.hasMoreElements()) {
                installerEDMDisplay.showProgress('.');
                JarEntry entry = entries.nextElement();
                if (!entry.getName().equals(edmCrossWalkClass)) {
                    JarEntry entryOld = new JarEntry(entry);
                    entryOld.setCompressedSize(-1);
                    jarOutputStream.putNextEntry(entryOld);
                    InputStream intputStream = oaiApiJarJarFile.getInputStream(entry);
                    int count;
                    byte data[] = new byte[BUFFER_SIZE];
                    while ((count = intputStream.read(data, 0, BUFFER_SIZE)) != -1) {
                        jarOutputStream.write(data, 0, count);
                    }
                    intputStream.close();
                }
            }
            installerEDMDisplay.showLn();
            // aadir class compilado
            addClass2Jar(jarOutputStream);
            // cerrar jar original
            oaiApiJarJarFile.close();
            // borrar jar original
            oaiApiJarWorkFile.delete();
            // cambiar jar original por nuevo
            try {
                /*if (newJarFile.renameTo(oaiApiJarWorkFile) && oaiApiJarWorkFile.setExecutable(true, true)) {
                oaiApiJarWorkFile = new File(oaiApiJarName);
                } else {
                throw new IOException();
                }*/
                if (jarOutputStream != null)
                    jarOutputStream.close();
                FileUtils.moveFile(newJarFile, oaiApiJarWorkFile);
                oaiApiJarWorkFile.setExecutable(true, true);
                oaiApiJarWorkFile = new File(oaiApiJarName);
            } catch (Exception io) {
                io.printStackTrace();
                throw new IOException();
            }
        } finally {
            if (jarOutputStream != null) {
                jarOutputStream.close();
            }
        }
    }

    /**
     * Aade contenido archivo class a nuevo archivo class en el jar
     *
     * @param jarOutputStream flujo de escritura para el jar
     * @throws IOException
     */
    protected void addClass2Jar(JarOutputStream jarOutputStream) throws IOException {
        File file = new File(myInstallerWorkDirPath + fileSeparator + edmCrossWalkClass);
        byte[] fileData = new byte[(int) file.length()];
        DataInputStream dis = new DataInputStream(new FileInputStream(file));
        dis.readFully(fileData);
        dis.close();
        jarOutputStream.putNextEntry(new JarEntry(edmCrossWalkClass));
        jarOutputStream.write(fileData);
        jarOutputStream.closeEntry();
    }

}

/**
 * Clase con el fuente preparado para se compilado
 */
class DynamicJavaSourceCodeObject extends SimpleJavaFileObject {
    private String qualifiedName;
    private String sourceCode;

    /**
     * Constructor
     *
     * @param name nombre del fuente
     * @param code contenido del fuente
     */
    protected DynamicJavaSourceCodeObject(String name, String code) {
        super(URI.create("string:///" + name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
        this.qualifiedName = name;
        this.sourceCode = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return sourceCode;
    }

    public String getQualifiedName() {
        return qualifiedName;
    }

    public void setQualifiedName(String qualifiedName) {
        this.qualifiedName = qualifiedName;
    }

    public String getSourceCode() {
        return sourceCode;
    }

    public void setSourceCode(String sourceCode) {
        this.sourceCode = sourceCode;
    }
}