Package org.restlet.engine.local

Source Code of org.restlet.engine.local.ZipClientHelper

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.engine.local;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.restlet.Client;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.LocalReference;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.ReferenceList;
import org.restlet.data.Status;
import org.restlet.engine.io.BioUtils;
import org.restlet.representation.Representation;
import org.restlet.service.MetadataService;

/**
* ZIP and JAR client connector. Only works for archives available as local
* files.<br>
* <br>
* Handles GET, HEAD and PUT request on resources referenced as :
* zip:file://<file path>
*
* @author Remi Dewitte <remi@gide.net>
*/
public class ZipClientHelper extends LocalClientHelper {

    /**
     * Constructor.
     *
     * @param client
     *            The helped client.
     */
    public ZipClientHelper(Client client) {
        super(client);
        getProtocols().add(Protocol.ZIP);
        getProtocols().add(Protocol.JAR);
    }

    /**
     * Handles a call for a local entity. By default, only GET and HEAD methods
     * are implemented.
     *
     * @param request
     *            The request to handle.
     * @param response
     *            The response to update.
     * @param decodedPath
     *            The URL decoded entity path.
     */
    @Override
    protected void handleLocal(Request request, Response response,
            String decodedPath) {
        int spi = decodedPath.indexOf("!/");
        String fileUri;
        String entryName;
        if (spi != -1) {
            fileUri = decodedPath.substring(0, spi);
            entryName = decodedPath.substring(spi + 2);
        } else {
            fileUri = decodedPath;
            entryName = "";
        }

        LocalReference fileRef = new LocalReference(fileUri);
        if (Protocol.FILE.equals(fileRef.getSchemeProtocol())) {
            final File file = fileRef.getFile();
            if (Method.GET.equals(request.getMethod())
                    || Method.HEAD.equals(request.getMethod())) {
                handleGet(request, response, file, entryName,
                        getMetadataService());
            } else if (Method.PUT.equals(request.getMethod())) {
                handlePut(request, response, file, entryName);
            } else {
                response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
                response.getAllowedMethods().add(Method.GET);
                response.getAllowedMethods().add(Method.HEAD);
                response.getAllowedMethods().add(Method.PUT);
            }
        } else {
            response.setStatus(Status.SERVER_ERROR_NOT_IMPLEMENTED,
                    "Only works on local files.");
        }
    }

    /**
     * Handles a GET call.
     *
     * @param request
     *            The request to answer.
     * @param response
     *            The response to update.
     * @param file
     *            The Zip archive file.
     * @param entryName
     *            The Zip archive entry name.
     * @param metadataService
     *            The metadata service.
     */
    protected void handleGet(Request request, Response response, File file,
            String entryName, final MetadataService metadataService) {

        if (!file.exists()) {
            response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
        } else {
            ZipFile zipFile;

            try {
                zipFile = new ZipFile(file);
            } catch (Exception e) {
                response.setStatus(Status.SERVER_ERROR_INTERNAL, e);
                return;
            }

            Entity entity = new ZipEntryEntity(zipFile, entryName,
                    metadataService);
            if (!entity.exists()) {
                response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            } else {
                final Representation output;

                if (entity.isDirectory()) {
                    // Return the directory listing
                    final Collection<Entity> children = entity.getChildren();
                    final ReferenceList rl = new ReferenceList(children.size());
                    String fileUri = LocalReference.createFileReference(file)
                            .toString();
                    String scheme = request.getResourceRef().getScheme();
                    String baseUri = scheme + ":" + fileUri + "!/";

                    for (final Entity entry : children) {
                        rl.add(baseUri + entry.getName());
                    }

                    output = rl.getTextRepresentation();

                    try {
                        zipFile.close();
                    } catch (IOException e) {
                        // Do something ???
                    }
                } else {
                    // Return the file content
                    output = entity.getRepresentation(metadataService
                            .getDefaultMediaType(), getTimeToLive());
                    output.setLocationRef(request.getResourceRef());
                    Entity.updateMetadata(entity.getName(), output, true,
                            getMetadataService());
                }

                response.setStatus(Status.SUCCESS_OK);
                response.setEntity(output);
            }
        }
    }

