/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.portal.datasource.el;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import com.enonic.cms.core.portal.PortalInstanceKey;
import com.enonic.cms.core.portal.page.PageRequestFactory;
import com.enonic.cms.core.preference.PreferenceEntity;
import com.enonic.cms.core.preference.PreferenceKey;
import com.enonic.cms.core.preference.PreferenceScope;
import com.enonic.cms.core.preference.PreferenceScopeKey;
import com.enonic.cms.core.preference.PreferenceScopeKeyResolver;
import com.enonic.cms.core.preference.PreferenceScopeResolver;
import com.enonic.cms.core.preference.PreferenceScopeType;
import com.enonic.cms.core.preference.PreferenceService;
import com.enonic.cms.core.structure.menuitem.MenuItemEntity;
import com.enonic.cms.core.structure.menuitem.MenuItemKeysByPathResolver;
import com.enonic.cms.core.structure.portlet.PortletKey;
import com.enonic.cms.core.time.TimeService;
import com.enonic.cms.store.dao.MenuItemDao;
/**
*
*/
public class ExpressionFunctions
{
private PreferenceService preferenceService;
private ExpressionContext context;
private TimeService timeService;
private MenuItemDao menuItemDao;
public boolean isnotblank( String str )
{
return StringUtils.isNotBlank( str );
}
public boolean isblank( String str )
{
return StringUtils.isBlank( str );
}
public boolean isnotempty( String str )
{
return StringUtils.isNotEmpty( str );
}
public boolean isempty( String str )
{
return StringUtils.isEmpty( str );
}
/**
* Select the first value that is not null and not empty.
*
* @param s1 The first value checked
* @param s2 The second value.
* @return The first value, if it is not null or empty. Otherwise, the second value, no matter what it is.
*/
public String select( String s1, String s2 )
{
if ( s1 == null )
{
return s2;
}
else if ( s1.trim().length() > 0 )
{
return s1;
}
else
{
return s2;
}
}
public String concat( String... str )
{
StringBuilder sb = new StringBuilder();
for ( String s : str )
{
sb.append( s );
}
return sb.toString();
}
public String replace( String source, String regex, String replacement )
{
return source.replaceAll( regex, replacement );
}
public String substring( String source, int beginIndex, int endIndex )
{
return source.substring( beginIndex, endIndex );
}
public int stringlength( String source )
{
return source != null ? source.length() : 0;
}
public String lower( String source )
{
return source.toLowerCase();
}
public String upper( String source )
{
return source.toUpperCase();
}
public String trim( String source )
{
return source.trim();
}
public int min( int v1, int v2 )
{
return Math.min( v1, v2 );
}
public int max( int v1, int v2 )
{
return Math.max( v1, v2 );
}
public String currentDate( String format )
{
SimpleDateFormat fmt = new SimpleDateFormat( format );
return fmt.format( timeService.getNowAsDateTime().toDate() );
}
public String currentDatePlusOffset( String format, String periodStr )
{
DateTime nowDateTime = timeService.getNowAsDateTime();
PeriodFormatter periodFormatter = ISOPeriodFormat.standard();
Period period = periodFormatter.parsePeriod( periodStr );
DateTime offsetDateTime = nowDateTime.plus( period );
SimpleDateFormat fmt = new SimpleDateFormat( format );
return fmt.format( offsetDateTime.toDate() );
}
public String currentDateMinusOffset( String format, String periodStr )
{
DateTime nowDateTime = timeService.getNowAsDateTime();
PeriodFormatter periodFormatter = ISOPeriodFormat.standard();
Period period = periodFormatter.parsePeriod( periodStr );
DateTime offsetDateTime = nowDateTime.minus( period );
SimpleDateFormat fmt = new SimpleDateFormat( format );
return fmt.format( offsetDateTime.toDate() );
}
public String periodHoursMinutes( int hours, int minutes )
{
Period period = new Period( hours, minutes, 0, 0 );
return period.toString();
}
public String pref( String scope, String key )
{
if ( context.getUser() == null || context.getUser().isAnonymous() )
{
return "";
}
final PortletKey portletKey = PageRequestFactory.getPageRequest().getCurrentPortletKey();
PreferenceEntity preferenceEntity = getPreferenceEntity( scope, portletKey, key );
return preferenceEntity != null ? preferenceEntity.getValue() : "";
}
private PreferenceEntity getPreferenceEntity( String scope, PortletKey portletKey, String key )
{
PreferenceEntity preferenceEntity = null;
PreferenceScopeKey scopeKey;
PreferenceScopeType scopeType = PreferenceScopeType.parse( scope );
PortalInstanceKey instanceKey = context.getPortalInstanceKey();
if ( scopeType != null )
{
/* Scope supplied - try with supplied key and nothing else... */
scopeKey = PreferenceScopeKeyResolver.resolve( scopeType, instanceKey, instanceKey.getSiteKey() );
preferenceEntity = preferenceService.getPreference( new PreferenceKey( context.getUser().getKey(), scopeType, scopeKey, key ) );
}
else
{
/* No scope supplied - try to resolve scope and find preference... */
List<PreferenceScope> scopes = PreferenceScopeResolver.resolveAllScopes( instanceKey, instanceKey.getSiteKey() );
for ( int i = 0; i < scopes.size() && preferenceEntity == null; i++ )
{
preferenceEntity = preferenceService.getPreference( new PreferenceKey( context.getUser().getKey(), scopes.get( i ), key ) );
}
}
return preferenceEntity;
}
/**
* This method will take a freetext search string and create a valid query that can be used in the getContent* methods. The search
* string is spilt into tokens. Using the operator, it may be specified whether the field must contain all or any of the words in the
* search string.
*
* @param fieldName The name of the field to search for the words in the search string.
* @param searchString The words to search for.
* @param operator Must be either AND or OR. Case doesn't matter.
* @return A syntactically correct search that may be used as the query parameter in getContent* methods on the data source. With care,
* it may also be merged with other queries using AND or OR.
* @throws IllegalArgumentException If any of the parameters are empty or the operator is not AND or OR.
*/
public String buildFreetextQuery( String fieldName, String searchString, String operator )
{
if ( searchString == null || searchString.trim().equals( "" ) )
{
return "";
}
if ( fieldName == null || fieldName.trim().equals( "" ) )
{
throw new IllegalArgumentException( "fieldName can not be empty." );
}
String op = "";
if ( operator != null )
{
op = operator.trim().toUpperCase();
}
if ( !( op.equals( "AND" ) || op.equals( "OR" ) ) )
{
throw new IllegalArgumentException( "Illegal operator: " + operator );
}
boolean first = true;
StringBuilder queryTokens = new StringBuilder();
Reader searchStringReader = new StringReader( searchString );
StreamTokenizer searchStringTokens = new StreamTokenizer( searchStringReader );
searchStringTokens.slashSlashComments( false );
searchStringTokens.slashStarComments( false );
searchStringTokens.eolIsSignificant( false );
searchStringTokens.ordinaryChar( '!' );
searchStringTokens.ordinaryChars( '#', '}' );
searchStringTokens.wordChars( '!', '!' );
searchStringTokens.wordChars( '#', '}' );
try
{
while ( searchStringTokens.nextToken() != StreamTokenizer.TT_EOF )
{
String token = searchStringTokens.sval;
addQueryPart( queryTokens, first, fieldName, token, op );
if ( first )
{
first = false;
}
}
}
catch ( IOException e )
{
throw new IllegalStateException( "This should never happen, since the IO class is wrapping a string!" );
}
return queryTokens.toString();
}
public String getPageKey()
{
return context.getMenuItem().getKey().toString();
}
public String getWindowKey()
{
return context.getPortalInstanceKey().getWindowKey().asString();
}
private void addQueryPart( StringBuilder query, boolean first, String fieldName, String token, String op )
{
if ( !first )
{
query.append( ' ' );
query.append( op );
query.append( ' ' );
}
query.append( fieldName );
query.append( " CONTAINS \"" );
query.append( token );
query.append( "\"" );
}
public String getPageKeyByPath( String path )
{
MenuItemEntity menuItem = menuItemDao.findByKey( context.getMenuItem().getKey() );
MenuItemKeysByPathResolver menuItemKeysByPathResolver = new MenuItemKeysByPathResolver( menuItem );
return menuItemKeysByPathResolver.getPageKeyByPath( path );
}
public String getPageKeysByPath( String path )
{
MenuItemEntity menuItem = menuItemDao.findByKey( context.getMenuItem().getKey() );
MenuItemKeysByPathResolver menuItemKeysByPathResolver = new MenuItemKeysByPathResolver( menuItem );
return menuItemKeysByPathResolver.getPageKeysByPath( path );
}
public void setPreferenceService( PreferenceService preferenceService )
{
this.preferenceService = preferenceService;
}
public void setContext( ExpressionContext context )
{
this.context = context;
}
public void setTimeService( TimeService timeService )
{
this.timeService = timeService;
}
public void setMenuItemDao( MenuItemDao menuItemDao )
{
this.menuItemDao = menuItemDao;
}
public String urlEncode( String source )
{
if ( StringUtils.isBlank( source ) )
{
return "";
}
try
{
return URLEncoder.encode( source, "UTF-8" );
}
catch ( UnsupportedEncodingException e )
{
throw new RuntimeException( e );
}
}
}