/* * Copyright 2010 FatWire Corporation. 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.fatwire.gst.foundation.url; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import com.fatwire.cs.core.uri.Assembler; import com.fatwire.cs.core.uri.Definition; import com.fatwire.cs.core.uri.QueryAssembler; import com.fatwire.cs.core.uri.Simple; import com.openmarket.xcelerate.publish.PubConstants; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static COM.FutureTense.Interfaces.Utilities.goodString; /** * Web-referenceable asset path assembler. * * @author Tony Field * @since Jul 20, 2010 * * * @deprecated as of release 12.x, replace with WCS 12c's native vanity URLs support. * */ public final class WraPathAssembler extends LightweightAbstractAssembler { protected static final Logger LOG = LoggerFactory.getLogger("tools.gsf.legacy.url.WraPathAssembler"); /** * Name of query string parameter for virtual webroot */ private static final String VIRTUAL_WEBROOT = "virtual-webroot"; /** * Name of query string parameter for url-path */ private static final String URL_PATH = "url-path"; /** * Name of packedargs param */ private static final String PACKEDARGS = "packedargs"; /** * The assembler to use in case the input does not support the WRAPath * approach */ private Assembler theBackupAssembler; /** * The pagename that is used when disassembling URLs */ private String[] pagename = { "GST/Dispatcher" }; /** * List of parameters that are effectively embedded in the URL. These * parameters will not be relayed through the URL as query string * parameters. */ private static List<String> EMBEDDED_PARAMS = Arrays.asList(PubConstants.PAGENAME, PubConstants.CHILDPAGENAME, VIRTUAL_WEBROOT, URL_PATH, PubConstants.c, PubConstants.cid); /** * Configuration property for overriding the default dispatcher pagename. * The default is GST/Dispatcher. */ public static final String DISPATCHER_PROPNAME = "com.fatwire.gst.foundation.url.wrapathassembler.dispatcher"; /** * Configuration property for overriding the backup assembler. URLs that * can't be built using this assembler, that is, URLs for assets that are * not WRAs (or for WRAs missing critical fields), are built using the * backup assembler. The default backup assembler is the standard * QueryAssembler. */ public static final String BACKUP_ASSEMBLER_PROPNAME = "com.fatwire.gst.foundation.url.wrapathassembler.backup-assembler"; /** * Set properties, initializing the assembler * * @param properties configuration properties */ public void setProperties(Properties properties) { super.setProperties(properties); String backupAssemblerClass = getProperty(BACKUP_ASSEMBLER_PROPNAME, QueryAssembler.class.getName()); theBackupAssembler = _instantiateBackupAssembler(backupAssemblerClass); theBackupAssembler.setProperties(properties); pagename[0] = getProperty(DISPATCHER_PROPNAME, "GST/Dispatcher"); LOG.info("Initialized " + WraPathAssembler.class + " with backup assembler " + backupAssemblerClass + " using properties " + properties); } private Assembler _instantiateBackupAssembler(String classname) { try { Class<?> c = Class.forName(classname); Object o = c.newInstance(); return (Assembler) o; } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Illegal class name for backup assembler: " + classname, e); } catch (InstantiationException e) { throw new IllegalStateException("Could not instantiate backup assembler: " + classname, e); } catch (IllegalAccessException e) { throw new IllegalStateException("Could not instantiate backup assembler: " + classname, e); } catch (ClassCastException e) { throw new IllegalArgumentException("Backup assembler class is not an instance of Assembler: " + classname, e); } } /** * Looks for virtual-webroot and url-path. If found, concatenates * virtual-webroot and url-path. Once core query params are suppressed, the * remaining params are appended to the URL. * * @param definition definition object * @return valid URI * @throws URISyntaxException exception on URI syntax */ public URI assemble(Definition definition) throws URISyntaxException { // get packedargs just in case we need them Map<String, String[]> packedargs = getPackedargs(definition); String virtualWebroot = definition.getParameter(VIRTUAL_WEBROOT); if (!goodString(virtualWebroot) && packedargs.containsKey(VIRTUAL_WEBROOT)) { String[] s = packedargs.get(VIRTUAL_WEBROOT); if (s != null && s.length > 0) virtualWebroot = s[0]; } String urlPath = definition.getParameter(URL_PATH); if (!goodString(urlPath) && packedargs.containsKey(URL_PATH)) { String[] s = packedargs.get(URL_PATH); if (s != null && s.length > 0) urlPath = s[0]; } if (!goodString(virtualWebroot) || !goodString(urlPath)) { if (LOG.isDebugEnabled()) { LOG.debug("WRAPathAssembler can't assemble definition due to missing '" + VIRTUAL_WEBROOT + "' and/or '" + URL_PATH + "' params. Definition: " + definition); } return theBackupAssembler.assemble(definition); // Can't assemble // this URL. } if (LOG.isDebugEnabled()) { LOG.debug("WRAPathAssembler is assembling definition: " + definition); } String quotedQueryString = _getQuotedQueryString(definition); URI out = constructURI(virtualWebroot, urlPath, quotedQueryString, definition.getFragment()); if (LOG.isDebugEnabled()) { LOG.debug(this.getClass().getName() + ".assemble: output of constructURI = " + out); } return out; } private String _getQuotedQueryString(Definition definition) { Map<String, String[]> newQryParams = new HashMap<String, String[]>(); // build the query string if there is one for (Object o : definition.getParameterNames()) { // Get the parameter name String key = (String) o; // Don't add embedded params to the query string if (!EMBEDDED_PARAMS.contains(key)) { String[] vals = definition.getParameters(key); if (key.equals(PACKEDARGS)) { vals = excludeFromPackedargs(vals, EMBEDDED_PARAMS); } newQryParams.put(key, vals); } } return constructQueryString(newQryParams); } @SuppressWarnings("unchecked") private Map<String, String[]> getPackedargs(Definition definition) { String[] packedargs = definition.getParameters(PACKEDARGS); if (packedargs != null && packedargs.length > 0) { return parseQueryString(packedargs[0]); } return Collections.EMPTY_MAP; } /** * Construct a query string using the required input for this assembler. * * @param virtualWebroot as defined in the GST Site Foundation spec * @param uriPath as defined in the GST Site Foundation spec * @param quotedQueryString query string excluding embedded params, quoted * @param fragment fragment from definition * @return valid URL * @throws URISyntaxException on bad input data * @see LightweightAbstractAssembler#constructURI for inspiration if edits * are required */ private static final URI constructURI(final String virtualWebroot, String uriPath, String quotedQueryString, String fragment) throws URISyntaxException { StringBuilder bf = new StringBuilder(); bf.append(virtualWebroot); // Path needs quoting though, so let the URI object do it for us. // Use the toASCIIString() method because we need the quoted values. // (toString() is really just for readability and debugging, not // programmatic use) bf.append(new URI(null, null, uriPath, null, null).getRawPath()); if (goodString(quotedQueryString)) { bf.append('?').append(quotedQueryString); // already quoted } // needs quoting if (goodString(fragment)) { bf.append(new URI(null, null, null, null, fragment).toASCIIString()); } URI uri = new URI(bf.toString()); if (LOG.isDebugEnabled()) { StringBuilder msg = new StringBuilder(); if (LOG.isTraceEnabled()) { msg.append("Constructing new URI using the following components: \n\tvirtual-webroot=") .append(virtualWebroot).append("\n\turi-path=").append(uriPath) .append("\n\tquotedQueryString=").append(quotedQueryString).append("\n\tfragment=") .append(fragment); msg.append("\n"); } msg.append("Assembled URI").append(uri.toASCIIString()); if (LOG.isTraceEnabled()) LOG.trace(msg.toString()); else LOG.debug(msg.toString()); } return uri; } public Definition disassemble(URI uri, Definition.ContainerType containerType) throws URISyntaxException { Map<String, String[]> params = parseQueryString(uri.getRawQuery()); String[] virtualWebrootArr = params.get(VIRTUAL_WEBROOT); String[] uriPathArr = params.get(URL_PATH); if (virtualWebrootArr == null || virtualWebrootArr.length != 1) { if (LOG.isTraceEnabled()) LOG.trace("WRAPathAssembler cannot disassemble URI '" + uri + "' because the " + VIRTUAL_WEBROOT + " parameter is either missing or has more than one value"); return theBackupAssembler.disassemble(uri, containerType); } if (uriPathArr == null || uriPathArr.length != 1) { if (LOG.isTraceEnabled()) LOG.trace("WRAPathAssembler cannot disassemble URI '" + uri + "' because the " + URL_PATH + " parameter is either missing or has more than one value"); return theBackupAssembler.disassemble(uri, containerType); } if (LOG.isDebugEnabled()) { LOG.debug("Disassembling URI: " + uri); } Simple result; try { String[] request_pagename = params.get(PubConstants.PAGENAME); if (request_pagename == null || request_pagename.length == 0 || StringUtils.isBlank(request_pagename[0])) { params.put(PubConstants.PAGENAME, pagename); } final Definition.AppType appType = Definition.AppType.CONTENT_SERVER; final Definition.SatelliteContext satelliteContext = Definition.SatelliteContext.SATELLITE_SERVER; final boolean sessionEncode = false; final String scheme = uri.getScheme(); final String authority = uri.getAuthority(); final String fragment = uri.getFragment(); if (LOG.isDebugEnabled()) { LOG.debug("Will attempt instantiating Simple with: \n sessionEncode = " + sessionEncode + " \n satelliteContext = " + satelliteContext + " \n containerType = " + containerType + " \n scheme = " + scheme + " \n authority = " + authority + " \n appType " + appType + " \n fragment = " + fragment + " \n query string params = " + params); } result = new Simple(sessionEncode, satelliteContext, containerType, scheme, authority, appType, fragment); result.setQueryStringParameters(params); LOG.debug("Simple object successfully instantiated by WraPathAsssembler"); } catch (IllegalArgumentException e) { // Something bad happened throw new URISyntaxException(uri.toString(), e.toString()); } return result; } }