001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.template;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.template.TemplateConstants;
020    import com.liferay.portal.kernel.template.TemplateException;
021    import com.liferay.portal.kernel.template.TemplateResource;
022    import com.liferay.portal.kernel.template.URLTemplateResource;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.CharPool;
025    import com.liferay.portal.kernel.util.FileUtil;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.StringUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    
030    import java.io.IOException;
031    
032    import java.net.URL;
033    
034    import java.util.ArrayList;
035    import java.util.List;
036    
037    /**
038     * @author Tina Tian
039     */
040    public abstract class URLResourceParser implements TemplateResourceParser {
041    
042            @Override
043            public TemplateResource getTemplateResource(String templateId)
044                    throws TemplateException {
045    
046                    templateId = normalizePath(templateId);
047    
048                    try {
049                            URL url = getURL(templateId);
050    
051                            if (url == null) {
052                                    return null;
053                            }
054    
055                            return new URLTemplateResource(templateId, url);
056                    }
057                    catch (IOException ioe) {
058                            throw new TemplateException(ioe);
059                    }
060            }
061    
062            public abstract URL getURL(String templateId) throws IOException;
063    
064            @Override
065            public boolean isTemplateResourceValid(String templateId, String langType) {
066                    if (Validator.isBlank(templateId)) {
067                            return true;
068                    }
069    
070                    char[] chars = templateId.toCharArray();
071    
072                    for (int i = 0; i < chars.length; i++) {
073                            char c = chars[i];
074    
075                            if ((c == CharPool.PERCENT) || (c == CharPool.POUND) ||
076                                    (c == CharPool.QUESTION) || (c == CharPool.SEMICOLON)) {
077    
078                                    if (_log.isWarnEnabled()) {
079                                            _log.warn(
080                                                    "Unable to load template " + templateId +
081                                                            " because the template name contains one or more " +
082                                                                    "special characters: %, #, ?, or ;");
083                                    }
084    
085                                    return false;
086                            }
087    
088                            if (c == CharPool.BACK_SLASH) {
089                                    if (_log.isWarnEnabled()) {
090                                            _log.warn(
091                                                    "Unable to load template " + templateId +
092                                                            " because the template name contains a backslash");
093                                    }
094    
095                                    return false;
096                            }
097                    }
098    
099                    String extension = FileUtil.getExtension(templateId);
100    
101                    if (!extension.equals(langType) &&
102                            !ArrayUtil.contains(
103                                            TemplateConstants.ALLOWED_LANG_TYPES, extension)) {
104    
105                            return false;
106                    }
107    
108                    return true;
109            }
110    
111            protected static String normalizePath(String path) {
112                    List<String> elements = new ArrayList<String>();
113    
114                    boolean absolutePath = false;
115    
116                    int previousIndex = -1;
117    
118                    for (int index;
119                            (index = path.indexOf(CharPool.SLASH, previousIndex + 1)) != -1;
120                            previousIndex = index) {
121    
122                            if ((previousIndex + 1) == index) {
123    
124                                    // Starts with "/"
125    
126                                    if (previousIndex == -1) {
127                                            absolutePath = true;
128    
129                                            continue;
130                                    }
131    
132                                    // "//" is illegal
133    
134                                    throw new IllegalArgumentException(
135                                            "Unable to parse path " + path);
136                            }
137    
138                            String pathElement = path.substring(previousIndex + 1, index);
139    
140                            // "." needs no handling
141    
142                            if (pathElement.equals(StringPool.PERIOD)) {
143                                    continue;
144                            }
145    
146                            // ".." pops up stack
147    
148                            if (pathElement.equals(StringPool.DOUBLE_PERIOD)) {
149                                    if (elements.isEmpty()) {
150                                            throw new IllegalArgumentException(
151                                                    "Unable to parse path " + path);
152                                    }
153    
154                                    elements.remove(elements.size() - 1);
155    
156                                    continue;
157                            }
158    
159                            // Others push down stack
160    
161                            elements.add(pathElement);
162                    }
163    
164                    if (previousIndex == -1) {
165                            elements.add(path);
166                    }
167                    else if ((previousIndex + 1) < path.length()) {
168                            elements.add(path.substring(previousIndex + 1));
169                    }
170    
171                    String normalizedPath = StringUtil.merge(elements, StringPool.SLASH);
172    
173                    if (absolutePath) {
174                            normalizedPath = StringPool.SLASH.concat(normalizedPath);
175                    }
176    
177                    return normalizedPath;
178            }
179    
180            private static Log _log = LogFactoryUtil.getLog(URLResourceParser.class);
181    }