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.webengine.jaxrs.views;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.OutputStreamWriter;
025import java.io.Writer;
026import java.net.MalformedURLException;
027import java.net.URL;
028import java.util.HashMap;
029import java.util.Map;
030
031import org.nuxeo.ecm.platform.rendering.api.RenderingException;
032import org.nuxeo.ecm.platform.rendering.api.ResourceLocator;
033import org.nuxeo.ecm.platform.rendering.fm.FreemarkerEngine;
034import org.osgi.framework.Bundle;
035
036/**
037 * Template for compatibility with Nuxeo WebEngine
038 *
039 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
040 */
041public class TemplateView {
042
043    private static final FreemarkerEngine engine = new FreemarkerEngine(null, new Locator());
044
045    private static final Map<String, TemplateView> locators = new HashMap<>();
046
047    public static URL resolveFile(File file) throws ViewNotFoundException {
048        if (!file.isFile()) {
049            throw new ViewNotFoundException(null, null, file.getAbsolutePath());
050        }
051        try {
052            return file.toURI().toURL();
053        } catch (MalformedURLException e) {
054            throw new ViewNotFoundException(e, null, file.getAbsolutePath());
055        }
056    }
057
058    public static URL resolveResource(Object owner, String name) throws ViewNotFoundException {
059        URL url = owner.getClass().getResource(name);
060        if (url == null) {
061            throw new ViewNotFoundException(null, owner, name);
062        }
063        return url;
064    }
065
066    public static URL resolveResourceFromBundle(Bundle bundle, String name) throws ViewNotFoundException {
067        URL url = bundle.getEntry(name);
068        if (url == null) {
069            throw new ViewNotFoundException(null, bundle, name);
070        }
071        return url;
072    }
073
074    private static URL resolveResource(Bundle bundle, Object owner, String name) throws ViewNotFoundException {
075        return bundle != null ? resolveResourceFromBundle(bundle, name) : resolveResource(owner, name);
076    }
077
078    protected Object owner;
079
080    protected final URL url;
081
082    protected final Map<String, Object> vars;
083
084    public TemplateView(String name) {
085        this(null, null, name);
086    }
087
088    public TemplateView(Object owner, String name) {
089        this(null, owner, name);
090    }
091
092    public TemplateView(Bundle bundle, Object owner, String name) {
093        this(owner, resolveResource(bundle, owner, name));
094    }
095
096    public TemplateView(File file) {
097        this(null, file);
098    }
099
100    public TemplateView(Object owner, File file) {
101        this(owner, resolveFile(file));
102    }
103
104    public TemplateView(URL url) {
105        this(null, url);
106    }
107
108    public TemplateView(Object owner, URL url) {
109        vars = new HashMap<>();
110        this.url = url;
111        if (owner != null) {
112            forObject(owner);
113        }
114    }
115
116    public TemplateView forObject(Object owner) {
117        this.owner = owner;
118        vars.put("This", owner);
119        return this;
120    }
121
122    public URL getUrl() {
123        return url;
124    }
125
126    public Object getOwner() {
127        return owner;
128    }
129
130    public TemplateView arg(String key, Object value) {
131        vars.put(key, value);
132        return this;
133    }
134
135    public void render(Writer writer) throws RenderingException, IOException {
136        String id = addLocator(this);
137        try {
138            engine.render(id, vars, writer);
139            writer.flush();
140        } finally {
141            removeLocator(id);
142        }
143    }
144
145    public void render(OutputStream out) throws RenderingException, IOException {
146        render(new OutputStreamWriter(out, "UTF-8"));
147    }
148
149    private static synchronized String addLocator(TemplateView view) {
150        String locatorId = "view:/" + view.getUrl().toExternalForm();
151        locators.put(locatorId, view);
152        return locatorId;
153    }
154
155    private static synchronized void removeLocator(String id) {
156        locators.remove(id);
157    }
158
159    private static synchronized TemplateView getLocator(String id) {
160        return locators.get(id);
161    }
162
163    static class Locator implements ResourceLocator {
164        @Override
165        public File getResourceFile(String key) {
166            return null;
167        }
168
169        @Override
170        public URL getResourceURL(String key) {
171            TemplateView view = getLocator(key);
172            if (view != null) {
173                return view.getUrl();
174            }
175            return null;
176        }
177    }
178
179}