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