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.contentrepository.impl.endpoint; import ch.entwine.weblounge.common.content.Resource; import ch.entwine.weblounge.common.content.ResourceURI; import ch.entwine.weblounge.common.content.ResourceUtils; import ch.entwine.weblounge.common.content.SearchQuery; import ch.entwine.weblounge.common.content.SearchQuery.Order; import ch.entwine.weblounge.common.content.SearchResult; import ch.entwine.weblounge.common.content.SearchResultItem; 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.impl.content.GeneralResourceURIImpl; import ch.entwine.weblounge.common.impl.content.ResourceURIImpl; import ch.entwine.weblounge.common.impl.content.SearchQueryImpl; import ch.entwine.weblounge.common.impl.content.SearchResultImpl; import ch.entwine.weblounge.common.impl.content.page.PageImpl; import ch.entwine.weblounge.common.impl.content.page.PageReader; import ch.entwine.weblounge.common.impl.content.page.PageSearchResultItemImpl; import ch.entwine.weblounge.common.impl.content.page.PageURIImpl; import ch.entwine.weblounge.common.impl.security.SecurityUtils; import ch.entwine.weblounge.common.impl.security.SystemRole; import ch.entwine.weblounge.common.impl.security.UserImpl; import ch.entwine.weblounge.common.impl.url.WebUrlImpl; import ch.entwine.weblounge.common.impl.util.WebloungeDateFormat; import ch.entwine.weblounge.common.repository.ContentRepository; import ch.entwine.weblounge.common.repository.ContentRepositoryException; import ch.entwine.weblounge.common.repository.ReferentialIntegrityException; import ch.entwine.weblounge.common.repository.WritableContentRepository; import ch.entwine.weblounge.common.security.SecurityService; import ch.entwine.weblounge.common.security.User; import ch.entwine.weblounge.common.site.Site; import ch.entwine.weblounge.common.url.UrlUtils; import ch.entwine.weblounge.common.url.WebUrl; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.StringTokenizer; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.xml.parsers.ParserConfigurationException; /** * This class implements the <code>REST</code> endpoint for page data. */ @Path("/") @Produces(MediaType.APPLICATION_XML) public class PagesEndpoint extends ContentRepositoryEndpoint { /** Logging facility */ private static final Logger logger = LoggerFactory.getLogger(PagesEndpoint.class); /** The security service */ protected SecurityService securityService = null; /** The endpoint documentation */ private String docs = null; /** * Returns a collection of pages which match the given criteria. * * @param request * the request * @param path * the page path (e.g. <code>/my/simple/path</code>) * @param subjectstring * one ore more subjects, divided by a comma * @param searchterms * fulltext search terms * @param sort * sort order, possible values are * <code>created-asc, created-desc, published-asc, published-desc, modified-asc & modified-desc</code> * @param limit * search result limit * @param offset * search result offset (for paging in combination with limit) * @param details * switch for providing pages including their bodies * @return a collection of matching pages */ @GET @Path("/") public Response getAllPages(@Context HttpServletRequest request, @QueryParam("path") String path, @QueryParam("subjects") String subjectstring, @QueryParam("searchterms") String searchterms, @QueryParam("filter") String filter, @QueryParam("sort") @DefaultValue("modified-desc") String sort, @QueryParam("version") @DefaultValue("-1") long version, @QueryParam("preferredversion") @DefaultValue("-1") long preferredVersion, @QueryParam("limit") @DefaultValue("10") int limit, @QueryParam("offset") @DefaultValue("0") int offset, @QueryParam("details") @DefaultValue("false") boolean details) { // Create search query Site site = getSite(request); SearchQuery q = new SearchQueryImpl(site); q.withTypes(Page.TYPE); if (version != -1) q.withVersion(version); if (preferredVersion != -1) q.withPreferredVersion(preferredVersion); // Path if (StringUtils.isNotBlank(path)) q.withPath(path); // Subjects if (StringUtils.isNotBlank(subjectstring)) { StringTokenizer subjects = new StringTokenizer(subjectstring, ","); while (subjects.hasMoreTokens()) q.withSubject(subjects.nextToken()); } // Search terms if (StringUtils.isNotBlank(searchterms)) q.withText(true, searchterms); Calendar today = Calendar.getInstance(); today.set(Calendar.HOUR_OF_DAY, 0); today.set(Calendar.MINUTE, 0); today.set(Calendar.SECOND, 0); today.set(Calendar.MILLISECOND, 0); Calendar yesterday = Calendar.getInstance(); yesterday.add(Calendar.DATE, -1); yesterday.set(Calendar.HOUR_OF_DAY, 0); yesterday.set(Calendar.MINUTE, 0); yesterday.set(Calendar.SECOND, 0); yesterday.set(Calendar.MILLISECOND, 0); Calendar tomorrow = Calendar.getInstance(); tomorrow.add(Calendar.DATE, 1); tomorrow.set(Calendar.HOUR_OF_DAY, 0); tomorrow.set(Calendar.MINUTE, 0); tomorrow.set(Calendar.SECOND, 0); tomorrow.set(Calendar.MILLISECOND, 0); // Filter query if (StringUtils.isNotBlank(filter)) { if ("/".equals(filter)) { q.withPath("/"); } else if (filter.contains("state:work")) { q.withVersion(Resource.WORK); q.withPreferredVersion(-1); } else if (filter.contains("state:live")) { q.withVersion(Resource.LIVE); q.withPreferredVersion(-1); } else if (filter.contains("state:locked")) { q.withLockOwner(); } // by user else if (filter.startsWith("locked:") && filter.length() > "locked:".length()) { String lockOwner = StringUtils.trim(filter.substring("locked:".length())); if ("me".equals(lockOwner)) q.withLockOwner(securityService.getUser()); else q.withLockOwner(new UserImpl(lockOwner)); } else if (filter.startsWith("creator:") && filter.length() > "creator:".length()) { String creator = StringUtils.trim(filter.substring("creator:".length())); if ("me".equals(creator)) q.withCreator(securityService.getUser()); else q.withCreator(new UserImpl(creator)); } else if (filter.startsWith("modifier:") && filter.length() > "modifier:".length()) { String modifier = StringUtils.trim(filter.substring("modifier:".length())); if ("me".equals(modifier)) q.withModifier(securityService.getUser()); else q.withModifier(new UserImpl(modifier)); } else if (filter.startsWith("publisher:") && filter.length() > "publisher:".length()) { String publisher = StringUtils.trim(filter.substring("publisher:".length())); if ("me".equals(publisher)) q.withPublisher(securityService.getUser()); else q.withPublisher(new UserImpl(publisher)); } // by date else if (filter.startsWith("created:") && filter.length() > "created:".length()) { String created = StringUtils.trim(filter.substring("created:".length())); if ("today".equals(created)) q.withCreationDateBetween(today.getTime()).and(tomorrow.getTime()); else if ("yesterday".equals(created)) q.withCreationDateBetween(yesterday.getTime()).and(today.getTime()); else q.withCreationDate(tomorrow.getTime()); } else if (filter.startsWith("modified:") && filter.length() > "modified:".length()) { String modified = StringUtils.trim(filter.substring("modified:".length())); if ("today".equals(modified)) q.withModificationDateBetween(today.getTime()).and(tomorrow.getTime()); else if ("yesterday".equals(modified)) q.withModificationDateBetween(yesterday.getTime()).and(today.getTime()); else q.withCreationDate(tomorrow.getTime()); } else if (filter.startsWith("publisher:") && filter.length() > "publisher:".length()) { String published = StringUtils.trim(filter.substring("published:".length())); if ("today".equals(published)) q.withPublishingDateBetween(today.getTime()).and(tomorrow.getTime()); else if ("yesterday".equals(published)) q.withPublishingDateBetween(yesterday.getTime()).and(today.getTime()); else q.withCreationDate(tomorrow.getTime()); } // by id else if (filter.contains("id:")) { String[] searchTerms = StringUtils.split(filter); for (String searchTerm : searchTerms) { if (searchTerm.startsWith("id:") && filter.length() > "id:".length()) { q.withIdentifier(StringUtils.trim(searchTerm.substring("id:".length()))); } } } // simple filter else if (filter.contains("/")) { q.withPathPrefix(filter); } else { q.withFulltext(true, filter); } } // Limit and Offset q.withLimit(limit); q.withOffset(offset); // Sort order if (StringUtils.equalsIgnoreCase("modified-asc", sort)) { q.sortByModificationDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("modified-desc", sort)) { q.sortByModificationDate(Order.Descending); } else if (StringUtils.equalsIgnoreCase("created-asc", sort)) { q.sortByCreationDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("created-desc", sort)) { q.sortByCreationDate(Order.Descending); } else if (StringUtils.equalsIgnoreCase("published-asc", sort)) { q.sortByPublishingDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("published-desc", sort)) { q.sortByPublishingDate(Order.Descending); } // Load the result String result = loadResultSet(q, details); return Response.ok(result).build(); } /** * Returns a collection of pages that are defined as pending. * * @param request * the request * @param filter * further search result filtering * @param sort * sort order, possible values are * <code>created-asc, created-desc, published-asc, published-desc, modified-asc & modified-desc</code> * @param limit * search result limit * @param offset * search result offset (for paging in combination with limit) * @param details * switch for providing pages including their bodies * @return a collection of matching pages */ @GET @Path("/pending") public Response getPending(@Context HttpServletRequest request, @QueryParam("filter") String filter, @QueryParam("sort") @DefaultValue("modified-desc") String sort, @QueryParam("limit") @DefaultValue("10") int limit, @QueryParam("offset") @DefaultValue("0") int offset, @QueryParam("details") @DefaultValue("false") boolean details) { // Create search query Site site = getSite(request); SearchQuery q = new SearchQueryImpl(site); q.withVersion(Resource.WORK); // Only take resources that have not been modified q.withoutPublication(); // Type q.withTypes(Page.TYPE); // Filter query if (StringUtils.isNotBlank(filter)) q.withFilter(filter); // Limit and Offset q.withLimit(limit); q.withOffset(offset); // Sort order if (StringUtils.equalsIgnoreCase("modified-asc", sort)) { q.sortByModificationDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("modified-desc", sort)) { q.sortByModificationDate(Order.Descending); } else if (StringUtils.equalsIgnoreCase("created-asc", sort)) { q.sortByCreationDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("created-desc", sort)) { q.sortByCreationDate(Order.Descending); } else if (StringUtils.equalsIgnoreCase("published-asc", sort)) { q.sortByPublishingDate(Order.Ascending); } else if (StringUtils.equalsIgnoreCase("published-desc", sort)) { q.sortByPublishingDate(Order.Descending); } // Load the result String result = loadResultSet(q, details); // Return the response return Response.ok(result).build(); } /** * Returns the page with the given identifier or a <code>404</code> if the * page could not be found. * * @param request * the request * @param pageId * the page identifier * @return the page */ @GET @Path("/{page}") public Response getPageById(@Context HttpServletRequest request, @PathParam("page") String pageId, @QueryParam("version") @DefaultValue("0") long version) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Resolve name clash if ("docs".equals(pageId)) { return Response.ok(getDocumentation(request)).type(MediaType.TEXT_HTML).build(); } // Load the page Page page = (Page) loadResource(request, pageId, Page.TYPE, version); if (page == null) { return Response.status(Status.NOT_FOUND).build(); } // Is there an up-to-date, cached version on the client side? if (!ResourceUtils.hasChanged(request, page)) { return Response.notModified().build(); } // Create the response ResponseBuilder response = Response.ok(page.toXml()); response.tag(ResourceUtils.getETagValue(page)); response.lastModified(ResourceUtils.getModificationDate(page)); return response.build(); } /** * Returns child pages of the page with the given identifier or a * <code>404</code> if the page could not be found. * * @param request * the request * @param pageId * the page identifier * @return the child pages */ @GET @Path("/{page}/children") public Response getChildPagesByURI(@Context HttpServletRequest request, @PathParam("page") String pageId) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Load the page Page page = (Page) loadResource(request, pageId, Page.TYPE); if (page == null) { return Response.status(Status.NOT_FOUND).build(); } Site site = getSite(request); SearchQuery q = new SearchQueryImpl(site); q.withVersion(Resource.LIVE); q.withTypes(Page.TYPE); q.withPathPrefix(page.getURI().getPath()); ContentRepository repository = getContentRepository(site, false); SearchResult result = null; try { result = repository.find(q); } catch (ContentRepositoryException e) { return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } StringBuffer buf = new StringBuffer("<pages>"); for (SearchResultItem item : result.getItems()) { if (pageId.equals(item.getId())) continue; String headerXml = ((PageSearchResultItemImpl) item).getPageHeaderXml(); buf.append(headerXml); } buf.append("</pages>"); // Create the response return Response.ok(buf.toString()).build(); } /** * Returns pages containing pagelets with properties of name * <code>resourceid</code> and a value equal to that of the page identifier. * * @param request * the request * @param pageId * the page identifier * @return the referring pages */ @GET @Path("/{page}/referrer") public Response getReferencesByURI(@Context HttpServletRequest request, @PathParam("page") String pageId) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); Site site = getSite(request); SearchQuery q = new SearchQueryImpl(site); q.withTypes(Page.TYPE); q.withVersion(Resource.LIVE); q.withProperty("resourceid", pageId); ContentRepository repository = getContentRepository(site, false); SearchResult result = null; try { result = repository.find(q); } catch (ContentRepositoryException e) { return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } StringBuffer buf = new StringBuffer("<pages>"); for (SearchResultItem item : result.getItems()) { String headerXml = ((PageSearchResultItemImpl) item).getPageHeaderXml(); buf.append(headerXml); } buf.append("</pages>"); // Create the response return Response.ok(buf.toString()).build(); } /** * Updates the indicated page. * * @param request * the http request * @param pageId * the page identifier * @param pageXml * the updated page * @param ifMatchHeader * the page's <code>etag</code> value * @param asynchronous * <code>true</code> to prevent blocking while content is being * updated * @return response an empty response * @throws WebApplicationException * if the update fails */ @PUT @Path("/{page}") public Response updatePage(@Context HttpServletRequest request, @PathParam("page") String pageId, @FormParam("content") String pageXml, @HeaderParam("If-Match") String ifMatchHeader, @FormParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); if (pageXml == null) return Response.status(Status.BAD_REQUEST).build(); // Extract the site Site site = getSite(request); // Make sure the content repository is writable if (site.getContentRepository().isReadOnly()) { logger.warn("Attempt to write to read-only content repository {}", site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI workURI = new PageURIImpl(site, null, pageId, Resource.WORK); // Does the page exist? Page currentPage = null; try { currentPage = (Page) contentRepository.get(workURI); if (currentPage == null) { logger.warn("Attempt to update a page without creating a work version first"); throw new WebApplicationException(Status.PRECONDITION_FAILED); } workURI.setPath(currentPage.getURI().getPath()); } catch (ContentRepositoryException e) { logger.warn("Error lookup up page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Check the value of the If-Match header against the etag if (ifMatchHeader != null) { String etag = ResourceUtils.getETagValue(currentPage); if (!etag.equals(ifMatchHeader)) { throw new WebApplicationException(Status.PRECONDITION_FAILED); } } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has editing rights if (!SecurityUtils.userHasRole(user, SystemRole.EDITOR)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (currentPage.isLocked() && (!currentPage.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Parse the page and update it in the repository Page page = null; try { PageReader pageReader = new PageReader(); page = pageReader.read(IOUtils.toInputStream(pageXml, "utf-8"), site); if (StringUtils.isBlank(page.getURI().getPath())) throw new WebApplicationException(Status.PRECONDITION_FAILED); page.setModified(user, new Date()); page.setVersion(Resource.WORK); // TODO: Preview generation disabled due to performance problems contentRepository.putAsynchronously(page, false); // Check if the page has been moved String currentPath = currentPage.getURI().getPath(); String newPath = page.getURI().getPath(); if ((currentPath != null && !currentPath.equals(newPath) || (currentPath == null && newPath != null))) { contentRepository.moveAsynchronously(currentPage.getURI(), newPath, true); } } catch (SecurityException e) { logger.warn("Tried to update page {} of site '{}' without permission", workURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error reading updated page {} from request", workURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ParserConfigurationException e) { logger.warn("Error configuring parser to read updated page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SAXException e) { logger.warn("Error parsing updated page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.BAD_REQUEST); } catch (IllegalStateException e) { logger.warn("Error updating page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error updating page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.ok(); response.tag(ResourceUtils.getETagValue(page)); response.lastModified(ResourceUtils.getModificationDate(page)); return response.build(); } /** * Creates a page at the site's content repository and returns the location to * post updates to. * <p> * Note that any of identifier, path and version that may be contained in an * initial <code>pageXml</code> will be overwritten. * * @param request * the http request * @param pageXml * the new page * @param path * the path to store the page at * @param asynchronous * <code>true</code> to prevent blocking while the page is being * created in the database * @return response the page location */ @POST @Path("/") public Response createPage(@Context HttpServletRequest request, @FormParam("content") String pageXml, @FormParam("path") String path, @FormParam("asynchronous") boolean asynchronous) { Site site = getSite(request); WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); // Create the page uri ResourceURIImpl pageURI = null; String uuid = UUID.randomUUID().toString(); if (!StringUtils.isBlank(path)) { try { if (!path.startsWith("/")) path = "/" + path; WebUrl url = new WebUrlImpl(site, path); path = url.getPath(); } catch (IllegalArgumentException e) { logger.warn("Tried to create a page with an invalid path '{}': {}", path, e.getMessage()); throw new WebApplicationException(Status.BAD_REQUEST); } } else { path = "/" + uuid.replaceAll("-", ""); } pageURI = new PageURIImpl(site, path, uuid, Resource.WORK); // Make sure the page doesn't exist try { if (contentRepository.existsInAnyVersion(new GeneralResourceURIImpl(site, pageURI.getPath()))) { logger.warn("Tried to create already existing page {} in site '{}'", pageURI, site); throw new WebApplicationException(Status.CONFLICT); } } catch (IllegalArgumentException e) { logger.warn("Tried to create a page with an invalid path '{}': {}", path, e.getMessage()); throw new WebApplicationException(Status.BAD_REQUEST); } catch (ContentRepositoryException e) { logger.warn("Page lookup {} failed for site '{}'", pageURI, site); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has editing rights if (!SecurityUtils.userHasRole(user, SystemRole.EDITOR)) throw new WebApplicationException(Status.UNAUTHORIZED); // Parse the page and store it PageImpl page = null; URI uri = null; if (!StringUtils.isBlank(pageXml)) { logger.debug("Adding page to {}", pageURI); try { PageReader pageReader = new PageReader(); page = pageReader.read(IOUtils.toInputStream(pageXml, "utf-8"), site); page.setIdentifier(pageURI.getIdentifier()); page.setPath(pageURI.getPath()); page.setVersion(pageURI.getVersion()); } catch (IOException e) { logger.warn("Error reading page {} from request", pageURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ParserConfigurationException e) { logger.warn("Error configuring parser to read updated page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SAXException e) { logger.warn("Error parsing updated page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.BAD_REQUEST); } } else { logger.debug("Creating new page at {}", pageURI); page = new PageImpl(pageURI); page.setTemplate(site.getDefaultTemplate().getIdentifier()); page.setCreated(user, new Date()); } // Store the new page try { contentRepository.put(page, true); uri = new URI(UrlUtils.concat(request.getRequestURL().toString(), pageURI.getIdentifier())); } catch (URISyntaxException e) { logger.warn("Error creating a uri for page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SecurityException e) { logger.warn("Tried to update page {} of site '{}' without permission", pageURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error writing new page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error adding new page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error adding new page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.created(uri); response.tag(ResourceUtils.getETagValue(page)); response.lastModified(ResourceUtils.getModificationDate(page)); return response.build(); } /** * Removes the indicated page from the site. * * @param request * the http request * @param pageId * the page identifier * @param asynchronous * <code>true</code> to prevent blocking while the page is being * deleted from the database * @return response an empty response */ @DELETE @Path("/{page}") public Response deletePage(@Context HttpServletRequest request, @PathParam("page") String pageId, @QueryParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); Site site = getSite(request); WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI livePageURI = new PageURIImpl(site, null, pageId, Resource.LIVE); ResourceURI workPageURI = new PageURIImpl(site, null, pageId, Resource.WORK); try { if (!contentRepository.existsInAnyVersion(livePageURI)) { logger.warn("Tried to delete non existing page {} in site '{}'", livePageURI, site); throw new WebApplicationException(Status.NOT_FOUND); } } catch (ContentRepositoryException e) { logger.warn("Page lookup {} failed for site '{}'", livePageURI, site); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } Page page = null; try { page = (Page) contentRepository.get(livePageURI); if (page != null) { livePageURI.setPath(page.getURI().getPath()); } else { page = (Page) contentRepository.get(workPageURI); workPageURI.setPath(page.getURI().getPath()); } } catch (ContentRepositoryException e) { logger.warn("Error lookup up page {} from repository: {}", livePageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has editing rights if (!SecurityUtils.userHasRole(user, SystemRole.EDITOR)) throw new WebApplicationException(Status.UNAUTHORIZED); // If the page is published, the user needs publishing rights if (page.isPublished() && !SecurityUtils.userHasRole(user, SystemRole.PUBLISHER)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (page.isLocked() && (!page.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Delete the page try { contentRepository.delete(page.getURI(), true); } catch (SecurityException e) { logger.warn("Tried to delete page {} of site '{}' without permission", livePageURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (ReferentialIntegrityException e) { logger.warn("Tried to delete referenced page {} of site '{}'", livePageURI, site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (IOException e) { logger.warn("Error deleting page {} from site '{}': {}", new Object[] { livePageURI, site, e.getMessage() }); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ContentRepositoryException e) { logger.warn("Error deleting page {} from site '{}': {}", new Object[] { livePageURI, site, e.getMessage() }); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } return Response.ok().build(); } /** * Returns the composer specified by <code>composerId</code> and * <code>pageletIndex</code> or a <code>404</code> if either the page or the * composer does not exist. * * @param request * the request * @param pageId * the page identifier * @param composerId * the composer identifier * @return the composer */ @GET @Path("/{page}/composers/{composer}") public Response getComposer(@Context HttpServletRequest request, @PathParam("page") String pageId, @PathParam("composer") String composerId, @QueryParam("version") @DefaultValue("0") long version) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); else if (composerId == null) return Response.status(Status.BAD_REQUEST).build(); // Load the page Page page = (Page) loadResource(request, pageId, Page.TYPE, version); if (page == null) { return Response.status(Status.NOT_FOUND).build(); } // Is there an up-to-date, cached version on the client side? if (!ResourceUtils.hasChanged(request, page)) { return Response.notModified().build(); } // Load the composer Composer composer = page.getComposer(composerId); if (composer == null) { return Response.status(Status.NOT_FOUND).build(); } // Return the composer return Response.ok(composer.toXml()).lastModified(ResourceUtils.getModificationDate(page)).build(); } /** * Returns the pagelet specified by <code>pageId</code>, * <code>composerId</code> and <code>pageletIndex</code> or a <code>404</code> * if either of the the page, the composer or the pagelet does not exist. * * @param request * the request * @param pageId * the page identifier * @param composerId * the composer identifier * @param pageletIndex * the pagelet index within the composer * @return the pagelet */ @GET @Path("/{page}/composers/{composer}/pagelets/{pageletindex}") public Response getPagelet(@Context HttpServletRequest request, @PathParam("page") String pageId, @PathParam("composer") String composerId, @PathParam("pageletindex") int pageletIndex, @QueryParam("version") @DefaultValue("0") long version) { if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); else if (composerId == null) return Response.status(Status.BAD_REQUEST).build(); // Load the page Page page = (Page) loadResource(request, pageId, Page.TYPE, version); if (page == null) { return Response.status(Status.NOT_FOUND).build(); } // Is there an up-to-date, cached version on the client side? if (!ResourceUtils.hasChanged(request, page)) { return Response.notModified().build(); } // Load the composer Composer composer = page.getComposer(composerId); if (composer == null || composer.size() < pageletIndex) { return Response.status(Status.NOT_FOUND).build(); } // Return the pagelet ResponseBuilder response = Response.ok(composer.getPagelet(pageletIndex).toXml()); response.lastModified(ResourceUtils.getModificationDate(page)); return response.build(); } /** * Locks the page and returns with a <code>200</code> status code if the lock * operation succeeds, <code>400</code> if the page is not found or * <code>403</code> if another user has already locked the page. * <p> * If <code>user</code> is not specified, then the current user will be used * for lock acquisition. * * @param request * the request * @param pageId * the page identifier * @param asynchronous * <code>true</code> to prevent blocking while the page is being * locked * @return the page */ @PUT @Path("/{page}/lock") public Response lockPage(@Context HttpServletRequest request, @PathParam("page") String pageId, @HeaderParam("If-Match") String ifMatchHeader, @FormParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Extract the site Site site = getSite(request); // Make sure the content repository is writable if (site.getContentRepository().isReadOnly()) { logger.warn("Attempt to lock a page in a read-only content repository {}", site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI workURI = new PageURIImpl(site, null, pageId, Resource.WORK); // Does the page exist at all? Page workPage = null; try { if (!contentRepository.existsInAnyVersion(workURI)) throw new WebApplicationException(Status.NOT_FOUND); } catch (ContentRepositoryException e) { logger.warn("Error looking up page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Make sure we have a work page. If it doesn't exist yet, it needs // to be created as a result of the lock operation ResourceURI liveURI = new PageURIImpl(site, null, pageId, Resource.LIVE); try { workPage = (Page) contentRepository.get(workURI); if (workPage == null) { logger.debug("Creating work version of {}", liveURI); PageReader reader = new PageReader(); Page livePage = (Page) contentRepository.get(liveURI); workPage = reader.read(IOUtils.toInputStream(livePage.toXml(), "utf-8"), site); workPage.setVersion(Resource.WORK); contentRepository.putAsynchronously(workPage, false); } else { workURI.setPath(workPage.getURI().getPath()); } } catch (ContentRepositoryException e) { logger.warn("Error lookup up page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error putting a page work copy {} to repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (IOException e) { logger.warn("Error putting a page work copy {} to repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ParserConfigurationException e) { logger.warn("Error reading live page {} from repository: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SAXException e) { logger.warn("Error reading live page {} from repository: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Check the value of the If-Match header against the etag if (ifMatchHeader != null) { String etag = ResourceUtils.getETagValue(workPage); if (!etag.equals(ifMatchHeader)) { throw new WebApplicationException(Status.PRECONDITION_FAILED); } } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has editing rights if (!SecurityUtils.userHasRole(user, SystemRole.EDITOR)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (workPage.isLocked() && (!workPage.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Finally, perform the lock operation (on all resource versions) try { contentRepository.lockAsynchronously(workURI, user); logger.info("Page {} has been locked by {}", workURI, user); } catch (SecurityException e) { logger.warn("Tried to lock page {} of site '{}' without permission", workURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error writing page lock {} to repository", workURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error locking page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error locking page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.ok(); response.tag(ResourceUtils.getETagValue(workPage)); response.lastModified(workPage.getLastModified()); return response.build(); } /** * Unlocks the page and returns with a <code>200</code> status code if the * unlock operation succeeds, <code>400</code> if the page is not found or * <code>403</code> if the page is locked by a different user. * * @param request * the request * @param pageId * the page identifier * @param asynchronous * <code>true</code> to prevent blocking while the page is being * unlocked * @return the page */ @DELETE @Path("/{page}/lock") public Response unlockPage(@Context HttpServletRequest request, @PathParam("page") String pageId, @HeaderParam("If-Match") String ifMatchHeader, @QueryParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Extract the site Site site = getSite(request); // Make sure the content repository is writable if (site.getContentRepository().isReadOnly()) { logger.warn("Attempt to unlock a page in a read-only content repository {}", site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI pageURI = new PageURIImpl(site, null, pageId, Resource.WORK); // Does the page exist? Page page = null; try { ResourceURI[] versions = contentRepository.getVersions(pageURI); if (versions.length == 0) throw new WebApplicationException(Status.NOT_FOUND); page = (Page) contentRepository.get(versions[0]); if (page == null) throw new WebApplicationException(Status.NOT_FOUND); pageURI.setPath(page.getURI().getPath()); } catch (ContentRepositoryException e) { logger.warn("Error lookup up page {} from repository: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Check the value of the If-Match header against the etag if (ifMatchHeader != null) { String etag = ResourceUtils.getETagValue(page); if (!etag.equals(ifMatchHeader)) { throw new WebApplicationException(Status.PRECONDITION_FAILED); } } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has editing rights if (!SecurityUtils.userHasRole(user, SystemRole.EDITOR)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (page.isLocked() && (!page.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Finally, perform the lock operation (on all resource versions) try { contentRepository.unlockAsynchronously(pageURI, user); logger.info("Page {} has been unlocked by {}", pageURI, user); } catch (SecurityException e) { logger.warn("Tried to unlock page {} of site '{}' without permission", pageURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error removing page lock {} from repository", pageURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error unlocking page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error unlocking page {}: {}", pageURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.ok(); response.tag(ResourceUtils.getETagValue(page)); response.lastModified(ResourceUtils.getModificationDate(page)); return response.build(); } /** * Publishes the page for the given date range and returns with a * <code>200</code> status code if the publish operation succeeds, * <code>400</code> if the page is not found or <code>403</code> if the page * is currently locked by a different user. * <p> * If <code>startdate</code> is not specified, then the page will be published * immediately. A missing <code>enddate</code> indicates to publish the page * forever. * * @param request * the request * @param pageId * the page identifier * @param startDateText * the optional publishing start date * @param endDateText * the optional publishing end date * @param modified * <code>true</code> to update the page's modified date * @param asynchronous * <code>true</code> to prevent blocking while the page is being * published * @return the page */ @PUT @Path("/{page}/publish") public Response publishPage(@Context HttpServletRequest request, @PathParam("page") String pageId, @FormParam("startdate") String startDateText, @FormParam("enddate") String endDateText, @HeaderParam("If-Match") String ifMatchHeader, @FormParam("modified") boolean setModified, @FormParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Extract the site Site site = getSite(request); // Make sure the content repository is writable if (site.getContentRepository().isReadOnly()) { logger.warn("Attempt to publish a page in a read-only content repository {}", site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI workURI = new PageURIImpl(site, null, pageId, Resource.WORK); // Does the work page exist? Page workPage = null; try { if (!contentRepository.existsInAnyVersion(workURI)) throw new WebApplicationException(Status.NOT_FOUND); workPage = (Page) contentRepository.get(workURI); if (workPage == null) throw new WebApplicationException(Status.PRECONDITION_FAILED); workURI.setPath(workPage.getURI().getPath()); } catch (ContentRepositoryException e) { logger.warn("Error looking up page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Check the value of the If-Match header against the etag if (ifMatchHeader != null) { String etag = ResourceUtils.getETagValue(workPage); if (!etag.equals(ifMatchHeader)) { throw new WebApplicationException(Status.PRECONDITION_FAILED); } } // Make sure the page does not contain references to resources that don't // exist anymore. logger.debug("Checking referenced resources on {}", workPage); try { for (Pagelet pagelet : workPage.getPagelets()) { String resourceId = pagelet.getProperty("resourceid"); if (StringUtils.isEmpty(resourceId)) continue; ResourceURI resourceURI = contentRepository.getResourceURI(resourceId); if (resourceURI == null) { logger.warn("Page {} references non existing resource '{}'", workPage, resourceId); throw new WebApplicationException(Status.PRECONDITION_FAILED); } resourceURI.setVersion(Resource.LIVE); if (!contentRepository.exists(resourceURI)) { logger.warn("Page {} references unpublished resource '{}'", workPage, resourceURI); throw new WebApplicationException(Status.PRECONDITION_FAILED); } } } catch (ContentRepositoryException e) { logger.warn("Error looking up referenced resources", e); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has publishing rights if (!SecurityUtils.userHasRole(user, SystemRole.PUBLISHER)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (workPage.isLocked() && (!workPage.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Fix the dates Date startDate = null; Date endDate = null; DateFormat df = new SimpleDateFormat(); // Parse the start date if (StringUtils.isNotBlank(startDateText)) { try { startDate = df.parse(startDateText); } catch (ParseException e) { try { startDate = WebloungeDateFormat.parseStatic(startDateText); } catch (ParseException e2) { throw new WebApplicationException(Status.BAD_REQUEST); } } } else { startDate = new Date(); } // Parse the end date if (StringUtils.isNotBlank(endDateText)) { try { endDate = df.parse(endDateText); } catch (ParseException e) { try { endDate = WebloungeDateFormat.parseStatic(endDateText); } catch (ParseException e2) { throw new WebApplicationException(Status.BAD_REQUEST); } } } // Finally, perform the publish operation try { PageReader reader = new PageReader(); Page livePage = reader.read(IOUtils.toInputStream(workPage.toXml(), "utf-8"), site); livePage.setVersion(Resource.LIVE); if (setModified) livePage.setModified(user, new Date()); if (!livePage.isPublished()) livePage.setPublished(user, startDate, endDate); contentRepository.putAsynchronously(livePage); contentRepository.deleteAsynchronously(workURI); logger.info("Page {} has been published by {}", workURI, user); } catch (SecurityException e) { logger.warn("Tried to publish page {} of site '{}' without permission", workURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error writing published page {} to repository", workURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error publishing page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error publishing page {}: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ParserConfigurationException e) { logger.warn("Error reading work page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SAXException e) { logger.warn("Error reading work page {} from repository: {}", workURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.ok(); response.tag(ResourceUtils.getETagValue(workPage)); response.lastModified(workPage.getLastModified()); return response.build(); } /** * Unpublishes the page on the given date and returns with a <code>200</code> * status code if the unlock operation succeeds, <code>400</code> if the page * is not found or <code>403</code> if the page is locked by a different user. * * @param request * the request * @param pageId * the page identifier * @param enddate * the optional publishing end date * @param asynchronous * <code>true</code> to prevent blocking while the page is being * unpublished * @return the page */ @DELETE @Path("/{page}/publish") public Response unpublishPage(@Context HttpServletRequest request, @PathParam("page") String pageId, @HeaderParam("If-Match") String ifMatchHeader, @QueryParam("asynchronous") boolean asynchronous) { // Check the parameters if (pageId == null) return Response.status(Status.BAD_REQUEST).build(); // Extract the site Site site = getSite(request); // Make sure the content repository is writable if (site.getContentRepository().isReadOnly()) { logger.warn("Attempt to unlock a page in a read-only content repository {}", site); throw new WebApplicationException(Status.PRECONDITION_FAILED); } WritableContentRepository contentRepository = (WritableContentRepository) getContentRepository(site, true); ResourceURI liveURI = new PageURIImpl(site, null, pageId, Resource.LIVE); // Does the page exist? Page livePage = null; try { if (!contentRepository.existsInAnyVersion(liveURI)) throw new WebApplicationException(Status.NOT_FOUND); livePage = (Page) contentRepository.get(liveURI); if (livePage == null) throw new WebApplicationException(Status.PRECONDITION_FAILED); liveURI.setPath(livePage.getURI().getPath()); } catch (ContentRepositoryException e) { logger.warn("Error lookup up page {} from repository: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error unpublishing page {}: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } // Check the value of the If-Match header against the etag if (ifMatchHeader != null) { String etag = ResourceUtils.getETagValue(livePage); if (!etag.equals(ifMatchHeader)) { throw new WebApplicationException(Status.PRECONDITION_FAILED); } } // Get the user User user = securityService.getUser(); if (user == null) throw new WebApplicationException(Status.UNAUTHORIZED); // Make sure the user has publishing rights if (!SecurityUtils.userHasRole(user, SystemRole.PUBLISHER)) throw new WebApplicationException(Status.UNAUTHORIZED); boolean isAdmin = SecurityUtils.userHasRole(user, SystemRole.SITEADMIN); // If the page is locked by a different user, refuse if (livePage.isLocked() && (!livePage.getLockOwner().equals(user) && !isAdmin)) { return Response.status(Status.FORBIDDEN).build(); } // Finally, perform the unpublish operation, including saving the current // live version of the page as the new work version. try { contentRepository.delete(liveURI); ResourceURI workURI = new ResourceURIImpl(liveURI, Resource.WORK); if (!contentRepository.exists(workURI)) { logger.debug("Creating work version of {}", workURI); PageReader reader = new PageReader(); Page workPage = reader.read(IOUtils.toInputStream(livePage.toXml(), "utf-8"), site); workPage.setVersion(Resource.WORK); workPage.setPublished(null, null, null); contentRepository.putAsynchronously(workPage); } logger.info("Page {} has been unpublished by {}", liveURI, user); } catch (SecurityException e) { logger.warn("Tried to unpublish page {} of site '{}' without permission", liveURI, site); throw new WebApplicationException(Status.FORBIDDEN); } catch (IOException e) { logger.warn("Error removing writing unpublished page {} to repository", liveURI); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (IllegalStateException e) { logger.warn("Error unpublishing page {}: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.PRECONDITION_FAILED); } catch (ContentRepositoryException e) { logger.warn("Error unpublishing page {}: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (ParserConfigurationException e) { logger.warn("Error reading live page {} from repository: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } catch (SAXException e) { logger.warn("Error reading live page {} from repository: {}", liveURI, e.getMessage()); throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); } // Create the response ResponseBuilder response = Response.ok(); response.tag(ResourceUtils.getETagValue(livePage)); response.lastModified(ResourceUtils.getModificationDate(livePage)); return response.build(); } /** * Returns the endpoint documentation. * * @return the endpoint documentation */ @GET @Path("/docs") @Produces(MediaType.TEXT_HTML) public String getDocumentation(@Context HttpServletRequest request) { if (docs == null) { String docsPath = request.getRequestURI(); String docsPathExtension = request.getPathInfo(); String servicePath = request.getRequestURI().substring(0, docsPath.length() - docsPathExtension.length()); docs = PagesEndpointDocs.createDocumentation(servicePath); } return docs; } /** * Callback from OSGi to set the security service. * * @param securityService * the security service */ void setSecurityService(SecurityService securityService) { this.securityService = securityService; } /** * Loads the pages from the site's content repository. * * @param q * the search query * @param details * whether to display detailed information or just the header * @return the files * @throws WebApplicationException * if the content repository is unavailable or if the content can't * be loaded */ private String loadResultSet(SearchQuery q, boolean details) throws WebApplicationException { ContentRepository repository = getContentRepository(q.getSite(), false); if (repository == null) throw new WebApplicationException(Status.SERVICE_UNAVAILABLE); SearchResult result = null; Page pageByPath = null; try { if (q.getVersion() == Resource.WORK && q.getPath() != null) { ResourceURI uri = new PageURIImpl(q.getSite(), q.getPath(), q.getVersion()); pageByPath = (Page) repository.get(uri); int count = pageByPath != null ? 1 : 0; result = new SearchResultImpl(q, count, count); } else { result = repository.find(q); } } catch (ContentRepositoryException e) { throw new WebApplicationException(e); } StringBuffer buf = new StringBuffer("<pages "); buf.append("hits=\"").append(result.getHitCount()).append("\" "); buf.append("offset=\"").append(result.getOffset()).append("\" "); if (q.getLimit() > 0) buf.append("limit=\"").append(result.getLimit()).append("\" "); buf.append("page=\"").append(result.getPage()).append("\" "); buf.append("pagesize=\"").append(result.getPageSize()).append("\""); buf.append(">"); if (pageByPath != null) { String xml = pageByPath.toXml(); if (!details) { xml = xml.replaceAll("<body>.*</body>", ""); xml = xml.replaceAll("<body/>", ""); } buf.append(xml); } else { for (SearchResultItem item : result.getItems()) { String xml = null; if (details) xml = ((PageSearchResultItemImpl) item).getResourceXml(); else xml = ((PageSearchResultItemImpl) item).getPageHeaderXml(); buf.append(xml); } } buf.append("</pages>"); return buf.toString(); } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { return "Pages rest endpoint"; } }