Java tutorial
/******************************************************************************* * Copyright (c) 2014 SAP AG or an SAP affiliate company. All rights reserved. * Licensed 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 com.sap.dirigible.runtime.registry; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.MissingResourceException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.http.client.utils.DateUtils; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.sap.dirigible.repository.api.ContentTypeHelper; import com.sap.dirigible.repository.api.ICollection; import com.sap.dirigible.repository.api.IEntity; import com.sap.dirigible.repository.api.IEntityInformation; import com.sap.dirigible.repository.api.IRepository; import com.sap.dirigible.repository.api.IResource; import com.sap.dirigible.runtime.logger.Logger; /** * Servlet implementation class RegistryServlet */ public class RegistryServlet extends AbstractRegistryServlet { private static final String CONTENT_LENGTH_HEADER = "Content-Length"; private static final String LAST_MODIFIED_HEADER = "Last-Modified"; private static final String EXPIRES_HEADER = "Expires"; private static final String IF_MODIFIED_SINCE_HEADER = "If-Modified-Since"; private static final String ACCEPT_HEADER = "Accept"; //$NON-NLS-1$ private static final String INDEX_HTML = "index.html"; //$NON-NLS-1$ private static final String LISTING_OF_FOLDERS_IS_FORBIDDEN = Messages .getString("RegistryServlet.LISTING_OF_FOLDERS_IS_FORBIDDEN"); //$NON-NLS-1$ private static final String JSON = "json"; //$NON-NLS-1$ private static final String JSON_FOLDER = "folder"; //$NON-NLS-1$ private static final String JSON_ROOT = "root"; //$NON-NLS-1$ private static final String JSON_PATH = "path"; //$NON-NLS-1$ private static final String JSON_NAME = "name"; //$NON-NLS-1$ private static final String JSON_FILES = "files"; //$NON-NLS-1$ private static final String REQUEST_PROCESSING_FAILED_S = ""; //$NON-NLS-1$ private static final long serialVersionUID = 7435479651482177443L; private static final Logger logger = Logger.getLogger(RegistryServlet.class); @Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { String repositoryPath = null; final String requestPath = request.getPathInfo(); boolean deep = false; if (requestPath == null) { deep = true; } final OutputStream out = response.getOutputStream(); try { repositoryPath = extractRepositoryPath(request); final IEntity entity = getEntity(repositoryPath, request); byte[] data; if (entity != null) { if (entity instanceof IResource) { data = buildResourceData(entity, request, response); } else if (entity instanceof ICollection) { String collectionPath = request.getRequestURI().toString(); String acceptHeader = request.getHeader(ACCEPT_HEADER); if (acceptHeader != null && acceptHeader.contains(JSON)) { if (!collectionPath.endsWith(IRepository.SEPARATOR)) { collectionPath += IRepository.SEPARATOR; } data = buildCollectionData(deep, entity, collectionPath); } else { // welcome file support IResource index = ((ICollection) entity).getResource(INDEX_HTML); if (index.exists() && (collectionPath.endsWith(IRepository.SEPARATOR))) { data = buildResourceData(index, request, response); } else { // listing of collections is forbidden exceptionHandler(response, repositoryPath, HttpServletResponse.SC_FORBIDDEN, LISTING_OF_FOLDERS_IS_FORBIDDEN); return; } } } else { exceptionHandler(response, repositoryPath, HttpServletResponse.SC_FORBIDDEN, LISTING_OF_FOLDERS_IS_FORBIDDEN); return; } } else { exceptionHandler(response, repositoryPath, HttpServletResponse.SC_NOT_FOUND, String.format("Resource at [%s] does not exist", requestPath)); return; } if (entity instanceof IResource) { final IResource resource = (IResource) entity; String mimeType = null; String extension = ContentTypeHelper.getExtension(resource.getName()); if ((mimeType = ContentTypeHelper.getContentType(extension)) != null) { response.setContentType(mimeType); } else { response.setContentType(resource.getContentType()); } } sendData(out, data); } catch (final IllegalArgumentException ex) { exceptionHandler(response, repositoryPath, HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); } catch (final MissingResourceException ex) { exceptionHandler(response, repositoryPath, HttpServletResponse.SC_NO_CONTENT, ex.getMessage()); } catch (final RuntimeException ex) { exceptionHandler(response, repositoryPath, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage()); } finally { out.flush(); out.close(); } } private void exceptionHandler(final HttpServletResponse response, final String repositoryPath, final int errorMessage, final String exceptionMessage) throws IOException { logger.error(String.format(REQUEST_PROCESSING_FAILED_S, repositoryPath) + exceptionMessage); response.sendError(errorMessage, exceptionMessage); } protected byte[] buildCollectionData(final boolean deep, final IEntity entity, final String collectionPath) throws IOException { byte[] data; final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final PrintWriter writer = new PrintWriter(baos); final JsonObject rootObject = new JsonObject(); rootObject.addProperty(JSON_NAME, JSON_ROOT); rootObject.addProperty(JSON_PATH, IRepository.SEPARATOR); rootObject.add(JSON_FILES, enumerateCollectionData(collectionPath, (ICollection) entity, deep)); writer.println(new Gson().toJsonTree(rootObject)); writer.flush(); data = baos.toByteArray(); return data; } protected byte[] buildResourceData(final IEntity entity, final HttpServletRequest request, final HttpServletResponse response) throws IOException { byte[] data = new byte[] {}; if (!setCacheHeaders(entity, request, response)) { data = readResourceData((IResource) entity); setContentLengthHeader(entity, data.length, request, response); } return data; } private void setContentLengthHeader(IEntity entity, int contentLength, HttpServletRequest request, HttpServletResponse response) throws IOException { response.setHeader(CONTENT_LENGTH_HEADER, Integer.toString(contentLength)); } private boolean setCacheHeaders(IEntity entity, HttpServletRequest request, HttpServletResponse response) throws IOException { boolean cached = false; IEntityInformation entityInformation = entity.getInformation(); String modifiedSinceHeader = request.getHeader(IF_MODIFIED_SINCE_HEADER); if ((entityInformation != null)) { Calendar lastModified = getCalendar(entityInformation.getModifiedAt()); if ((!StringUtils.isEmpty(modifiedSinceHeader))) { Calendar modifiedSince = getCalendar(DateUtils.parseDate(modifiedSinceHeader)); if (lastModified.compareTo(modifiedSince) <= 0) { Calendar expires = getCalendar(lastModified); expires.add(Calendar.MONTH, 1); response.setDateHeader(EXPIRES_HEADER, expires.getTimeInMillis()); response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); cached = true; } } response.setDateHeader(LAST_MODIFIED_HEADER, lastModified.getTimeInMillis()); } return cached; } private Calendar getCalendar(Calendar calendar) { return getCalendar(calendar.getTime()); } private Calendar getCalendar(Date time) { Calendar calendar = Calendar.getInstance(); calendar.setTime(time); calendar.clear(Calendar.MILLISECOND); return calendar; } private JsonArray enumerateCollectionData(final String collectionPath, final ICollection collection, final boolean deep) throws IOException { final JsonArray arr = new JsonArray(); childItterate(arr, collectionPath, collection, deep, collection.getCollectionsNames(), true); childItterate(arr, collectionPath, collection, deep, collection.getResourcesNames(), false); return arr; } private void childItterate(final JsonArray arr, final String collectionPath, final ICollection collection, final boolean deep, final List<String> collections, final Boolean isFolder) throws IOException { for (final String collectionName : collections) { final String path = collectionPath + collectionName + (isFolder ? IRepository.SEPARATOR : ""); //$NON-NLS-1$ final JsonObject elementObject = new JsonObject(); elementObject.addProperty(JSON_NAME, collectionName); elementObject.addProperty(JSON_PATH, path); if (isFolder) { elementObject.addProperty(JSON_FOLDER, isFolder); } if (deep && isFolder) { final JsonArray children = enumerateCollectionData(path, collection.getCollection(collectionName), deep); // We don't care about empty folders if (children.size() != 0) { elementObject.add(JSON_FILES, children); } } arr.add(elementObject); } } }