| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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 |
| * |
| * 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 org.apache.tuscany.sca.binding.rest.provider; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.Reader; |
| import java.io.StringWriter; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Type; |
| |
| import javax.activation.DataSource; |
| import javax.jws.WebParam; |
| import javax.jws.WebResult; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.ext.Provider; |
| import javax.xml.namespace.QName; |
| |
| import org.apache.tuscany.sca.core.ExtensionPointRegistry; |
| import org.apache.tuscany.sca.core.UtilityExtensionPoint; |
| import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint; |
| import org.apache.tuscany.sca.databinding.Mediator; |
| import org.apache.tuscany.sca.interfacedef.DataType; |
| import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; |
| import org.apache.tuscany.sca.interfacedef.util.XMLType; |
| |
| /** |
| * A JAX-RS provider that leverages Tuscany's databinding framework to handle read/write |
| * for JAX-RS runtime |
| */ |
| @Provider |
| public abstract class DataBindingJAXRSProvider { |
| protected DataBindingExtensionPoint dataBindingExtensionPoint; |
| protected Mediator mediator; |
| |
| public DataBindingJAXRSProvider(ExtensionPointRegistry registry) { |
| this.dataBindingExtensionPoint = registry.getExtensionPoint(DataBindingExtensionPoint.class); |
| UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); |
| this.mediator = utilities.getUtility(Mediator.class); |
| } |
| |
| protected <A extends Annotation> A getAnnotation(Annotation[] annotations, Class<A> type) { |
| if(annotations == null) { |
| return null; |
| } |
| for (Annotation a : annotations) { |
| if (a.annotationType() == type) { |
| return type.cast(a); |
| } |
| } |
| return null; |
| } |
| |
| protected void introspectAnnotations(Annotation[] annotations, DataType targetDataType) { |
| WebResult result = getAnnotation(annotations, WebResult.class); |
| if (result != null) { |
| QName name = new QName(result.targetNamespace(), result.name()); |
| targetDataType.setLogical(new XMLType(name, null)); |
| } |
| |
| WebParam param = getAnnotation(annotations, WebParam.class); |
| if (param != null) { |
| QName name = new QName(param.targetNamespace(), param.name()); |
| targetDataType.setLogical(new XMLType(name, null)); |
| } |
| } |
| |
| protected DataType createDataType(Class<?> type, Type genericType) { |
| DataType dataType = new DataTypeImpl(null, type, genericType, genericType); |
| dataBindingExtensionPoint.introspectType(dataType, null); |
| return dataType; |
| } |
| |
| protected boolean supports(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { |
| // Some media types have parameters |
| mediaType = new MediaType(mediaType.getType(), mediaType.getSubtype()); |
| return MediaType.APPLICATION_JSON_TYPE.isCompatible(mediaType) || MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType) |
| || MediaType.TEXT_XML_TYPE.isCompatible(mediaType); |
| } |
| |
| protected Object convert(InputStream content, String contentType, Class<?> type) throws IOException { |
| if (type == DataSource.class) { |
| return type.cast(new InputStreamDataSource(content, contentType)); |
| } else if (type == InputStream.class) { |
| return type.cast(content); |
| } else if (type == Reader.class) { |
| return type.cast(new InputStreamReader(content, "UTF-8")); |
| } else if (type == String.class) { |
| try { |
| StringWriter sw = new StringWriter(); |
| InputStreamReader reader = new InputStreamReader(content, "UTF-8"); |
| char[] buf = new char[8192]; |
| while (true) { |
| int size = reader.read(buf); |
| if (size < 0) { |
| break; |
| } |
| sw.write(buf, 0, size); |
| } |
| return type.cast(sw.toString()); |
| } catch (Exception e) { |
| throw new IllegalArgumentException(e); |
| } |
| } else if (type == byte[].class) { |
| try { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| byte[] buf = new byte[8192]; |
| while (true) { |
| int size = content.read(buf); |
| if (size < 0) { |
| break; |
| } |
| bos.write(buf, 0, size); |
| } |
| return type.cast(bos.toByteArray()); |
| } catch (Exception e) { |
| throw new IllegalArgumentException(e); |
| } |
| } else { |
| return content; |
| } |
| } |
| |
| protected void write(OutputStream out, Object content, Class<?> type) throws IOException { |
| if (content == null) { |
| return; |
| } |
| InputStream in = null; |
| if (DataSource.class.isAssignableFrom(type)) { |
| in = ((DataSource)content).getInputStream(); |
| } else if (InputStream.class.isAssignableFrom(type)) { |
| in = (InputStream)content; |
| } else if (type == String.class) { |
| in = new ByteArrayInputStream(((String)content).getBytes("UTF-8")); |
| } else if (type == byte[].class) { |
| in = new ByteArrayInputStream((byte[])content); |
| } |
| if (in == null) { |
| throw new IllegalArgumentException("Type is not supported: " + type); |
| } |
| byte[] buf = new byte[8192]; |
| while (true) { |
| int len = in.read(buf); |
| if (len < 0) { |
| in.close(); |
| break; |
| } |
| out.write(buf, 0, len); |
| } |
| } |
| |
| public static final class InputStreamDataSource implements DataSource { |
| |
| public static final String DEFAULT_TYPE = "application/octet-stream"; |
| |
| private final InputStream in; |
| private final String ctype; |
| |
| public InputStreamDataSource(InputStream in) { |
| this(in, null); |
| } |
| |
| public InputStreamDataSource(InputStream in, String ctype) { |
| this.in = in; |
| this.ctype = (ctype != null) ? ctype : DEFAULT_TYPE; |
| } |
| |
| public String getContentType() { |
| return ctype; |
| } |
| |
| public String getName() { |
| return null; |
| } |
| |
| public InputStream getInputStream() throws IOException { |
| return in; |
| } |
| |
| public OutputStream getOutputStream() throws IOException { |
| return null; |
| } |
| |
| } |
| } |