/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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 org.apereo.portal.io.xml.dlm; import java.io.IOException; import java.util.Collections; import java.util.Set; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stax.StAXSource; import javax.xml.xpath.XPathConstants; import org.apereo.portal.io.xml.IDataImporter; import org.apereo.portal.io.xml.PortalDataKey; import org.apereo.portal.layout.dlm.FragmentDefinition; import org.apereo.portal.layout.dlm.IFragmentDefinitionDao; import org.apereo.portal.utils.Tuple; import org.apereo.portal.xml.XmlUtilities; import org.apereo.portal.xml.xpath.XPathOperations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.oxm.Unmarshaller; import org.springframework.oxm.XmlMappingException; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.xml.FixedXMLEventStreamReader; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Imports a uPortal 3.1 style fragment definition data file * */ public class FragmentDefinitionImporter implements IDataImporter<Tuple<String, Document>>, Unmarshaller { private IFragmentDefinitionDao fragmentDefinitionDao; private XmlUtilities xmlUtilities; private XPathOperations xPathOperations; @Autowired public void setFragmentDefinitionDao(IFragmentDefinitionDao fragmentDefinitionDao) { this.fragmentDefinitionDao = fragmentDefinitionDao; } @Autowired public void setXmlUtilities(XmlUtilities xmlUtilities) { this.xmlUtilities = xmlUtilities; } @Autowired public void setxPathOperations(XPathOperations xPathOperations) { this.xPathOperations = xPathOperations; } /* (non-Javadoc) * @see org.apereo.portal.io.xml.IDataImporter#getImportDataKeys() */ @Override public Set<PortalDataKey> getImportDataKeys() { return Collections.singleton(FragmentDefinitionPortalDataType.IMPORT_31_DATA_KEY); } /* (non-Javadoc) * @see org.apereo.portal.io.xml.IDataImporter#importData(java.lang.Object) */ @Override @Transactional public void importData(Tuple<String, Document> data) { final Document resultDoc = data.second; final Element fragmentDefElement = this.xPathOperations.evaluate( "//*[local-name() = 'fragment']", resultDoc, XPathConstants.NODE); if (fragmentDefElement == null) { throw new IllegalArgumentException( "Could not find required dlm:fragment element in fragment-definition file"); } final String fragmentName = fragmentDefElement.getAttribute("name"); FragmentDefinition fragmentDefinition = this.fragmentDefinitionDao.getFragmentDefinition(fragmentName); if (fragmentDefinition == null) { fragmentDefinition = new FragmentDefinition(fragmentDefElement); } fragmentDefinition.loadFromEelement(fragmentDefElement); this.fragmentDefinitionDao.updateFragmentDefinition(fragmentDefinition); } /* (non-Javadoc) * @see org.apereo.portal.io.xml.IDataImporter#getUnmarshaller() */ @Override public Unmarshaller getUnmarshaller() { return this; } /* (non-Javadoc) * @see org.springframework.oxm.Unmarshaller#supports(java.lang.Class) */ @Override public boolean supports(Class<?> clazz) { throw new UnsupportedOperationException(); } /* (non-Javadoc) * @see org.springframework.oxm.Unmarshaller#unmarshal(javax.xml.transform.Source) */ @Override public Object unmarshal(Source source) throws IOException, XmlMappingException { if (source instanceof StAXSource) { source = fixStAXSource((StAXSource) source); } final Transformer identityTransformer; try { identityTransformer = this.xmlUtilities.getIdentityTransformer(); } catch (TransformerConfigurationException e) { throw new RuntimeException("Failed to create identity Transformer", e); } final DOMResult domResult = new DOMResult(); try { identityTransformer.transform(source, domResult); } catch (TransformerException e) { throw new RuntimeException("Failed to transform " + source + " into Document", e); } final Document resultDoc = (Document) domResult.getNode(); return new Tuple<String, Document>(source.getSystemId(), resultDoc); } protected Source fixStAXSource(StAXSource staxSource) { XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader(); if (xmlStreamReader != null) { return staxSource; } final XMLEventReader xmlEventReader = staxSource.getXMLEventReader(); //Wrap the event reader in a stream reader to avoid a JDK bug final XMLStreamReader streamReader; try { streamReader = new VersionCachingXMLEventStreamReader(xmlEventReader); } catch (XMLStreamException e) { throw new RuntimeException("Failed to create XMLStreamReader from XMLEventReader", e); } return new StAXSource(streamReader); } private static class VersionCachingXMLEventStreamReader extends FixedXMLEventStreamReader { private String version; public VersionCachingXMLEventStreamReader(XMLEventReader eventReader) throws XMLStreamException { super(eventReader); if (this.getEventType() == XMLEvent.START_DOCUMENT) { version = super.getVersion(); } } /* (non-Javadoc) * @see org.springframework.util.xml.FixedXMLEventStreamReader#getVersion() */ @Override public String getVersion() { final String superVersion = super.getVersion(); if (superVersion != null) { return superVersion; } return version; } /* (non-Javadoc) * @see org.springframework.util.xml.FixedXMLEventStreamReader#next() */ @Override public int next() throws XMLStreamException { final int eventType = super.next(); if (eventType == XMLEvent.START_DOCUMENT) { version = super.getVersion(); } return eventType; } } }