/*
* Copyright 2012 Adaptrex, LLC
*
* 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 com.adaptrex.core.view;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import com.adaptrex.core.ext.ExtConfig;
import com.adaptrex.core.ext.Filter;
import com.adaptrex.core.ext.Sorter;
import com.adaptrex.core.ext.StoreDefinition;
import com.adaptrex.core.ext.TouchStoreDefinition;
import com.adaptrex.core.persistence.api.AdaptrexStoreData;
import com.adaptrex.core.utilities.Inflector;
import com.adaptrex.core.utilities.StringUtilities;
public class StoreComponent {
private static Logger log = Logger.getLogger(StoreComponent.class);
private HttpServletRequest request;
private Boolean inline = false;
private Object rest;
private Boolean autoLoad;
private Integer start;
private Integer pageSize;
private String where;
private Map<String, Object> params = new HashMap<String,Object>();
private List<Filter> filters = new ArrayList<Filter>();
private List<Sorter> sorters = new ArrayList<Sorter>();
private List<Sorter> groupers = new ArrayList<Sorter>();
private Boolean buffered;
private Integer trailingBufferZone;
private Integer leadingBufferZone;
private Integer purgePageCount;
private Boolean clearOnPageLoad;
private Boolean clearRemovedOnLoad;
private Boolean autoSync;
private Boolean remoteGroup;
private Boolean remoteSort;
private Boolean remoteFilter;
private Boolean sortOnFilter;
private ExtConfig extConfig;
private ConfigComponent configComponent;
public StoreComponent(HttpServletRequest request, String entityClassName, String factoryName, String namespace) {
this.request = request;
/*
* Get or create our config component
*/
this.configComponent = (ConfigComponent) request.getAttribute(ConfigComponent.ATTRIBUTE);
if (this.configComponent == null) {
configComponent = new ConfigComponent(request, namespace, false);
this.configComponent = (ConfigComponent) request.getAttribute(ConfigComponent.ATTRIBUTE);
}
this.extConfig = new ExtConfig(request.getServletContext(), entityClassName, factoryName);
};
public String getJavaScript() throws Exception {
ExtConfig config = this.extConfig;
if (config.getEntityClass() == null) {
String str = "Adaptrex Store Error: Persistent Class Not Found (" + this.extConfig.getModelName() + ")";
log.warn(str);
return StringUtilities.getErrorJavaScript(str);
}
String namespace = configComponent.getNamespace();
String modelName = config.getModelName();
/*
* The first thing a store needs is a model
*/
ModelComponent modelComponent = new ModelComponent(
request,
this.configComponent,
extConfig
);
modelComponent.applyRest(this.rest);
String fullModelName = namespace + ".model." + modelName;
String storeName = Inflector.getInstance().pluralize(modelName);
String fullStoreName = namespace + ".store." + storeName;
/*
* Create the store definition
*/
log.debug("Creating store definition for " + fullModelName);
StoreDefinition storeDefinition = this.configComponent.isTouch()
? new TouchStoreDefinition()
: new StoreDefinition();
storeDefinition.setModelName(fullModelName);
storeDefinition.setClearOnPageLoad(this.clearOnPageLoad);
storeDefinition.setClearRemovedOnLoad(this.clearRemovedOnLoad);
storeDefinition.setAutoSync(this.autoSync);
storeDefinition.setAutoLoad(this.autoLoad);
storeDefinition.setRemoteGroup(this.remoteGroup);
storeDefinition.setRemoteSort(this.remoteSort);
storeDefinition.setRemoteFilter(this.remoteFilter);
storeDefinition.setSortOnFilter(this.sortOnFilter);
storeDefinition.setBuffered(this.buffered);
storeDefinition.setTrailingBufferZone(this.trailingBufferZone);
storeDefinition.setLeadingBufferZone(this.leadingBufferZone);
storeDefinition.setPurgePageCount(this.purgePageCount);
storeDefinition.setGroupers(this.groupers);
storeDefinition.setSorters(this.sorters);
storeDefinition.setPageSize(this.pageSize);
storeDefinition.setFilters(this.filters);
if (this.inline != null && this.inline) {
AdaptrexStoreData storeData = config.getORMPersistenceManager().getStoreData(config);
storeData.setFilters(this.filters);
storeData.setGroupers(this.groupers);
storeData.setLimit(this.pageSize);
storeData.setParams(this.params);
storeData.setSorters(this.sorters);
storeData.setStart(this.start);
storeData.setWhere(this.where);
storeDefinition.setData(storeData.getData());
storeDefinition.setTotalCount(storeData.getTotalCount());
}
boolean isTouch = this.configComponent.isTouch();
String storeOutput = "<script type='text/javascript'>\n" +
"Ext.define('" + fullStoreName + "', " +
//(isTouch ? "{extend:'Ext.data.Store', config:" : "") +
StringUtilities.json(storeDefinition, this.request.getServletContext()) +
//(isTouch ? "}" : "") + ");\n" +
")</script>";
StringBuffer javascript = new StringBuffer();
if (!configComponent.isWritten()) {
javascript.append(configComponent.getJavaScript());
}
javascript.append(modelComponent.getJavaScript());
javascript.append(storeOutput);
return javascript.toString();
}
/*
* Custom Model Name
*/
public StoreComponent applyModelName(String modelName) {
if (modelName != null) {
this.extConfig.setModelName(modelName);
}
return this;
}
/*
* Load Store Data Inline
*/
public StoreComponent applyInline(Object inline) {
this.inline = getBoolean(inline);
return this;
}
/*
* Enable Rest Proxy
*/
public StoreComponent applyRest(Object rest) {
this.rest = rest;
return this;
}
/*
* Enable Autoloading of Rest Stores
*/
public StoreComponent applyAutoLoad(Object autoLoad) {
this.autoLoad = getBoolean(autoLoad);
return this;
}
/*
* Set start position of results
*/
public StoreComponent applyStart(Object start) {
this.start = getInteger(start);
return this;
}
/*
* Set store page size
*/
public StoreComponent applyPageSize(Object pageSize) {
this.pageSize = getInteger(pageSize);
return this;
}
/*
* Included Fields
* TODO: Not part of the store component,
* only used for data retrieval and proxy.
* Do we need to actually set this on the
* store or just the data config?
*/
public StoreComponent applyInclude(String includes) {
if (includes != null) {
this.extConfig.setIncludes(includes);
}
return this;
}
/*
* Excluded Fields
* TODO: Not part of the store component,
* only used for data retrieval and proxy.
* Do we need to actually set this on the
* store or just the data config?
*/
public StoreComponent applyExclude(String excludes) {
if (excludes != null) {
this.extConfig.setExcludes(excludes);
}
return this;
}
/*
* Associations
* TODO: Not part of the store component,
* only used for data retrieval and proxy.
* Do we need to actually set this on the
* store or just the data config?
*/
public StoreComponent applyAssociations(String associations) {
if (associations != null) {
this.extConfig.setAssociations(associations);
}
return this;
}
/*
* Set JPQL where clause on ORMs that support it
*/
public StoreComponent applyWhere(String where) {
this.where = where;
return this;
}
/*
* Add Params for our JPQL where clause
*/
public StoreComponent applyParams(String paramString) {
if (paramString != null) {
for (String param : paramString.split(",")) {
String[] parts = param.split("=");
this.applyParam(parts[0], parts[1]);
}
}
return this;
}
public StoreComponent applyParam(String property, String value) {
params.put(property, value);
return this;
}
/*
* Filter
*
*
* We can accept several formats to customize our filter. We may add additional functionality
* that are only available when using remote filtering. Any features that are available in
* local filtering should function the same on either local or remote.
*
*/
public StoreComponent applyFilters(String filterText) {
if (filterText != null) {
for (String item : filterText.split("(?![^(]*\\)),")) {
Map<String,String> f = processParamTag(item);
filters.add(new Filter(
f.get("key"),
f.get("value"),
Integer.valueOf(f.get("filterType")),
Boolean.valueOf(f.get("_anyMatch")),
Boolean.valueOf(f.get("_caseSensitive")),
Boolean.valueOf(f.get("_exactMatch"))
));
}
}
return this;
}
/*
* sorters
*/
public StoreComponent applySorters(String sorterText) {
if (sorterText != null) {
for (String sortItem : sorterText.split("(?![^(]*\\)),")) {
Map<String,String> params = processParamTag(sortItem);
String direction = params.get("_direction");
if (direction == null) direction = params.get("_");
this.addSorter(params.get("value"), direction);
}
}
return this;
}
public StoreComponent addSorter(String property, String direction) {
sorters.add(new Sorter(property, direction));
return this;
}
/*
* groupers
*/
public StoreComponent applyGroupers(String grouperText) {
if (grouperText != null) {
for (String groupItem : grouperText.split("(?![^(]*\\)),")) {
Map<String,String> params = processParamTag(groupItem);
String direction = params.get("_direction");
if (direction == null) direction = params.get("_");
this.addGrouper(params.get("value"), direction);
}
}
return this;
}
public StoreComponent addGrouper(String property, String direction) {
groupers.add(new Sorter(property, direction));
return this;
}
/*
* buffered
*/
public StoreComponent applyBuffered(Object buffered) {
this.buffered = getBoolean(buffered);
return this;
}
/*
* trailingBufferZone
*/
public StoreComponent applyTrailingBufferZone(Object trailingBufferZone) {
this.trailingBufferZone = getInteger(trailingBufferZone);
return this;
}
/*
* loadingBufferZone
*/
public StoreComponent applyLeadingBufferZone(Object leadingBufferZone) {
this.leadingBufferZone = getInteger(leadingBufferZone);
return this;
}
/*
* purgePageCount
*/
public StoreComponent applyPurgePageCount(Object purgePageCount) {
this.purgePageCount = getInteger(purgePageCount);
return this;
}
/*
* clearOnPageLoad
*/
public StoreComponent applyClearOnPageLoad(Object clearOnPageLoad) {
this.clearOnPageLoad = getBoolean(clearOnPageLoad);
return this;
}
/*
* clearRemovedOnLoad
*/
public StoreComponent applyClearRemovedOnLoad(Object clearRemovedOnLoad) {
this.clearRemovedOnLoad = getBoolean(clearRemovedOnLoad);
return this;
}
/*
* autoSync
*/
public StoreComponent applyAutoSync(Object autoSync) {
this.autoSync = getBoolean(autoSync);
return this;
}
/*
* remoteGroup
*/
public StoreComponent applyRemoteGroup(Object remoteGroup) {
this.remoteGroup = getBoolean(remoteGroup);
return this;
}
/*
* remoteSort
*/
public StoreComponent applyRemoteSort(Object remoteSort) {
this.remoteSort = getBoolean(remoteSort);
return this;
}
/*
* remoteFilter
*/
public StoreComponent applyRemoteFilter(Object remoteFilter) {
this.remoteFilter = getBoolean(remoteFilter);
return this;
}
/*
* sortOnFilter
*/
public StoreComponent applySortOnFilter(Object sortOnFilter) {
this.sortOnFilter = getBoolean(sortOnFilter);
return this;
}
private Boolean getBoolean(Object testValue) {
if (testValue == null) return null;
if (testValue instanceof Boolean) return (Boolean) testValue;
return Boolean.valueOf((String) testValue);
}
private Integer getInteger(Object testValue) {
if (testValue == null) return null;
if (testValue instanceof Integer) return (Integer) testValue;
return Integer.valueOf((String) testValue);
}
private Map<String,String> processParamTag(String attribute) {
Map<String,String> params = new HashMap<String,String>();
if (attribute.contains("(")) {
String[] attributeParts = attribute.split("\\(");
params.putAll(processParamKeyValue(attributeParts[0]));
for (String attributeParam : attributeParts[1].replace(")", "").split(",")) {
Map<String,String> attributeParamKeyVal = processParamKeyValue(attributeParam);
String key = attributeParamKeyVal.get("key");
params.put("_" + (key == null ? "" : key), attributeParamKeyVal.get("value"));
}
} else {
params.putAll(processParamKeyValue(attribute));
}
return params;
}
private Map<String,String> processParamKeyValue(String keyValue) {
Map<String,String> params = new HashMap<String,String>();
String[] parts = null;
if (keyValue.contains(">=")) {
parts = keyValue.split(">=");
params.put("filterType", Filter.GREATER_THAN_EQUAL.toString());
} else if (keyValue.contains("<=")) {
parts = keyValue.split("<=");
params.put("filterType", Filter.LESS_THAN_EQUAL.toString());
} else if (keyValue.contains(">")) {
parts = keyValue.split(">");
params.put("filterType", Filter.GREATER_THAN.toString());
} else if (keyValue.contains("<")) {
parts = keyValue.split("<");
params.put("filterType", Filter.LESS_THAN.toString());
} else if (keyValue.contains("!=")) {
parts = keyValue.split("!=");
params.put("filterType", Filter.NOT_EQUAL.toString());
} else if (keyValue.contains("=")) {
parts = keyValue.split("=");
params.put("filterType", Filter.EQUAL.toString());
}
if (parts != null) {
params.put("key", parts[0]);
params.put("value", parts[1]);
} else {
params.put("value", keyValue);
}
return params;
}
}