/*******************************************************************************
* 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.wink.common.internal.providers.jaxb;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Providers;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLStreamException;
import org.apache.wink.common.RuntimeContext;
import org.apache.wink.common.internal.WinkConfiguration;
import org.apache.wink.common.internal.contexts.MediaTypeCharsetAdjuster;
import org.apache.wink.common.internal.providers.entity.xml.JAXBCollectionXmlProvider;
import org.apache.wink.common.internal.providers.jaxb.jaxb1.AddNumbers;
import org.apache.wink.common.internal.providers.jaxb.jaxb1.MyPojo;
import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.common.model.JAXBUnmarshalOptions;
import org.apache.wink.common.model.XmlFormattingOptions;
import org.jmock.Expectations;
import org.jmock.integration.junit3.MockObjectTestCase;
import org.junit.After;
import org.junit.Before;
import org.w3c.dom.Document;
public class AbstractJAXBCollectionProviderTest extends MockObjectTestCase {
public class MyJAXBXmlProvider extends JAXBCollectionXmlProvider {
MyJAXBXmlProvider() {
super();
providers = AbstractJAXBCollectionProviderTest.this.providers;
}
/*
* simulate what would happen if application had supplied a JAXBContext provider
*/
@Override
protected JAXBContext getContext(Class<?> type, MediaType mediaType)
throws JAXBException {
// use JAXBContext.newInstance(String). The default in AbstractJAXBProvider is JAXBContext.newInstance(Class)
return JAXBContext.newInstance(type.getPackage().getName());
}
}
static String path = null;
static {
String classpath = System.getProperty("java.class.path");
StringTokenizer tokenizer = new StringTokenizer(classpath, System.getProperty("path.separator"));
while (tokenizer.hasMoreTokens()) {
path = tokenizer.nextToken();
if (path.endsWith("test-classes")) {
break;
}
}
// for windows:
int driveIndex = path.indexOf(":");
if(driveIndex != -1) {
path = path.substring(driveIndex + 1);
}
}
static final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<addNumberss>" +
"<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:arg0>1</ns2:arg0>" +
"<ns2:arg1>2</ns2:arg1>" +
"</ns2:addNumbers>" +
"<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:arg0>1</ns2:arg0>" +
"<ns2:arg1>3</ns2:arg1>" +
"</ns2:addNumbers>" +
"</addNumberss>";
static final String xmlMyPojo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<myPojos>" +
"<ns2:myPojo xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:stringdata>1</ns2:stringdata>" +
"</ns2:myPojo>" +
"<ns2:myPojo xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:stringdata>2</ns2:stringdata>" +
"</ns2:myPojo>" +
"</myPojos>";
static final String xmlWithDTD = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<!DOCTYPE data [<!ENTITY file SYSTEM \"file:"+ path +"/etc/ProvidersJAXBTest.txt\">]>" +
"<addNumberss>" +
"<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:arg0>&file;</ns2:arg0>" +
"<ns2:arg1>2</ns2:arg1>" +
"</ns2:addNumbers>" +
"<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:arg0>&file;</ns2:arg0>" +
"<ns2:arg1>3</ns2:arg1>" +
"</ns2:addNumbers>" +
"</addNumberss>";
static final String xmlMyPojoWithDTD = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<!DOCTYPE data [<!ENTITY file SYSTEM \"file:"+ path +"/etc/ProvidersJAXBTest.txt\">]>" +
"<myPojos>" +
"<ns2:myPojo xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:stringdata>&file;</ns2:stringdata>" +
"</ns2:myPojo>" +
"<ns2:myPojo xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
"<ns2:stringdata>&file;</ns2:stringdata>" +
"</ns2:myPojo>" +
"</myPojos>";
private MessageBodyReader jaxbProviderReader = null;
private MessageBodyWriter jaxbProviderWriter = null;
private Providers providers;
public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {
public JAXBContext getContext(Class<?> arg0) {
try {
return JAXBContext.newInstance(arg0);
} catch (JAXBException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
@Before
public void setUp() {
providers = mock(Providers.class);
final RuntimeContext runtimeContext = mock(RuntimeContext.class);
final WinkConfiguration winkConfiguration = mock(WinkConfiguration.class);
checking(new Expectations() {{
allowing(providers).getContextResolver(JAXBContext.class, MediaType.TEXT_XML_TYPE); will(returnValue(new MyJAXBContextResolver()));
allowing(providers).getContextResolver(XmlFormattingOptions.class, MediaType.TEXT_XML_TYPE); will(returnValue(null));
allowing(providers).getContextResolver(JAXBUnmarshalOptions.class, MediaType.TEXT_XML_TYPE); will(returnValue(null));
allowing(runtimeContext).getAttribute(MediaTypeCharsetAdjuster.class); will(returnValue(null));
allowing(runtimeContext).getAttribute(WinkConfiguration.class); will(returnValue(winkConfiguration));
allowing(winkConfiguration).getProperties(); will(returnValue(null));
}});
RuntimeContextTLS.setRuntimeContext(runtimeContext);
jaxbProviderReader = new MyJAXBXmlProvider();
jaxbProviderWriter = new MyJAXBXmlProvider();
}
@After
public void tearDown() {
// clean up the mess.
RuntimeContextTLS.setRuntimeContext(null);
}
public void testXml() throws Exception {
GenericEntity<List<AddNumbers>> type1 =
new GenericEntity<List<AddNumbers>>(new ArrayList<AddNumbers>()) {
};
assertTrue(jaxbProviderReader.isReadable(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE));
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
Object obj = jaxbProviderReader.readFrom(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE, null, bais);
assertTrue(obj instanceof ArrayList);
ArrayList alist = (ArrayList)obj;
// make sure the objects in the returned list are the actual jaxb objects, not JAXBElement, and the unmarshal worked:
assertEquals(1, ((AddNumbers)alist.get(0)).getArg0());
assertEquals(2, ((AddNumbers)alist.get(0)).getArg1());
assertEquals(1, ((AddNumbers)alist.get(1)).getArg0());
assertEquals(3, ((AddNumbers)alist.get(1)).getArg1());
}
public void testXmlWithDTD() throws Exception {
GenericEntity<List<AddNumbers>> type1 =
new GenericEntity<List<AddNumbers>>(new ArrayList<AddNumbers>()) {
};
assertTrue(jaxbProviderReader.isReadable(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE));
Exception ex = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(xmlWithDTD.getBytes());
Object obj = jaxbProviderReader.readFrom(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE, null, bais);
fail("should have got an exception");
} catch (Exception e) {
ex = e;
}
assertTrue("expected an XMLStreamException", ex.getCause() instanceof XMLStreamException);
// parse it just as a sanity check to make sure our xml is good. No exceptions means good xml!
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(new ByteArrayInputStream(xmlWithDTD.getBytes()));
}
public void testXmlMyPojo() throws Exception {
GenericEntity<List<MyPojo>> type1 =
new GenericEntity<List<MyPojo>>(new ArrayList<MyPojo>()) {
};
assertTrue(jaxbProviderReader.isReadable(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE));
ByteArrayInputStream bais = new ByteArrayInputStream(xmlMyPojo.getBytes());
Object obj = jaxbProviderReader.readFrom(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE, null, bais);
assertTrue(obj instanceof ArrayList);
ArrayList alist = (ArrayList)obj;
// make sure the objects in the returned list are the actual jaxb objects, not JAXBElement, and the unmarshal worked:
assertEquals("1", ((MyPojo)alist.get(0)).getStringdata());
assertEquals("2", ((MyPojo)alist.get(1)).getStringdata());
}
public void testXmlMyPojoWithDTD() throws Exception {
GenericEntity<List<MyPojo>> type1 =
new GenericEntity<List<MyPojo>>(new ArrayList<MyPojo>()) {
};
assertTrue(jaxbProviderReader.isReadable(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE));
Exception ex = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(xmlMyPojoWithDTD.getBytes());
Object obj = jaxbProviderReader.readFrom(type1.getRawType(), type1.getType(), null, MediaType.TEXT_XML_TYPE, null, bais);
fail("should have got an exception");
} catch (Exception e) {
ex = e;
}
assertTrue("expected an XMLStreamException", ex.getCause() instanceof XMLStreamException);
// parse it just as a sanity check to make sure our xml is good. No exceptions means good xml!
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(new ByteArrayInputStream(xmlMyPojoWithDTD.getBytes()));
}
}