/**
* Copyright (C) 2014 Cohesive Integrations, LLC (info@cohesiveintegrations.com)
*
* Licensed 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 net.di2e.ecdr.commons.util;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import net.di2e.ecdr.api.config.DateTypeConfiguration;
import net.di2e.ecdr.api.config.SortTypeConfiguration;
import net.di2e.ecdr.commons.constants.SearchConstants;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;
import org.joda.time.format.ISODateTimeFormat;
import org.opengis.filter.Filter;
import org.opengis.filter.sort.SortBy;
import org.opengis.filter.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.filter.impl.SortByImpl;
import ddf.catalog.operation.Query;
import ddf.catalog.operation.QueryResponse;
import ddf.catalog.source.UnsupportedQueryException;
/**
* Utility class that contains helper methods.
*/
public final class SearchUtils {
private static final Logger LOGGER = LoggerFactory.getLogger( SearchUtils.class );
private static final String MAP_ENTRY_DELIMITER = "=";
private static DateTimeFormatter formatter;
/*
* The OpenSearch specification uses RFC 3339, which is a specific profile of the ISO 8601 standard and corresponds
* to the second and (as a "rarely used option") the first parser below. We additionally support the corresponding
* ISO 8601 Basic profiles.
*/
static {
DateTimeParser[] parsers = { ISODateTimeFormat.date().getParser(), ISODateTimeFormat.dateTime().getParser(), ISODateTimeFormat.dateTimeNoMillis().getParser(),
ISODateTimeFormat.basicDateTime().getParser(), ISODateTimeFormat.basicDateTimeNoMillis().getParser() };
formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter();
}
private SearchUtils() {
}
public static Map<String, Serializable> getTransformLinkProperties( UriInfo uriInfo, Query query, QueryResponse response, String scheme, String host, Integer port ) {
Map<String, Serializable> properties = new HashMap<String, Serializable>();
UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
uriBuilder = updateURLWithPlatformValues( uriBuilder, scheme, host, port );
String selfLink = uriBuilder.toTemplate();
properties.put( SearchConstants.SELF_LINK_REL, selfLink );
LOGGER.debug( "Adding self link parameter[{}] with value [{}] to transform properties to be sent to result transformer", SearchConstants.SELF_LINK_REL, selfLink );
int startIndex = query.getStartIndex();
int pageSize = query.getPageSize();
long totalCount = response.getHits();
if ( startIndex + pageSize <= totalCount ) {
String template = uriBuilder.replaceQueryParam( SearchConstants.STARTINDEX_PARAMETER, String.valueOf( startIndex + pageSize ) ).toTemplate();
properties.put( SearchConstants.NEXT_LINK_REL, template );
LOGGER.debug( "Adding next link parameter[{}] with value [{}] to transform properties to be sent to result transformer", SearchConstants.NEXT_LINK_REL, template );
}
if ( startIndex > 1 ) {
String template = uriBuilder.replaceQueryParam( SearchConstants.STARTINDEX_PARAMETER, String.valueOf( Math.max( 1, startIndex - pageSize ) ) ).toTemplate();
properties.put( SearchConstants.PREV_LINK_REL, template );
LOGGER.debug( "Adding previous link parameter[{}] with value [{}] to transform properties to be sent to result transformer", SearchConstants.PREV_LINK_REL, template );
}
return properties;
}
public static UriBuilder updateURLWithPlatformValues( UriBuilder builder, String scheme, String host, Integer port ) {
if ( StringUtils.isNotBlank( scheme ) && StringUtils.isNotBlank( host ) ) {
LOGGER.debug( "Using values from Platform Configuration for Atom Links host[" + host + "], scheme[" + scheme + "], and port[" + port + "]" );
builder.scheme( scheme );
builder.host( host );
if ( port != null ) {
builder.port( port );
}
}
return builder;
}
public static Boolean getBoolean( String booleanString, Boolean defaultValue ) {
Boolean bool = null;
if ( booleanString != null ) {
booleanString = booleanString.trim();
if ( "1".equals( booleanString ) || Boolean.TRUE.toString().equalsIgnoreCase( booleanString ) ) {
bool = Boolean.TRUE;
} else if ( "0".equals( booleanString ) || Boolean.FALSE.toString().equalsIgnoreCase( booleanString ) ) {
bool = Boolean.FALSE;
}
}
return bool != null ? bool : defaultValue;
}
public static Map<String, String> convertToMap( String mapStr ) {
Map<String, String> inputMap = new HashMap<String, String>();
if ( StringUtils.isNotBlank( mapStr ) ) {
inputMap = convertToMap( Arrays.asList( mapStr.split( "," ) ) );
}
return inputMap;
}
public static Map<String, String> convertToMap( List<String> mapList ) {
Map<String, String> inputMap = new HashMap<>();
if ( CollectionUtils.isNotEmpty( mapList ) ) {
for ( String sortPair : mapList ) {
String[] pairAry = sortPair.split( MAP_ENTRY_DELIMITER );
if ( pairAry.length == 2 ) {
inputMap.put( StringUtils.trimToEmpty( pairAry[0] ), StringUtils.trimToEmpty( pairAry[1] ) );
} else {
LOGGER.warn( "Could not parse out map entry from {}, skipping this item.", sortPair );
}
}
}
return inputMap;
}
public static Map<String, String> convertDateTypeToMap( List<DateTypeConfiguration> dateTypeList ) {
Map<String, String> inputMap = new HashMap<>();
if ( CollectionUtils.isNotEmpty( dateTypeList ) ) {
for ( DateTypeConfiguration dateType : dateTypeList ) {
inputMap.put( dateType.getCDRDateType(), dateType.getInternalDateType() );
}
}
return inputMap;
}
public static <T extends Enum<?>> T enumEqualsIgnoreCase( Class<T> enumeration, String search ) {
for ( T each : enumeration.getEnumConstants() ) {
if ( StringUtils.equalsIgnoreCase( each.name(), search ) ) {
return each;
}
}
return null;
}
public static Date parseDate( String date ) throws UnsupportedQueryException {
Date returnDate = null;
if ( StringUtils.isNotBlank( date ) ) {
try {
returnDate = formatter.parseDateTime( date ).toDate();
} catch ( IllegalArgumentException e ) {
LOGGER.warn( "Could not process date because of invalid format [{}]", date );
throw new UnsupportedQueryException( "Invalid date format [" + date + "]" );
}
}
return returnDate;
}
public static SortBy getSortBy( String sortByString, List<SortTypeConfiguration> sortTypeConfigurationList, boolean supportWildcards ) {
SortBy sortBy = null;
if ( StringUtils.isNotBlank( sortByString ) ) {
String[] sortValues = sortByString.split( "," );
String sortKey = sortValues[0];
if ( StringUtils.isNotBlank( sortKey ) ) {
SortTypeConfiguration sortType = getSortConfiguration( sortKey, sortTypeConfigurationList, supportWildcards );
if ( sortType != null ) {
String sortAttribute = sortType.getSortAttribute();
SortOrder sortOrder = null;
if ( sortValues.length >= 3 ) {
if ( Boolean.FALSE.toString().equalsIgnoreCase( sortValues[2] ) ) {
sortOrder = SortOrder.DESCENDING;
} else {
sortOrder = SortOrder.ASCENDING;
}
} else {
sortOrder = SortOrder.valueOf( sortType.getSortOrder() );
}
sortBy = new SortByImpl( sortAttribute, sortOrder );
}
}
}
return sortBy;
}
public static void logSort( SortBy sortBy ) {
if ( LOGGER.isDebugEnabled() ) {
if ( sortBy != null ) {
LOGGER.debug( "SortBy for query is set to [{}]", sortBy.getPropertyName().getPropertyName() + "/" + sortBy.getSortOrder() );
} else {
LOGGER.debug( "SortBy for query is set to null" );
}
}
}
private static SortTypeConfiguration getSortConfiguration( String sortKey, List<SortTypeConfiguration> sortTypeConfigurationList, boolean supportWildcard ) {
for ( SortTypeConfiguration sortType : sortTypeConfigurationList ) {
String configSortKey = sortType.getSortKey();
LOGGER.trace( "Comparing incoming sort key of {} with configuration of key {}", sortKey, configSortKey );
if ( supportWildcard ) {
if ( configSortKey.startsWith( SortTypeConfiguration.SORT_WILDCARD ) ) {
configSortKey = StringUtils.substringAfterLast( configSortKey, SortTypeConfiguration.SORT_XPATH_DELIMITTER );
if ( sortKey.contains( SortTypeConfiguration.SORT_XPATH_DELIMITTER ) ) {
sortKey = StringUtils.substringAfterLast( sortKey, SortTypeConfiguration.SORT_XPATH_DELIMITTER );
}
}
LOGGER.trace( "SortKeys being compated after wildcard normalization query sortKey=[{}] and configuration sortKey=[{}]", sortKey, configSortKey );
}
if ( StringUtils.equalsIgnoreCase( configSortKey, sortKey ) ) {
return sortType;
}
}
return null;
}
protected static boolean isBoolean( String value ) {
boolean isBoolean = false;
if ( StringUtils.isNotBlank( value ) ) {
value = value.toLowerCase();
isBoolean = value.equals( "false" ) || value.equals( "true" ) || value.equals( "0" ) || value.equals( "1" );
}
return isBoolean;
}
public static boolean isBooleanNullOrBlank( String value ) {
boolean isBoolOrNull = true;
if ( StringUtils.isNotBlank( value ) ) {
isBoolOrNull = isBoolean( value );
}
return isBoolOrNull;
}
public static Boolean getBoolean( String booleanString ) {
Boolean bool = null;
if ( booleanString != null ) {
booleanString = booleanString.trim();
if ( "1".equals( booleanString ) || Boolean.TRUE.toString().equalsIgnoreCase( booleanString ) ) {
bool = Boolean.TRUE;
} else if ( "0".equals( booleanString ) || Boolean.FALSE.toString().equalsIgnoreCase( booleanString ) ) {
bool = Boolean.FALSE;
}
}
return bool;
}
public static void addFilter( List<Filter> filters, Filter filter ) {
if ( filter != null ) {
LOGGER.debug( "Filter was not null, and will be added to the list of valid filters" );
filters.add( filter );
} else {
LOGGER.debug( "Filter was null, not adding to the Filter list" );
}
}
public static String getAllowedSortValues( List<SortTypeConfiguration> sortTypes ) {
StringBuilder sb = new StringBuilder();
for ( SortTypeConfiguration sortType : sortTypes ) {
sb.append( "'" + sortType.getSortKey() + "' " );
}
return sb.toString();
}
}