/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.faces.config.processor;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.DocumentInfo;
import com.sun.faces.util.FacesLogger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ResourceLibraryContractsConfigProcessor extends AbstractConfigProcessor {
/**
* Stores the logger.
*/
private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
/**
* <code>/faces-config/resource-library-contracts</code>
*/
private static final String RESOURCE_LIBRARY_CONTRACTS = "resource-library-contracts";
/**
* Constructor.
*/
public ResourceLibraryContractsConfigProcessor() {
}
/**
* Process the configuration documents.
*
* @param servletContext the servlet context.
* @param documentInfos the document info(s).
* @throws Exception when an error occurs.
*/
@Override
public void process(ServletContext servletContext, DocumentInfo[] documentInfos) throws Exception {
HashMap<String, List<String>> map = new HashMap<>();
for (int i = 0; i < documentInfos.length; i++) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, MessageFormat.format(
"Processing factory elements for document: ''{0}''",
documentInfos[i].getSourceURI()));
}
Document document = documentInfos[i].getDocument();
String namespace = document.getDocumentElement().getNamespaceURI();
NodeList resourceLibraryContracts = document.getDocumentElement().getElementsByTagNameNS(namespace, RESOURCE_LIBRARY_CONTRACTS);
if (resourceLibraryContracts != null && resourceLibraryContracts.getLength() > 0) {
processResourceLibraryContracts(resourceLibraryContracts, map);
}
}
if (!map.isEmpty()) {
ApplicationAssociate associate = ApplicationAssociate.getCurrentInstance();
associate.setResourceLibraryContracts(map);
}
invokeNext(servletContext, documentInfos);
}
/**
* Process the resource library contracts.
*
* @param resourceLibraryContracts the resource library contracts.
* @param map the set of resource library contracts.
*/
private void processResourceLibraryContracts(NodeList resourceLibraryContracts, HashMap<String, List<String>> map) {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new FacesConfigNamespaceContext());
for (int c = 0; c < resourceLibraryContracts.getLength(); c++) {
Node node = resourceLibraryContracts.item(c);
try {
NodeList mappings = (NodeList) xpath.evaluate(".//ns1:contract-mapping", node, XPathConstants.NODESET);
if (mappings != null) {
for (int m = 0; m < mappings.getLength(); m++) {
Node contractMapping = mappings.item(m);
NodeList urlPatterns = (NodeList) xpath.evaluate(".//ns1:url-pattern/text()", contractMapping, XPathConstants.NODESET);
if (urlPatterns != null) {
for (int p = 0; p < urlPatterns.getLength(); p++) {
String urlPattern = urlPatterns.item(p).getNodeValue().trim();
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Processing resource library contract mapping for url-pattern: {0}", urlPattern);
}
if (!map.containsKey(urlPattern)) {
/*
* If there is no urlPattern then add it to the list,
*/
ArrayList<String> list = new ArrayList<>();
NodeList contracts = (NodeList) xpath.evaluate(".//ns1:contracts/text()", contractMapping, XPathConstants.NODESET);
if (contracts != null && contracts.getLength() > 0) {
for (int j = 0; j < contracts.getLength(); j++) {
String[] contractStrings = contracts.item(j).getNodeValue().trim().split(",");
for (int k = 0; k < contractStrings.length; k++) {
if (!list.contains(contractStrings[k])) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO,
"Added contract: {0} for url-pattern: {1}",
new Object[]{contractStrings[k], urlPattern});
}
list.add(contractStrings[k]);
} else {
/*
* We found the contract again in the list for the specified url-pattern.
*/
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO,
"Duplicate contract: {0} found for url-pattern: {1}",
new Object[]{contractStrings[k], urlPattern});
}
}
}
}
}
if (!list.isEmpty()) {
/*
* Now add the url-pattern and its contracts.
*/
map.put(urlPattern, list);
} else {
/*
* The list was empty, log there were no contracts specified.
*/
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "No contracts found for url-pattern: {0}", urlPattern);
}
}
} else {
/*
* Otherwise log there is a duplicate url-pattern found.
*/
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Duplicate url-patern found: {0}, ignoring it", urlPattern);
}
}
}
}
}
}
} catch (XPathExpressionException exception) {
/*
* This particular exception will never happen since the
* above valid XPath expressions never change, but the XPath
* runtime defines it as a checked exception so we have to
* deal with it.
*/
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Unable to parse XPath expression", exception);
}
}
}
}
}