use of ddf.catalog.data.BinaryContent in project ddf by codice.
the class Query method getMetacardForId.
/**
* @param searchPhrase The search phrase used to query for the metacard.
* @param proxyTicket The CAS proxy ticket that will be used by the STS to get a SAML assertion.
* @return
*/
private String getMetacardForId(String searchPhrase, String proxyTicket) {
Filter filter = filterBuilder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase);
LOGGER.info("Query filter: {}", filter.toString());
String queryError = "Unable to perform query " + filter.toString() + ".";
QueryRequest request = new QueryRequestImpl(new QueryImpl(filter), true);
StringBuilder responseString = new StringBuilder();
try {
Subject subject = securityManager.getSubject(new CasAuthenticationToken(proxyTicket));
LOGGER.info("Adding {} property with value {} to request", SecurityConstants.SECURITY_SUBJECT, subject);
request.getProperties().put(SecurityConstants.SECURITY_SUBJECT, subject);
} catch (SecurityServiceException se) {
LOGGER.error("Could not retrieve subject from securitymanager.", se);
return queryError;
}
try {
LOGGER.debug("About to query the catalog framework with query {}", filter.toString());
QueryResponse queryResponse = catalogFramework.query(request, null);
LOGGER.debug("Got query response from catalog framework for query {}", filter.toString());
List<Result> results = queryResponse.getResults();
if (results != null) {
String message = "The query for " + filter.toString() + " returned " + results.size() + " results.";
responseString.append(message);
LOGGER.debug(message);
for (Result curResult : results) {
Metacard metacard = curResult.getMetacard();
LOGGER.debug("Transforming the metacard with id [{}] to xml.", metacard.getId());
BinaryContent content = catalogFramework.transform(metacard, "xml", null);
StringWriter writer = new StringWriter();
IOUtils.copy(content.getInputStream(), writer, "UTF8");
LOGGER.debug("Formatting xml for metacard with id [{}].", metacard.getId());
responseString.append(format(writer.toString()));
}
} else {
String message = "The query for " + filter.toString() + " returned a null result.";
responseString.append(message);
LOGGER.warn(message);
}
} catch (SourceUnavailableException e) {
LOGGER.error(queryError, e);
} catch (UnsupportedQueryException e) {
LOGGER.error(queryError, e);
} catch (FederationException e) {
LOGGER.error(queryError, e);
} catch (CatalogTransformerException e) {
LOGGER.error(queryError, e);
} catch (IOException e) {
LOGGER.error(queryError, e);
}
return responseString.toString();
}
use of ddf.catalog.data.BinaryContent in project ddf by codice.
the class RESTEndpoint method getDocument.
/**
* REST Get. Retrieves the metadata entry specified by the id from the federated source
* specified by sourceid. Transformer argument is optional, but is used to specify what format
* the data should be returned.
*
* @param encodedSourceId
* @param encodedId
* @param transformerParam
* @param uriInfo
* @return
*/
@GET
@Path("/sources/{sourceid}/{id}")
public Response getDocument(@Encoded @PathParam("sourceid") String encodedSourceId, @Encoded @PathParam("id") String encodedId, @QueryParam("transform") String transformerParam, @Context UriInfo uriInfo, @Context HttpServletRequest httpRequest) {
Response response = null;
Response.ResponseBuilder responseBuilder;
QueryResponse queryResponse;
Metacard card = null;
LOGGER.trace("GET");
URI absolutePath = uriInfo.getAbsolutePath();
MultivaluedMap<String, String> map = uriInfo.getQueryParameters();
if (encodedId != null) {
LOGGER.debug("Got id: {}", encodedId);
LOGGER.debug("Got service: {}", transformerParam);
LOGGER.debug("Map of query parameters: \n{}", map.toString());
Map<String, Serializable> convertedMap = convert(map);
convertedMap.put("url", absolutePath.toString());
LOGGER.debug("Map converted, retrieving product.");
// default to xml if no transformer specified
try {
String id = URLDecoder.decode(encodedId, CharEncoding.UTF_8);
String transformer = DEFAULT_METACARD_TRANSFORMER;
if (transformerParam != null) {
transformer = transformerParam;
}
Filter filter = getFilterBuilder().attribute(Metacard.ID).is().equalTo().text(id);
Collection<String> sources = null;
if (encodedSourceId != null) {
String sourceid = URLDecoder.decode(encodedSourceId, CharEncoding.UTF_8);
sources = new ArrayList<String>();
sources.add(sourceid);
}
QueryRequestImpl request = new QueryRequestImpl(new QueryImpl(filter), sources);
request.setProperties(convertedMap);
queryResponse = catalogFramework.query(request, null);
// pull the metacard out of the blocking queue
List<Result> results = queryResponse.getResults();
// return null if timeout elapsed)
if (results != null && !results.isEmpty()) {
card = results.get(0).getMetacard();
}
if (card == null) {
throw new ServerErrorException("Unable to retrieve requested metacard.", Status.NOT_FOUND);
}
// Check for Range header set the value in the map appropriately so that the catalogFramework
// can take care of the skipping
long bytesToSkip = getRangeStart(httpRequest);
if (bytesToSkip > 0) {
LOGGER.debug("Bytes to skip: {}", String.valueOf(bytesToSkip));
convertedMap.put(BYTES_TO_SKIP, bytesToSkip);
}
LOGGER.debug("Calling transform.");
final BinaryContent content = catalogFramework.transform(card, transformer, convertedMap);
LOGGER.debug("Read and transform complete, preparing response.");
responseBuilder = Response.ok(content.getInputStream(), content.getMimeTypeValue());
// Add the Accept-ranges header to let the client know that we accept ranges in bytes
responseBuilder.header(HEADER_ACCEPT_RANGES, BYTES);
String filename = null;
if (content instanceof Resource) {
// If we got a resource, we can extract the filename.
filename = ((Resource) content).getName();
} else {
String fileExtension = getFileExtensionForMimeType(content.getMimeTypeValue());
if (StringUtils.isNotBlank(fileExtension)) {
filename = id + fileExtension;
}
}
if (StringUtils.isNotBlank(filename)) {
LOGGER.debug("filename: {}", filename);
responseBuilder.header(HEADER_CONTENT_DISPOSITION, "inline; filename=\"" + filename + "\"");
}
long size = content.getSize();
if (size > 0) {
responseBuilder.header(HEADER_CONTENT_LENGTH, size);
}
response = responseBuilder.build();
} catch (FederationException e) {
String exceptionMessage = "READ failed due to unexpected exception: ";
LOGGER.info(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.INTERNAL_SERVER_ERROR);
} catch (CatalogTransformerException e) {
String exceptionMessage = "Unable to transform Metacard. Try different transformer: ";
LOGGER.info(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.INTERNAL_SERVER_ERROR);
} catch (SourceUnavailableException e) {
String exceptionMessage = "Cannot obtain query results because source is unavailable: ";
LOGGER.info(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.INTERNAL_SERVER_ERROR);
} catch (UnsupportedQueryException e) {
String exceptionMessage = "Specified query is unsupported. Change query and resubmit: ";
LOGGER.info(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.BAD_REQUEST);
} catch (DataUsageLimitExceededException e) {
String exceptionMessage = "Unable to process request. Data usage limit exceeded: ";
LOGGER.debug(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.REQUEST_ENTITY_TOO_LARGE);
// The catalog framework will throw this if any of the transformers blow up.
// We need to catch this exception here or else execution will return to CXF and
// we'll lose this message and end up with a huge stack trace in a GUI or whatever
// else is connected to this endpoint
} catch (RuntimeException | UnsupportedEncodingException e) {
String exceptionMessage = "Unknown error occurred while processing request: ";
LOGGER.info(exceptionMessage, e);
throw new ServerErrorException(exceptionMessage, Status.INTERNAL_SERVER_ERROR);
}
} else {
throw new ServerErrorException("No ID specified.", Status.BAD_REQUEST);
}
return response;
}
use of ddf.catalog.data.BinaryContent in project ddf by codice.
the class RESTEndpoint method getDocument.
/**
* REST Get. Retrieves information regarding sources available.
*
* @param uriInfo
* @param httpRequest
* @return
*/
@GET
@Path(SOURCES_PATH)
public Response getDocument(@Context UriInfo uriInfo, @Context HttpServletRequest httpRequest) {
BinaryContent content;
ResponseBuilder responseBuilder;
String sourcesString = null;
JSONArray resultsList = new JSONArray();
SourceInfoResponse sources;
try {
SourceInfoRequestEnterprise sourceInfoRequestEnterprise = new SourceInfoRequestEnterprise(true);
sources = catalogFramework.getSourceInfo(sourceInfoRequestEnterprise);
for (SourceDescriptor source : sources.getSourceInfo()) {
JSONObject sourceObj = new JSONObject();
sourceObj.put("id", source.getSourceId());
sourceObj.put("version", source.getVersion() != null ? source.getVersion() : "");
sourceObj.put("available", Boolean.valueOf(source.isAvailable()));
JSONArray contentTypesObj = new JSONArray();
if (source.getContentTypes() != null) {
for (ContentType contentType : source.getContentTypes()) {
if (contentType != null && contentType.getName() != null) {
JSONObject contentTypeObj = new JSONObject();
contentTypeObj.put("name", contentType.getName());
contentTypeObj.put("version", contentType.getVersion() != null ? contentType.getVersion() : "");
contentTypesObj.add(contentTypeObj);
}
}
}
sourceObj.put("contentTypes", contentTypesObj);
resultsList.add(sourceObj);
}
} catch (SourceUnavailableException e) {
LOGGER.info("Unable to retrieve Sources. {}", e.getMessage());
LOGGER.debug("Unable to retrieve Sources", e);
}
sourcesString = JSONValue.toJSONString(resultsList);
content = new BinaryContentImpl(new ByteArrayInputStream(sourcesString.getBytes(StandardCharsets.UTF_8)), jsonMimeType);
responseBuilder = Response.ok(content.getInputStream(), content.getMimeTypeValue());
// Add the Accept-ranges header to let the client know that we accept ranges in bytes
responseBuilder.header(HEADER_ACCEPT_RANGES, BYTES);
return responseBuilder.build();
}
use of ddf.catalog.data.BinaryContent in project ddf by codice.
the class TestRestEndpoint method mockTestSetup.
/**
* Creates the mock setup for the GET tests above. Parameters provide the CatalogFramework, which will be
* setup for the test, and also specify which test case is being run.
*
* @param framework
* @param testType
* @return
* @throws Exception
*/
protected String mockTestSetup(CatalogFramework framework, TestType testType) throws Exception, ResourceNotSupportedException {
String transformer = null;
QueryResponse queryResponse = mock(QueryResponse.class);
when(framework.query(isA(QueryRequest.class), isNull(FederationStrategy.class))).thenReturn(queryResponse);
List<Result> list = null;
MetacardImpl metacard = null;
Result result = mock(Result.class);
InputStream inputStream = null;
switch(testType) {
case QUERY_RESPONSE_TEST:
when(queryResponse.getResults()).thenReturn(list);
break;
case METACARD_TEST:
list = new ArrayList<Result>();
list.add(result);
when(queryResponse.getResults()).thenReturn(list);
when(result.getMetacard()).thenReturn(metacard);
break;
case RESOURCE_TEST:
transformer = "resource";
case SUCCESS_TEST:
list = new ArrayList<Result>();
list.add(result);
when(queryResponse.getResults()).thenReturn(list);
metacard = new MetacardImpl();
metacard.setSourceId(GET_SITENAME);
when(result.getMetacard()).thenReturn(metacard);
Resource resource = mock(Resource.class);
inputStream = new ByteArrayInputStream(GET_STREAM.getBytes(GET_OUTPUT_TYPE));
when(resource.getInputStream()).thenReturn(inputStream);
when(resource.getMimeTypeValue()).thenReturn(GET_MIME_TYPE);
when(resource.getName()).thenReturn(GET_FILENAME);
when(framework.transform(isA(Metacard.class), anyString(), isA(Map.class))).thenReturn(resource);
break;
case KML_TEST:
transformer = "kml";
list = new ArrayList<Result>();
list.add(result);
when(queryResponse.getResults()).thenReturn(list);
metacard = new MetacardImpl();
metacard.setSourceId(GET_SITENAME);
when(result.getMetacard()).thenReturn(metacard);
BinaryContent content = mock(BinaryContent.class);
inputStream = new ByteArrayInputStream(GET_STREAM.getBytes(GET_OUTPUT_TYPE));
when(content.getInputStream()).thenReturn(inputStream);
when(content.getMimeTypeValue()).thenReturn(GET_KML_MIME_TYPE);
when(framework.transform(isA(Metacard.class), anyString(), isA(Map.class))).thenReturn(content);
break;
}
return transformer;
}
use of ddf.catalog.data.BinaryContent in project ddf by codice.
the class AtomTransformer method transform.
@Override
public BinaryContent transform(SourceResponse sourceResponse, Map<String, Serializable> arguments) throws CatalogTransformerException {
if (sourceResponse == null) {
throw new CatalogTransformerException("Cannot transform null " + SourceResponse.class.getName());
}
Date currentDate = new Date();
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
Feed feed = null;
try {
Thread.currentThread().setContextClassLoader(AtomTransformer.class.getClassLoader());
feed = ABDERA.newFeed();
} finally {
Thread.currentThread().setContextClassLoader(tccl);
}
/*
* Atom spec text (rfc4287) Sect 4.2.14: "The "atom:title" element is a Text construct that
* conveys a human- readable title for an entry or feed."
*/
feed.setTitle(DEFAULT_FEED_TITLE);
feed.setUpdated(currentDate);
// TODO Use the same id for the same query
// one challenge is a query in one site should not have the same feed id
// as a query in another site probably could factor in ddf.host and port
// into the algorithm
feed.setId(URN_UUID + UUID.randomUUID().toString());
// TODO SELF LINK For the Feed, possible design --> serialize Query into
// a URL
/*
* Atom spec text (rfc4287): "atom:feed elements SHOULD contain one atom:link element with a
* rel attribute value of self. This is the preferred URI for retrieving Atom Feed Documents
* representing this Atom feed. "
*/
feed.addLink("#", Link.REL_SELF);
if (!StringUtils.isEmpty(SystemInfo.getOrganization())) {
feed.addAuthor(SystemInfo.getOrganization());
} else {
feed.addAuthor(DEFAULT_AUTHOR);
}
/*
* Atom spec text (rfc4287 sect. 4.2.4): "The "atom:generator" element's content identifies
* the agent used to generate a feed, for debugging and other purposes." Generator is not
* required in the atom:feed element.
*/
if (!StringUtils.isEmpty(SystemInfo.getSiteName())) {
// text is required.
feed.setGenerator(null, SystemInfo.getVersion(), SystemInfo.getSiteName());
}
/*
* According to http://www.opensearch.org/Specifications/OpenSearch/1.1 specification,
* totalResults must be a non-negative integer. Requirements: This attribute is optional.
*/
if (sourceResponse.getHits() > -1) {
Element hits = feed.addExtension(OpenSearchConstants.TOTAL_RESULTS);
hits.setText(Long.toString(sourceResponse.getHits()));
}
if (sourceResponse.getRequest() != null && sourceResponse.getRequest().getQuery() != null) {
Element itemsPerPage = feed.addExtension(OpenSearchConstants.ITEMS_PER_PAGE);
Element startIndex = feed.addExtension(OpenSearchConstants.START_INDEX);
/*
* According to http://www.opensearch.org/Specifications/OpenSearch/1.1 specification,
* itemsPerPage must be a non-negative integer. It is possible that Catalog pageSize is
* set to a non-negative integer though. When non-negative we will instead we will
* change it to the number of search results on current page.
*/
if (sourceResponse.getRequest().getQuery().getPageSize() > -1) {
itemsPerPage.setText(Integer.toString(sourceResponse.getRequest().getQuery().getPageSize()));
} else {
if (sourceResponse.getResults() != null) {
itemsPerPage.setText(Integer.toString(sourceResponse.getResults().size()));
}
}
startIndex.setText(Integer.toString(sourceResponse.getRequest().getQuery().getStartIndex()));
}
for (Result result : sourceResponse.getResults()) {
Metacard metacard = result.getMetacard();
if (metacard == null) {
continue;
}
Entry entry = feed.addEntry();
String sourceName = DEFAULT_SOURCE_ID;
if (result.getMetacard().getSourceId() != null) {
sourceName = result.getMetacard().getSourceId();
}
Element source = entry.addExtension(new QName(FEDERATION_EXTENSION_NAMESPACE, "resultSource", "fs"));
/*
* According to the os-federation.xsd, the resultSource element text has a max length of
* 16 and is the shortname of the source id. Previously, we were duplicating the names
* in both positions, but since we truly do not have a shortname for our source ids, I
* am purposely omitting the shortname text and leaving it as the empty string. The real
* source id can still be found in the attribute instead.
*/
source.setAttributeValue(new QName(FEDERATION_EXTENSION_NAMESPACE, "sourceId"), sourceName);
if (result.getRelevanceScore() != null) {
Element relevance = entry.addExtension(new QName("http://a9.com/-/opensearch/extensions/relevance/1.0/", "score", "relevance"));
relevance.setText(result.getRelevanceScore().toString());
}
entry.setId(URN_CATALOG_ID + metacard.getId());
/*
* Atom spec text (rfc4287): "The "atom:title" element is a Text construct that conveys
* a human- readable title for an entry or feed."
*/
entry.setTitle(metacard.getTitle());
/*
* Atom spec text (rfc4287): "The "atom:updated" element is a Date construct indicating
* the most recent instant in time when an entry or feed was modified in a way the
* publisher considers significant." Therefore, a new Date is used because we are making
* the entry for the first time.
*/
if (metacard.getModifiedDate() != null) {
entry.setUpdated(metacard.getModifiedDate());
} else {
entry.setUpdated(currentDate);
}
/*
* Atom spec text (rfc4287): "Typically, atom:published will be associated with the
* initial creation or first availability of the resource."
*/
if (metacard.getCreatedDate() != null) {
entry.setPublished(metacard.getCreatedDate());
}
/*
* For atom:link elements, Atom spec text (rfc4287): "The value "related" signifies that
* the IRI in the value of the href attribute identifies a resource related to the
* resource described by the containing element."
*/
addLink(resourceActionProvider, metacard, entry, Link.REL_RELATED);
addLink(viewMetacardActionProvider, metacard, entry, Link.REL_ALTERNATE);
addLink(thumbnailActionProvider, metacard, entry, REL_PREVIEW);
/*
* Atom spec text (rfc4287) Sect. 4.2.2.: "The "atom:category" element conveys
* information about a category associated with an entry or feed. This specification
* assigns no meaning to the content (if any) of this element."
*/
if (metacard.getContentTypeName() != null) {
entry.addCategory(metacard.getContentTypeName());
}
for (Position position : getGeoRssPositions(metacard)) {
GeoHelper.addPosition(entry, position, Encoding.GML);
}
BinaryContent binaryContent = null;
String contentOutput = metacard.getId();
Type atomContentType = Type.TEXT;
if (metacardTransformer != null) {
try {
binaryContent = metacardTransformer.transform(metacard, new HashMap<>());
} catch (CatalogTransformerException | RuntimeException e) {
LOGGER.debug(COULD_NOT_CREATE_XML_CONTENT_MESSAGE, e);
}
if (binaryContent != null) {
try {
byte[] xmlBytes = binaryContent.getByteArray();
if (xmlBytes != null && xmlBytes.length > 0) {
contentOutput = new String(xmlBytes, StandardCharsets.UTF_8);
atomContentType = Type.XML;
}
} catch (IOException e) {
LOGGER.debug(COULD_NOT_CREATE_XML_CONTENT_MESSAGE, e);
}
}
}
tccl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(AtomTransformer.class.getClassLoader());
entry.setContent(contentOutput, atomContentType);
} finally {
Thread.currentThread().setContextClassLoader(tccl);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
tccl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(AtomTransformer.class.getClassLoader());
feed.writeTo(baos);
} finally {
Thread.currentThread().setContextClassLoader(tccl);
}
} catch (IOException e) {
LOGGER.info("Could not write to output stream.", e);
throw new CatalogTransformerException("Could not transform into Atom.", e);
}
return new BinaryContentImpl(new ByteArrayInputStream(baos.toByteArray()), MIME_TYPE);
}
Aggregations