/* * Copyright 2008 Federal Chancellery Austria and * Graz University of Technology * * 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 at.gv.egiz.bku.slcommands.impl; import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import at.buergerkarte.namespaces.securitylayer._1.InfoboxAssocArrayPairType; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadDataAssocArrayType; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType; import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; import at.buergerkarte.namespaces.securitylayer._1.XMLContentType; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadKeys; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadPairs; import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadValue; import at.gv.egiz.bku.slcommands.InfoboxReadResult; import at.gv.egiz.bku.slcommands.SLCommandContext; import at.gv.egiz.bku.slcommands.SLCommandFactory; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.marshal.MarshallerFactory; import javax.xml.bind.PropertyException; /** * An abstract base class for {@link Infobox} implementations of type associative array. * * @author mcentner */ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl implements AssocArrayInfobox { /** * Logging facility. */ private static Log log = LogFactory.getLog(AbstractAssocArrayInfobox.class); /** * The search string pattern. */ public static final String SEARCH_STRING_PATTERN = "(.&&[^/])+(/.&&[^/])*"; /** * @return the keys available in this infobox. */ public abstract String[] getKeys(); /** * @return true if the values are XML entities, or false otherwise. */ public abstract boolean isValuesAreXMLEntities(); /** * Returns a key to value mapping for the given keys. * * @param keys a list of keys * @param cmdCtx the command context * * @return a key to value mapping for the given keys. * * @throws SLCommandException if obtaining the values fails */ public abstract Map getValues(List keys, SLCommandContext cmdCtx) throws SLCommandException; /** * Returns all keys that match the given searchString. * * @param searchString the search string * * @return all keys that match the given searchString * * @throws SLCommandException if the given search string is invalid */ protected List selectKeys(String searchString) throws SLCommandException { if ("*".equals(searchString) || "**".equals(searchString)) { return Arrays.asList(getKeys()); } if (!searchString.contains("*")) { Arrays.asList(getKeys()).contains(searchString); return Collections.singletonList(searchString); } if (Pattern.matches(SEARCH_STRING_PATTERN, searchString)) { // for (int i = 0; i < searchString.length(); i++) { // int codePoint = searchString.codePointAt(i); // // } // TODO : build pattern return Collections.emptyList(); } else { log.info("Got invalid search string '" + searchString + "'"); throw new SLCommandException(4010); } } /** * Read all keys specified by readKeys. * * @param readKeys * the ReadKeys element * @param cmdCtx * the command context * @return a corresponding InfoboxReadResult * * @throws SLCommandException * if the ReadKeys element is invalid or obtaining the corresponding * values fails */ protected InfoboxReadResult readKeys(ReadKeys readKeys, SLCommandContext cmdCtx) throws SLCommandException { List selectedKeys = selectKeys(readKeys.getSearchString()); if (readKeys.isUserMakesUnique() && selectedKeys.size() > 1) { log.info("UserMakesUnique not supported"); // TODO: give more specific error message throw new SLCommandException(4010); } ObjectFactory objectFactory = new ObjectFactory(); InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory .createInfoboxReadDataAssocArrayType(); List keys = infoboxReadDataAssocArrayType.getKey(); keys.addAll(selectedKeys); return new InfoboxReadResultImpl(infoboxReadDataAssocArrayType); } /** * Read all pairs specified by readPairs. * * @param readPairs * the readPairs element * @param cmdCtx * the command context * @return a corresponding InfoboxReadResult * * @throws SLCommandException * if the ReadPairs element is invalid or obtaining the corresponding * values fails */ protected InfoboxReadResult readPairs(ReadPairs readPairs, SLCommandContext cmdCtx) throws SLCommandException { if (readPairs.isValuesAreXMLEntities() && !isValuesAreXMLEntities()) { log.info("Got valuesAreXMLEntities=" + readPairs.isValuesAreXMLEntities() + " but infobox type is binary."); throw new SLCommandException(4010); } List selectedKeys = selectKeys(readPairs.getSearchString()); if (readPairs.isUserMakesUnique() && selectedKeys.size() > 1) { log.info("UserMakesUnique not supported"); // TODO: give more specific error message throw new SLCommandException(4010); } return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues( selectedKeys, cmdCtx), readPairs.isValuesAreXMLEntities())); } /** * Read the value specified by readPairs. * * @param readValue * the readValue element * @param cmdCtx * the command context * @return a corresponding InfoboxReadResult * * @throws SLCommandException * if the ReadValue element is invalid or obtaining the corresponding * values fails */ protected InfoboxReadResult readValue(ReadValue readValue, SLCommandContext cmdCtx) throws SLCommandException { if (readValue.isValueIsXMLEntity() && !isValuesAreXMLEntities()) { log.info("Got valuesAreXMLEntities=" + readValue.isValueIsXMLEntity() + " but infobox type is binary."); throw new SLCommandException(4010); } List selectedKeys; if (Arrays.asList(getKeys()).contains(readValue.getKey())) { selectedKeys = Collections.singletonList(readValue.getKey()); } else { selectedKeys = Collections.emptyList(); } return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues( selectedKeys, cmdCtx), readValue.isValueIsXMLEntity())); } protected InfoboxReadDataAssocArrayType marshallPairs(List selectedKeys, Map values, boolean areXMLEntities) throws SLCommandException { ObjectFactory objectFactory = new ObjectFactory(); InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory.createInfoboxReadDataAssocArrayType(); for (String key : selectedKeys) { InfoboxAssocArrayPairType infoboxAssocArrayPairType = objectFactory.createInfoboxAssocArrayPairType(); infoboxAssocArrayPairType.setKey(key); Object value = values.get(key); if (areXMLEntities) { if (value instanceof byte[]) { log.info("Got valuesAreXMLEntities=" + areXMLEntities + " but infobox type is binary."); throw new SLCommandException(4122); } else { XMLContentType contentType = objectFactory.createXMLContentType(); contentType.getContent().add(value); infoboxAssocArrayPairType.setXMLContent(contentType); } } else { infoboxAssocArrayPairType.setBase64Content((value instanceof byte[]) ? (byte[]) value : marshallValue(value)); } infoboxReadDataAssocArrayType.getPair().add(infoboxAssocArrayPairType); } return infoboxReadDataAssocArrayType; } protected byte[] marshallValue(Object jaxbElement) throws SLCommandException { SLCommandFactory commandFactory = SLCommandFactory.getInstance(); JAXBContext jaxbContext = commandFactory.getJaxbContext(); ByteArrayOutputStream result; try { Marshaller marshaller = MarshallerFactory.createMarshaller(jaxbContext); result = new ByteArrayOutputStream(); marshaller.marshal(jaxbElement, result); } catch (JAXBException e) { log.info("Failed to marshall infobox content.", e); throw new SLCommandException(4122); } return result.toByteArray(); } @Override public InfoboxReadResult read(InfoboxReadRequestType req, SLCommandContext cmdCtx) throws SLCommandException { InfoboxReadParamsAssocArrayType assocArrayParameters = req .getAssocArrayParameters(); if (assocArrayParameters == null) { log.info("Infobox type is AssocArray but got no AssocArrayParameters."); throw new SLCommandException(4010); } if (assocArrayParameters.getReadKeys() != null) { return readKeys(assocArrayParameters.getReadKeys(), cmdCtx); } if (assocArrayParameters.getReadPairs() != null) { return readPairs(assocArrayParameters.getReadPairs(), cmdCtx); } // ReadValue if (assocArrayParameters.getReadValue() != null) { return readValue(assocArrayParameters.getReadValue(), cmdCtx); } log .info("Infobox type is AssocArray but got invalid AssocArrayParameters."); throw new SLCommandException(4010); } }