001/*
002 * (C) Copyright 2006-2016 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 *     Nuxeo - initial API and implementation
018 */
019package org.nuxeo.ecm.platform.url.codec;
020
021import java.io.UnsupportedEncodingException;
022import java.net.URLDecoder;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.nuxeo.common.utils.StringUtils;
029import org.nuxeo.common.utils.URIUtils;
030import org.nuxeo.ecm.core.api.DocumentLocation;
031import org.nuxeo.ecm.core.api.DocumentModel;
032import org.nuxeo.ecm.core.api.DocumentRef;
033import org.nuxeo.ecm.core.api.IdRef;
034import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl;
035import org.nuxeo.ecm.core.utils.DocumentModelUtils;
036import org.nuxeo.ecm.platform.url.DocumentViewImpl;
037import org.nuxeo.ecm.platform.url.api.DocumentView;
038import org.nuxeo.ecm.platform.url.service.AbstractDocumentViewCodec;
039
040public class DocumentFileCodec extends AbstractDocumentViewCodec {
041
042    public static final String FILE_PROPERTY_PATH_KEY = "FILE_PROPERTY_PATH";
043
044    public static final String FILENAME_KEY = "FILENAME";
045
046    // nxdoc/server/docId/property_path/filename/?requestParams
047    public static final String URLPattern = "/(\\w+)/([a-zA-Z_0-9\\-]+)(/([a-zA-Z_0-9/:\\-\\.\\]\\[]*))+(/([^\\?]*))+(\\?)?(.*)?";
048
049    public DocumentFileCodec() {
050    }
051
052    public DocumentFileCodec(String prefix) {
053        this.prefix = prefix;
054    }
055
056    @Override
057    public String getUrlFromDocumentView(DocumentView docView) {
058        DocumentLocation docLoc = docView.getDocumentLocation();
059        String filepath = docView.getParameter(FILE_PROPERTY_PATH_KEY);
060        String filename = docView.getParameter(FILENAME_KEY);
061        if (docLoc != null && filepath != null && filename != null) {
062            StringBuilder buf = new StringBuilder();
063            buf.append(getPrefix());
064            buf.append("/");
065            buf.append(docLoc.getServerName());
066            buf.append("/");
067            buf.append(docLoc.getDocRef().toString());
068            buf.append("/");
069            buf.append(filepath);
070            buf.append("/");
071            buf.append(URIUtils.quoteURIPathToken(filename));
072            String uri = buf.toString();
073            Map<String, String> requestParams = new HashMap<>(docView.getParameters());
074            requestParams.remove(FILE_PROPERTY_PATH_KEY);
075            requestParams.remove(FILENAME_KEY);
076            return URIUtils.addParametersToURIQuery(uri, requestParams);
077        }
078        return null;
079    }
080
081    /**
082     * Extracts document location from a Zope-like URL ie : server/path_or_docId/view_id/tab_id .
083     */
084    @Override
085    public DocumentView getDocumentViewFromUrl(String url) {
086        final Pattern pattern = Pattern.compile(getPrefix() + URLPattern);
087        Matcher m = pattern.matcher(url);
088        if (m.matches()) {
089            if (m.groupCount() >= 4) {
090
091                // for debug
092                // for (int i = 1; i < m.groupCount() + 1; i++) {
093                // System.err.println(i + ": " + m.group(i));
094                // }
095
096                final String server = m.group(1);
097                String uuid = m.group(2);
098                final DocumentRef docRef = new IdRef(uuid);
099
100                // get other parameters
101
102                Map<String, String> params = new HashMap<>();
103                if (m.groupCount() >= 4) {
104                    String filePropertyPath = m.group(4);
105                    params.put(FILE_PROPERTY_PATH_KEY, filePropertyPath);
106                }
107
108                if (m.groupCount() >= 6) {
109                    String filename = m.group(6);
110                    try {
111                        filename = URLDecoder.decode(filename, "UTF-8");
112                    } catch (UnsupportedEncodingException e) {
113                        filename = StringUtils.toAscii(filename);
114                    }
115                    int jsessionidIndex = filename.indexOf(";jsessionid");
116                    if (jsessionidIndex != -1) {
117                        filename = filename.substring(0, jsessionidIndex);
118                    }
119                    params.put(FILENAME_KEY, filename);
120                }
121
122                if (m.groupCount() >= 8) {
123                    String query = m.group(8);
124                    Map<String, String> requestParams = URIUtils.getRequestParameters(query);
125                    if (requestParams != null) {
126                        params.putAll(requestParams);
127                    }
128                }
129
130                final DocumentLocation docLoc = new DocumentLocationImpl(server, docRef);
131
132                return new DocumentViewImpl(docLoc, null, params);
133            }
134        }
135
136        return null;
137    }
138
139    public static String getFilename(DocumentModel doc, DocumentView docView) {
140        String filename = docView.getParameter(FILENAME_KEY);
141        if (filename == null) {
142            // try to get it from document
143            String propertyPath = docView.getParameter(FILE_PROPERTY_PATH_KEY);
144            String propertyName = DocumentModelUtils.decodePropertyName(propertyPath);
145            if (propertyName != null) {
146                filename = (String) DocumentModelUtils.getPropertyValue(doc, propertyName + "/filename");
147            }
148        }
149        return filename;
150    }
151
152}