blob: e59012939bd34149ab60e61720857455961c156f [file] [log] [blame]
/**
* Copyright (c) 2011, 2014 - Lunifera GmbH (Gross Enzersdorf)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.vaaclipse.addons.app.resources;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.osbp.vaaclipse.api.ResourceInfoProvider;
import org.eclipse.osbp.vaaclipse.publicapi.theme.Theme;
import org.eclipse.osbp.vaaclipse.publicapi.theme.ThemeContribution;
import org.eclipse.osbp.vaaclipse.publicapi.theme.ThemeEngine;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.http.HttpService;
/**
* This class runs as an OSGi component and serves the themes and widgetsets
* directly from the core Vaadin bundle.
* <p/>
*
* To add your own theme or widget set create a fragment which contains your
* theme/widgetset files and export those as packages. The
* <code>Fragment-Host</code> should be set to the Vaadin core bundle. The
* fragment containing your theme/widgetset resources will be added to the core
* Vaadin bundle dynamically.
* <p/>
*
* Of course static resources should really be deployed separately to a web
* server that proxies servlet requests on to the container.
*
* @author brindy
*/
@SuppressWarnings("serial")
@Component(immediate = true, enabled = true, property = { "http.alias=/VAADIN" })
public class StaticResources extends HttpServlet {
/** The http service. */
private HttpService httpService;
/** The resource info provider. */
private ResourceInfoProvider resourceInfoProvider;
/** The theme engine. */
private ThemeEngine themeEngine;
/** The alias. */
private String alias;
/**
* Instantiates a new static resources.
*/
public StaticResources() {
}
/**
* Bind.
*
* @param httpService
* the http service
*/
@Reference(name = "bindHttpService", service = HttpService.class, target = "(org.eclipse.osbp.ecview.jetty.serviceType=application)", cardinality = ReferenceCardinality.MANDATORY)
public void bind(HttpService httpService) {
this.httpService = httpService;
}
/**
* Unbind.
*
* @param httpService
* the http service
*/
public void unbind(HttpService httpService) {
this.httpService = null;
}
/**
* Bind resource info provider.
*
* @param provider
* the provider
*/
@Reference(name = "bindResourceInfoProvider", service = ResourceInfoProvider.class, cardinality = ReferenceCardinality.MANDATORY)
public void bindResourceInfoProvider(ResourceInfoProvider provider) {
this.resourceInfoProvider = provider;
}
/**
* Unbind resource info provider.
*
* @param provider
* the provider
*/
public void unbindResourceInfoProvider(ResourceInfoProvider provider) {
this.resourceInfoProvider = null;
}
/**
* Bind theme engine.
*
* @param themeEngine
* the theme engine
*/
@Reference(name = "bindThemeEngine", service = ThemeEngine.class, cardinality = ReferenceCardinality.MANDATORY)
public void bindThemeEngine(ThemeEngine themeEngine) {
this.themeEngine = themeEngine;
}
/**
* Unbind theme engine.
*
* @param themeEngine
* the theme engine
*/
public void unbindThemeEngine(ThemeEngine themeEngine) {
this.themeEngine = null;
}
/**
* Start.
*
* @param ctx
* the ctx
* @param properties
* the properties
* @throws Exception
* the exception
*/
@Activate
public void start(BundleContext ctx, Map<String, String> properties)
throws Exception {
alias = properties.get("http.alias");
httpService.registerServlet(alias, this, null, null);
}
/**
* Stop.
*/
@Deactivate
public void stop() {
httpService.unregister(alias);
}
/*
* (non-Javadoc)
*
* @see
* javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest
* , javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (this.resourceInfoProvider == null)
resp.sendError(HttpServletResponse.SC_CONFLICT);
String path = req.getPathInfo();
if (path.endsWith("css")) {
resp.setContentType("text/css");
}
String resourcePath = alias + path;
String themeId = null;
if (path.startsWith("/themes")) {
themeId = path.split("/")[2];
}
if (themeId == null || themeId.isEmpty()) {
themeId = resourceInfoProvider.getCssTheme();
}
InputStream in = getInputStream(resourcePath,
themeEngine.getTheme(themeId),
resourceInfoProvider.getApplicationtWidgetset(),
resourceInfoProvider.getApplicationtWidgetsetName(),
resourceInfoProvider.getApplicationHeaderIcon());
if (in == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
try {
OutputStream out = resp.getOutputStream();
byte[] buffer = new byte[1024];
int read = 0;
try {
while (-1 != (read = in.read(buffer))) {
out.write(buffer, 0, read);
}
} finally {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
} finally {
in.close();
}
}
/**
* Gets the input stream.
*
* @param url
* the url
* @param theme
* the theme
* @param e4WidgetsetUri
* the e4 widgetset uri
* @param e4WidgetsetName
* the e4 widgetset name
* @param headerIconUri
* the header icon uri
* @return the input stream
*/
public InputStream getInputStream(String url, Theme theme,
String e4WidgetsetUri, String e4WidgetsetName, String headerIconUri) {
String path = null;
StringBuffer urlString = new StringBuffer(url);
urlString.trimToSize();
if (urlString.length() == 0)
throw new IllegalArgumentException();
if (urlString.charAt(0) != '/')
throw new IllegalArgumentException();
String processedUrl = urlString.substring(1);
String[] segments = processedUrl.split("/");
if (segments.length < 2)
throw new IllegalArgumentException();
if (!"VAADIN".equals(segments[0]))
throw new IllegalArgumentException();
if (segments[1].equals("widgetsets")) {
// return
// "platform:/plugin/org.eclipse.osbp.vaaclipse.resources" +
// url;
String widgetSetName = segments[2];
if (e4WidgetsetName.equals(widgetSetName)) {
String restPath = buildSegments(segments, 3);
path = e4WidgetsetUri + "/" + restPath;
} else {
path = "platform:/plugin/com.vaadin.client-compiled" + url;
}
} else if (segments[1].equals("themes")) {
String themeName = segments[2];
if (theme.getWebId().equals(themeName)) {
if ("styles.css".equals(segments[3])) {
return theme.getCssAsStream();
} else if ("original_styles.css".equals(segments[3])) {
path = theme.getCssUri();
} else {
if ("plugin".equals(segments[3])) // this is absolute
// bundle path
{
String bundleName = segments[4];
path = "platform:/plugin/" + bundleName + "/"
+ buildSegments(segments, 5);
} else {// this is relative theme path
if (url.endsWith("css")) {
String cssFileName = url.substring(url
.lastIndexOf('/') + 1);
cssFileName = cssFileName.substring(0,
cssFileName.lastIndexOf('.'));
ThemeContribution themeContribution = themeEngine
.getThemeContributionByWebId(cssFileName);
if (themeContribution != null)
path = themeContribution.getCssUri();
else {
for (String cssUri : theme.getAllCssURIs()) {
String relPath = buildSegments(
segments, 3);
String cssPath = cssUri.substring(0,
cssUri.lastIndexOf('/'))
+ "/"
+ relPath;
try {
URL cssUrl = new URL(cssPath);
return cssUrl.openStream();
} catch (Exception e) {
}
}
}
} else {
String relPath = buildSegments(segments, 3);
return theme.getThemeResourceAsStream(relPath);
}
}
}
} else // any theme
{
if ("styles.css".equals(segments[3])) {
Theme inheritedTheme = themeEngine.getTheme(themeName);
path = inheritedTheme.getCssUri();
} else {
path = "platform:/plugin/com.vaadin.themes" + url;
}
}
} else if ("vaadinBootstrap.js".equals(segments[1])) {
path = "platform:/plugin/com.vaadin.server" + url;
} else if ("vaadinPush.debug.js".equals(segments[1])) {
path = "platform:/plugin/com.vaadin.push" + url;
} else if ("vaadinPush.js".equals(segments[1])) {
path = "platform:/plugin/com.vaadin.push" + url;
} else {
return null;
}
try {
URL u = new URL(path);
return u.openStream();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Builds the segments.
*
* @param segments
* the segments
* @param start
* the start
* @return the string
*/
private static String buildSegments(String[] segments, int start) {
StringBuffer b = new StringBuffer();
for (int i = start; i < segments.length; i++) {
b.append(segments[i]);
b.append('/');
}
if (b.length() > 0)
return b.substring(0, b.length() - 1);
else
return "";
}
}