package org.frameworkset.http.converter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.MarshalException; import javax.xml.bind.Marshaller; import javax.xml.bind.PropertyException; import javax.xml.bind.UnmarshalException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.frameworkset.http.HttpHeaders; import org.frameworkset.http.HttpInputMessage; import org.frameworkset.http.HttpOutputMessage; import org.frameworkset.http.MediaType; import org.frameworkset.util.Assert; import org.frameworkset.util.ClassUtils; import org.frameworkset.util.FileCopyUtils; import org.frameworkset.util.annotations.ValueConstants; import com.thoughtworks.xstream.XStream; public class XMLHttpMessageConverter extends AbstractHttpMessageConverter<Object> { private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>(); public static Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private final List<Charset> availableCharsets; private boolean writeAcceptCharset = true; public XMLHttpMessageConverter() { super(xmlmediatypes); this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values()); } /** * Indicates whether the {@code Accept-Charset} should be written to any outgoing request. * <p>Default is {@code true}. */ public void setWriteAcceptCharset(boolean writeAcceptCharset) { this.writeAcceptCharset = writeAcceptCharset; } @Override public boolean supports(Class<?> clazz) { return true; } protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException { try { Unmarshaller unmarshaller = createUnmarshaller(clazz); if (clazz.isAnnotationPresent(XmlRootElement.class)) { return unmarshaller.unmarshal(source); } else { JAXBElement jaxbElement = unmarshaller.unmarshal(source, clazz); return jaxbElement.getValue(); } } catch (UnmarshalException ex) { throw new HttpMessageNotReadableException("Could not unmarshal to [" + clazz + "]: " + ex.getMessage(), ex); } catch (JAXBException ex) { throw new HttpMessageConversionException("Could not instantiate JAXBContext: " + ex.getMessage(), ex); } } // @Override // protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException { // MediaType contentType = inputMessage.getHeaders().getContentType(); // Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; // return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset)); // } @Override public final Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException { if(String.class.isAssignableFrom(clazz)) { MediaType contentType = inputMessage.getHeaders().getContentType(); Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset)); } else { if (clazz.isAnnotationPresent(XmlRootElement.class)) { return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody())); } else { XStream xStream = new XStream(); MediaType contentType = inputMessage.getHeaders().getContentType(); Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; return xStream.fromXML(new InputStreamReader(inputMessage.getBody(), charset)); } } } public boolean canWrite(MediaType mediaType) { if (mediaType == null || MediaType.ALL.equals(mediaType)) { return false; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.includes(mediaType)) { return true; } } return false; } /** * Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types} * include the given media type. * @param mediaType the media type to read, can be {@code null} if not specified. Typically the value of a * {@code Content-Type} header. * @return true if the supported media types include the media type, or if the media type is {@code null} */ public boolean canRead(MediaType mediaType) { if (mediaType == null) { return false; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.includes(mediaType)) { return true; } } return false; } private void convertToXML(Object s,HttpOutputMessage outputMessage) throws IOException { if(s == null) ; else if(s instanceof String) { MediaType contentType = outputMessage.getHeaders().getContentType(); Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; FileCopyUtils.copy((String)s, new OutputStreamWriter(outputMessage.getBody(), charset)); } else { try { Class clazz = ClassUtils.getUserClass(s); if (clazz.isAnnotationPresent(XmlRootElement.class)) { Marshaller marshaller = createMarshaller(clazz); try { setCharset(outputMessage.getHeaders().getContentType(), marshaller); marshaller.marshal(s, new StreamResult(outputMessage.getBody())); } catch (MarshalException ex) { throw new HttpMessageNotWritableException("Could not marshal [" + s + "]: " + ex.getMessage(), ex); } catch (JAXBException ex) { throw new HttpMessageConversionException("Could not instantiate JAXBContext: " + ex.getMessage(), ex); } } else { XStream xStream = new XStream(); MediaType contentType = outputMessage.getHeaders().getContentType(); Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; xStream.toXML(s,new OutputStreamWriter(outputMessage.getBody(), charset)); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public Long getContentLength(Object s, MediaType contentType) { if(s instanceof String) { if (contentType != null && contentType.getCharSet() != null) { Charset charset = contentType.getCharSet(); try { return (long) ((String)s).getBytes(charset.name()).length; } catch (UnsupportedEncodingException ex) { // should not occur throw new InternalError(ex.getMessage()); } } else return null; } else { return null; } } @Override public void writeInternal(Object s, HttpOutputMessage outputMessage,HttpInputMessage inputMessage) throws IOException { if (writeAcceptCharset) { outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets()); } convertToXML(s,outputMessage); // if(str != null) // { // MediaType contentType = outputMessage.getHeaders().getContentType(); // Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; // FileCopyUtils.copy(str, new OutputStreamWriter(outputMessage.getBody(), charset)); // } // FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset)); } /** * Return the list of supported {@link Charset}. * * <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses. * * @return the list of accepted charsets */ protected List<Charset> getAcceptedCharsets() { return this.availableCharsets; } public void setResponseCharset(String charset) { super.responsecontenteype = new MediaType("application","xml",Charset.forName(charset)); } /** * Creates a new {@link Marshaller} for the given class. * * @param clazz the class to create the marshaller for * @return the {@code Marshaller} * @throws HttpMessageConversionException in case of JAXB errors */ protected final Marshaller createMarshaller(Class clazz) { try { JAXBContext jaxbContext = getJaxbContext(clazz); return jaxbContext.createMarshaller(); } catch (JAXBException ex) { throw new HttpMessageConversionException( "Could not create Marshaller for class [" + clazz + "]: " + ex.getMessage(), ex); } } /** * Creates a new {@link Unmarshaller} for the given class. * * @param clazz the class to create the unmarshaller for * @return the {@code Unmarshaller} * @throws HttpMessageConversionException in case of JAXB errors */ protected final Unmarshaller createUnmarshaller(Class clazz) throws JAXBException { try { JAXBContext jaxbContext = getJaxbContext(clazz); return jaxbContext.createUnmarshaller(); } catch (JAXBException ex) { throw new HttpMessageConversionException( "Could not create Unmarshaller for class [" + clazz + "]: " + ex.getMessage(), ex); } } /** * Returns a {@link JAXBContext} for the given class. * * @param clazz the class to return the context for * @return the {@code JAXBContext} * @throws HttpMessageConversionException in case of JAXB errors */ protected final JAXBContext getJaxbContext(Class clazz) { Assert.notNull(clazz, "'clazz' must not be null"); JAXBContext jaxbContext = jaxbContexts.get(clazz); if (jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(clazz); jaxbContexts.putIfAbsent(clazz, jaxbContext); } catch (JAXBException ex) { throw new HttpMessageConversionException( "Could not instantiate JAXBContext for class [" + clazz + "]: " + ex.getMessage(), ex); } } return jaxbContext; } protected boolean writeToResult(Object o, HttpHeaders headers, Result result) throws IOException { try { Class clazz = ClassUtils.getUserClass(o); if (clazz.isAnnotationPresent(XmlRootElement.class)) { Marshaller marshaller = createMarshaller(clazz); setCharset(headers.getContentType(), marshaller); marshaller.marshal(o, result); return true; } else { return false; } } catch (MarshalException ex) { throw new HttpMessageNotWritableException("Could not marshal [" + o + "]: " + ex.getMessage(), ex); } catch (JAXBException ex) { throw new HttpMessageConversionException("Could not instantiate JAXBContext: " + ex.getMessage(), ex); } } private void setCharset(MediaType contentType, Marshaller marshaller) throws PropertyException { if (contentType != null && contentType.getCharSet() != null) { marshaller.setProperty(Marshaller.JAXB_ENCODING, contentType.getCharSet().name()); } } @Override public String getRequetBodyDataType() { return ValueConstants.datatype_xml; } /** * 获取用户响应报文对应的数据类型:String,json,xml * @return */ public String getResponseBodyDataType() { return ValueConstants.datatype_xml; } public boolean canWrite(String datatype) { // TODO Auto-generated method stub if(datatype == null) return false; if(datatype.equals(ValueConstants.datatype_xml)) return true; else return false; } }