Java tutorial
/* ********************************************************************* * This Source Code Form is copyright of 51Degrees Mobile Experts Limited. * Copyright 2015 51Degrees Mobile Experts Limited, 5 Charlotte Close, * Caversham, Reading, Berkshire, United Kingdom RG4 7BY * * This Source Code Form is the subject of the following patent * applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte * Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY: * European Patent Application No. 13192291.6; and * United States Patent Application Nos. 14/085,223 and 14/085,301. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. * * If a copy of the MPL was not distributed with this file, You can obtain * one at http://mozilla.org/MPL/2.0/. * * This Source Code Form is "Incompatible With Secondary Licenses", as * defined by the Mozilla Public License, v. 2.0. * ********************************************************************* */ package fiftyone.mobile.detection.webapp; import fiftyone.mobile.detection.Dataset; import fiftyone.mobile.detection.entities.Property; import fiftyone.mobile.detection.entities.Property.PropertyValueType; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; /** * Provides a mechanism to send one of the 51Degrees JavaScript scripts as * a response. * <p> * You should not access objects of this class directly or instantiate new * objects using this class as they are part of the internal logic. */ class JavascriptProvider { private static final int DEFAULT_BUFFER_SIZE = 10240; static void sendJavaScript(HttpServletRequest request, HttpServletResponse response, Dataset dataSet, StringBuilder javascript) throws IOException { response.reset(); response.setContentType("application/x-javascript"); response.setCharacterEncoding("UTF-8"); response.setHeader("Vary", "User-Agent"); response.setHeader("Cache-Control", "public"); response.setHeader("Expires", dataSet.nextUpdate.toString()); response.setHeader("Last-Modified", dataSet.published.toString()); try { response.setHeader("ETag", eTagHash(dataSet, request)); } catch (Exception ex) { // The response doesn't support eTags. Nothing we can do. } response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setHeader("Content-Length", Integer.toString(javascript.length())); response.getOutputStream().println(javascript.toString()); response.getOutputStream().flush(); response.getOutputStream().close(); } static void sendCoreJavaScript(HttpServletRequest request, HttpServletResponse response) throws IOException { StringBuilder javascript = new StringBuilder("// Copyright 51 Degrees Mobile Experts Limited\r\n"); String fodIo = ImageOptimizer.getJavascript(request); if (fodIo != null) { javascript.append(fodIo); } String fodBw = Bandwidth.getJavascript(request); if (fodBw != null) { javascript.append(fodBw); } String fodPo = ProfileOverride.getJavascript(request); if (fodPo != null) { javascript.append(fodPo); } sendJavaScript(request, response, WebProvider.getActiveProvider(request.getServletContext()).dataSet, javascript); } /** * Responds with the JavaScript listing the featured properties and values. * @param request * @param response * @throws IOException */ static void sendFeatureJavaScript(HttpServletRequest request, HttpServletResponse response) throws IOException { StringBuilder javascript = new StringBuilder("// Copyright 51 Degrees Mobile Experts Limited\r\n"); Dataset dataSet = WebProvider.getActiveProvider(request.getServletContext()).dataSet; final Map<String, String[]> results = WebProvider.getResult(request); List<String> features = new ArrayList<String>(); String query = request.getQueryString(); if (query == null) { for (Property property : dataSet.properties) { if (property.valueType != PropertyValueType.JAVASCRIPT) { getFeatureJavaScript(results, features, property); } } } else { Set<String> requestedProperties = new HashSet<String>(Arrays.asList(query.split("&"))); for (Property property : dataSet.properties) { if (property.valueType != PropertyValueType.JAVASCRIPT) { for (String name : requestedProperties) { if (name.equalsIgnoreCase(property.getName())) { getFeatureJavaScript(results, features, property); } } } } } javascript.append(String.format("var FODF={%s};", stringJoin(",", features))); sendJavaScript(request, response, WebProvider.getActiveProvider(request.getServletContext()).dataSet, javascript); } private static void getFeatureJavaScript(Map<String, String[]> results, List<String> features, Property property) throws IOException { String[] values = results.get(property.getName()); if (values != null && values.length > 0) { switch (property.valueType) { case BOOL: try { features.add(String.format("%s:%s", property.getJavaScriptName(), Boolean.parseBoolean(values[0]) ? "true" : "false")); } catch (NumberFormatException ex) { // Ignore the property as there isn't a value that // converts to a boolean. } break; case INT: try { features.add(String.format("%s:%d", property.getJavaScriptName(), Integer.parseInt(values[0]))); } catch (NumberFormatException ex) { // Ignore the property as there isn't a value that // converts to a boolean. } break; case DOUBLE: try { features.add( String.format("%s:%s", property.getJavaScriptName(), Double.parseDouble(values[0]))); } catch (NumberFormatException ex) { // Ignore the property as there isn't a value that // converts to a boolean. } break; default: features.add(String.format("%s:\"%s\"", property.getJavaScriptName(), stringJoin(fiftyone.properties.DetectionConstants.VALUE_SEPARATOR, values))); break; } } } /** * Returns a base 64 encoded version of the hash for the core JavaScript * being returned. * @param dataSet providing the JavaScript properties. * @param request * @return */ private static String eTagHash(Dataset dataSet, HttpServletRequest request) throws IOException, NoSuchAlgorithmException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); dos.writeLong(dataSet.published.getTime()); dos.writeChars(request.getHeader("User-Agent")); dos.writeChars(request.getQueryString()); return Base64.encodeBase64String(MessageDigest.getInstance("MD5").digest(bos.toByteArray())); } /** * Joins the array of strings separated by the separator provided. * @param seperator * @param values * @return */ private static String stringJoin(String seperator, String[] values) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < values.length; i++) { stringBuilder.append(values[i]); if (i < values.length - 1) { stringBuilder.append(seperator); } } return stringBuilder.toString(); } /** * Joins the list of strings separated by the separator provided. * @param seperator * @param values * @return */ private static String stringJoin(String seperator, List<String> values) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < values.size(); i++) { stringBuilder.append(values.get(i)); if (i < values.size() - 1) { stringBuilder.append(seperator); } } return stringBuilder.toString(); } }