org.efaps.esjp.admin.update.UpdatePack.java Source code

Java tutorial

Introduction

Here is the source code for org.efaps.esjp.admin.update.UpdatePack.java

Source

/*
 * Copyright 2003 - 2016 The eFaps Team
 *
 * 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.efaps.esjp.admin.update;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.efaps.admin.AppConfigHandler;
import org.efaps.admin.event.Parameter;
import org.efaps.admin.event.Return;
import org.efaps.admin.program.esjp.EFapsApplication;
import org.efaps.admin.program.esjp.EFapsUUID;
import org.efaps.ci.CIAdmin;
import org.efaps.ci.CIAdminAccess;
import org.efaps.ci.CIAdminCommon;
import org.efaps.ci.CIAdminProgram;
import org.efaps.ci.CIAdminUser;
import org.efaps.ci.CIAdminUserInterface;
import org.efaps.ci.CIType;
import org.efaps.db.Context;
import org.efaps.db.MultiPrintQuery;
import org.efaps.db.QueryBuilder;
import org.efaps.db.SelectBuilder;
import org.efaps.esjp.ci.CICommon;
import org.efaps.rest.Update;
import org.efaps.update.FileType;
import org.efaps.update.Install;
import org.efaps.update.Install.InstallFile;
import org.efaps.update.util.InstallationException;
import org.efaps.util.EFapsException;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 */
@EFapsUUID("ae1aac5a-5c81-44f3-9e8d-ca66f71fab1f")
@EFapsApplication("eFaps-Kernel")
public class UpdatePack {
    /**
     * Logger for this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(UpdatePack.class);

    /**
     * Check revisions.
     *
     * @param _parameter Parameter as passed by the eFaps API
     * @return the return
     * @throws EFapsException on error
     * @throws InstallationException on error
     */
    public Return execute(final Parameter _parameter) throws EFapsException, InstallationException {
        final Context context = Context.getThreadContext();
        final Context.FileParameter fileItem = context.getFileParameters().get("pack");
        final boolean compress = GzipUtils.isCompressedFilename(fileItem.getName());

        try (final TarArchiveInputStream tarInput = new TarArchiveInputStream(
                compress ? new GzipCompressorInputStream(fileItem.getInputStream()) : fileItem.getInputStream());) {

            File tmpfld = AppConfigHandler.get().getTempFolder();
            if (tmpfld == null) {
                final File temp = File.createTempFile("eFaps", ".tmp");
                tmpfld = temp.getParentFile();
                temp.delete();
            }
            final File updateFolder = new File(tmpfld, Update.TMPFOLDERNAME);
            if (!updateFolder.exists()) {
                updateFolder.mkdirs();
            }
            final File dateFolder = new File(updateFolder, ((Long) new Date().getTime()).toString());
            dateFolder.mkdirs();

            final Map<String, URL> files = new HashMap<>();
            TarArchiveEntry currentEntry = tarInput.getNextTarEntry();
            while (currentEntry != null) {
                final byte[] bytess = new byte[(int) currentEntry.getSize()];
                tarInput.read(bytess);
                final File file = new File(dateFolder.getAbsolutePath() + "/" + currentEntry.getName());
                file.getParentFile().mkdirs();
                final FileOutputStream output = new FileOutputStream(file);
                output.write(bytess);
                output.close();
                files.put(currentEntry.getName(), file.toURI().toURL());
                currentEntry = tarInput.getNextTarEntry();
            }

            final Map<RevItem, InstallFile> installFiles = new HashMap<>();

            final URL json = files.get("revisions.json");
            final ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JodaModule());
            final List<RevItem> items = mapper.readValue(new File(json.toURI()),
                    mapper.getTypeFactory().constructCollectionType(List.class, RevItem.class));
            final List<RevItem> allItems = new ArrayList<>();
            allItems.addAll(items);

            installFiles.putAll(getInstallFiles(files, items, CIAdmin.Abstract));
            installFiles.putAll(getInstallFiles(files, items, CIAdminUser.Abstract));
            installFiles.putAll(getInstallFiles(files, items, CIAdminAccess.AccessSet));
            installFiles.putAll(getInstallFiles(files, items, CICommon.DBPropertiesBundle));

            final Iterator<RevItem> iter = items.iterator();
            int i = 0;
            while (iter.hasNext()) {
                final RevItem item = iter.next();
                LOG.info("Adding unfound Item {} / {}: {}", i, items.size(), item.getIdentifier());
                final InstallFile installFile = new InstallFile().setName(item.getName4InstallFile())
                        .setURL(item.getURL(files)).setType(item.getFileType().getType())
                        .setRevision(item.getRevision()).setDate(item.getDate());
                installFiles.put(item, installFile);
                i++;
            }

            final List<InstallFile> installFileList = new ArrayList<>(installFiles.values());
            Collections.sort(installFileList, new Comparator<InstallFile>() {
                @Override
                public int compare(final InstallFile _installFile0, final InstallFile _installFile1) {
                    return _installFile0.getName().compareTo(_installFile1.getName());
                }
            });

            final List<InstallFile> dependendFileList = new ArrayList<>();
            // check if a object that depends on another object must be added to the update
            final Map<String, String> depenMap = getDependendMap();
            final Set<String> tobeAdded = new HashSet<>();
            for (final RevItem item : installFiles.keySet()) {
                if (depenMap.containsKey(item.getIdentifier())) {
                    tobeAdded.add(depenMap.get(item.getIdentifier()));
                }
            }
            if (!tobeAdded.isEmpty()) {
                // check if the object to be added is already part ot the list
                for (final RevItem item : installFiles.keySet()) {
                    final Iterator<String> tobeiter = tobeAdded.iterator();
                    while (tobeiter.hasNext()) {
                        final String ident = tobeiter.next();
                        if (item.getIdentifier().equals(ident)) {
                            tobeiter.remove();
                        }
                    }
                }
            }
            if (!tobeAdded.isEmpty()) {
                i = 1;
                // add the objects to the list taht are missing
                for (final RevItem item : allItems) {
                    if (tobeAdded.contains(item.getIdentifier())) {
                        LOG.info("Adding releated Item {} / {}: {}", i, tobeAdded.size(), item);
                        final InstallFile installFile = new InstallFile().setName(item.getName4InstallFile())
                                .setURL(item.getURL(files)).setType(item.getFileType().getType())
                                .setRevision(item.getRevision()).setDate(item.getDate());
                        dependendFileList.add(installFile);
                        i++;
                    }
                }
            }

            if (!installFileList.isEmpty()) {
                final Install install = new Install(true);
                for (final InstallFile installFile : installFileList) {
                    LOG.info("...Adding to Update: '{}' ", installFile.getName());
                    install.addFile(installFile);
                }
                install.updateLatest(null);
            }
            if (!dependendFileList.isEmpty()) {
                LOG.info("Update for related Items");
                final Install install = new Install(true);
                for (final InstallFile installFile : dependendFileList) {
                    LOG.info("...Adding to Update: '{}' ", installFile.getName());
                    install.addFile(installFile);
                }
                install.updateLatest(null);
            }
            LOG.info("Terminated update.");
        } catch (final IOException e) {
            LOG.error("Catched", e);
        } catch (final URISyntaxException e) {
            LOG.error("Catched", e);
        }
        return new Return();
    }

    /**
     * Gets the dependend map.
     *
     * @return the dependend map
     * @throws EFapsException the e faps exception
     */
    private Map<String, String> getDependendMap() throws EFapsException {
        final Map<String, String> ret = new HashMap<>();
        final QueryBuilder queryBldr = new QueryBuilder(CIAdminUserInterface.Menu2Command);
        final MultiPrintQuery multi = queryBldr.getPrint();
        final SelectBuilder selFromUUID = SelectBuilder.get().linkto(CIAdminUserInterface.Menu2Command.FromMenu)
                .attribute(CIAdminUserInterface.Menu.UUID);
        final SelectBuilder selToUUID = SelectBuilder.get().linkto(CIAdminUserInterface.Menu2Command.ToCommand)
                .attribute(CIAdminUserInterface.Command.UUID);
        multi.addSelect(selFromUUID, selToUUID);
        multi.executeWithoutAccessCheck();
        while (multi.next()) {
            ret.put(multi.<String>getSelect(selFromUUID), multi.<String>getSelect(selToUUID));
        }
        return ret;
    }

    /**
     * Gets the install files.
     *
     * @param _files the files
     * @param _items the items
     * @param _ciType the ci type
     * @return the install files
     * @throws EFapsException on error
     */
    private Map<RevItem, InstallFile> getInstallFiles(final Map<String, URL> _files, final List<RevItem> _items,
            final CIType _ciType) throws EFapsException {
        final Map<RevItem, InstallFile> ret = new HashMap<>();
        final Iterator<RevItem> iter = _items.iterator();
        int i = 0;
        while (iter.hasNext()) {
            final RevItem item = iter.next();
            LOG.info("Checking Item {} / {}: {}", i, _items.size(), item.getIdentifier());

            final MultiPrintQuery multi = getQueryBldr(item, _ciType).getPrint();
            final SelectBuilder selRevision = SelectBuilder.get().linkto(CIAdmin.Abstract.RevisionLink)
                    .attribute(CIAdminCommon.ApplicationRevision.Revision);
            final SelectBuilder selRevDate = SelectBuilder.get().linkto(CIAdmin.Abstract.RevisionLink)
                    .attribute(CIAdminCommon.ApplicationRevision.Date);
            final SelectBuilder selApp = SelectBuilder.get().linkto(CIAdmin.Abstract.RevisionLink)
                    .linkto(CIAdminCommon.ApplicationRevision.ApplicationLink)
                    .attribute(CIAdminCommon.Application.Name);
            multi.addSelect(selRevision, selApp, selRevDate);
            multi.addAttribute(CIAdmin.Abstract.Name);
            multi.execute();
            boolean update = false;
            if (multi.next()) {
                final String revision = multi.getSelect(selRevision);
                final DateTime revDate = multi.getSelect(selRevDate);
                final String app = multi.getSelect(selApp);
                final String name = multi.getAttribute(CIAdmin.Abstract.Name);
                LOG.info("Found obj: {}, type: {}, name: {},  app: {}, date: {}, revision: {} ",
                        multi.getCurrentInstance().getOid(), multi.getCurrentInstance().getType().getName(), name,
                        app, revDate, revision);
                if (!item.getApplication().equals(app)) {
                    LOG.warn("Different Application: {} - {}", item.getApplication(), app);
                    update = true;
                }
                if (!item.getRevision().equals(revision)) {
                    LOG.warn("Different Revision: {} - {}", item.getRevision(), revision);
                    update = true;
                }
                if (!update && item.getDate().isAfter(revDate)) {
                    LOG.warn("Different Date: {} - {}", item.getDate(), revDate);
                    update = true;
                }

                if (update) {
                    final InstallFile installFile = new InstallFile().setName(item.getName4InstallFile(name))
                            .setURL(item.getURL(_files)).setType(item.getFileType().getType())
                            .setRevision(item.getRevision()).setDate(item.getDate());
                    ret.put(item, installFile);
                }
                iter.remove();
            }
            i++;
        }
        return ret;
    }

    /**
     * Gets the query bldr.
     *
     * @param _item the item
     * @param _ciType the ci type
     * @return the query bldr
     * @throws EFapsException on error
     */
    private QueryBuilder getQueryBldr(final RevItem _item, final CIType _ciType) throws EFapsException {
        QueryBuilder ret = null;
        switch (_item.getFileType()) {
        case XML:
            ret = new QueryBuilder(_ciType);
            ret.addWhereAttrEqValue(CIAdmin.Abstract.UUID, _item.getIdentifier());
            break;
        case JAVA:
            ret = new QueryBuilder(CIAdminProgram.Java);
            ret.addWhereAttrEqValue(CIAdminProgram.Java.Name, _item.getIdentifier());
            break;
        case CSS:
            ret = new QueryBuilder(CIAdminProgram.CSS);
            ret.addWhereAttrEqValue(CIAdminProgram.CSS.Name, _item.getIdentifier());
            break;
        case JS:
            ret = new QueryBuilder(CIAdminProgram.JavaScript);
            ret.addWhereAttrEqValue(CIAdminProgram.JavaScript.Name, _item.getIdentifier());
            break;
        case JRXML:
            ret = new QueryBuilder(CIAdminProgram.JasperReport);
            ret.addWhereAttrEqValue(CIAdminProgram.JasperReport.UUID, _item.getIdentifier());
            break;
        default:
            break;
        }
        return ret;
    }

    /**
     * The Class RevItem.
     *
     * @author The eFaps Team
     */
    public static class RevItem {

        /** The file type. */
        private FileType fileType;

        /** The identifier. */
        private String identifier;

        /** The application. */
        private String application;

        /** The revision. */
        private String revision;

        /** The date. */
        private DateTime date;

        /**
         * Gets the file type.
         *
         * @return the file type
         */
        public FileType getFileType() {
            return this.fileType;
        }

        /**
         * Sets the file type.
         *
         * @param _fileType the new file type
         */
        public void setFileType(final FileType _fileType) {
            this.fileType = _fileType;
        }

        /**
         * Getter method for the instance variable {@link #application}.
         *
         * @return value of instance variable {@link #application}
         */
        public String getApplication() {
            return this.application;
        }

        /**
         * Sets the application.
         *
         * @param _application the new application
         */
        public void setApplication(final String _application) {
            this.application = _application;
        }

        /**
         * Getter method for the instance variable {@link #revision}.
         *
         * @return value of instance variable {@link #revision}
         */
        public String getRevision() {
            return this.revision;
        }

        /**
         * Sets the revision.
         *
         * @param _revision the new revision
         */
        public void setRevision(final String _revision) {
            this.revision = _revision;
        }

        /**
         * Getter method for the instance variable {@link #identifier}.
         *
         * @return value of instance variable {@link #identifier}
         */
        public String getIdentifier() {
            return this.identifier;
        }

        /**
         * Sets the identifier.
         *
         * @param _identifier the new identifier
         */
        public void setIdentifier(final String _identifier) {
            this.identifier = _identifier;
        }

        /**
         * Gets the date.
         *
         * @return the date
         */
        public DateTime getDate() {
            return this.date;
        }

        /**
         * Sets the date.
         *
         * @param _date the new date
         */
        public void setDate(final DateTime _date) {
            this.date = _date;
        }

        /**
         * Gets the name 4 install file.
         *
         * @return the name 4 install file
         */
        public String getName4InstallFile() {
            final String ret;
            switch (getFileType()) {
            case JAVA:
                ret = getIdentifier() + ".java";
                break;
            default:
                ret = getIdentifier();
                break;
            }
            return ret;
        }

        /**
         * Gets the name 4 install file.
         *
         * @param _name the name
         * @return the name 4 install file
         */
        public String getName4InstallFile(final String _name) {
            final String ret;
            switch (getFileType()) {
            case JAVA:
                ret = getIdentifier() + ".java";
                break;
            default:
                ret = _name;
                break;
            }
            return ret;
        }

        /**
         * Gets the url.
         *
         * @param _files the files
         * @return the url
         */
        public URL getURL(final Map<String, URL> _files) {
            final URL ret;
            switch (getFileType()) {
            case JAVA:
                ret = _files.get(getIdentifier().replaceAll("\\.", "/") + ".java");
                break;
            case CSS:
                ret = _files.get(StringUtils.removeEnd(getIdentifier(), ".css").replaceAll("\\.", "/") + ".css");
                break;
            case JS:
                ret = _files.get(StringUtils.removeEnd(getIdentifier(), ".js").replaceAll("\\.", "/") + ".js");
                break;
            case JRXML:
                ret = _files.get(getIdentifier() + ".jrxml");
                break;
            default:
                ret = _files.get(getIdentifier());
                break;
            }
            return ret;
        }

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this);
        }
    }
}