Java tutorial
/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.workbench; import ch.entwine.weblounge.common.content.ResourceURI; import ch.entwine.weblounge.common.content.page.Composer; import ch.entwine.weblounge.common.content.page.Page; import ch.entwine.weblounge.common.content.page.Pagelet; import ch.entwine.weblounge.common.content.page.PageletRenderer; import ch.entwine.weblounge.common.impl.content.page.PageReader; import ch.entwine.weblounge.common.impl.testing.MockHttpServletRequest; import ch.entwine.weblounge.common.impl.testing.MockHttpServletResponse; import ch.entwine.weblounge.common.repository.ContentRepository; import ch.entwine.weblounge.common.repository.ContentRepositoryException; import ch.entwine.weblounge.common.request.WebloungeRequest; import ch.entwine.weblounge.common.site.Environment; import ch.entwine.weblounge.common.site.Module; import ch.entwine.weblounge.common.site.Site; import ch.entwine.weblounge.common.url.UrlUtils; import ch.entwine.weblounge.workbench.suggest.SimpleSuggestion; import org.apache.commons.io.IOUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import javax.xml.parsers.ParserConfigurationException; /** * Implementation of a weblounge workbench. The workbench provides support for * management applications and the page editor. */ public class WorkbenchService { /** The logging facility */ private static Logger logger = LoggerFactory.getLogger(WorkbenchService.class); /** The site servlets */ private static Map<String, Servlet> siteServlets = new HashMap<String, Servlet>(); /** The cache service tracker */ private ServiceTracker siteServletTracker = null; /** Filter expression used to look up site servlets */ private static final String serviceFilter = "(&(objectclass=" + Servlet.class.getName() + ")(" + Site.class.getName().toLowerCase() + "=*))"; /** * Callback from OSGi declarative services on component startup. * * @param ctx * the component context */ void activate(ComponentContext ctx) { try { Filter filter = ctx.getBundleContext().createFilter(serviceFilter); siteServletTracker = new SiteServletTracker(ctx.getBundleContext(), filter); siteServletTracker.open(); } catch (InvalidSyntaxException e) { throw new IllegalStateException(e); } } /** * Callback from OSGi declarative services on component shutdown. */ void deactivate() { if (siteServletTracker != null) { siteServletTracker.close(); } } /** * Returns a list of tags from the given site that are suggested based on what * is passed in as <code>text</code>. If <code>limit</code> is larger than * <code>0</code>, then this is the maximum number of facet values returned. * * @param site * the site * @param text * the starting test * @param limit * the maximum number of tags to return * @return the list of suggested tags * @throws IllegalStateException * if the content repository is not available * @throws ContentRepositoryException * if querying fails */ public List<SimpleSuggestion> suggestTags(Site site, String text, int limit) throws IllegalStateException { List<SimpleSuggestion> tags = new ArrayList<SimpleSuggestion>(); List<String> suggestions; try { suggestions = site.getContentRepository().suggest("subject", text, limit); for (String s : suggestions) { tags.add(new SimpleSuggestion("subject", s)); } } catch (ContentRepositoryException e) { logger.warn("Error loading subject suggestions for '" + text + "'", e); return null; } return tags; } /** * Returns the pagelet editor or <code>null</code> if either one of the page, * the composer or the is not available. * * @param site * the site * @param pageURI * the page uri * @param composerId * the composer id * @param pageletIndex * the pagelet index * @param language * the environment * @param environment * the execution environment * @return the pagelet editor * @throws IOException * if reading the pagelet fails */ public PageletEditor getEditor(Site site, ResourceURI pageURI, String composerId, int pageletIndex, String language, Environment environment) throws IOException { if (site == null) throw new IllegalArgumentException("Site must not be null"); if (composerId == null) throw new IllegalArgumentException("Composer must not be null"); if (pageletIndex < 0) throw new IllegalArgumentException("Pagelet index must be a positive integer"); Page page = getPage(site, pageURI); if (page == null) { logger.warn("Client requested pagelet editor for non existing page {}", pageURI); return null; } // Load the composer Composer composer = page.getComposer(composerId); if (composer == null) { logger.warn("Client requested pagelet editor for non existing composer '{}' on page {}", composerId, pageURI); return null; } // Get the pagelet if (composer.getPagelets().length <= pageletIndex || composer.size() <= pageletIndex) { logger.warn("Client requested pagelet editor for non existing pagelet on page {}", pageURI); return null; } Pagelet pagelet = composer.getPagelet(pageletIndex); pagelet = new TrimpathPageletWrapper(pagelet); PageletEditor pageletEditor = new PageletEditor(pagelet, pageURI, composerId, pageletIndex, environment); // Load the contents of the editor url URL editorURL = pageletEditor.getEditorURL(); if (editorURL != null) { String rendererContent = null; try { rendererContent = loadContents(editorURL, site, page, composer, pagelet, environment, language); pageletEditor.setEditor(rendererContent); } catch (ServletException e) { logger.warn("Error processing the pagelet renderer at {}: {}", editorURL, e.getMessage()); } } return pageletEditor; } /** * Returns the page or <code>null</code> if the page is not found. * * @param site * the site * @param pageURI * the pareURI * @return the page */ private Page getPage(Site site, ResourceURI pageURI) { // Get hold of the site's content repository ContentRepository contentRepository = site.getContentRepository(); if (contentRepository == null) { logger.warn("No content repository found for site '{}'", site); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Load the page Page page = null; try { page = (Page) contentRepository.get(pageURI); } catch (ContentRepositoryException e) { logger.error("Error trying to access content repository {}: {}", contentRepository, e); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } return page; } /** * Returns the pagelet renderer or <code>null</code> if either one of the * page, the composer or the is not available. * * @param site * the site * @param pageURI * the page uri * @param composerId * the composer id * @param pageletIndex * the pagelet index * @param language * the language * @param environment * the environment * @return the pagelet renderer * @throws IOException * if reading the pagelet fails */ public String getRenderer(Site site, ResourceURI pageURI, String composerId, int pageletIndex, String language, Environment environment) throws IOException { Page page = getPage(site, pageURI); if (page == null) { logger.warn("Client requested pagelet renderer for non existing page {}", pageURI); return null; } // Load the composer Composer composer = page.getComposer(composerId); if (composer == null) { logger.warn("Client requested pagelet renderer for non existing composer {} on page {}", composerId, pageURI); return null; } // Get the pagelet if (composer.getPagelets().length <= pageletIndex || composer.size() <= pageletIndex) { logger.warn("Client requested pagelet renderer for non existing pagelet on page {}", pageURI); return null; } Pagelet pagelet = composer.getPagelet(pageletIndex); Module module = site.getModule(pagelet.getModule()); if (module == null) { logger.warn("Client requested pagelet renderer for non existing module {}", pagelet.getModule()); return null; } PageletRenderer renderer = module.getRenderer(pagelet.getIdentifier()); if (renderer == null) { logger.warn("Client requested pagelet renderer for non existing renderer on pagelet {}", pagelet.getIdentifier()); return null; } // Load the contents of the renderer url renderer.setEnvironment(environment); URL rendererURL = renderer.getRenderer(); String rendererContent = null; if (rendererURL != null) { try { rendererContent = loadContents(rendererURL, site, page, composer, pagelet, environment, language); } catch (ServletException e) { logger.warn("Error processing the pagelet renderer at {}: {}", rendererURL, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } } return rendererContent; } public String getRenderer(Site site, ResourceURI pageURI, String composerId, int pageletIndex, String pageXml, String language, Environment environment) throws IOException, ParserConfigurationException, SAXException { InputStream is = null; Page page = null; try { PageReader pageReader = new PageReader(); is = IOUtils.toInputStream(pageXml, "utf-8"); page = pageReader.read(is, site); } finally { IOUtils.closeQuietly(is); } // Load the composer Composer composer = page.getComposer(composerId); if (composer == null) { logger.warn("Client requested pagelet renderer for non existing composer {} on page {}", composerId, pageURI); return null; } // Get the pagelet if (composer.getPagelets().length <= pageletIndex || composer.size() <= pageletIndex) { logger.warn("Client requested pagelet renderer for non existing pagelet on page {}", pageURI); return null; } Pagelet pagelet = composer.getPagelet(pageletIndex); Module module = site.getModule(pagelet.getModule()); if (module == null) { logger.warn("Client requested pagelet renderer for non existing module {}", pagelet.getModule()); return null; } PageletRenderer renderer = module.getRenderer(pagelet.getIdentifier()); if (renderer == null) { logger.warn("Client requested pagelet renderer for non existing renderer on pagelet {}", pagelet.getIdentifier()); return null; } // Load the contents of the renderer url renderer.setEnvironment(environment); URL rendererURL = renderer.getRenderer(); String rendererContent = null; if (rendererURL != null) { try { rendererContent = loadContents(rendererURL, site, page, composer, pagelet, environment, language); } catch (ServletException e) { logger.warn("Error processing the pagelet renderer at {}: {}", rendererURL, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } } return rendererContent; } /** * Asks the site servlet to render the given url using the page, composer and * pagelet as the rendering environment. If the no servlet is available for * the given site, the contents are loaded from the url directly. * * @param rendererURL * the renderer url * @param site * the site * @param page * the page * @param composer * the composer * @param pagelet * the pagelet * @param environment * the environment * @param language * the language * @return the servlet response, serialized to a string * @throws IOException * if the servlet fails to create the response * @throws ServletException * if an exception occurs while processing */ private String loadContents(URL rendererURL, Site site, Page page, Composer composer, Pagelet pagelet, Environment environment, String language) throws IOException, ServletException { Servlet servlet = siteServlets.get(site.getIdentifier()); String httpContextURI = UrlUtils.concat("/weblounge-sites", site.getIdentifier()); int httpContextURILength = httpContextURI.length(); String url = rendererURL.toExternalForm(); int uriInPath = url.indexOf(httpContextURI); if (uriInPath > 0) { String pathInfo = url.substring(uriInPath + httpContextURILength); // Prepare the mock request MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); request.setServerName(site.getHostname(environment).getURL().getHost()); request.setServerPort(site.getHostname(environment).getURL().getPort()); request.setMethod(site.getHostname(environment).getURL().getProtocol()); if (language != null) request.addPreferredLocale(new Locale(language)); request.setAttribute(WebloungeRequest.PAGE, page); request.setAttribute(WebloungeRequest.COMPOSER, composer); request.setAttribute(WebloungeRequest.PAGELET, pagelet); request.setPathInfo(pathInfo); request.setRequestURI(UrlUtils.concat(httpContextURI, pathInfo)); MockHttpServletResponse response = new MockHttpServletResponse(); servlet.service(request, response); return response.getContentAsString(); } else { InputStream is = null; try { is = rendererURL.openStream(); return IOUtils.toString(is, "utf-8"); } finally { IOUtils.closeQuietly(is); } } } /** * Adds the site servlet to the list of servlets. * * @param id * the site identifier * @param servlet * the site servlet */ void addSiteServlet(String id, Servlet servlet) { logger.debug("Site servlet attached to {} workbench", id); siteServlets.put(id, servlet); } /** * Removes the site servlet from the list of servlets * * @param site * the site identifier */ void removeSiteServlet(String id) { logger.debug("Site servlet detached from {} workbench", id); siteServlets.remove(id); } /** * Implementation of a <code>ServiceTracker</code> that is tracking instances * of type {@link Servlet} with an associated <code>site</code> attribute. */ private class SiteServletTracker extends ServiceTracker { /** * Creates a new servlet tracker that is using the given bundle context to * look up service instances. * * @param ctx * the bundle context * @param filter * the service filter */ SiteServletTracker(BundleContext ctx, Filter filter) { super(ctx, filter, null); } /** * {@inheritDoc} * * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference) */ @Override public Object addingService(ServiceReference reference) { Servlet servlet = (Servlet) super.addingService(reference); String site = (String) reference.getProperty(Site.class.getName().toLowerCase()); addSiteServlet(site, servlet); return servlet; } /** * {@inheritDoc} * * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, * java.lang.Object) */ @Override public void removedService(ServiceReference reference, Object service) { String site = (String) reference.getProperty("site"); removeSiteServlet(site); } } }