/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.camel.component.catalog;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import javax.activation.MimeType;
import org.apache.camel.CamelContext;
import org.apache.camel.Component;
import org.apache.camel.Exchange;
import org.apache.camel.FailedToCreateProducerException;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.tika.io.IOUtils;
import org.junit.Test;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.InputTransformer;
import ddf.mime.MimeTypeToTransformerMapper;
import de.kalpatec.pojosr.framework.PojoServiceRegistryFactoryImpl;
import de.kalpatec.pojosr.framework.launch.PojoServiceRegistry;
public class CatalogComponentTest extends CamelTestSupport {
private static final transient Logger LOGGER =
LoggerFactory.getLogger(CatalogComponentTest.class);
private static final String SAMPLE_ID = "12345678900987654321abcdeffedcba";
private final String xmlInput =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<ns3:metacard xmlns:ns1=\"http://www.opengis.net/gml\" xmlns:ns2=\"http://www.w3.org/1999/xlink\" xmlns:ns3=\"urn:catalog:metacard\" xmlns:ns4=\"http://www.w3.org/2001/SMIL20/\" xmlns:ns6=\"http://www.w3.org/2001/SMIL20/Language\" ns1:id=\"1234567890987654321\">\n"
+
"<ns3:type>ddf.metacard</ns3:type>\n" +
"<ns3:source>foobar</ns3:source>\n" +
"<ns3:string name=\"title\">\n" +
"<ns3:value>Title!</ns3:value>\n" +
"</ns3:string>\n" +
"<ns3:dateTime name=\"modified\"/>\n" +
"<ns3:string name=\"metadata-content-type-version\"/>\n" +
"<ns3:base64Binary name=\"thumbnail\">\n" +
"<ns3:value>AAABAAABAQEAAQAAAQEBAAEAAAEBAQABAAABAQEAAQAAAQEBAAEAAAEBAQABAAABAQE=</ns3:value>\n"
+
"</ns3:base64Binary>\n" +
"<ns3:dateTime name=\"expiration\">\n" +
"<ns3:value>2012-12-27T16:31:01.641-07:00</ns3:value>\n" +
"</ns3:dateTime>\n" +
"<ns3:string name=\"metadata-target-namespace\"/>\n" +
"<ns3:dateTime name=\"created\"/>\n" +
"<ns3:stringxml name=\"metadata\">\n" +
"<ns3:value>\n" +
"<foo xmlns=\"http://foo.com\">\n" +
"<bar/>\n" +
"</foo>\n" +
"</ns3:value>\n" +
"</ns3:stringxml>\n" +
"<ns3:string name=\"resource-size\"/>\n" +
"<ns3:string name=\"metadata-content-type\"/>\n" +
"<ns3:geometry name=\"location\">\n" +
"<ns3:value>\n" +
"<ns1:Polygon>\n" +
"<ns1:exterior>\n" +
"<ns1:LinearRing>\n" +
"<ns1:pos>35.0 10.0</ns1:pos>\n" +
"<ns1:pos>10.0 20.0</ns1:pos>\n" +
"<ns1:pos>15.0 40.0</ns1:pos>\n" +
"<ns1:pos>45.0 45.0</ns1:pos>\n" +
"<ns1:pos>35.0 10.0</ns1:pos>\n" +
"</ns1:LinearRing>\n" +
"</ns1:exterior>\n" +
"<ns1:interior>\n" +
"<ns1:LinearRing>\n" +
"<ns1:pos>20.0 30.0</ns1:pos>\n" +
"<ns1:pos>35.0 35.0</ns1:pos>\n" +
"<ns1:pos>30.0 20.0</ns1:pos>\n" +
"<ns1:pos>20.0 30.0</ns1:pos>\n" +
"</ns1:LinearRing>\n" +
"</ns1:interior>\n" +
"</ns1:Polygon>\n" +
"</ns3:value>\n" +
"</ns3:geometry>\n" +
"<ns3:string name=\"resource-uri\"/>\n" +
"<ns3:dateTime name=\"effective\"/>\n" +
"</ns3:metacard>";
private BundleContext bundleContext;
private CatalogComponent catalogComponent;
// The route being tested
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
// NOTE: While this supports defining multiple routes, each route
// must
// have a different from URI. So it is not possible to test multiple
// routes
// in a single unit test class/file.
public void configure() {
LOGGER.debug("INSIDE RouteBuilder.configure()");
from("catalog:inputtransformer?" + CatalogComponent.MIME_TYPE_PARAMETER
+ "=text/xml&id=identity").to(
"catalog:inputtransformer?" + CatalogComponent.MIME_TYPE_PARAMETER
+ "=text/xml&id=xml")
.to("mock:result");
}
};
}
@Override
protected CamelContext createCamelContext() throws Exception {
LOGGER.debug("INSIDE createCamelContext");
CamelContext camelContext = super.createCamelContext();
// Configure PojoSR to be our mock OSGi Registry
PojoServiceRegistry reg =
new PojoServiceRegistryFactoryImpl().newPojoServiceRegistry(new HashMap());
bundleContext = reg.getBundleContext();
// Since the Camel BlueprintComponentResolver does not execute outside
// of an OSGi container, we cannot
// rely on the CatalogComponentResolver to be used for resolving the
// CatalogComponent when Camel loads the route.
// Therefore, we Mock what the CatalogComponent's blueprint.xml file
// would have done by creating a
// CatalogComponent explicitly and adding it to the CamelContext used
// for this unit test.
catalogComponent = new CatalogComponent();
catalogComponent.setBundleContext(bundleContext);
camelContext.addComponent(CatalogComponent.NAME, catalogComponent);
return camelContext;
}
@Test
public void testCatalogComponentResolver() throws Exception {
CatalogComponentResolver resolver = new CatalogComponentResolver(catalogComponent);
assertNotNull(resolver);
Component component = resolver.resolveComponent(CatalogComponent.NAME, null);
assertNotNull(component);
component = resolver.resolveComponent("invalid_name", null);
assertNull(component);
}
@Test
public void testInvalidContextPathForProducer() {
try {
LOGGER.debug("INSIDE testInvalidContextPathForProducer");
template.sendBody("catalog:unknown?mimeType=text/xml&id=identity", "<xml></xml>");
fail("Should have thrown a FailedToCreateProducerException");
} catch (FailedToCreateProducerException e) {
LOGGER.error("Failed to create producer", e);
assertTrue("Should be an IllegalArgumentException exception",
e.getCause() instanceof IllegalArgumentException);
assertEquals("Unable to create producer for context path [unknown]",
e.getCause()
.getMessage());
}
}
@Test
public void testInvalidContextPathForProducer2() {
try {
LOGGER.debug("INSIDE testInvalidContextPathForProducer2");
context.getEndpoint("catalog:unknown?mimeType=text/xml&id=identity")
.createProducer();
fail("Should have thrown a IllegalArgumentException");
} catch (Exception e) {
LOGGER.error("Failed testInvalidContextPathForProducer2", e);
assertTrue("Should be an IllegalArgumentException exception",
e instanceof IllegalArgumentException);
assertEquals("Unable to create producer for context path [unknown]", e.getMessage());
}
}
@Test
public void testInvalidContextPathForConsumer() {
try {
LOGGER.debug("INSIDE testInvalidContextPathForConsumer");
context.getEndpoint("catalog:unknown?mimeType=text/xml&id=identity")
.createConsumer(new Processor() {
public void process(Exchange exchange) throws Exception {
}
});
fail("Should have thrown a IllegalArgumentException");
} catch (Exception e) {
LOGGER.error("Failed testInvalidContextPathForConsumer", e);
assertTrue("Should be an IllegalArgumentException exception",
e instanceof IllegalArgumentException);
assertEquals("Unable to create consumer for context path [unknown]", e.getMessage());
}
}
@Test
public void testTransformMetacardNoMimeTypeToTransformerMapperRegistered() throws Exception {
LOGGER.debug("Running testTransformMetacard_NoMimeTypeToTransformerMapperRegistered()");
catalogComponent.setMimeTypeToTransformerMapper(null);
// Mock a XML InputTransformer and register it in the OSGi Registry
// (PojoSR)
InputTransformer mockTransformer = getMockInputTransformer();
Hashtable<String, String> props = new Hashtable<String, String>();
props.put(MimeTypeToTransformerMapper.ID_KEY, "xml");
props.put(MimeTypeToTransformerMapper.MIME_TYPE_KEY, "text/xml");
bundleContext.registerService(InputTransformer.class.getName(), mockTransformer, props);
// Send in sample XML as InputStream to InputTransformer
InputStream input = IOUtils.toInputStream(xmlInput);
// Get the InputTransformer registered with the ID associated with the
// <from> node in the Camel route
InputTransformer transformer = getTransformer("text/xml", "identity");
assertNotNull("InputTransformer for text/xml;id=identity not found", transformer);
// Attempt to transform the XML input into a Metacard
try {
transformer.transform(input);
fail("Should have thrown a CatalogTransformerException");
} catch (CatalogTransformerException e) {
assertEquals("Did not find a MimeTypeToTransformerMapper service", e.getMessage());
}
}
@Test
public void testTransformMetacardNoProducerInputTransformerRegistered() throws Exception {
LOGGER.debug("Running testTransformMetacard()");
// Mock the MimeTypeToTransformerMapper and register it in the OSGi
// Registry (PojoSR)
MimeTypeToTransformerMapper matchingService = mock(MimeTypeToTransformerMapper.class);
// bundleContext.registerService(
// MimeTypeToTransformerMapper.class.getName(), matchingService, null );
catalogComponent.setMimeTypeToTransformerMapper(matchingService);
// Mock the MimeTypeToTransformerMapper returning empty list of
// InputTransformers
List list = new ArrayList<InputTransformer>();
when(matchingService.findMatches(eq(InputTransformer.class),
isA(MimeType.class))).thenReturn(list);
// Send in sample XML as InputStream to InputTransformer
InputStream input = IOUtils.toInputStream(xmlInput);
// Get the InputTransformer registered with the ID associated with the
// <from> node in the Camel route
InputTransformer transformer = getTransformer("text/xml", "identity");
assertNotNull("InputTransformer for text/xml;id=identity not found", transformer);
// Attempt to transform the XML input into a Metacard
try {
transformer.transform(input);
fail("Should have thrown a CatalogTransformerException");
} catch (CatalogTransformerException e) {
assertEquals("Did not find an InputTransformer for MIME Type [text/xml] and id [xml]",
e.getMessage());
}
}
@Test
public void testTransformMetacard() throws Exception {
LOGGER.debug("Running testTransformMetacard()");
MockEndpoint mock = getMockEndpoint("mock:result");
mock.expectedMinimumMessageCount(1);
// Mock a XML InputTransformer and register it in the OSGi Registry
// (PojoSR)
InputTransformer mockTransformer = getMockInputTransformer();
Hashtable<String, String> props = new Hashtable<String, String>();
props.put(MimeTypeToTransformerMapper.ID_KEY, "xml");
props.put(MimeTypeToTransformerMapper.MIME_TYPE_KEY, "text/xml");
bundleContext.registerService(InputTransformer.class.getName(), mockTransformer, props);
// Mock the MimeTypeToTransformerMapper and register it in the OSGi
// Registry (PojoSR)
MimeTypeToTransformerMapper matchingService = mock(MimeTypeToTransformerMapper.class);
// HUGH bundleContext.registerService(
// MimeTypeToTransformerMapper.class.getName(), matchingService, null );
catalogComponent.setMimeTypeToTransformerMapper(matchingService);
// Mock the MimeTypeToTransformerMapper returning the mock XML
// InputTransformer
when(matchingService.findMatches(eq(InputTransformer.class),
isA(MimeType.class))).thenReturn((List) Arrays.asList(mockTransformer));
// Send in sample XML as InputStream to InputTransformer
InputStream input = IOUtils.toInputStream(xmlInput);
// Get the InputTransformer registered with the ID associated with the
// <from> node in the Camel route
InputTransformer transformer = getTransformer("text/xml", "identity");
assertNotNull("InputTransformer for mimeType=text/xml&id=identity not found", transformer);
// Transform the XML input into a Metacard
Metacard metacard = transformer.transform(input);
assertNotNull(metacard);
assertMockEndpointsSatisfied();
}
/**
* Looks up the InputTransformer registered in the OSGi registry (PojoSR) that maps to the mime
* type that the <from> node in the Camel route registered as.
*
* @param mimeType
* @return
* @throws Exception
*/
private InputTransformer getTransformer(String mimeType, String id) throws Exception {
LOGGER.trace("ENTERING: getTransformer");
InputTransformer transformer = null;
ServiceReference[] refs = null;
try {
String filter =
"(&(" + MimeTypeToTransformerMapper.MIME_TYPE_KEY + "=" + mimeType + ")("
+ MimeTypeToTransformerMapper.ID_KEY + "=" + id + "))";
LOGGER.debug("Looking for InputTransformer with filter: {}", filter);
refs = bundleContext.getServiceReferences(InputTransformer.class.getName(), filter);
} catch (Exception e) {
String msg = "Invalid input transformer for mime type: " + mimeType;
LOGGER.debug(msg, e);
throw new Exception(msg);
}
if (refs != null && refs.length > 0) {
transformer = (InputTransformer) bundleContext.getService(refs[0]);
LOGGER.debug("Found an InputTransformer: {}",
transformer.getClass()
.getName());
}
LOGGER.trace("EXITING: getTransformer");
return transformer;
}
/**
* Mock an InputTransformer, returning a canned Metacard when the transform() method is invoked
* on the InputTransformer.
*
* @return
*/
protected InputTransformer getMockInputTransformer() {
InputTransformer inputTransformer = mock(InputTransformer.class);
Metacard generatedMetacard = getSimpleMetacard();
try {
when(inputTransformer.transform(isA(InputStream.class))).thenReturn(generatedMetacard);
when(inputTransformer.transform(isA(InputStream.class), isA(String.class))).thenReturn(
generatedMetacard);
} catch (IOException e) {
LOGGER.debug("IOException", e);
} catch (CatalogTransformerException e) {
LOGGER.debug("CatalogTransformerException", e);
}
return inputTransformer;
}
protected Metacard getSimpleMetacard() {
MetacardImpl generatedMetacard = new MetacardImpl();
generatedMetacard.setMetadata(getSample());
generatedMetacard.setId(SAMPLE_ID);
return generatedMetacard;
}
private String getSample() {
return "<xml></xml>";
}
}