/******************************************************************************* * 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.apache.wink.server.internal.resources; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; import org.apache.wink.common.RestConstants; import org.apache.wink.common.internal.registry.metadata.MethodMetadata; import org.apache.wink.common.internal.runtime.RuntimeContextTLS; import org.apache.wink.common.internal.uri.UriEncoder; import org.apache.wink.common.internal.utils.MediaTypeUtils; import org.apache.wink.common.internal.utils.UriHelper; import org.apache.wink.server.internal.registry.ResourceRecord; import org.apache.wink.server.internal.registry.ResourceRegistry; @Path("/") public class HtmlServiceDocumentResource extends RootResource { private static final String APP_SERVICE_DOCUMENT_TYPE = MediaTypeUtils .toEncodedString(MediaTypeUtils.ATOM_SERVICE_DOCUMENT_TYPE); private static final String TEXT_CSS = "text/css"; //$NON-NLS-1$ private String serviceDocumentCssPath; private static final String START_HTML = "<html>"; //$NON-NLS-1$ private static final String END_HTML = "</html>"; //$NON-NLS-1$ private static final String START_HEAD = "<head>"; //$NON-NLS-1$ private static final String CSS = "<style type=\"text/css\" media=\"all\"> h1 { padding: 4px 4px 4px 24px; color: #333333; background-color: #C8C8C8; font-weight: bold; font-size: 24px;} h2 { padding: 4px 4px 4px 24px; color: #F8F8F8; background-color: #686868; font-weight: bold; font-size: 16px;} </style>"; //$NON-NLS-1$ private static final String END_HEAD = "</head>"; //$NON-NLS-1$ private static final String START_TITLE = "<title>"; //$NON-NLS-1$ private static final String END_TITLE = "</title>"; //$NON-NLS-1$ private static final String START_LINK = "<link rel="; //$NON-NLS-1$ private static final String END_TAG = "/>"; //$NON-NLS-1$ private static final String CLOSE_TAG = ">"; //$NON-NLS-1$ private static final String START_BODY = "<body>"; //$NON-NLS-1$ private static final String END_BODY = "</body>"; //$NON-NLS-1$ private static final String START_HEAD_1 = "<h1>"; //$NON-NLS-1$ private static final String END_HEAD_1 = "</h1>"; //$NON-NLS-1$ private static final String START_PARAGRAPH = "<p>"; //$NON-NLS-1$ private static final String END_PARAGRAPH = "</p>"; //$NON-NLS-1$ private static final String START_A_HREF = "<a "; //$NON-NLS-1$ private static final String END_A_HREF = "</a>"; //$NON-NLS-1$ private static final String START_HEAD_2 = "<h2>"; //$NON-NLS-1$ private static final String END_HEAD_2 = "</h2>"; //$NON-NLS-1$ private static final String START_TABLE = "<table>"; //$NON-NLS-1$ private static final String END_TABLE = "</table>"; //$NON-NLS-1$ private static final String START_T_BODY = "<tbody>"; //$NON-NLS-1$ private static final String END_T_BODY = "</tbody>"; //$NON-NLS-1$ private static final String START_TR = "<tr>"; //$NON-NLS-1$ private static final String END_TR = "</tr>"; //$NON-NLS-1$ private static final String START_TD = "<td>"; //$NON-NLS-1$ private static final String END_TD = "</td>"; //$NON-NLS-1$ private static final String TYPE = "type="; //$NON-NLS-1$ private static final String HREF = "href="; //$NON-NLS-1$ private static final String TITLE = "title="; //$NON-NLS-1$ private static final String SPACE = " "; //$NON-NLS-1$ private static final String APOSTROPHE = "\""; //$NON-NLS-1$ private static final String CSS_REL = "stylesheet"; //$NON-NLS-1$ private static final String OPEN_SEARCH_REL = "search"; //$NON-NLS-1$ /** * Sets the service document CSS path for HTML representation. * * @param serviceDocumentCssPath the path to the service document's CSS file */ public void setServiceDocumentCssPath(String serviceDocumentCssPath) { this.serviceDocumentCssPath = serviceDocumentCssPath; } /** * Gets the service document CSS path for HTML representation. * * @return the path to the service document's CSS file */ public String getServiceDocumentCssPath() { return serviceDocumentCssPath; } /** * This method returns the HTML view of the Service Document. * * @return a complete HTML page */ @GET @Produces(MediaType.TEXT_HTML) public String getServiceDocumentHtml(@Context UriInfo uriInfo) { final String baseUri = uriInfo.getBaseUri().toString(); final String titleValue = "Service Document"; // use //$NON-NLS-1$ // Accept-Langugage StringBuilder htmlDocStrBldr = new StringBuilder(START_HTML); // head htmlDocStrBldr.append(START_HEAD).append(START_TITLE).append(titleValue).append(END_TITLE); addCssLink(htmlDocStrBldr); addOpenSearchLinks(htmlDocStrBldr, baseUri); htmlDocStrBldr.append(END_HEAD); // body htmlDocStrBldr.append(START_BODY).append(START_HEAD_1).append(titleValue) .append(END_HEAD_1); // add a link to ATOM view - user can click on the link and view the // Service Document in // ATOM. String linkToAdd = uriInfo.getAbsolutePathBuilder().queryParam(RestConstants.REST_PARAM_MEDIA_TYPE, APP_SERVICE_DOCUMENT_TYPE).build() .toString(); htmlDocStrBldr.append(START_PARAGRAPH).append(START_A_HREF).append(HREF).append(APOSTROPHE) .append(linkToAdd).append(APOSTROPHE).append(CLOSE_TAG) .append("View Service Document in XML format").append(END_A_HREF).append(END_PARAGRAPH); //$NON-NLS-1$ // go over each workspace and print its collections Map<String, List<ServiceDocumentCollectionData>> workspaces = new LinkedHashMap<String, List<ServiceDocumentCollectionData>>(); List<ServiceDocumentCollectionData> serviceDocumentCollectionList = getCollections(uriInfo); for (ServiceDocumentCollectionData collection : serviceDocumentCollectionList) { List<ServiceDocumentCollectionData> serviceDocumentCollections = workspaces.get(collection.getWorkspace()); if (serviceDocumentCollections == null) { serviceDocumentCollections = new ArrayList<ServiceDocumentCollectionData>(1); workspaces.put(collection.getWorkspace(), serviceDocumentCollections); } serviceDocumentCollections.add(collection); } for (Map.Entry<String, List<ServiceDocumentCollectionData>> workspace : workspaces .entrySet()) { String workspaceTitleValue = workspace.getKey(); List<ServiceDocumentCollectionData> collections = workspace.getValue(); if (collections != null) { htmlDocStrBldr.append(START_HEAD_2).append(workspaceTitleValue).append(END_HEAD_2); // go over each collection and display its html URI (if exists), // if html URI doesn't // exist --> display its default URI. htmlDocStrBldr.append(START_TABLE).append(START_T_BODY); for (ServiceDocumentCollectionData collection : collections) { String collectionName = collection.getTitle(); String template = collection.getUri(); String colUri = UriHelper.appendPathToBaseUri(baseUri, template); // if the collection can be produced as HTML, add the // ?alt="text/html" to the // collection URI if (collection.getProduces() != null && collection.getProduces() .contains(MediaType.TEXT_HTML_TYPE)) { colUri = UriHelper.appendAltToPath(colUri, MediaType.TEXT_HTML_TYPE); } // check if there is parameter on the path of the resource, // if yes --> don't // display it as a link boolean isParameterOnUri = collectionHasTemplateHref(template); htmlDocStrBldr.append(START_TR).append(START_TD).append(collectionName) .append(":").append(END_TD); //$NON-NLS-1$ htmlDocStrBldr.append(START_TD); if (!isParameterOnUri) { // only if parameter isn't // included, display the path // as link htmlDocStrBldr.append("  ").append(START_A_HREF).append(HREF) //$NON-NLS-1$ .append(APOSTROPHE).append(colUri).append(APOSTROPHE).append(CLOSE_TAG) .append(UriEncoder.decodeString(colUri)).append(END_A_HREF); } else { htmlDocStrBldr.append("  ").append(UriEncoder //$NON-NLS-1$ .decodeString(colUri)); } htmlDocStrBldr.append(END_TD).append(END_TR); } htmlDocStrBldr.append(END_T_BODY).append(END_TABLE); } } htmlDocStrBldr.append(END_BODY).append(END_HTML); return htmlDocStrBldr.toString(); } private boolean collectionHasTemplateHref(String collectionUri) { return collectionUri.indexOf('{') > 0; } private void addCssLink(StringBuilder htmlDocStrBldr) { if (serviceDocumentCssPath != null && !serviceDocumentCssPath.equals("")) { //$NON-NLS-1$ htmlDocStrBldr.append(START_LINK).append(APOSTROPHE).append(CSS_REL).append(APOSTROPHE) .append(SPACE).append(TYPE).append(APOSTROPHE).append(TEXT_CSS).append(APOSTROPHE) .append(SPACE).append(HREF).append(APOSTROPHE).append(serviceDocumentCssPath) .append(APOSTROPHE).append(END_TAG); } else { htmlDocStrBldr.append(CSS); } } /** * append links to OpenSearch descriptors. This will enable to add the open * search as a search engine in the browser. * * @param msgContext * @param head append to this * @param baseUri base service uri */ private void addOpenSearchLinks(StringBuilder htmlDocStrBldr, String baseUri) { ResourceRegistry registry = RuntimeContextTLS.getRuntimeContext().getAttribute(ResourceRegistry.class); for (ResourceRecord record : registry.getRecords()) { if (providesOpenSearch(record) && !collectionHasTemplateHref(record .getTemplateProcessor().getTemplate())) { htmlDocStrBldr.append(START_LINK).append(APOSTROPHE).append(OPEN_SEARCH_REL) .append(APOSTROPHE).append(SPACE).append(TYPE).append(APOSTROPHE) .append(MediaTypeUtils.OPENSEARCH).append(APOSTROPHE); String template = record.getTemplateProcessor().getTemplate(); htmlDocStrBldr.append(SPACE).append(HREF).append(APOSTROPHE).append(UriHelper .appendAltToPath(UriHelper.appendPathToBaseUri(baseUri, template), MediaTypeUtils.OPENSEARCH_TYPE)).append(APOSTROPHE); htmlDocStrBldr.append(SPACE).append(TITLE).append(APOSTROPHE).append(record .getMetadata().getCollectionTitle()).append(SPACE).append("Search") //$NON-NLS-1$ .append(APOSTROPHE).append(END_TAG); } } } private boolean providesOpenSearch(ResourceRecord record) { for (MethodMetadata method : record.getMetadata().getResourceMethods()) { if (providesOpenSearch(method)) { return true; } } for (MethodMetadata method : record.getMetadata().getSubResourceMethods()) { if (providesOpenSearch(method)) { return true; } } return false; } private boolean providesOpenSearch(MethodMetadata method) { if (method.getHttpMethod().equals(HttpMethod.GET) && method.getProduces() .equals(MediaTypeUtils.OPENSEARCH_TYPE)) { return true; } return false; } }