001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.automation.client.jaxrs.spi;
013
014import static org.nuxeo.ecm.automation.client.Constants.CTYPE_AUTOMATION;
015import static org.nuxeo.ecm.automation.client.Constants.CTYPE_ENTITY;
016import static org.nuxeo.ecm.automation.client.Constants.CTYPE_MULTIPART_MIXED;
017
018import java.io.File;
019import java.io.FileInputStream;
020import java.io.IOException;
021import java.io.InputStream;
022import java.util.HashMap;
023import java.util.regex.Matcher;
024import java.util.regex.Pattern;
025
026import javax.mail.BodyPart;
027import javax.mail.MessagingException;
028import javax.mail.internet.MimeMultipart;
029
030import org.nuxeo.ecm.automation.client.RemoteException;
031import org.nuxeo.ecm.automation.client.jaxrs.spi.marshallers.ExceptionMarshaller;
032import org.nuxeo.ecm.automation.client.jaxrs.util.IOUtils;
033import org.nuxeo.ecm.automation.client.jaxrs.util.InputStreamDataSource;
034import org.nuxeo.ecm.automation.client.model.Blob;
035import org.nuxeo.ecm.automation.client.model.Blobs;
036import org.nuxeo.ecm.automation.client.model.FileBlob;
037
038/**
039 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
040 */
041public class Request extends HashMap<String, String> {
042
043    public static final int GET = 0;
044
045    public static final int POST = 1;
046
047    private static final long serialVersionUID = 1L;
048
049    protected static Pattern ATTR_PATTERN = Pattern.compile(";?\\s*filename\\s*=\\s*([^;]+)\\s*",
050            Pattern.CASE_INSENSITIVE);
051
052    protected final int method;
053
054    protected final String url;
055
056    protected final boolean isMultiPart;
057
058    protected Object entity;
059
060    public Request(int method, String url) {
061        this.method = method;
062        this.url = url;
063        isMultiPart = false;
064    }
065
066    public Request(int method, String url, MimeMultipart entity) {
067        this.method = method;
068        this.url = url;
069        this.entity = entity;
070        isMultiPart = true;
071    }
072
073    public Request(int method, String url, String entity) {
074        this.method = method;
075        this.url = url;
076        this.entity = entity;
077        isMultiPart = false;
078    }
079
080    public int getMethod() {
081        return method;
082    }
083
084    public String getUrl() {
085        return url;
086    }
087
088    public Object getEntity() {
089        return entity;
090    }
091
092    public final boolean isMultiPart() {
093        return isMultiPart;
094    }
095
096    public MimeMultipart asMultiPartEntity() {
097        return isMultiPart ? (MimeMultipart) entity : null;
098    }
099
100    public String asStringEntity() {
101        return isMultiPart ? null : (String) entity;
102    }
103
104    /**
105     * Must read the object from the server response and return it or throw a {@link RemoteException} if server sent an
106     * error.
107     */
108    public Object handleResult(int status, String ctype, String disp, InputStream stream) throws RemoteException,
109            IOException {
110        if (status == 204) { // no content
111            return null;
112        } else if (status >= 400) {
113            handleException(status, ctype, stream);
114        }
115        String lctype = ctype.toLowerCase();
116        if (lctype.startsWith(CTYPE_ENTITY)) {
117            return JsonMarshalling.readEntity(IOUtils.read(stream));
118        } else if (lctype.startsWith(CTYPE_AUTOMATION)) {
119            return JsonMarshalling.readRegistry(IOUtils.read(stream));
120        } else if (lctype.startsWith(CTYPE_MULTIPART_MIXED)) { // list of
121                                                               // blobs
122            return readBlobs(ctype, stream);
123        } else { // a blob?
124            String fname = null;
125            if (disp != null) {
126                fname = getFileName(disp);
127            }
128            return readBlob(ctype, fname, stream);
129        }
130    }
131
132    protected static Blobs readBlobs(String ctype, InputStream in) throws IOException {
133        Blobs files = new Blobs();
134        // save the stream to a temporary file
135        File file = IOUtils.copyToTempFile(in);
136        FileInputStream fin = new FileInputStream(file);
137        try {
138            MimeMultipart mp = new MimeMultipart(new InputStreamDataSource(fin, ctype));
139            int size = mp.getCount();
140            for (int i = 0; i < size; i++) {
141                BodyPart part = mp.getBodyPart(i);
142                String fname = part.getFileName();
143                files.add(readBlob(part.getContentType(), fname, part.getInputStream()));
144            }
145        } catch (MessagingException e) {
146            throw new IOException(e);
147        } finally {
148            try {
149                fin.close();
150            } catch (IOException e) {
151            }
152            file.delete();
153        }
154        return files;
155    }
156
157    protected static Blob readBlob(String ctype, String fileName, InputStream in) throws IOException {
158        File file = IOUtils.copyToTempFile(in);
159        FileBlob blob = new FileBlob(file);
160        blob.setMimeType(ctype);
161        if (fileName != null) {
162            blob.setFileName(fileName);
163        }
164        return blob;
165    }
166
167    protected static String getFileName(String ctype) {
168        Matcher m = ATTR_PATTERN.matcher(ctype);
169        if (m.find()) {
170            return m.group(1);
171        }
172        return null;
173    }
174
175    protected void handleException(int status, String ctype, InputStream stream) throws RemoteException, IOException {
176        if (CTYPE_ENTITY.equalsIgnoreCase(ctype)) {
177            String content = IOUtils.read(stream);
178            RemoteException e = null;
179            try {
180                e = ExceptionMarshaller.readException(content);
181            } catch (IOException t) {
182                throw new RemoteException(status, "ServerError", "Server Error", content);
183            }
184            throw e;
185        } else {
186            throw new RemoteException(status, "ServerError", "Server Error", IOUtils.read(stream));
187        }
188    }
189
190}