001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
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.TemplateException;
020    import com.liferay.portal.kernel.template.TemplateResource;
021    import com.liferay.portal.kernel.template.URLTemplateResource;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.FileUtil;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.Validator;
027    
028    import java.io.IOException;
029    
030    import java.net.URL;
031    
032    import java.util.ArrayList;
033    import java.util.List;
034    
035    /**
036     * @author Tina Tian
037     */
038    public abstract class URLResourceParser implements TemplateResourceParser {
039    
040            @Override
041            public TemplateResource getTemplateResource(String templateId)
042                    throws TemplateException {
043    
044                    templateId = normalizePath(templateId);
045    
046                    try {
047                            URL url = getURL(templateId);
048    
049                            if (url == null) {
050                                    return null;
051                            }
052    
053                            return new URLTemplateResource(templateId, url);
054                    }
055                    catch (IOException ioe) {
056                            throw new TemplateException(ioe);
057                    }
058            }
059    
060            public abstract URL getURL(String templateId) throws IOException;
061    
062            @Override
063            public boolean isTemplateResourceValid(String templateId, String langType) {
064                    if (Validator.isBlank(templateId)) {
065                            return true;
066                    }
067    
068                    char[] chars = templateId.toCharArray();
069    
070                    for (int i = 0; i < chars.length; i++) {
071                            char c = chars[i];
072    
073                            if ((c == CharPool.PERCENT) || (c == CharPool.POUND) ||
074                                    (c == CharPool.QUESTION) || (c == CharPool.SEMICOLON)) {
075    
076                                    if (_log.isWarnEnabled()) {
077                                            _log.warn(
078                                                    "Unable to load template " + templateId +
079                                                            " because the template name contains one or more " +
080                                                                    "special characters: %, #, ?, or ;");
081                                    }
082    
083                                    return false;
084                            }
085    
086                            if (c == CharPool.BACK_SLASH) {
087                                    if (_log.isWarnEnabled()) {
088                                            _log.warn(
089                                                    "Unable to load template " + templateId +
090                                                            " because the template name contains a backslash");
091                                    }
092    
093                                    return false;
094                            }
095                    }
096    
097                    String extension = FileUtil.getExtension(templateId);
098    
099                    if (!extension.equals(langType)) {
100                            return false;
101                    }
102    
103                    return true;
104            }
105    
106            protected static String normalizePath(String path) {
107                    List<String> elements = new ArrayList<>();
108    
109                    boolean absolutePath = false;
110    
111                    int previousIndex = -1;
112    
113                    for (int index;
114                            (index = path.indexOf(CharPool.SLASH, previousIndex + 1)) != -1;
115                            previousIndex = index) {
116    
117                            if ((previousIndex + 1) == index) {
118    
119                                    // Starts with "/"
120    
121                                    if (previousIndex == -1) {
122                                            absolutePath = true;
123    
124                                            continue;
125                                    }
126    
127                                    // "//" is illegal
128    
129                                    throw new IllegalArgumentException(
130                                            "Unable to parse path " + path);
131                            }
132    
133                            String pathElement = path.substring(previousIndex + 1, index);
134    
135                            // "." needs no handling
136    
137                            if (pathElement.equals(StringPool.PERIOD)) {
138                                    continue;
139                            }
140    
141                            // ".." pops up stack
142    
143                            if (pathElement.equals(StringPool.DOUBLE_PERIOD)) {
144                                    if (elements.isEmpty()) {
145                                            throw new IllegalArgumentException(
146                                                    "Unable to parse path " + path);
147                                    }
148    
149                                    elements.remove(elements.size() - 1);
150    
151                                    continue;
152                            }
153    
154                            // Others push down stack
155    
156                            elements.add(pathElement);
157                    }
158    
159                    if (previousIndex == -1) {
160                            elements.add(path);
161                    }
162                    else if ((previousIndex + 1) < path.length()) {
163                            elements.add(path.substring(previousIndex + 1));
164                    }
165    
166                    String normalizedPath = StringUtil.merge(elements, StringPool.SLASH);
167    
168                    if (absolutePath) {
169                            normalizedPath = StringPool.SLASH.concat(normalizedPath);
170                    }
171    
172                    return normalizedPath;
173            }
174    
175            private static final Log _log = LogFactoryUtil.getLog(
176                    URLResourceParser.class);
177    
178    }