/*
* Weblounge: Web Content Management System
* Copyright (c) 2003 - 2011 The Weblounge Team
* http://entwinemedia.com/weblounge
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package ch.entwine.weblounge.common.impl.content;
import static ch.entwine.weblounge.common.content.SearchQuery.Quantifier.Any;
import ch.entwine.weblounge.common.content.Resource;
import ch.entwine.weblounge.common.content.SearchQuery;
import ch.entwine.weblounge.common.content.SearchTerms;
import ch.entwine.weblounge.common.content.page.Pagelet;
import ch.entwine.weblounge.common.content.page.PageletURI;
import ch.entwine.weblounge.common.impl.content.page.PageletImpl;
import ch.entwine.weblounge.common.impl.content.page.PageletURIImpl;
import ch.entwine.weblounge.common.impl.security.UserImpl;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.security.User;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.url.UrlUtils;
import ch.entwine.weblounge.common.url.WebUrl;
import org.apache.commons.lang.StringUtils;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
* Default implementation for the search query api.
*/
public class SearchQueryImpl implements SearchQuery {
/** Name of the stage composer */
public static final String STAGE_COMPOSER = "#stage#";
/** Id of the wild card user */
public static final String ANY_USER = "#any#";
/** The list of fields to return */
protected List<String> fields = null;
/** The site */
protected Site site = null;
/** The search language */
protected Language language = null;
/** Query configuration stack */
protected Stack<Object> stack = new Stack<Object>();
/** The object that needs to show up next */
protected Class<?> expectation = null;
/** The resource identifier */
protected List<String> resourceId = new ArrayList<String>();
/** The path */
protected String path = null;
/** The types */
protected List<String> types = new ArrayList<String>();
/** The types to block */
protected List<String> withoutTypes = new ArrayList<String>();
/** The template */
protected String template = null;
/** The layout */
protected String layout = null;
/** Stationary flag */
protected boolean stationary = false;
/** The list of required pagelets */
protected List<SearchTerms<Pagelet>> pagelets = null;
/** The list of required subjects */
protected List<SearchTerms<String>> subjects = null;
/** The list of required series */
protected List<String> series = new ArrayList<String>();
/** The external location */
protected URL externalLocation = null;
/** The source */
protected String source = null;
/** The properties */
protected Map<String, String> properties = new HashMap<String, String>();
/** The elements */
protected Map<String, String> elements = new HashMap<String, String>();
/** The last method called */
protected String lastMethod = null;
/** The creation date */
protected Date creationDateFrom = null;
/** The end of the range for the creation date */
protected Date creationDateTo = null;
/** True if the resource must not have a modification date */
protected boolean withoutModification = false;
/** The modification date */
protected Date modificationDateFrom = null;
/** The end of the range for the modification date */
protected Date modificationDateTo = null;
/** True if the resource must not have a publishing date */
protected boolean withoutPublication = false;
/** The publishing date */
protected Date publishingDateFrom = null;
/** The end of the range for the publishing date */
protected Date publishingDateTo = null;
/** The author */
protected User author = null;
/** The creator */
protected User creator = null;
/** The modifier */
protected User modifier = null;
/** The publisher */
protected User publisher = null;
/** The lock owner */
protected User lockOwner = null;
/** The path prefix */
protected String pathPrefix = null;
/** The filename */
protected String filename = null;
/** The mime type */
protected String mimetype = null;
/** Fulltext query terms */
protected List<SearchTerms<String>> fulltext = null;
/** Query terms */
protected List<SearchTerms<String>> text = null;
/** True if the search text should be matched using wildcards */
protected boolean fuzzySearch = true;
/** Filter terms */
protected String filter = null;
/** The query offset */
protected int offset = -1;
/** The query limit */
protected int limit = -1;
/** True to boost more recent documents */
protected boolean recencyBoost = false;
/** Creation date order relation */
protected Order creationDateSearchOrder = Order.None;
/** Modification date order relation */
protected Order modificationDateSearchOrder = Order.None;
/** Publication date order relation */
protected Order publicationDateSearchOrder = Order.None;
/** The resource versions */
protected long version = Resource.ANY;
/** The preferred resource version */
protected long preferredVersion = -1L;
/**
* Creates a new search query that is operating on the given site.
*
* @param site
* the site
*/
public SearchQueryImpl(Site site) {
this(site, site.getDefaultLanguage());
}
/**
* Creates a new search query that is operating on the given site.
*
* @param site
* the site
* @param language
* the search language
*/
public SearchQueryImpl(Site site, Language language) {
this.site = site;
this.language = language;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withField(java.lang.String)
*/
@Override
public SearchQuery withField(String field) {
if (fields == null)
fields = new ArrayList<String>();
fields.add(field);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFields(java.lang.String[])
*/
@Override
public SearchQuery withFields(String... fields) {
for (String field : fields) {
withField(field);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getFields()
*/
@Override
public String[] getFields() {
if (fields == null)
return new String[] {};
return fields.toArray(new String[fields.size()]);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getSite()
*/
public Site getSite() {
return site;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withRececyPriority()
*/
@Override
public SearchQuery withRececyPriority() {
this.recencyBoost = true;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getRecencyPriority()
*/
@Override
public boolean getRecencyPriority() {
return recencyBoost;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withLimit(int)
*/
public SearchQuery withLimit(int limit) {
this.limit = limit;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getLimit()
*/
public int getLimit() {
return limit;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withOffset(int)
*/
public SearchQuery withOffset(int offset) {
this.offset = Math.max(0, offset);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getOffset()
*/
public int getOffset() {
return offset;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withIdentifier(java.lang.String)
*/
public SearchQuery withIdentifier(String id) {
if (StringUtils.isBlank(id))
throw new IllegalArgumentException("Id cannot be null");
this.resourceId.add(id);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getIdentifier()
*/
public String[] getIdentifier() {
return resourceId.toArray(new String[resourceId.size()]);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPath(java.lang.String)
*/
public SearchQuery withPath(String path) {
if (path == null)
throw new IllegalArgumentException("Path cannot be null");
this.path = UrlUtils.trim(path);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPath()
*/
public String getPath() {
return path;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withTemplate(java.lang.String)
*/
public SearchQuery withTemplate(String template) {
this.template = template;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getTemplate()
*/
public String getTemplate() {
return template;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withLayout(java.lang.String)
*/
public SearchQuery withLayout(String layout) {
this.layout = layout;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getLayout()
*/
public String getLayout() {
return layout;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withStationary()
*/
public SearchQuery withStationary() {
stationary = true;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#isStationary()
*/
public boolean isStationary() {
return stationary;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withTypes(java.lang.String)
*/
public SearchQuery withTypes(String... types) {
for (String type : types) {
this.types.add(type);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withoutTypes(java.lang.String)
*/
public SearchQuery withoutTypes(String... types) {
for (String type : types) {
this.withoutTypes.add(type);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getType()
*/
public String[] getTypes() {
return types.toArray(new String[types.size()]);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getWithoutTypes()
*/
public String[] getWithoutTypes() {
return withoutTypes.toArray(new String[withoutTypes.size()]);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#and(java.util.Date)
*/
public SearchQuery and(Date date) {
ensureExpectation(Date.class);
Date startDate = (Date) stack.peek();
if (startDate.equals(date) || startDate.after(date))
throw new IllegalStateException("End date must be after start date");
if ("withCreationDateBetween".equals(lastMethod))
creationDateTo = date;
else if ("withModificationDateBetween".equals(lastMethod))
modificationDateTo = date;
else if ("withPublishingDateBetween".equals(lastMethod))
publishingDateTo = date;
clearExpectations();
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#andProperty(java.lang.String,
* java.lang.String)
*/
public SearchQuery andProperty(String propertyName, String propertyValue)
throws IllegalStateException {
ensureConfigurationArray(Pagelet.class);
Pagelet[] pagelets = (Pagelet[]) stack.peek();
for (Pagelet pagelet : pagelets) {
pagelet.addProperty(propertyName, propertyValue);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#andElement(java.lang.String,
* java.lang.String)
*/
public SearchQuery andElement(String textName, String text)
throws IllegalStateException {
if (language == null)
throw new IllegalStateException("You need to specify the query language first");
ensureConfigurationArray(Pagelet.class);
Pagelet[] pagelets = (Pagelet[]) stack.peek();
for (Pagelet pagelet : pagelets) {
pagelet.setContent(textName, text, language);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#atPosition(int)
*/
public SearchQuery atPosition(int position) throws IllegalStateException {
ensureConfigurationArray(Pagelet.class);
Pagelet[] pagelets = (Pagelet[]) stack.peek();
for (Pagelet pagelet : pagelets) {
PageletURI uri = pagelet.getURI();
if (uri == null) {
uri = new PageletURIImpl(null, null, position);
} else {
uri.setPosition(position);
}
pagelet.setURI(uri);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#inComposer(java.lang.String)
*/
public SearchQuery inComposer(String composer) throws IllegalStateException {
ensureConfigurationArray(Pagelet.class);
Pagelet[] pagelets = (Pagelet[]) stack.peek();
for (Pagelet pagelet : pagelets) {
PageletURI uri = pagelet.getURI();
if (uri == null) {
uri = new PageletURIImpl(null, composer, -1);
} else {
uri.setComposer(composer);
}
pagelet.setURI(uri);
}
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#inStage()
*/
public SearchQuery inStage() throws IllegalStateException {
return inComposer(STAGE_COMPOSER);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withAuthor(ch.entwine.weblounge.common.security.User)
*/
public SearchQuery withAuthor(User author) {
clearExpectations();
this.author = author;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getAuthor()
*/
public User getAuthor() {
return author;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withLanguage(ch.entwine.weblounge.common.language.Language)
*/
public SearchQuery withLanguage(Language language) {
clearExpectations();
this.language = language;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getLanguage()
*/
public Language getLanguage() {
return language;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withSubject(java.lang.String)
*/
public SearchQuery withSubject(String subject) {
return withSubjects(Any, subject);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withSubjects(ch.entwine.weblounge.common.content.SearchQuery.Quantifier,
* String...)
*/
@Override
public SearchQuery withSubjects(Quantifier quantifier, String... subjects) {
if (quantifier == null)
throw new IllegalArgumentException("Quantifier must not be null");
if (subjects == null)
throw new IllegalArgumentException("Subjects must not be null");
// Make sure the collection is initialized
if (this.subjects == null)
this.subjects = new ArrayList<SearchTerms<String>>();
// Add the text to the search terms
clearExpectations();
with(this.subjects, quantifier, subjects);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getSubjects()
*/
public Collection<SearchTerms<String>> getSubjects() {
return subjects;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withCreationDate(java.util.Date)
*/
public SearchQuery withCreationDate(Date date) {
clearExpectations();
creationDateFrom = date;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withCreationDateBetween(java.util.Date)
*/
public SearchQuery withCreationDateBetween(Date date) {
clearExpectations();
configure(date);
creationDateFrom = date;
expect(Date.class);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getCreationDate()
*/
public Date getCreationDate() {
return creationDateFrom;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getCreationDateEnd()
*/
public Date getCreationDateEnd() {
return creationDateTo;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withModificationDate(java.util.Date)
*/
public SearchQuery withModificationDate(Date date) {
if (withoutModification)
throw new IllegalStateException("With modification date and without modification date are mutually exclusive");
clearExpectations();
modificationDateFrom = date;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withModificationDateBetween(java.util.Date)
*/
public SearchQuery withModificationDateBetween(Date date) {
if (withoutModification)
throw new IllegalStateException("With modification date and without modification date are mutually exclusive");
clearExpectations();
configure(date);
modificationDateFrom = date;
expect(Date.class);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getModificationDate()
*/
public Date getModificationDate() {
return modificationDateFrom;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getModificationDateEnd()
*/
public Date getModificationDateEnd() {
return modificationDateTo;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withoutModification()
*/
public SearchQuery withoutModification() {
if (modificationDateFrom != null || modificationDateTo != null)
throw new IllegalStateException("With modification date and without modification date are mutually exclusive");
if (modifier != null)
throw new IllegalStateException("With modifier and without modification date are mutually exclusive");
clearExpectations();
this.withoutModification = true;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getWithoutModification()
*/
public boolean getWithoutModification() {
return withoutModification;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPagelet(ch.entwine.weblounge.common.content.page.Pagelet)
*/
public SearchQuery withPagelet(Pagelet pagelet) {
return withPagelets(Any, pagelet);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPagelets(ch.entwine.weblounge.common.content.SearchQuery.Quantifier,
* ch.entwine.weblounge.common.content.page.Pagelet[])
*/
@Override
public SearchQuery withPagelets(Quantifier quantifier, Pagelet... pagelets) {
if (pagelets == null)
throw new IllegalArgumentException("Pagelet must not be null");
if (quantifier == null)
throw new IllegalArgumentException("Quantifier must not be null");
// Make sure the collection is initialized
if (this.pagelets == null)
this.pagelets = new ArrayList<SearchTerms<Pagelet>>();
int i = 0;
for (Pagelet p : pagelets) {
pagelets[i++] = new PageletImpl(p.getModule(), p.getIdentifier());
}
clearExpectations();
with(this.pagelets, quantifier, pagelets);
configure(pagelets);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPagelets()
*/
public Collection<SearchTerms<Pagelet>> getPagelets() {
return pagelets;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPathPrefix(java.lang.String)
*/
public SearchQuery withPathPrefix(String path) {
clearExpectations();
if (path.endsWith("/"))
path = path.substring(0, path.length() - 1);
this.pathPrefix = path;
if (pathPrefix == null)
throw new IllegalArgumentException("Path prefix must not be null");
if (!pathPrefix.startsWith(WebUrl.separator))
pathPrefix = WebUrl.separatorChar + pathPrefix;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPathPrefix()
*/
public String getPathPrefix() {
return pathPrefix;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withCreator(ch.entwine.weblounge.common.security.User)
*/
public SearchQuery withCreator(User creator) {
clearExpectations();
this.creator = creator;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getCreator()
*/
public User getCreator() {
return creator;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withModifier(ch.entwine.weblounge.common.security.User)
*/
public SearchQuery withModifier(User modifier) {
if (withoutModification)
throw new IllegalStateException("With modifier and without modification date are mutually exclusive");
clearExpectations();
this.modifier = modifier;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getModifier()
*/
public User getModifier() {
return modifier;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPublisher(ch.entwine.weblounge.common.security.User)
*/
public SearchQuery withPublisher(User publisher) {
if (withoutPublication)
throw new IllegalStateException("With publisher and without publication date are mutually exclusive");
clearExpectations();
this.publisher = publisher;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPublisher()
*/
public User getPublisher() {
return publisher;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPublishingDate(java.util.Date)
*/
public SearchQuery withPublishingDate(Date date) {
if (withoutPublication)
throw new IllegalStateException("With publishing date and without publication are mutually exclusive");
clearExpectations();
this.publishingDateFrom = date;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPublishingDateBetween(java.util.Date)
*/
public SearchQuery withPublishingDateBetween(Date date) {
if (withoutPublication)
throw new IllegalStateException("With publishing date and without publication are mutually exclusive");
clearExpectations();
configure(date);
this.publishingDateFrom = date;
expect(Date.class);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPublishingDate()
*/
public Date getPublishingDate() {
return publishingDateFrom;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPublishingDateEnd()
*/
public Date getPublishingDateEnd() {
return publishingDateTo;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withoutPublication()
*/
public SearchQuery withoutPublication() {
if (publishingDateFrom != null || publishingDateTo != null)
throw new IllegalStateException("With publishing date and without publishing date are mutually exclusive");
if (publisher != null)
throw new IllegalStateException("With publisher and without modification date are mutually exclusive");
clearExpectations();
this.withoutPublication = true;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getWithoutPublication()
*/
public boolean getWithoutPublication() {
return withoutPublication;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withLockOwner()
*/
public SearchQuery withLockOwner() {
clearExpectations();
this.lockOwner = new UserImpl(ANY_USER);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withLockOwner(ch.entwine.weblounge.common.security.User)
*/
public SearchQuery withLockOwner(User lockOwner) {
clearExpectations();
this.lockOwner = lockOwner;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getLockOwner()
*/
public User getLockOwner() {
return lockOwner;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withExternalLocation(java.net.URL)
*/
public SearchQuery withExternalLocation(URL url) {
this.externalLocation = url;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getExternalLocation()
*/
public URL getExternalLocation() {
return externalLocation;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withText(java.lang.String)
*/
public SearchQuery withText(String text) {
return withText(false, Any, text);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withText(boolean,
* java.lang.String)
*/
public SearchQuery withText(boolean wildcardSearch, String text) {
return withText(wildcardSearch, Any, text);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withText(boolean,
* ch.entwine.weblounge.common.content.SearchQuery.Quantifier,
* java.lang.String[])
*/
@Override
public SearchQuery withText(boolean wildcardSearch, Quantifier quantifier,
String... text) {
if (quantifier == null)
throw new IllegalArgumentException("Quantifier must not be null");
if (text == null)
throw new IllegalArgumentException("Text must not be null");
// Make sure the collection is initialized
if (this.text == null)
this.text = new ArrayList<SearchTerms<String>>();
// Add the text to the search terms
clearExpectations();
this.fuzzySearch = wildcardSearch;
with(this.text, quantifier, text);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getTerms()
*/
public Collection<SearchTerms<String>> getTerms() {
if (text == null)
return Collections.emptyList();
return text;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getQueryString()
*/
@Override
public String getQueryString() {
if (text == null)
return null;
StringBuffer query = new StringBuffer();
for (SearchTerms<String> s : text) {
for (String t : s.getTerms()) {
if (query.length() == 0)
query.append(" ");
query.append(t);
}
}
return query.toString();
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFulltext(java.lang.String)
*/
@Override
public SearchQuery withFulltext(String text) {
return withFulltext(false, Any, text);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFulltext(boolean,
* java.lang.String)
*/
@Override
public SearchQuery withFulltext(boolean fuzzy, String text) {
return withFulltext(fuzzy, Any, text);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFulltext(boolean,
* ch.entwine.weblounge.common.content.SearchQuery.Quantifier,
* java.lang.String[])
*/
public SearchQuery withFulltext(boolean fuzzy, Quantifier quantifier,
String... text) {
if (quantifier == null)
throw new IllegalArgumentException("Quantifier must not be null");
if (text == null)
throw new IllegalArgumentException("Text must not be null");
// Make sure the collection is initialized
if (this.fulltext == null)
this.fulltext = new ArrayList<SearchTerms<String>>();
// Add the text to the search terms
clearExpectations();
this.fuzzySearch = fuzzy;
with(this.fulltext, quantifier, text);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getFulltext()
*/
@Override
public Collection<SearchTerms<String>> getFulltext() {
return fulltext;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#isFuzzySearch()
*/
public boolean isFuzzySearch() {
return fuzzySearch;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFilter(java.lang.String)
*/
public SearchQuery withFilter(String filter) {
clearExpectations();
this.filter = filter;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getFilter()
*/
public String getFilter() {
return filter;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withElement(java.lang.String,
* java.lang.String)
*/
public SearchQuery withElement(String element, String value) {
elements.put(element, value);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getElements()
*/
public Map<String, String> getElements() {
return elements;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withProperty(java.lang.String,
* java.lang.String)
*/
public SearchQuery withProperty(String property, String value) {
properties.put(property, value);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getProperties()
*/
public Map<String, String> getProperties() {
return properties;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withFilename(java.lang.String)
*/
public SearchQuery withFilename(String filename) {
this.filename = filename;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getFilename()
*/
public String getFilename() {
return filename;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withMimetype(java.lang.String)
*/
public SearchQuery withMimetype(String mimetype) {
this.mimetype = mimetype;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getMimetype()
*/
public String getMimetype() {
return mimetype;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#sortByCreationDate(ch.entwine.weblounge.common.content.SearchQuery.Order)
*/
public SearchQuery sortByCreationDate(Order order) {
if (order == null)
creationDateSearchOrder = Order.None;
else
creationDateSearchOrder = order;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getCreationDateSortOrder()
*/
public Order getCreationDateSortOrder() {
return creationDateSearchOrder;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#sortByModificationDate(ch.entwine.weblounge.common.content.SearchQuery.Order)
*/
public SearchQuery sortByModificationDate(Order order) {
if (order == null)
modificationDateSearchOrder = Order.None;
else
modificationDateSearchOrder = order;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getModificationDateSortOrder()
*/
public Order getModificationDateSortOrder() {
return modificationDateSearchOrder;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#sortByPublishingDate(ch.entwine.weblounge.common.content.SearchQuery.Order)
*/
public SearchQuery sortByPublishingDate(Order order) {
if (order == null)
publicationDateSearchOrder = Order.None;
else
publicationDateSearchOrder = order;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPublishingDateSortOrder()
*/
public Order getPublishingDateSortOrder() {
return publicationDateSearchOrder;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withVersion(long)
*/
public SearchQuery withVersion(long version) {
this.version = version;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withPreferredVersion(long)
*/
public SearchQuery withPreferredVersion(long preferredVersion) {
this.preferredVersion = preferredVersion;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getVersion()
*/
public long getVersion() {
return version;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getPreferredVersion()
*/
public long getPreferredVersion() {
return preferredVersion;
}
/**
* Pushes the configuration object onto the stack.
*
* @param object
* the object
*/
private void configure(Object object) {
stack.push(object);
}
/**
* Sets the expectation to <code>c</code>, making sure that the next
* configuration object will either match <code>c</code> in terms of class of
* throw an <code>IllegalStateException</code> if it doesn't.
*
* @param c
* the class type
*/
private void expect(Class<?> c) {
lastMethod = Thread.currentThread().getStackTrace()[2].getMethodName();
this.expectation = c;
}
/**
* This method is called if nothing should be expected by anyone. If this is
* not the case (e. g. some unfinished query configuration is still in place)
* we throw an <code>IllegalStateException</code>.
*
* @throws IllegalStateException
* if some object is expected
*/
private void clearExpectations() throws IllegalStateException {
if (expectation != null)
throw new IllegalStateException("Query configuration expects " + expectation.getClass().getName());
stack.clear();
}
/**
* This method is called if a certain type of object is expected by someone.
* If this is not the case (e. g. query configuration is in good shape, then
* someone tries to "finish" a configuration part) we throw an
* <code>IllegalStateException</code>.
*
* @throws IllegalStateException
* if no or a different object is expected
*/
private void ensureExpectation(Class<?> c) throws IllegalStateException {
if (expectation == null)
throw new IllegalStateException("Malformed query configuration. No " + c.getClass().getName() + " is expected at this time");
if (!expectation.getCanonicalName().equals(c.getCanonicalName()))
throw new IllegalStateException("Malformed query configuration. Something of type " + c.getClass().getName() + " is expected at this time");
expectation = null;
}
/**
* Make sure that an object of type <code>c</code> is on the stack, throw an
* <code>IllegalStateException</code> otherwise.
*
* @throws IllegalStateException
* if no object of type <code>c</code> was found on the stack
*/
protected void ensureConfigurationObject(Class<?> c)
throws IllegalStateException {
for (Object o : stack) {
if (c.isAssignableFrom(o.getClass()))
return;
}
throw new IllegalStateException("Malformed query configuration. No " + c.getClass().getName() + " is expected at this time");
}
/**
* Make sure that an array of type <code>c</code> is on the stack, throw an
* <code>IllegalStateException</code> otherwise.
*
* @throws IllegalStateException
* if no array of type <code>c</code> was found on the stack
*/
protected void ensureConfigurationArray(Class<?> c)
throws IllegalStateException {
for (Object o : stack) {
if (o.getClass().isArray() && c.isAssignableFrom(o.getClass().getComponentType()))
return;
}
throw new IllegalStateException("Malformed query configuration. No " + c.getClass().getName() + " is expected at this time");
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withSource(java.lang.String)
*/
public SearchQuery withSource(String source) {
this.source = source;
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getSource()
*/
public String getSource() {
return source;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#withSeries(java.lang.String)
*/
public SearchQuery withSeries(String series) {
this.series.add(series);
return this;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.content.SearchQuery#getSeries()
*/
public String[] getSeries() {
return series.toArray(new String[series.size()]);
}
/**
* Utility method to add the given values to the list of search terms using
* the specified quantifier.
*
* @param searchTerms
* the terms
* @param quantifier
* the quantifier
* @param values
* the values
* @return the extended search terms
*/
private <T extends Object> SearchTerms<T> with(
List<SearchTerms<T>> searchTerms, Quantifier quantifier, T... values) {
SearchTerms<T> terms = null;
// Handle any quantifier
if (values.length == 1 || Any.equals(quantifier)) {
// Check if there is a default terms collection
for (SearchTerms<T> t : searchTerms) {
if (Quantifier.Any.equals(t.getQuantifier())) {
terms = t;
break;
}
}
// Has there been a default terms collection?
if (terms == null) {
terms = new SearchTermsImpl<T>(Quantifier.Any, values);
searchTerms.add(terms);
}
// Add the text
for (T v : values) {
terms.add(v);
}
}
// All quantifier
else {
terms = new SearchTermsImpl<T>(quantifier, values);
searchTerms.add(terms);
}
return terms;
}
}