Java tutorial
package org.ncbo.stanford.service.xml.impl; import java.io.File; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.validator.GenericValidator; import org.ncbo.stanford.bean.CategoryBean; import org.ncbo.stanford.bean.GroupBean; import org.ncbo.stanford.bean.NamespaceBean; import org.ncbo.stanford.bean.OntologyBean; import org.ncbo.stanford.bean.OntologyMetricsBean; import org.ncbo.stanford.bean.SubscriptionsBean; import org.ncbo.stanford.bean.UserBean; import org.ncbo.stanford.bean.acl.OntologyAcl; import org.ncbo.stanford.bean.acl.UserAcl; import org.ncbo.stanford.bean.concept.ClassBean; import org.ncbo.stanford.bean.concept.ConceptOntologyPairBean; import org.ncbo.stanford.bean.concept.InstanceBean; import org.ncbo.stanford.bean.concept.PropertyBean; import org.ncbo.stanford.bean.http.HttpInputStreamWrapper; import org.ncbo.stanford.bean.logging.UsageLoggingBean; import org.ncbo.stanford.bean.mapping.MappingBean; import org.ncbo.stanford.bean.mapping.MappingConceptStatsBean; import org.ncbo.stanford.bean.mapping.MappingOntologyPairStatsBean; import org.ncbo.stanford.bean.mapping.MappingOntologyStatsBean; import org.ncbo.stanford.bean.mapping.MappingResultConceptSetBean; import org.ncbo.stanford.bean.mapping.MappingUserStatsBean; import org.ncbo.stanford.bean.notes.AppliesToBean; import org.ncbo.stanford.bean.notes.NoteBean; import org.ncbo.stanford.bean.notes.ProposalNewRelationshipBean; import org.ncbo.stanford.bean.notes.ProposalNewTermBean; import org.ncbo.stanford.bean.notes.ProposalPropertyValueChangeBean; import org.ncbo.stanford.bean.response.AbstractResponseBean; import org.ncbo.stanford.bean.response.ErrorBean; import org.ncbo.stanford.bean.response.SuccessBean; import org.ncbo.stanford.bean.search.OntologyHitBean; import org.ncbo.stanford.bean.search.SearchBean; import org.ncbo.stanford.bean.user.OntologyLicense; import org.ncbo.stanford.enumeration.ConceptTypeEnum; import org.ncbo.stanford.enumeration.SearchRecordTypeEnum; import org.ncbo.stanford.enumeration.ViewingRestrictionEnum; import org.ncbo.stanford.service.session.RESTfulSession; import org.ncbo.stanford.service.xml.XMLSerializationService; import org.ncbo.stanford.service.xml.converters.ClassBeanListConverter; import org.ncbo.stanford.service.xml.converters.ClassBeanResultListBeanConverter; import org.ncbo.stanford.service.xml.converters.InstanceBeanResultListBeanConverter; import org.ncbo.stanford.service.xml.converters.MappingResultListBeanConverter; import org.ncbo.stanford.service.xml.converters.OntologyAclConverter; import org.ncbo.stanford.service.xml.converters.OntologyHitMapConverter; import org.ncbo.stanford.service.xml.converters.OntologyLicenseConverter; import org.ncbo.stanford.service.xml.converters.SearchResultListBeanConverter; import org.ncbo.stanford.service.xml.converters.UserAclConverter; import org.ncbo.stanford.util.MessageUtils; import org.ncbo.stanford.util.RequestUtils; import org.ncbo.stanford.util.constants.ApplicationConstants; import org.ncbo.stanford.util.paginator.impl.Page; import org.ncbo.stanford.util.security.SecurityContextHolder; import org.openrdf.model.URI; import org.openrdf.model.impl.URIImpl; import org.restlet.Request; import org.restlet.Response; import org.restlet.data.MediaType; import org.restlet.data.Status; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.enums.EnumSingleValueConverter; import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver; import com.thoughtworks.xstream.io.xml.TraxSource; import com.thoughtworks.xstream.mapper.Mapper; /** * A default implementation of the XMLSerializationService * * @author Michael Dorf * */ public class XMLSerializationServiceImpl implements XMLSerializationService { private static final Log log = LogFactory.getLog(XMLSerializationServiceImpl.class); private HashMap<String, Transformer> transformers = new HashMap<String, Transformer>(0); private XStream xmlSerializer = null; private XStream jsonSerializer = null; public XMLSerializationServiceImpl() { initXmlSerializer(); initJsonSerializer(); } /** * Generates Generic XML response which contains status info whether success * or fail. session id and access resource info is included. * * @param request * @param response */ public void generateStatusXMLResponse(Request request, Response response) { generateXMLResponse(request, response, null); } /** * Generates XML response. If SUCCESS - Entity info is displayed. else - * Error info is displayed. * * @param request * @param response * @param data */ public void generateXMLResponse(Request request, Response response, Object data) { AbstractResponseBean respBean = null; Status status = response.getStatus(); if (status.isError()) { respBean = getErrorBean(request, response); } else { respBean = getSuccessBean(request, data); } RequestUtils.setHttpServletResponse(response, status, respBean.getMediaType(), getResponseAsString(respBean)); } /** * Generates XML response then apply XSL transformation. This is useful to * filter huge XML response such as findAll() Ontologies. * * If SUCCESS - Entity info is displayed. else - Error info is displayed. * * @param request * @param response * @param data * @param xsltFile */ public void generateXMLResponse(Request request, Response response, Object data, String xsltFile) { if (response.getStatus().isError()) { generateStatusXMLResponse(request, response); } else { MediaType prefMediaType = getPreferredMediaType(request); if (prefMediaType.equals(MediaType.APPLICATION_JSON)) { generateXMLResponse(request, response, data); } else { try { RequestUtils.setHttpServletResponse(response, Status.SUCCESS_OK, prefMediaType, applyXSL(request, data, xsltFile)); } catch (TransformerException e) { // XML parse ERROR response.setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage()); generateStatusXMLResponse(request, response); e.printStackTrace(); log.error(e); } } } } /** * Process a get request and return a response * * @param baseUrl * @param getParams * @throws Exception */ public AbstractResponseBean processGet(String baseUrl, HashMap<String, String> getParams) throws Exception { AbstractResponseBean responseBean = null; HttpInputStreamWrapper inputStreamWrapper = RequestUtils.doHttpGet(baseUrl, getParams); Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() .parse(inputStreamWrapper.getInputStream()); removeWhitespaceNodes(doc.getDocumentElement()); if (inputStreamWrapper.isError()) { responseBean = populateErrorBean(doc, inputStreamWrapper.getResponseCode()); } else { responseBean = populateSuccessBean(doc); } return responseBean; } /** * Generate an XML representation of a successfully processed request with * XSL Transformation. * * @param request * @param data * @param xsltFile * @return String * @throws TransformerException */ private String applyXSL(Request request, Object data, String xsltFile) throws TransformerException { SuccessBean sb = getSuccessBean(request, data); // create source TraxSource traxSource = new TraxSource(sb, xmlSerializer); // create buffer for XML output Writer buffer = new StringWriter(); getTransformerInstance(xsltFile).transform(traxSource, new StreamResult(buffer)); return buffer.toString(); } /** * returns ErrorStatusBean */ private ErrorBean getErrorBean(Request request, Response response) { ErrorBean errorStatusBean = new ErrorBean(response.getStatus()); initResponseBean(request, errorStatusBean); return errorStatusBean; } /** * returns SuccessBean with apiKey, accessedResource populated */ private SuccessBean getSuccessBean(Request request) { SuccessBean successBean = new SuccessBean(); initResponseBean(request, successBean); return successBean; } /** * returns SuccessBean with apiKey, accessedResource and data populated */ private SuccessBean getSuccessBean(Request request, Object data) { SuccessBean successBean = getSuccessBean(request); if (data != null) { successBean.getData().add(data); } return successBean; } private void initResponseBean(Request request, AbstractResponseBean responseBean) { String accessedResource = request.getResourceRef().getPath(); if (!GenericValidator.isBlankOrNull(accessedResource)) { responseBean.setAccessedResource(accessedResource); } responseBean.setMediaType(getPreferredMediaType(request)); } private MediaType getPreferredMediaType(Request request) { List<MediaType> prefMediaTypes = new ArrayList<MediaType>(2); prefMediaTypes.add(MediaType.APPLICATION_XML); prefMediaTypes.add(MediaType.APPLICATION_JSON); MediaType prefMediaType = request.getClientInfo().getPreferredMediaType(prefMediaTypes); return (prefMediaType == null) ? MediaType.APPLICATION_XML : prefMediaType; } private void removeWhitespaceNodes(Element e) { NodeList children = e.getChildNodes(); for (int i = children.getLength() - 1; i >= 0; i--) { Node child = children.item(i); if (child instanceof Text && ((Text) child).getData().trim().length() == 0) { e.removeChild(child); } else if (child instanceof Element) { removeWhitespaceNodes((Element) child); } } } private ErrorBean populateErrorBean(Document doc, int responseCode) throws TransformerException { String node = getNodeAsXML(doc); ErrorBean errorBean = (ErrorBean) xmlSerializer.fromXML(node); errorBean.setStatus(new Status(responseCode)); return errorBean; } private SuccessBean populateSuccessBean(Document doc) throws TransformerException { SuccessBean sb = new SuccessBean(); String node = getNodeAsXML( doc.getElementsByTagName(ApplicationConstants.DATA_XML_TAG_NAME).item(0).getFirstChild()); sb.setDataXml(node); return sb; } private String getNodeAsXML(Node node) throws TransformerException { TransformerFactory transfac = TransformerFactory.newInstance(); Transformer trans = transfac.newTransformer(); trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(node); StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); trans.transform(source, result); return sw.toString(); } /** * returns a singleton transformer instance for a XSL file specified. do not * use synchronized since it is expensive. */ public Transformer getTransformerInstance(String xslFile) throws TransformerException { Transformer transformer = (Transformer) transformers.get(xslFile); if (transformer == null) { File ontologyXSLT = new File(xslFile); transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(ontologyXSLT)); transformers.put(xslFile, transformer); } return transformer; } @SuppressWarnings("unchecked") public void addImplicitCollection(Class ownerType, String fieldName) { xmlSerializer.addImplicitCollection(ownerType, fieldName); } @SuppressWarnings("unchecked") public void omitField(Class definedIn, String fieldName) { xmlSerializer.omitField(definedIn, fieldName); } @SuppressWarnings("unchecked") public void alias(String name, Class type) { xmlSerializer.alias(name, type); } @SuppressWarnings("unchecked") public void aliasField(String alias, Class definedIn, String fieldName) { xmlSerializer.aliasField(alias, definedIn, fieldName); } public Object fromXML(String xml) { return xmlSerializer.fromXML(xml); } public XStream getXmlSerializer() { return xmlSerializer; } /** * Generate a String representation of a request. * * @param responseBean * @return String */ private String getResponseAsString(AbstractResponseBean responseBean) { StringBuffer sb = new StringBuffer(); XStream serializer = null; if (responseBean.getMediaType().equals(MediaType.APPLICATION_JSON)) { serializer = jsonSerializer; } else { serializer = xmlSerializer; sb.append(ApplicationConstants.XML_DECLARATION); sb.append('\n'); } sb.append(serializer.toXML(responseBean)); return sb.toString(); } private void initXmlSerializer() { this.xmlSerializer = new XStream(); initSerializer(this.xmlSerializer); } private void initJsonSerializer() { this.jsonSerializer = new XStream(new JettisonMappedXmlDriver()); initSerializer(this.jsonSerializer); } private void initSerializer(XStream serializer) { serializer.setMode(XStream.NO_REFERENCES); setAliases(serializer); registerConverters(serializer); } /** * set aliases for xmlSerializer */ private void registerConverters(XStream xmlSerializer) { Mapper mapper = xmlSerializer.getMapper(); xmlSerializer.registerConverter(new OntologyHitMapConverter(mapper)); xmlSerializer.registerConverter(new SearchResultListBeanConverter(mapper)); xmlSerializer.registerConverter(new EnumSingleValueConverter(SearchRecordTypeEnum.class)); xmlSerializer.registerConverter(new EnumSingleValueConverter(ConceptTypeEnum.class)); xmlSerializer.registerConverter(new ClassBeanResultListBeanConverter(mapper)); xmlSerializer.registerConverter(new ClassBeanListConverter(mapper)); xmlSerializer.registerConverter(new InstanceBeanResultListBeanConverter(mapper)); xmlSerializer.registerConverter(new MappingResultListBeanConverter(mapper)); xmlSerializer.registerConverter(new UserAclConverter(mapper)); xmlSerializer.registerConverter(new OntologyAclConverter(mapper)); xmlSerializer.registerConverter(new OntologyLicenseConverter(mapper)); xmlSerializer.registerConverter(new EnumSingleValueConverter(ViewingRestrictionEnum.class)); } /** * set aliases for xmlSerializer */ private void setAliases(XStream xmlSerializer) { xmlSerializer.alias(MessageUtils.getMessage("entity.ontologybean"), OntologyBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.ontologymetricsbean"), OntologyMetricsBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.userbean"), UserBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.subscriptionsbean"), SubscriptionsBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.classbean"), ClassBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.categorybean"), CategoryBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.groupbean"), GroupBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.propertybean"), PropertyBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.instancebean"), InstanceBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.searchbean"), SearchBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.usageloggingbean"), UsageLoggingBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.page"), Page.class); xmlSerializer.alias(MessageUtils.getMessage("entity.ontologyhitbean"), OntologyHitBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.restfulsession"), RESTfulSession.class); xmlSerializer.alias(MessageUtils.getMessage("entity.securitycontextholder"), SecurityContextHolder.class); xmlSerializer.alias(MessageUtils.getMessage("entity.notebean"), NoteBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.appliesto"), AppliesToBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.proposalforchangepropertyvalue"), ProposalPropertyValueChangeBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.proposalforcreateentity"), ProposalNewTermBean.class); xmlSerializer.alias(MessageUtils.getMessage("entity.proposalforchangehierarchy"), ProposalNewRelationshipBean.class); xmlSerializer.alias(ApplicationConstants.RESPONSE_XML_TAG_NAME, SuccessBean.class); xmlSerializer.alias(ApplicationConstants.ERROR_STATUS_XML_TAG_NAME, ErrorBean.class); xmlSerializer.alias(ApplicationConstants.SUCCESS_XML_TAG_NAME, SuccessBean.class); xmlSerializer.alias("namespace", NamespaceBean.class); String aclAlias = MessageUtils.getMessage("entity.acl"); xmlSerializer.alias(aclAlias, OntologyAcl.class); xmlSerializer.alias(aclAlias, UserAcl.class); String licenseAlias = MessageUtils.getMessage("entity.ontologylicenses"); xmlSerializer.alias(licenseAlias, OntologyLicense.class); xmlSerializer.omitField(UserBean.class, "password"); xmlSerializer.omitField(UserBean.class, "apiKey"); xmlSerializer.omitField(AbstractResponseBean.class, "mediaType"); xmlSerializer.omitField(AbstractResponseBean.class, "status"); // Mapping aliases using annotations xmlSerializer.processAnnotations(MappingBean.class); xmlSerializer.processAnnotations(MappingOntologyStatsBean.class); xmlSerializer.processAnnotations(MappingConceptStatsBean.class); xmlSerializer.processAnnotations(MappingUserStatsBean.class); xmlSerializer.processAnnotations(MappingOntologyPairStatsBean.class); xmlSerializer.processAnnotations(MappingResultConceptSetBean.class); xmlSerializer.processAnnotations(ConceptOntologyPairBean.class); xmlSerializer.addDefaultImplementation(URIImpl.class, URI.class); xmlSerializer.addDefaultImplementation(ArrayList.class, List.class); } }