/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.vaadin.osgi.staticres;
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.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.http.HttpService;
import org.semanticsoft.vaaclipse.api.ResourceInfoProvider;
import org.semanticsoft.vaaclipse.publicapi.theme.Theme;
import org.semanticsoft.vaaclipse.publicapi.theme.ThemeConstants;
import org.semanticsoft.vaaclipse.publicapi.theme.ThemeContribution;
import org.semanticsoft.vaaclipse.publicapi.theme.ThemeEngine;
/**
* 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")
public class StaticResources extends HttpServlet {
private HttpService httpService;
private ResourceInfoProvider resourceInfoProvider;
private ThemeEngine themeEngine;
private String alias;
public void bind(HttpService httpService) {
this.httpService = httpService;
}
public void bindResourceInfoProvider(ResourceInfoProvider provider)
{
this.resourceInfoProvider = provider;
}
public void bindThemeEngine(ThemeEngine themeEngine)
{
this.themeEngine = themeEngine;
}
public void start(BundleContext ctx, Map<String, String> properties)
throws Exception {
alias = properties.get("http.alias");
httpService.registerServlet(alias, this, null, null);
}
public void stop() {
httpService.unregister(alias);
}
@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 = 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();
}
}
public InputStream getInputStream(String url, Theme theme, String e4WidgetsetUri, String e4WidgetsetName, String headerIconUri)
{
String path = null;
if (url.endsWith("favicon.ico"))
{
path = headerIconUri;
}
else
{
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.semanticsoft.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
return null;
}
try {
URL u = new URL(path);
return u.openStream();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
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 "";
}
}