    /**
     * Handles a PUT call.
     *
     * @param request
     *            The request to answer.
     * @param response
     *            The response to update.
     * @param file
     *            The Zip archive file.
     * @param entryName
     *            The Zip archive entry name.
     */
    protected void handlePut(Request request, Response response, File file,
            String entryName) {
        boolean zipExists = file.exists();
        ZipOutputStream zipOut = null;

        if ("".equals(entryName) && request.getEntity() != null
                && request.getEntity().getDisposition() != null) {
            entryName = request.getEntity().getDisposition().getFilename();
        }
        if (entryName == null) {
            response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST,
                    "Must specify an entry name.");
            return;
        }
        // boolean canAppend = true;
        boolean canAppend = !zipExists;
        boolean isDirectory = entryName.endsWith("/");
        boolean wrongReplace = false;
        try {
            if (zipExists) {
                ZipFile zipFile = new ZipFile(file);
                // Already exists ?
                canAppend &= null == zipFile.getEntry(entryName);
                // Directory with the same name ?
                if (isDirectory) {
                    wrongReplace = null != zipFile.getEntry(entryName
                            .substring(0, entryName.length() - 1));
                } else {
                    wrongReplace = null != zipFile.getEntry(entryName + "/");
                }

                canAppend &= !wrongReplace;
                zipFile.close();
            }

            Representation entity;
            if (isDirectory) {
                entity = null;
            } else {
                entity = request.getEntity();
            }

            if (canAppend) {
                try {
                    // zipOut = new ZipOutputStream(new BufferedOutputStream(new
                    // FileOutputStream(file, true)));
                    zipOut = new ZipOutputStream(new BufferedOutputStream(
                            new FileOutputStream(file)));
                    writeEntityStream(entity, zipOut, entryName);
                    zipOut.close();
                } catch (Exception e) {
                    response.setStatus(Status.SERVER_ERROR_INTERNAL, e);
                    return;
                } finally {
                    if (zipOut != null)
                        zipOut.close();
                }
                response.setStatus(Status.SUCCESS_CREATED);
            } else {
                if (wrongReplace) {
                    response
                            .setStatus(Status.CLIENT_ERROR_BAD_REQUEST,
                                    "Directory cannot be replace by a file or file by a directory.");
                } else {
                    File writeTo = null;
                    ZipFile zipFile = null;
                    try {
                        writeTo = File.createTempFile("restlet_zip_", "zip");
                        zipFile = new ZipFile(file);
                        zipOut = new ZipOutputStream(new BufferedOutputStream(
                                new FileOutputStream(writeTo)));
                        Enumeration<? extends ZipEntry> entries = zipFile
                                .entries();
                        boolean replaced = false;
                        while (entries.hasMoreElements()) {
                            ZipEntry e = entries.nextElement();
                            if (!replaced && entryName.equals(e.getName())) {
                                writeEntityStream(entity, zipOut, entryName);
                                replaced = true;
                            } else {
                                zipOut.putNextEntry(e);
                                BioUtils.copy(new BufferedInputStream(zipFile
                                        .getInputStream(e)), zipOut);
                                zipOut.closeEntry();
                            }
                        }
                        if (!replaced) {
                            writeEntityStream(entity, zipOut, entryName);
                        }
                        zipFile.close();
                        zipOut.close();
                    } finally {
                        try {
                            if (zipFile != null)
                                zipFile.close();
                        } finally {
                            if (zipOut != null)
                                zipOut.close();
                        }
                    }

                    if (!(BioUtils.delete(file) && writeTo.renameTo(file))) {
                        if (!file.exists())
                            file.createNewFile();
                        FileInputStream fis = null;
                        FileOutputStream fos = null;
                        try {
                            fis = new FileInputStream(writeTo);
                            fos = new FileOutputStream(file);
                            // ByteUtils.write(fis.getChannel(),
                            // fos.getChannel());
                            BioUtils.copy(fis, fos);
                            response.setStatus(Status.SUCCESS_OK);
                        } finally {
                            try {
                                if (fis != null)
                                    fis.close();
                            } finally {
                                if (fos != null)
                                    fos.close();
                            }
                        }
                    } else {
                        response.setStatus(Status.SUCCESS_OK);
                    }
                }
            }
        } catch (Exception e) {
            response.setStatus(Status.SERVER_ERROR_INTERNAL, e);
            return;
        }
    }

    /**
     * Writes an entity to a given ZIP output stream with a given ZIP entry
     * name.
     *
     * @param entity
     *            The entity to write.
     * @param out
     *            The ZIP output stream.
     * @param entryName
     *            The ZIP entry name.
     * @return True if the writing was successful.
     * @throws IOException
     */
    private boolean writeEntityStream(Representation entity,
            ZipOutputStream out, String entryName) throws IOException {
        if (entity != null && !entryName.endsWith("/")) {
            ZipEntry entry = new ZipEntry(entryName);
            if (entity.getModificationDate() != null)
                entry.setTime(entity.getModificationDate().getTime());
            else {
                entry.setTime(System.currentTimeMillis());
            }
            out.putNextEntry(entry);
            BioUtils.copy(new BufferedInputStream(entity.getStream()), out);
            out.closeEntry();
            return true;
        }

        out.putNextEntry(new ZipEntry(entryName));
        out.closeEntry();
        return false;
    }
}
TOP

Related Classes of org.restlet.engine.local.ZipClientHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.