/** * Compiles and caches a regexp pattern for the given string pattern. * * @param stringPattern a pattern string * @param caseSensitive case sensitive true/false * @return compiles and caches a regexp pattern for the given string pattern * @throws MalformedPatternException */ private Pattern getTestPattern(String stringPattern, boolean caseSensitive) throws MalformedPatternException { Pattern pattern = compiledPatterns.get(stringPattern); if (pattern == null) { if (caseSensitive) { pattern = compiler.compile(stringPattern); } else { pattern = compiler.compile(stringPattern, Perl5Compiler.CASE_INSENSITIVE_MASK); } compiledPatterns.put(stringPattern, pattern); Debug.logVerbose( "Compiled and cached a pattern: '" + stringPattern + "' - " + Thread.currentThread(), module); } return pattern; }
public static ModelReader getModelReader(String delegatorName) throws GenericEntityException { DelegatorInfo delegatorInfo = EntityConfigUtil.getDelegatorInfo(delegatorName); if (delegatorInfo == null) { throw new GenericEntityConfException( "Could not find a delegator with the name " + delegatorName); } String tempModelName = delegatorInfo.entityModelReader; ModelReader reader = readers.get(tempModelName); if (reader == null) { reader = new ModelReader(tempModelName); // preload caches... reader.getEntityCache(); reader = readers.putIfAbsentAndGet(tempModelName, reader); } return reader; }
private static FlexibleStringExpander getInstance( String expression, char[] chars, int offset, int length, boolean useCache) { if (length == 0) { return nullExpr; } if (!useCache) { return parse(chars, offset, length); } // Remove the next nine lines to cache all expressions if (!expression.contains(openBracket)) { if (chars.length == length) { return new ConstSimpleElem(chars); } else { return new ConstOffsetElem(chars, offset, length); } } Key key = chars.length == length ? new SimpleKey(chars) : new OffsetKey(chars, offset, length); FlexibleStringExpander fse = exprCache.get(key); if (fse == null) { exprCache.put(key, parse(chars, offset, length)); fse = exprCache.get(key); } return fse; }
/** Generic Entity - Entity Definition Reader */ @SuppressWarnings("serial") public class ModelReader implements Serializable { public static final String module = ModelReader.class.getName(); private static final UtilCache<String, ModelReader> readers = UtilCache.createUtilCache("entity.ModelReader", 0, 0); protected Map<String, ModelEntity> entityCache = null; protected int numEntities = 0; protected int numViewEntities = 0; protected int numFields = 0; protected int numRelations = 0; protected int numAutoRelations = 0; protected int numUniqueKeys = 0; protected String modelName; /** collection of filenames for entity definitions */ protected Collection<ResourceHandler> entityResourceHandlers; /** * contains a collection of entity names for each ResourceHandler, populated as they are loaded */ protected Map<ResourceHandler, Collection<String>> resourceHandlerEntities; /** for each entity contains a map to the ResourceHandler that the entity came from */ protected Map<String, ResourceHandler> entityResourceHandlerMap; public static ModelReader getModelReader(String delegatorName) throws GenericEntityException { DelegatorInfo delegatorInfo = EntityConfigUtil.getDelegatorInfo(delegatorName); if (delegatorInfo == null) { throw new GenericEntityConfException( "Could not find a delegator with the name " + delegatorName); } String tempModelName = delegatorInfo.entityModelReader; ModelReader reader = readers.get(tempModelName); if (reader == null) { reader = new ModelReader(tempModelName); // preload caches... reader.getEntityCache(); reader = readers.putIfAbsentAndGet(tempModelName, reader); } return reader; } public ModelReader(String modelName) throws GenericEntityException { this.modelName = modelName; entityResourceHandlers = FastList.newInstance(); resourceHandlerEntities = FastMap.newInstance(); entityResourceHandlerMap = FastMap.newInstance(); EntityModelReaderInfo entityModelReaderInfo = EntityConfigUtil.getEntityModelReaderInfo(modelName); if (entityModelReaderInfo == null) { throw new GenericEntityConfException( "Cound not find an entity-model-reader with the name " + modelName); } // get all of the main resource model stuff, ie specified in the entityengine.xml file for (Element resourceElement : entityModelReaderInfo.resourceElements) { ResourceHandler handler = new MainResourceHandler(EntityConfigUtil.ENTITY_ENGINE_XML_FILENAME, resourceElement); entityResourceHandlers.add(handler); } // get all of the component resource model stuff, ie specified in each ofbiz-component.xml file for (ComponentConfig.EntityResourceInfo componentResourceInfo : ComponentConfig.getAllEntityResourceInfos("model")) { if (modelName.equals(componentResourceInfo.readerName)) { entityResourceHandlers.add(componentResourceInfo.createResourceHandler()); } } } private ModelEntity buildEntity( ResourceHandler entityResourceHandler, Element curEntityElement, int i, ModelInfo def) throws GenericEntityException { boolean isEntity = "entity".equals(curEntityElement.getNodeName()); String entityName = UtilXml.checkEmpty(curEntityElement.getAttribute("entity-name")).intern(); // add entityName to appropriate resourceHandlerEntities collection Collection<String> resourceHandlerEntityNames = resourceHandlerEntities.get(entityResourceHandler); if (resourceHandlerEntityNames == null) { resourceHandlerEntityNames = FastList.newInstance(); resourceHandlerEntities.put(entityResourceHandler, resourceHandlerEntityNames); } resourceHandlerEntityNames.add(entityName); // check to see if entity with same name has already been read if (entityCache.containsKey(entityName)) { Debug.logWarning( "WARNING: Entity " + entityName + " is defined more than once, most recent will over-write " + "previous definition(s)", module); Debug.logWarning( "WARNING: Entity " + entityName + " was found in " + entityResourceHandler + ", but was already defined in " + entityResourceHandlerMap.get(entityName).toString(), module); } // add entityName, entityFileName pair to entityResourceHandlerMap map entityResourceHandlerMap.put(entityName, entityResourceHandler); // utilTimer.timerString(" After entityEntityName -- " + i + " --"); // ModelEntity entity = createModelEntity(curEntity, utilTimer); ModelEntity modelEntity = null; if (isEntity) { modelEntity = createModelEntity(curEntityElement, null, def); } else { modelEntity = createModelViewEntity(curEntityElement, null, def); } String resourceLocation = entityResourceHandler.getLocation(); try { resourceLocation = entityResourceHandler.getURL().toExternalForm(); } catch (GenericConfigException e) { Debug.logError(e, "Could not get resource URL", module); } // utilTimer.timerString(" After createModelEntity -- " + i + " --"); if (modelEntity != null) { modelEntity.setLocation(resourceLocation); // utilTimer.timerString(" After entityCache.put -- " + i + " --"); if (isEntity) { if (Debug.verboseOn()) Debug.logVerbose("-- [Entity]: #" + i + ": " + entityName, module); } else { if (Debug.verboseOn()) Debug.logVerbose("-- [ViewEntity]: #" + i + ": " + entityName, module); } } else { Debug.logWarning( "-- -- ENTITYGEN ERROR:getModelEntity: Could not create " + "entity for entityName: " + entityName, module); } return modelEntity; } public Map<String, ModelEntity> getEntityCache() throws GenericEntityException { if (entityCache == null) { // don't want to block here synchronized (ModelReader.class) { // must check if null again as one of the blocked threads can still enter if (entityCache == null) { // now it's safe numEntities = 0; numViewEntities = 0; numFields = 0; numRelations = 0; numAutoRelations = 0; entityCache = new HashMap<String, ModelEntity>(); List<ModelViewEntity> tempViewEntityList = FastList.newInstance(); List<Element> tempExtendEntityElementList = FastList.newInstance(); UtilTimer utilTimer = new UtilTimer(); for (ResourceHandler entityResourceHandler : entityResourceHandlers) { // utilTimer.timerString("Before getDocument in file " + entityFileName); Document document = null; try { document = entityResourceHandler.getDocument(); } catch (GenericConfigException e) { throw new GenericEntityConfException( "Error getting document from resource handler", e); } if (document == null) { throw new GenericEntityConfException( "Could not get document for " + entityResourceHandler.toString()); } // utilTimer.timerString("Before getDocumentElement in " + // entityResourceHandler.toString()); Element docElement = document.getDocumentElement(); if (docElement == null) { return null; } docElement.normalize(); Node curChild = docElement.getFirstChild(); ModelInfo def = new ModelInfo(); def.populateFromElements(docElement); int i = 0; if (curChild != null) { utilTimer.timerString( "Before start of entity loop in " + entityResourceHandler.toString()); do { boolean isEntity = "entity".equals(curChild.getNodeName()); boolean isViewEntity = "view-entity".equals(curChild.getNodeName()); boolean isExtendEntity = "extend-entity".equals(curChild.getNodeName()); if ((isEntity || isViewEntity) && curChild.getNodeType() == Node.ELEMENT_NODE) { i++; ModelEntity modelEntity = buildEntity(entityResourceHandler, (Element) curChild, i, def); // put the view entity in a list to get ready for the second pass to populate // fields... if (isViewEntity) { tempViewEntityList.add((ModelViewEntity) modelEntity); } else { entityCache.put(modelEntity.getEntityName(), modelEntity); } } else if (isExtendEntity && curChild.getNodeType() == Node.ELEMENT_NODE) { tempExtendEntityElementList.add((Element) curChild); } } while ((curChild = curChild.getNextSibling()) != null); } else { Debug.logWarning("No child nodes found.", module); } utilTimer.timerString( "Finished " + entityResourceHandler.toString() + " - Total Entities: " + i + " FINISHED"); } // all entity elements in, now go through extend-entity elements and add their stuff for (Element extendEntityElement : tempExtendEntityElementList) { String entityName = UtilXml.checkEmpty(extendEntityElement.getAttribute("entity-name")); ModelEntity modelEntity = entityCache.get(entityName); if (modelEntity == null) throw new GenericEntityConfException( "Entity to extend does not exist: " + entityName); modelEntity.addExtendEntity(this, extendEntityElement); } // do a pass on all of the view entities now that all of the entities have // loaded and populate the fields while (!tempViewEntityList.isEmpty()) { int startSize = tempViewEntityList.size(); Iterator<ModelViewEntity> mveIt = tempViewEntityList.iterator(); TEMP_VIEW_LOOP: while (mveIt.hasNext()) { ModelViewEntity curViewEntity = mveIt.next(); for (ModelViewEntity.ModelMemberEntity mve : curViewEntity.getAllModelMemberEntities()) { if (!entityCache.containsKey(mve.getEntityName())) { continue TEMP_VIEW_LOOP; } } mveIt.remove(); curViewEntity.populateFields(this); for (ModelViewEntity.ModelMemberEntity mve : curViewEntity.getAllModelMemberEntities()) { ModelEntity me = (ModelEntity) entityCache.get(mve.getEntityName()); me.addViewEntity(curViewEntity); } entityCache.put(curViewEntity.getEntityName(), curViewEntity); } if (tempViewEntityList.size() == startSize) { // Oops, the remaining views reference other entities // that can't be found, or they reference other views // that have some reference problem. break; } } if (!tempViewEntityList.isEmpty()) { StringBuilder sb = new StringBuilder("View entities reference non-existant members:\n"); Set<String> allViews = FastSet.newInstance(); for (ModelViewEntity curViewEntity : tempViewEntityList) { allViews.add(curViewEntity.getEntityName()); } for (ModelViewEntity curViewEntity : tempViewEntityList) { Set<String> perViewMissingEntities = FastSet.newInstance(); Iterator<ModelViewEntity.ModelMemberEntity> mmeIt = curViewEntity.getAllModelMemberEntities().iterator(); while (mmeIt.hasNext()) { ModelViewEntity.ModelMemberEntity mme = mmeIt.next(); String memberEntityName = mme.getEntityName(); if (!entityCache.containsKey(memberEntityName)) { // this member is not a real entity // check to see if it is a view if (!allViews.contains(memberEntityName)) { // not a view, it's a real missing entity perViewMissingEntities.add(memberEntityName); } } } for (String perViewMissingEntity : perViewMissingEntities) { sb.append("\t[") .append(curViewEntity.getEntityName()) .append("] missing member entity [") .append(perViewMissingEntity) .append("]\n"); } } throw new GenericEntityConfException(sb.toString()); } // auto-create relationships TreeSet<String> orderedMessages = new TreeSet<String>(); for (String curEntityName : new TreeSet<String>(this.getEntityNames())) { ModelEntity curModelEntity = this.getModelEntity(curEntityName); if (curModelEntity instanceof ModelViewEntity) { // for view-entities auto-create relationships for all member-entity relationships // that have all corresponding fields in the view-entity } else { // for entities auto-create many relationships for all type one relationships // just in case we add a new relation to the same entity, keep in a separate list and // add them at the end List<ModelRelation> newSameEntityRelations = FastList.newInstance(); Iterator<ModelRelation> relationsIter = curModelEntity.getRelationsIterator(); while (relationsIter.hasNext()) { ModelRelation modelRelation = relationsIter.next(); if (("one".equals(modelRelation.getType()) || "one-nofk".equals(modelRelation.getType())) && !modelRelation.isAutoRelation()) { ModelEntity relatedEnt = null; try { relatedEnt = this.getModelEntity(modelRelation.getRelEntityName()); } catch (GenericModelException e) { throw new GenericModelException( "Error getting related entity [" + modelRelation.getRelEntityName() + "] definition from entity [" + curEntityName + "]", e); } if (relatedEnt != null) { // don't do relationship to the same entity, unless title is "Parent", then do a // "Child" automatically String targetTitle = modelRelation.getTitle(); if (curModelEntity.getEntityName().equals(relatedEnt.getEntityName()) && "Parent".equals(targetTitle)) { targetTitle = "Child"; } // create the new relationship even if one exists so we can show what we are // looking for in the info message ModelRelation newRel = new ModelRelation(); newRel.setModelEntity(relatedEnt); newRel.setRelEntityName(curModelEntity.getEntityName()); newRel.setTitle(targetTitle); newRel.setAutoRelation(true); Set<String> curEntityKeyFields = FastSet.newInstance(); for (int kmn = 0; kmn < modelRelation.getKeyMapsSize(); kmn++) { ModelKeyMap curkm = modelRelation.getKeyMap(kmn); ModelKeyMap newkm = new ModelKeyMap(); newRel.addKeyMap(newkm); newkm.setFieldName(curkm.getRelFieldName()); newkm.setRelFieldName(curkm.getFieldName()); curEntityKeyFields.add(curkm.getFieldName()); } // decide whether it should be one or many by seeing if the key map represents // the complete pk of the relEntity if (curModelEntity.containsAllPkFieldNames(curEntityKeyFields)) { // always use one-nofk, we don't want auto-fks getting in for these automatic // ones newRel.setType("one-nofk"); // to keep it clean, remove any additional keys that aren't part of the PK List<String> curPkFieldNames = curModelEntity.getPkFieldNames(); Iterator<ModelKeyMap> nrkmIter = newRel.getKeyMapsIterator(); while (nrkmIter.hasNext()) { ModelKeyMap nrkm = nrkmIter.next(); String checkField = nrkm.getRelFieldName(); if (!curPkFieldNames.contains(checkField)) { nrkmIter.remove(); } } } else { newRel.setType("many"); } ModelRelation existingRelation = relatedEnt.getRelation(targetTitle + curModelEntity.getEntityName()); if (existingRelation == null) { numAutoRelations++; if (curModelEntity.getEntityName().equals(relatedEnt.getEntityName())) { newSameEntityRelations.add(newRel); } else { relatedEnt.addRelation(newRel); } } else { if (newRel.equals(existingRelation)) { // don't warn if the target title+entity = current title+entity if (!(targetTitle + curModelEntity.getEntityName()) .equals(modelRelation.getTitle() + modelRelation.getRelEntityName())) { // String errorMsg = "Relation already exists to entity [] with title [" + // targetTitle + "],from entity []"; String message = "Entity [" + relatedEnt.getPackageName() + ":" + relatedEnt.getEntityName() + "] already has identical relationship to entity [" + curModelEntity.getEntityName() + "] title [" + targetTitle + "]; would auto-create: type [" + newRel.getType() + "] and fields [" + newRel.keyMapString(",", "") + "]"; orderedMessages.add(message); } } else { String message = "Existing relationship with the same name, but different specs found from what would be auto-created for Entity [" + relatedEnt.getEntityName() + "] and relationship to entity [" + curModelEntity.getEntityName() + "] title [" + targetTitle + "]; would auto-create: type [" + newRel.getType() + "] and fields [" + newRel.keyMapString(",", "") + "]"; Debug.logVerbose(message, module); } } } else { String errorMsg = "Could not find related entity [" + modelRelation.getRelEntityName() + "], no reverse relation added."; Debug.logWarning(errorMsg, module); } } } if (newSameEntityRelations.size() > 0) { for (ModelRelation newRel : newSameEntityRelations) { curModelEntity.addRelation(newRel); } } } } for (String message : orderedMessages) { Debug.logInfo(message, module); } Debug.log( "FINISHED LOADING ENTITIES - ALL FILES; #Entities=" + numEntities + " #ViewEntities=" + numViewEntities + " #Fields=" + numFields + " #Relationships=" + numRelations + " #AutoRelationships=" + numAutoRelations, module); } } } return entityCache; } /** * rebuilds the resourceHandlerEntities Map of Collections based on the current * entityResourceHandlerMap Map, must be done whenever a manual change is made to the * entityResourceHandlerMap Map after the initial load to make them consistent again. */ public void rebuildResourceHandlerEntities() { resourceHandlerEntities = FastMap.newInstance(); Iterator<Map.Entry<String, ResourceHandler>> entityResourceIter = entityResourceHandlerMap.entrySet().iterator(); while (entityResourceIter.hasNext()) { Map.Entry<String, ResourceHandler> entry = entityResourceIter.next(); // add entityName to appropriate resourceHandlerEntities collection Collection<String> resourceHandlerEntityNames = resourceHandlerEntities.get(entry.getValue()); if (resourceHandlerEntityNames == null) { resourceHandlerEntityNames = FastList.newInstance(); resourceHandlerEntities.put(entry.getValue(), resourceHandlerEntityNames); } resourceHandlerEntityNames.add(entry.getKey()); } } public Iterator<ResourceHandler> getResourceHandlerEntitiesKeyIterator() { if (resourceHandlerEntities == null) return null; return resourceHandlerEntities.keySet().iterator(); } public Collection<String> getResourceHandlerEntities(ResourceHandler resourceHandler) { if (resourceHandlerEntities == null) return null; return resourceHandlerEntities.get(resourceHandler); } public void addEntityToResourceHandler(String entityName, String loaderName, String location) { entityResourceHandlerMap.put( entityName, new MainResourceHandler(EntityConfigUtil.ENTITY_ENGINE_XML_FILENAME, loaderName, location)); } public ResourceHandler getEntityResourceHandler(String entityName) { return entityResourceHandlerMap.get(entityName); } /** * Gets an Entity object based on a definition from the specified XML Entity descriptor file. * * @param entityName The entityName of the Entity definition to use. * @return An Entity object describing the specified entity of the specified descriptor file. */ public ModelEntity getModelEntity(String entityName) throws GenericEntityException { if (entityName == null) { throw new IllegalArgumentException("Tried to find entity definition for a null entityName"); } Map<String, ModelEntity> ec = getEntityCache(); if (ec == null) { throw new GenericEntityConfException("ERROR: Unable to load Entity Cache"); } ModelEntity modelEntity = ec.get(entityName); if (modelEntity == null) { String errMsg = "Could not find definition for entity name " + entityName; // Debug.logError(new Exception("Placeholder"), errMsg, module); throw new GenericModelException(errMsg); } return modelEntity; } public ModelEntity getModelEntityNoCheck(String entityName) { Map<String, ModelEntity> ec = null; try { ec = getEntityCache(); } catch (GenericEntityException e) { Debug.logError(e, "Error getting entity cache", module); } if (ec == null) { return null; } ModelEntity modelEntity = ec.get(entityName); return modelEntity; } /** * Creates a Iterator with the entityName of each Entity defined in the specified XML Entity * Descriptor file. * * @return A Iterator of entityName Strings */ public Iterator<String> getEntityNamesIterator() throws GenericEntityException { Collection<String> collection = getEntityNames(); if (collection != null) { return collection.iterator(); } else { return null; } } /** * Creates a Set with the entityName of each Entity defined in the specified XML Entity Descriptor * file. * * @return A Set of entityName Strings */ public Set<String> getEntityNames() throws GenericEntityException { Map<String, ModelEntity> ec = getEntityCache(); if (ec == null) { throw new GenericEntityConfException("ERROR: Unable to load Entity Cache"); } return ec.keySet(); } /** Get all entities, organized by package */ public Map<String, TreeSet<String>> getEntitiesByPackage( Set<String> packageFilterSet, Set<String> entityFilterSet) throws GenericEntityException { Map<String, TreeSet<String>> entitiesByPackage = FastMap.newInstance(); // put the entityNames TreeSets in a HashMap by packageName Iterator<String> ecIter = this.getEntityNames().iterator(); while (ecIter.hasNext()) { String entityName = ecIter.next(); ModelEntity entity = this.getModelEntity(entityName); String packageName = entity.getPackageName(); if (UtilValidate.isNotEmpty(packageFilterSet)) { // does it match any of these? boolean foundMatch = false; for (String packageFilter : packageFilterSet) { if (packageName.contains(packageFilter)) { foundMatch = true; } } if (!foundMatch) { // Debug.logInfo("Not including entity " + entityName + " becuase it is not in the package // set: " + packageFilterSet, module); continue; } } if (UtilValidate.isNotEmpty(entityFilterSet) && !entityFilterSet.contains(entityName)) { // Debug.logInfo("Not including entity " + entityName + " becuase it is not in the entity // set: " + entityFilterSet, module); continue; } TreeSet<String> entities = entitiesByPackage.get(entity.getPackageName()); if (entities == null) { entities = new TreeSet<String>(); entitiesByPackage.put(entity.getPackageName(), entities); } entities.add(entityName); } return entitiesByPackage; } /** * Util method to validate an entity name; if no entity is found with the name, characters are * stripped from the beginning of the name until a valid entity name is found. It is intended to * be used to determine the entity name from a relation name. * * @return A valid entityName or null */ public String validateEntityName(String entityName) throws GenericEntityException { if (entityName == null) { return null; } Set<String> allEntities = this.getEntityNames(); while (!allEntities.contains(entityName) && entityName.length() > 0) { entityName = entityName.substring(1); } return (entityName.length() > 0 ? entityName : null); } ModelEntity createModelEntity(Element entityElement, UtilTimer utilTimer, ModelInfo def) { if (entityElement == null) return null; this.numEntities++; ModelEntity entity = new ModelEntity(this, entityElement, utilTimer, def); return entity; } ModelEntity createModelViewEntity(Element entityElement, UtilTimer utilTimer, ModelInfo def) { if (entityElement == null) return null; this.numViewEntities++; ModelViewEntity entity = new ModelViewEntity(this, entityElement, utilTimer, def); return entity; } public ModelRelation createRelation(ModelEntity entity, Element relationElement) { this.numRelations++; ModelRelation relation = new ModelRelation(entity, relationElement); return relation; } public ModelUniqueKey createUniqueKey(ModelEntity entity, Element uniqueKeyElement) { this.numUniqueKeys++; ModelUniqueKey relation = new ModelUniqueKey(entity, uniqueKeyElement); return relation; } public ModelField findModelField(ModelEntity entity, String fieldName) { for (ModelField field : entity.fields) { if (field.name.compareTo(fieldName) == 0) { return field; } } return null; } public ModelField createModelField(String name, String type, String colName, boolean isPk) { this.numFields++; ModelField field = new ModelField(name, type, colName, isPk); return field; } public ModelField createModelField(Element fieldElement) { if (fieldElement == null) { return null; } this.numFields++; ModelField field = new ModelField(fieldElement); return field; } }
/** Widget Library - Screen model HTML class. */ @SuppressWarnings("serial") public class HtmlWidget extends ModelScreenWidget { public static final String module = HtmlWidget.class.getName(); public static UtilCache<String, Template> specialTemplateCache = UtilCache.createUtilCache("widget.screen.template.ftl.general", 0, 0, false); protected static BeansWrapper specialBeansWrapper = new ExtendedWrapper(); protected static Configuration specialConfig = FreeMarkerWorker.makeConfiguration(specialBeansWrapper); // not sure if this is the best way to get FTL to use my fancy MapModel derivative, but should // work at least... public static class ExtendedWrapper extends BeansWrapper { @Override public TemplateModel wrap(Object object) throws TemplateModelException { /* NOTE: don't use this and the StringHtmlWrapperForFtl or things will be double-encoded if (object instanceof GenericValue) { return new GenericValueHtmlWrapperForFtl((GenericValue) object, this); }*/ // This StringHtmlWrapperForFtl option seems to be the best option // and handles most things without causing too many problems if (object instanceof String) { return new StringHtmlWrapperForFtl((String) object, this); } return super.wrap(object); } } public static class StringHtmlWrapperForFtl extends StringModel { public StringHtmlWrapperForFtl(String str, BeansWrapper wrapper) { super(str, wrapper); } @Override public String getAsString() { return StringUtil.htmlEncoder.encode(super.getAsString()); } } // End Static, begin class section protected List<ModelScreenWidget> subWidgets = new ArrayList<ModelScreenWidget>(); public HtmlWidget(ModelScreen modelScreen, Element htmlElement) { super(modelScreen, htmlElement); List<? extends Element> childElementList = UtilXml.childElementList(htmlElement); for (Element childElement : childElementList) { if ("html-template".equals(childElement.getNodeName())) { this.subWidgets.add(new HtmlTemplate(modelScreen, childElement)); } else if ("html-template-decorator".equals(childElement.getNodeName())) { this.subWidgets.add(new HtmlTemplateDecorator(modelScreen, childElement)); } else { throw new IllegalArgumentException( "Tag not supported under the platform-specific -> html tag with name: " + childElement.getNodeName()); } } } @Override public void renderWidgetString( Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws GeneralException, IOException { for (ModelScreenWidget subWidget : subWidgets) { subWidget.renderWidgetString(writer, context, screenStringRenderer); } } @Override public String rawString() { StringBuilder buffer = new StringBuilder("<html-widget>"); for (ModelScreenWidget subWidget : subWidgets) { buffer.append(subWidget.rawString()); } buffer.append("</html-widget>"); return buffer.toString(); } public static void renderHtmlTemplate( Appendable writer, FlexibleStringExpander locationExdr, Map<String, Object> context) { String location = locationExdr.expandString(context); // Debug.logInfo("Rendering template at location [" + location + "] with context: \n" + context, // module); if (UtilValidate.isEmpty(location)) { throw new IllegalArgumentException("Template location is empty"); } /* // ======================================================================= // Go through the context and find GenericValue objects and wrap them // NOTE PROBLEM: there are still problems with this as it gets some things // but does not get non-entity data including lots of strings // directly in the context or things prepared or derived right in // the FTL file, like the results of service calls, etc; we could // do something more aggressive to encode and wrap EVERYTHING in // the context, but I've been thinking that even this is too much // overhead and that would be crazy // NOTE ALTERNATIVE1: considering instead to use the FTL features to wrap // everything in an <#escape x as x?html>...</#escape>, but that could // cause problems with ${} expansions that have HTML in them, including: // included screens (using ${screens.render(...)}), content that should // have HTML in it (lots of general, product, category, etc content), etc // NOTE ALTERNATIVE2: kind of like the "#escape X as x?html" option, // implement an FTL *Model class and load it through a ObjectWrapper // FINAL NOTE: after testing all of these alternatives, this one seems // to behave the best, so going with that for now. // isolate the scope so these wrapper objects go away after rendering is done MapStack<String> contextMs; if (!(context instanceof MapStack)) { contextMs = MapStack.create(context); context = contextMs; } else { contextMs = UtilGenerics.cast(context); } contextMs.push(); for(Map.Entry<String, Object> mapEntry: contextMs.entrySet()) { Object value = mapEntry.getValue(); if (value instanceof GenericValue) { contextMs.put(mapEntry.getKey(), GenericValueHtmlWrapper.create((GenericValue) value)); } else if (value instanceof List) { if (((List) value).size() > 0 && ((List) value).get(0) instanceof GenericValue) { List<GenericValue> theList = (List<GenericValue>) value; List<GenericValueHtmlWrapper> newList = FastList.newInstance(); for (GenericValue gv: theList) { newList.add(GenericValueHtmlWrapper.create(gv)); } contextMs.put(mapEntry.getKey(), newList); } } // TODO and NOTE: should get most stuff, but we could support Maps // and Lists in Maps and such; that's tricky because we have to go // through the entire Map and not just one entry, and we would // have to shallow copy the whole Map too } // this line goes at the end of the method, but moved up here to be part of the big comment about this contextMs.pop(); */ if (location.endsWith(".ftl")) { try { Map<String, ? extends Object> parameters = UtilGenerics.checkMap(context.get("parameters")); boolean insertWidgetBoundaryComments = ModelWidget.widgetBoundaryCommentsEnabled(parameters); if (insertWidgetBoundaryComments) { writer.append(HtmlWidgetRenderer.formatBoundaryComment("Begin", "Template", location)); } // FreeMarkerWorker.renderTemplateAtLocation(location, context, writer); Template template = null; if (location.endsWith(".fo.ftl")) { // FOP can't render correctly escaped characters template = FreeMarkerWorker.getTemplate(location); } else { template = FreeMarkerWorker.getTemplate(location, specialTemplateCache, specialConfig); } FreeMarkerWorker.renderTemplate(template, context, writer); if (insertWidgetBoundaryComments) { writer.append(HtmlWidgetRenderer.formatBoundaryComment("End", "Template", location)); } } catch (IllegalArgumentException e) { String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString(); Debug.logError(e, errMsg, module); writeError(writer, errMsg); } catch (MalformedURLException e) { String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString(); Debug.logError(e, errMsg, module); writeError(writer, errMsg); } catch (TemplateException e) { String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString(); Debug.logError(e, errMsg, module); writeError(writer, errMsg); } catch (IOException e) { String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString(); Debug.logError(e, errMsg, module); writeError(writer, errMsg); } } else { throw new IllegalArgumentException( "Rendering not yet supported for the template at location: " + location); } } // TODO: We can make this more fancy, but for now this is very functional public static void writeError(Appendable writer, String message) { try { writer.append(message); } catch (IOException e) { } } public static class HtmlTemplate extends ModelScreenWidget { protected FlexibleStringExpander locationExdr; public HtmlTemplate(ModelScreen modelScreen, Element htmlTemplateElement) { super(modelScreen, htmlTemplateElement); this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location")); } @Override public void renderWidgetString( Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) { renderHtmlTemplate(writer, this.locationExdr, context); } @Override public String rawString() { return "<html-template location=\"" + this.locationExdr.getOriginal() + "\"/>"; } } public static class HtmlTemplateDecorator extends ModelScreenWidget { protected FlexibleStringExpander locationExdr; protected Map<String, HtmlTemplateDecoratorSection> sectionMap = FastMap.newInstance(); public HtmlTemplateDecorator(ModelScreen modelScreen, Element htmlTemplateDecoratorElement) { super(modelScreen, htmlTemplateDecoratorElement); this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateDecoratorElement.getAttribute("location")); List<? extends Element> htmlTemplateDecoratorSectionElementList = UtilXml.childElementList(htmlTemplateDecoratorElement, "html-template-decorator-section"); for (Element htmlTemplateDecoratorSectionElement : htmlTemplateDecoratorSectionElementList) { String name = htmlTemplateDecoratorSectionElement.getAttribute("name"); this.sectionMap.put( name, new HtmlTemplateDecoratorSection(modelScreen, htmlTemplateDecoratorSectionElement)); } } @Override public void renderWidgetString( Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) { // isolate the scope MapStack<String> contextMs; if (!(context instanceof MapStack)) { contextMs = MapStack.create(context); context = contextMs; } else { contextMs = UtilGenerics.cast(context); } // create a standAloneStack, basically a "save point" for this SectionsRenderer, and make a // new "screens" object just for it so it is isolated and doesn't follow the stack down MapStack<String> standAloneStack = contextMs.standAloneChildStack(); standAloneStack.put( "screens", new ScreenRenderer(writer, standAloneStack, screenStringRenderer)); SectionsRenderer sections = new SectionsRenderer(this.sectionMap, standAloneStack, writer, screenStringRenderer); // put the sectionMap in the context, make sure it is in the sub-scope, ie after calling push // on the MapStack contextMs.push(); context.put("sections", sections); renderHtmlTemplate(writer, this.locationExdr, context); contextMs.pop(); } @Override public String rawString() { return "<html-template-decorator location=\"" + this.locationExdr.getOriginal() + "\"/>"; } } public static class HtmlTemplateDecoratorSection extends ModelScreenWidget { protected String name; protected List<ModelScreenWidget> subWidgets; public HtmlTemplateDecoratorSection( ModelScreen modelScreen, Element htmlTemplateDecoratorSectionElement) { super(modelScreen, htmlTemplateDecoratorSectionElement); this.name = htmlTemplateDecoratorSectionElement.getAttribute("name"); // read sub-widgets List<? extends Element> subElementList = UtilXml.childElementList(htmlTemplateDecoratorSectionElement); this.subWidgets = ModelScreenWidget.readSubWidgets(this.modelScreen, subElementList); } @Override public void renderWidgetString( Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws GeneralException, IOException { // render sub-widgets renderSubWidgetsString(this.subWidgets, writer, context, screenStringRenderer); } @Override public String rawString() { return "<html-template-decorator-section name=\"" + this.name + "\"/>"; } } }
/** Performs regular expression matching and compiled regular expression pattern caching. */ public class CompilerMatcher { public static final String module = CompilerMatcher.class.getName(); private static final UtilCache<String, Pattern> compiledPatterns = UtilCache.createUtilCache("regularExpression.compiledPatterns", false); private Perl5Compiler compiler = new Perl5Compiler(); private Perl5Matcher matcher = new Perl5Matcher(); private Perl5Util perl5Util = new Perl5Util(); /** * This class is *not* thread-safe so it must be accessed from a java.lang.ThreadLocal instance * for multi-thread usage. ThreadLocal causes slightly extra memory usage, but allows for faster * thread-safe processing than synchronization would afford. * * @return returns the ThreadLocal */ public static ThreadLocal<CompilerMatcher> getThreadLocal() { return new ThreadLocal<CompilerMatcher>() { @Override protected CompilerMatcher initialValue() { return new CompilerMatcher(); } }; } /** * Returns true if the compiled version of the patternString regular expression argument matches * the aString argument. Case sensitive * * @param aString a string * @param patternString a string pattern * @return returns true if the compiled version of the patternString regular expression argument * matches the aString argument * @throws MalformedPatternException */ public boolean matches(String aString, String patternString) throws MalformedPatternException { return this.matches(aString, patternString, true); } /** * Returns true if the compiled version of the patternString regular expression argument matches * the aString argument. * * @param aString a string * @param patternString a string pattern * @param caseSensitive case sensitive true/false * @return returns true if the compiled version of the patternString regular expression argument * matches the aString argument * @throws MalformedPatternException */ public boolean matches(String aString, String patternString, boolean caseSensitive) throws MalformedPatternException { return this.matcher.matches(aString, this.getTestPattern(patternString, caseSensitive)); } /** * Returns true if the compiled version of the patternString regular expression argument is * contained in the aString argument. * * @param aString a string * @param patternString a pattern string * @return Returns true if the compiled version of the patternString regular expression argument * is contained in the aString argument * @throws MalformedPatternException */ public boolean contains(String aString, String patternString) throws MalformedPatternException { return this.matcher.contains(aString, this.getTestPattern(patternString)); } /** * Compiles and caches a case sensitive regexp pattern for the given string pattern. * * @param stringPattern a pattern string * @return compiles and caches a case sensitive regexp pattern for the given string pattern * @throws MalformedPatternException */ private Pattern getTestPattern(String stringPattern) throws MalformedPatternException { return this.getTestPattern(stringPattern, true); } /** * Compiles and caches a regexp pattern for the given string pattern. * * @param stringPattern a pattern string * @param caseSensitive case sensitive true/false * @return compiles and caches a regexp pattern for the given string pattern * @throws MalformedPatternException */ private Pattern getTestPattern(String stringPattern, boolean caseSensitive) throws MalformedPatternException { Pattern pattern = compiledPatterns.get(stringPattern); if (pattern == null) { if (caseSensitive) { pattern = compiler.compile(stringPattern); } else { pattern = compiler.compile(stringPattern, Perl5Compiler.CASE_INSENSITIVE_MASK); } compiledPatterns.put(stringPattern, pattern); Debug.logVerbose( "Compiled and cached a pattern: '" + stringPattern + "' - " + Thread.currentThread(), module); } return pattern; } /** * Perl5Util's substitute() function implements Perl's s/// operator. It takes two arguments: a * substitution expression, and an input. * * @param stringPattern a pattern string * @param input the input string * @return returns the perl5Util's substitute() function implements Perl's */ public String substitute(String stringPattern, String input) { return this.perl5Util.substitute(stringPattern, input); } }
/** * Expands String values that contain Unified Expression Language (JSR 245) syntax. This class also * supports the execution of bsh scripts by using the 'bsh:' prefix, and Groovy scripts by using the * 'groovy:' prefix. Further it is possible to control the output by specifying the suffix * '?currency(XXX)' to format the output according to the supplied locale and specified (XXX) * currency. * * <p>This class extends the UEL by allowing nested expressions. */ @SourceMonitored @SuppressWarnings("serial") public abstract class FlexibleStringExpander implements Serializable { public static final String module = FlexibleStringExpander.class.getName(); public static final String openBracket = "${"; public static final String closeBracket = "}"; protected static final UtilCache<Key, FlexibleStringExpander> exprCache = UtilCache.createUtilCache("flexibleStringExpander.ExpressionCache"); protected static final FlexibleStringExpander nullExpr = new ConstSimpleElem(new char[0]); /** * Evaluate an expression and return the result as a <code>String</code>. Null expressions return * <code>null</code>. A null <code>context</code> argument will return the original expression. * * <p>Note that the behavior of this method is not the same as using <code> * FlexibleStringExpander.getInstance(expression).expandString(context)</code> because it returns * <code>null</code> when given a null <code>expression</code> argument, and <code> * FlexibleStringExpander.getInstance(expression).expandString(context)</code> returns an empty * <code>String</code>. * * @param expression The original expression * @param context The evaluation context * @return The original expression's evaluation result as a <code>String</code> */ public static String expandString(String expression, Map<String, ? extends Object> context) { return expandString(expression, context, null, null); } /** * Evaluate an expression and return the result as a <code>String</code>. Null expressions return * <code>null</code>. A null <code>context</code> argument will return the original expression. * * <p>Note that the behavior of this method is not the same as using <code> * FlexibleStringExpander.getInstance(expression).expandString(context, locale)</code> because it * returns <code>null</code> when given a null <code>expression</code> argument, and <code> * FlexibleStringExpander.getInstance(expression).expandString(context, locale)</code> returns an * empty <code>String</code>. * * @param expression The original expression * @param context The evaluation context * @param locale The locale to be used for localization * @return The original expression's evaluation result as a <code>String</code> */ public static String expandString( String expression, Map<String, ? extends Object> context, Locale locale) { return expandString(expression, context, null, locale); } /** * Evaluate an expression and return the result as a <code>String</code>. Null expressions return * <code>null</code>. A null <code>context</code> argument will return the original expression. * * <p>Note that the behavior of this method is not the same as using <code> * FlexibleStringExpander.getInstance(expression).expandString(context, timeZone locale)</code> * because it returns <code>null</code> when given a null <code>expression</code> argument, and * <code>FlexibleStringExpander.getInstance(expression).expandString(context, timeZone, locale) * </code> returns an empty <code>String</code>. * * @param expression The original expression * @param context The evaluation context * @param timeZone The time zone to be used for localization * @param locale The locale to be used for localization * @return The original expression's evaluation result as a <code>String</code> */ public static String expandString( String expression, Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { if (expression == null) { return ""; } if (context == null || !expression.contains(openBracket)) { return expression; } FlexibleStringExpander fse = FlexibleStringExpander.getInstance(expression); return fse.expandString(context, timeZone, locale); } /** * Returns a <code>FlexibleStringExpander</code> object. * * <p>A null or empty argument will return a <code>FlexibleStringExpander</code> object that * represents an empty expression. That object is a shared singleton, so there is no memory or * performance penalty in using it. * * <p>If the method is passed a <code>String</code> argument that doesn't contain an expression, * the <code>FlexibleStringExpander</code> object that is returned does not perform any * evaluations on the original <code>String</code> - any methods that return a <code>String</code> * will return the original <code>String</code>. The object returned by this method is very * compact - taking less memory than the original <code>String</code>. * * @param expression The original expression * @return A <code>FlexibleStringExpander</code> instance */ public static FlexibleStringExpander getInstance(String expression) { return getInstance(expression, true); } /* Returns a <code>FlexibleStringExpander</code> object. <p>A null or * empty argument will return a <code>FlexibleStringExpander</code> * object that represents an empty expression. That object is a shared * singleton, so there is no memory or performance penalty in using it.</p> * <p>If the method is passed a <code>String</code> argument that doesn't * contain an expression, the <code>FlexibleStringExpander</code> object * that is returned does not perform any evaluations on the original * <code>String</code> - any methods that return a <code>String</code> * will return the original <code>String</code>. The object returned by * this method is very compact - taking less memory than the original * <code>String</code>.</p> * * @param expression The original expression * @param useCache whether to store things into a global cache * @return A <code>FlexibleStringExpander</code> instance */ public static FlexibleStringExpander getInstance(String expression, boolean useCache) { if (UtilValidate.isEmpty(expression)) { return nullExpr; } return getInstance(expression, expression.toCharArray(), 0, expression.length(), useCache); } private static FlexibleStringExpander getInstance( String expression, char[] chars, int offset, int length, boolean useCache) { if (length == 0) { return nullExpr; } if (!useCache) { return parse(chars, offset, length); } // Remove the next nine lines to cache all expressions if (!expression.contains(openBracket)) { if (chars.length == length) { return new ConstSimpleElem(chars); } else { return new ConstOffsetElem(chars, offset, length); } } Key key = chars.length == length ? new SimpleKey(chars) : new OffsetKey(chars, offset, length); FlexibleStringExpander fse = exprCache.get(key); if (fse == null) { exprCache.put(key, parse(chars, offset, length)); fse = exprCache.get(key); } return fse; } private abstract static class Key { @Override public final boolean equals(Object o) { // No class test here, nor null, as this class is only used // internally return toString().equals(o.toString()); } @Override public final int hashCode() { return toString().hashCode(); } } private static final class SimpleKey extends Key { private final char[] chars; protected SimpleKey(char[] chars) { this.chars = chars; } @Override public String toString() { return new String(chars); } } private static final class OffsetKey extends Key { private final char[] chars; private final int offset; private final int length; protected OffsetKey(char[] chars, int offset, int length) { this.chars = chars; this.offset = offset; this.length = length; } @Override public String toString() { return new String(chars, offset, length); } } private static FlexibleStringExpander parse(char[] chars, int offset, int length) { FlexibleStringExpander[] strElems = getStrElems(chars, offset, length); if (strElems.length == 1) { return strElems[0]; } else { return new Elements(chars, offset, length, strElems); } } protected static FlexibleStringExpander[] getStrElems(char[] chars, int offset, int length) { String expression = new String(chars, 0, length + offset); int start = expression.indexOf(openBracket, offset); if (start == -1) { return new FlexibleStringExpander[] {new ConstOffsetElem(chars, offset, length)}; } int origLen = length; ArrayList<FlexibleStringExpander> strElems = new ArrayList<FlexibleStringExpander>(); int currentInd = offset; int end = -1; while (start != -1) { end = expression.indexOf(closeBracket, start); if (end == -1) { Debug.logWarning( "Found a ${ without a closing } (curly-brace) in the String: " + expression, module); break; } // Check for escaped expression boolean escapedExpression = (start - 1 >= 0 && expression.charAt(start - 1) == '\\'); if (start > currentInd) { // append everything from the current index to the start of the expression strElems.add( new ConstOffsetElem( chars, currentInd, (escapedExpression ? start - 1 : start) - currentInd)); } if (expression.indexOf("bsh:", start + 2) == start + 2 && !escapedExpression) { // checks to see if this starts with a "bsh:", if so treat the rest of the expression as a // bsh scriptlet strElems.add( new BshElem( chars, start, Math.min(end + 1, start + length) - start, start + 6, end - start - 6)); } else if (expression.indexOf("groovy:", start + 2) == start + 2 && !escapedExpression) { // checks to see if this starts with a "groovy:", if so treat the rest of the expression as // a groovy scriptlet strElems.add( new GroovyElem( chars, start, Math.min(end + 1, start + length) - start, start + 9, end - start - 9)); } else { // Scan for matching closing bracket int ptr = expression.indexOf(openBracket, start + 2); while (ptr != -1 && end != -1 && ptr < end) { end = expression.indexOf(closeBracket, end + 1); ptr = expression.indexOf(openBracket, ptr + 2); } if (end == -1) { end = origLen; } // Evaluation sequence is important - do not change it if (escapedExpression) { strElems.add(new ConstOffsetElem(chars, start, end + 1 - start)); } else { String subExpression = expression.substring(start + 2, end); int currencyPos = subExpression.indexOf("?currency("); int closeParen = currencyPos > 0 ? subExpression.indexOf(")", currencyPos + 10) : -1; if (closeParen != -1) { strElems.add( new CurrElem( chars, start, Math.min(end + 1, start + length) - start, start + 2, end - start - 1)); } else if (subExpression.contains(openBracket)) { strElems.add( new NestedVarElem( chars, start, Math.min(end + 1, start + length) - start, start + 2, Math.min(end - 2, start + length) - start)); } else { strElems.add( new VarElem( chars, start, Math.min(end + 1, start + length) - start, start + 2, Math.min(end - 2, start + length) - start)); } } } // reset the current index to after the expression, and the start to the beginning of the next // expression currentInd = end + 1; if (currentInd > origLen + offset) { currentInd = origLen + offset; } start = expression.indexOf(openBracket, currentInd); } // append the rest of the original string, ie after the last expression if (currentInd < origLen + offset) { strElems.add(new ConstOffsetElem(chars, currentInd, offset + length - currentInd)); } return strElems.toArray(new FlexibleStringExpander[strElems.size()]); } // Note: a character array is used instead of a String to keep the memory footprint small. protected final char[] chars; protected int hint = 20; protected FlexibleStringExpander(char[] chars) { this.chars = chars; } protected abstract Object get( Map<String, ? extends Object> context, TimeZone timeZone, Locale locale); private static Locale getLocale(Locale locale, Map<String, ? extends Object> context) { if (locale == null) { locale = (Locale) context.get("locale"); if (locale == null && context.containsKey("autoUserLogin")) { Map<String, Object> autoUserLogin = UtilGenerics.cast(context.get("autoUserLogin")); locale = UtilMisc.ensureLocale(autoUserLogin.get("lastLocale")); } if (locale == null) { locale = Locale.getDefault(); } } return locale; } private static TimeZone getTimeZone(TimeZone timeZone, Map<String, ? extends Object> context) { if (timeZone == null) { timeZone = (TimeZone) context.get("timeZone"); if (timeZone == null && context.containsKey("autoUserLogin")) { Map<String, String> autoUserLogin = UtilGenerics.cast(context.get("autoUserLogin")); timeZone = UtilDateTime.toTimeZone(autoUserLogin.get("lastTimeZone")); } if (timeZone == null) { timeZone = TimeZone.getDefault(); } } return timeZone; } /** * Evaluate this object's expression and return the result as a <code>String</code>. Null or empty * expressions return an empty <code>String</code>. A <code>null context</code> argument will * return the original expression. * * @param context The evaluation context * @return This object's expression result as a <code>String</code> */ public String expandString(Map<String, ? extends Object> context) { return this.expandString(context, null, null); } /** * Evaluate this object's expression and return the result as a <code>String</code>. Null or empty * expressions return an empty <code>String</code>. A <code>null context</code> argument will * return the original expression. * * @param context The evaluation context * @param locale The locale to be used for localization * @return This object's expression result as a <code>String</code> */ public String expandString(Map<String, ? extends Object> context, Locale locale) { return this.expandString(context, null, locale); } /** * Evaluate this object's expression and return the result as a <code>String</code>. Null or empty * expressions return an empty <code>String</code>. A <code>null context</code> argument will * return the original expression. * * @param context The evaluation context * @param timeZone The time zone to be used for localization * @param locale The locale to be used for localization * @return This object's expression result as a <code>String</code> */ public String expandString( Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { if (context == null) { return this.toString(); } timeZone = getTimeZone(timeZone, context); locale = getLocale(locale, context); Object obj = get(context, timeZone, locale); StringBuilder buffer = new StringBuilder(this.hint); try { if (obj instanceof String && UtilValidate.isEmpty(obj)) { } else if (obj != null) { buffer.append(ObjectType.simpleTypeConvert(obj, "String", null, timeZone, locale, true)); } } catch (Exception e) { buffer.append(obj); } if (buffer.length() > this.hint) { this.hint = buffer.length(); } return buffer.toString(); } /** * Evaluate this object's expression and return the result as an <code>Object</code>. Null or * empty expressions return an empty <code>String</code>. A <code>null context</code> argument * will return the original expression. * * @param context The evaluation context * @return This object's expression result as a <code>String</code> */ public Object expand(Map<String, ? extends Object> context) { return this.expand(context, null, null); } /** * Evaluate this object's expression and return the result as an <code>Object</code>. Null or * empty expressions return an empty <code>String</code>. A <code>null context</code> argument * will return the original expression. * * @param context The evaluation context * @param locale The locale to be used for localization * @return This object's expression result as a <code>String</code> */ public Object expand(Map<String, ? extends Object> context, Locale locale) { return this.expand(context, null, locale); } /** * Evaluate this object's expression and return the result as an <code>Object</code>. Null or * empty expressions return an empty <code>String</code>. A <code>null context</code> argument * will return the original expression. * * @param context The evaluation context * @param timeZone The time zone to be used for localization * @param locale The locale to be used for localization * @return This object's expression result as a <code>String</code> */ public Object expand(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { if (context == null) { return null; } return get(context, getTimeZone(timeZone, context), getLocale(locale, context)); } /** * Returns a copy of the original expression. * * @return The original expression */ public abstract String getOriginal(); /** * Returns <code>true</code> if the original expression is empty or <code>null</code>. * * @return <code>true</code> if the original expression is empty or <code>null</code> */ public abstract boolean isEmpty(); /** * Returns a copy of the original expression. * * @return The original expression */ @Override public String toString() { return this.getOriginal(); } protected abstract static class ArrayOffsetString extends FlexibleStringExpander { protected final int offset; protected final int length; protected ArrayOffsetString(char[] chars, int offset, int length) { super(chars); this.offset = offset; this.length = length; } @Override public boolean isEmpty() { // This is always false; the complex child classes can't be // empty, as they contain at least ${; constant elements // with a length of 0 will never be created. return false; } @Override public String getOriginal() { return new String(this.chars, this.offset, this.length); } } /** An object that represents a <code>${bsh:}</code> expression. */ protected static class BshElem extends ArrayOffsetString { private final int parseStart; private final int parseLength; protected BshElem(char[] chars, int offset, int length, int parseStart, int parseLength) { super(chars, offset, length); this.parseStart = parseStart; this.parseLength = parseLength; } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { try { Object obj = BshUtil.eval( new String(this.chars, this.parseStart, this.parseLength), UtilMisc.makeMapWritable(context)); if (obj != null) { return obj; } else { if (Debug.verboseOn()) { Debug.logVerbose( "BSH scriptlet evaluated to null [" + this + "], got no return so inserting nothing.", module); } } } catch (EvalError e) { Debug.logWarning( e, "Error evaluating BSH scriptlet [" + this + "], inserting nothing; error was: " + e, module); } return null; } } /** An object that represents a <code>String</code> constant portion of an expression. */ protected static class ConstSimpleElem extends FlexibleStringExpander { protected ConstSimpleElem(char[] chars) { super(chars); } @Override public boolean isEmpty() { return this.chars.length == 0; } @Override public String getOriginal() { return new String(this.chars); } @Override public String expandString( Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { return getOriginal(); } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { return isEmpty() ? null : getOriginal(); } } /** An object that represents a <code>String</code> constant portion of an expression. */ protected static class ConstOffsetElem extends ArrayOffsetString { protected ConstOffsetElem(char[] chars, int offset, int length) { super(chars, offset, length); } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { return getOriginal(); } @Override public String expandString( Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { return new String(this.chars, this.offset, this.length); } } /** An object that represents a currency portion of an expression. */ protected static class CurrElem extends ArrayOffsetString { protected final char[] valueStr; protected final FlexibleStringExpander codeExpr; protected CurrElem(char[] chars, int offset, int length, int parseStart, int parseLength) { super(chars, offset, length); String parse = new String(chars, parseStart, parseLength); int currencyPos = parse.indexOf("?currency("); int closeParen = parse.indexOf(")", currencyPos + 10); this.codeExpr = FlexibleStringExpander.getInstance( parse, chars, parseStart + currencyPos + 10, closeParen - currencyPos - 10, true); this.valueStr = openBracket.concat(parse.substring(0, currencyPos)).concat(closeBracket).toCharArray(); } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { try { Object obj = UelUtil.evaluate(context, new String(this.valueStr)); if (obj != null) { String currencyCode = this.codeExpr.expandString(context, timeZone, locale); return UtilFormatOut.formatCurrency(new BigDecimal(obj.toString()), currencyCode, locale); } } catch (PropertyNotFoundException e) { if (Debug.verboseOn()) { Debug.logVerbose("Error evaluating expression: " + e, module); } } catch (Exception e) { Debug.logError("Error evaluating expression: " + e, module); } return null; } } /** A container object that contains expression fragments. */ protected static class Elements extends ArrayOffsetString { protected final FlexibleStringExpander[] childElems; protected Elements(char[] chars, int offset, int length, FlexibleStringExpander[] childElems) { super(chars, offset, length); this.childElems = childElems; } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { StringBuilder buffer = new StringBuilder(); for (FlexibleStringExpander child : this.childElems) { buffer.append(child.expandString(context, timeZone, locale)); } return buffer.toString(); } } /** An object that represents a <code>${groovy:}</code> expression. */ protected static class GroovyElem extends ArrayOffsetString { protected final Class<?> parsedScript; protected GroovyElem(char[] chars, int offset, int length, int parseStart, int parseLength) { super(chars, offset, length); this.parsedScript = GroovyUtil.parseClass(new String(chars, parseStart, parseLength)); } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { try { Object obj = InvokerHelper.createScript(this.parsedScript, GroovyUtil.getBinding(context)).run(); if (obj != null) { return obj; } else { if (Debug.verboseOn()) { Debug.logVerbose( "Groovy scriptlet evaluated to null [" + this + "], got no return so inserting nothing.", module); } } } catch (Exception e) { // handle other things, like the groovy.lang.MissingPropertyException Debug.logWarning( e, "Error evaluating Groovy scriptlet [" + this + "], inserting nothing; error was: " + e, module); } return null; } } /** An object that represents a nested expression. */ protected static class NestedVarElem extends ArrayOffsetString { protected final FlexibleStringExpander[] childElems; protected NestedVarElem(char[] chars, int offset, int length, int parseStart, int parseLength) { super(chars, offset, length); this.childElems = getStrElems(chars, parseStart, parseLength); if (length > this.hint) { this.hint = length; } } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { StringBuilder expr = new StringBuilder(this.hint); for (FlexibleStringExpander child : this.childElems) { expr.append(child.expandString(context, timeZone, locale)); } if (expr.length() == 0) { return ""; } try { return UelUtil.evaluate(context, openBracket.concat(expr.toString()).concat(closeBracket)); } catch (PropertyNotFoundException e) { if (Debug.verboseOn()) { Debug.logVerbose("Error evaluating expression: " + e, module); } } catch (Exception e) { Debug.logError("Error evaluating expression: " + e, module); } return ""; } } /** An object that represents a simple, non-nested expression. */ protected static class VarElem extends ArrayOffsetString { protected final char[] bracketedOriginal; protected VarElem(char[] chars, int offset, int length, int parseStart, int parseLength) { super(chars, offset, length); this.bracketedOriginal = openBracket .concat(UelUtil.prepareExpression(new String(chars, parseStart, parseLength))) .concat(closeBracket) .toCharArray(); } @Override protected Object get(Map<String, ? extends Object> context, TimeZone timeZone, Locale locale) { Object obj = null; try { obj = UelUtil.evaluate(context, new String(this.bracketedOriginal)); } catch (PropertyNotFoundException e) { if (Debug.verboseOn()) { Debug.logVerbose("Error evaluating expression " + this + ": " + e, module); } } catch (Exception e) { Debug.logError("Error evaluating expression " + this + ": " + e, module); } if (obj != null) { try { // Check for runtime nesting String str = (String) obj; if (str.contains(openBracket)) { FlexibleStringExpander fse = FlexibleStringExpander.getInstance(str); return fse.get(context, timeZone, locale); } } catch (ClassCastException e) { } } return obj; } } }
public void render( String name, String page, String info, String contentType, String encoding, HttpServletRequest request, HttpServletResponse response) throws ViewHandlerException { // some containers call filters on EVERY request, even forwarded ones, // so let it know that it came from the control servlet if (request == null) { throw new ViewHandlerException( "The HttpServletRequest object was null, how did that happen?"); } if (UtilValidate.isEmpty(page)) { throw new ViewHandlerException("View page was null or empty, but must be specified"); } if (UtilValidate.isEmpty(info)) { Debug.logInfo( "View info string was null or empty, (optionally used to specify an Entity that is mapped to the Entity Engine datasource that the report will use).", module); } // tell the ContextFilter we are forwarding request.setAttribute(ContextFilter.FORWARDED_FROM_SERVLET, Boolean.valueOf(true)); Delegator delegator = (Delegator) request.getAttribute("delegator"); if (delegator == null) { throw new ViewHandlerException("The delegator object was null, how did that happen?"); } try { JasperReport report = (JasperReport) jasperReportsCompiledCache.get(page); if (report == null) { synchronized (this) { report = (JasperReport) jasperReportsCompiledCache.get(page); if (report == null) { InputStream is = context.getResourceAsStream(page); report = JasperCompileManager.compileReport(is); jasperReportsCompiledCache.put(page, report); } } } response.setContentType("application/xls"); Map parameters = (Map) request.getAttribute("jrParameters"); if (parameters == null) { parameters = UtilHttp.getParameterMap(request); } JRDataSource jrDataSource = (JRDataSource) request.getAttribute("jrDataSource"); JasperPrint jp = null; if (jrDataSource == null) { String datasourceName = delegator.getEntityHelperName(info); if (UtilValidate.isNotEmpty(datasourceName)) { Debug.logInfo( "Filling report with connection from datasource: " + datasourceName, module); jp = JasperFillManager.fillReport( report, parameters, ConnectionFactory.getConnection(datasourceName)); } else { Debug.logInfo("Filling report with an empty JR datasource", module); jp = JasperFillManager.fillReport(report, parameters, new JREmptyDataSource()); } } else { Debug.logInfo("Filling report with a passed in jrDataSource", module); jp = JasperFillManager.fillReport(report, parameters, jrDataSource); } if (jp.getPages().size() < 1) { throw new ViewHandlerException("Report is Empty (no results?)"); } else { Debug.logInfo("Got report, there are " + jp.getPages().size() + " pages.", module); } JExcelApiExporter exporter = new JExcelApiExporter(); exporter.setParameter(JExcelApiExporterParameter.JASPER_PRINT, jp); exporter.setParameter(JExcelApiExporterParameter.OUTPUT_STREAM, response.getOutputStream()); exporter.exportReport(); } catch (IOException ie) { throw new ViewHandlerException("IO Error in report", ie); } catch (java.sql.SQLException e) { throw new ViewHandlerException("Database error while running report", e); } catch (Exception e) { throw new ViewHandlerException("Error in report", e); // } catch (ServletException se) { // throw new ViewHandlerException("Error in region", se.getRootCause()); } }
/** Widget Library - Tree factory class */ public class TreeFactory { public static final String module = TreeFactory.class.getName(); public static final UtilCache<String, Map<String, ModelTree>> treeLocationCache = UtilCache.createUtilCache("widget.tree.locationResource", 0, 0, false); public static final UtilCache<String, Map<String, ModelTree>> treeWebappCache = UtilCache.createUtilCache("widget.tree.webappResource", 0, 0, false); public static ModelTree getTreeFromLocation( String resourceName, String treeName, Delegator delegator, LocalDispatcher dispatcher) throws IOException, SAXException, ParserConfigurationException { Map<String, ModelTree> modelTreeMap = treeLocationCache.get(resourceName); if (modelTreeMap == null) { synchronized (TreeFactory.class) { modelTreeMap = treeLocationCache.get(resourceName); if (modelTreeMap == null) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { loader = TreeFactory.class.getClassLoader(); } URL treeFileUrl = null; treeFileUrl = FlexibleLocation.resolveLocation(resourceName); // , loader); Document treeFileDoc = UtilXml.readXmlDocument(treeFileUrl, true); modelTreeMap = readTreeDocument(treeFileDoc, delegator, dispatcher, resourceName); treeLocationCache.put(resourceName, modelTreeMap); } } } ModelTree modelTree = (ModelTree) modelTreeMap.get(treeName); if (modelTree == null) { throw new IllegalArgumentException( "Could not find tree with name [" + treeName + "] in class resource [" + resourceName + "]"); } return modelTree; } public static ModelTree getTreeFromWebappContext( String resourceName, String treeName, HttpServletRequest request) throws IOException, SAXException, ParserConfigurationException { String webappName = UtilHttp.getApplicationName(request); String cacheKey = webappName + "::" + resourceName; Map<String, ModelTree> modelTreeMap = treeWebappCache.get(cacheKey); if (modelTreeMap == null) { synchronized (TreeFactory.class) { modelTreeMap = treeWebappCache.get(cacheKey); if (modelTreeMap == null) { ServletContext servletContext = (ServletContext) request.getAttribute("servletContext"); Delegator delegator = (Delegator) request.getAttribute("delegator"); LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); URL treeFileUrl = servletContext.getResource(resourceName); Document treeFileDoc = UtilXml.readXmlDocument(treeFileUrl, true); modelTreeMap = readTreeDocument(treeFileDoc, delegator, dispatcher, cacheKey); treeWebappCache.put(cacheKey, modelTreeMap); } } } ModelTree modelTree = (ModelTree) modelTreeMap.get(treeName); if (modelTree == null) { throw new IllegalArgumentException( "Could not find tree with name [" + treeName + "] in webapp resource [" + resourceName + "] in the webapp [" + webappName + "]"); } return modelTree; } public static Map<String, ModelTree> readTreeDocument( Document treeFileDoc, Delegator delegator, LocalDispatcher dispatcher, String treeLocation) { Map<String, ModelTree> modelTreeMap = new HashMap<String, ModelTree>(); if (treeFileDoc != null) { // read document and construct ModelTree for each tree element Element rootElement = treeFileDoc.getDocumentElement(); for (Element treeElement : UtilXml.childElementList(rootElement, "tree")) { ModelTree modelTree = new ModelTree(treeElement, delegator, dispatcher); modelTree.setTreeLocation(treeLocation); modelTreeMap.put(modelTree.getName(), modelTree); } } return modelTreeMap; } }
/** EntityEcaUtil */ public class EntityEcaUtil { public static final String module = EntityEcaUtil.class.getName(); public static UtilCache<String, Map<String, Map<String, List<EntityEcaRule>>>> entityEcaReaders = UtilCache.createUtilCache("entity.EcaReaders", 0, 0, false); public static Map<String, Map<String, List<EntityEcaRule>>> getEntityEcaCache( String entityEcaReaderName) { Map<String, Map<String, List<EntityEcaRule>>> ecaCache = entityEcaReaders.get(entityEcaReaderName); if (ecaCache == null) { synchronized (EntityEcaUtil.class) { ecaCache = entityEcaReaders.get(entityEcaReaderName); if (ecaCache == null) { ecaCache = FastMap.newInstance(); readConfig(entityEcaReaderName, ecaCache); entityEcaReaders.put(entityEcaReaderName, ecaCache); } } } return ecaCache; } public static String getEntityEcaReaderName(String delegatorName) { DelegatorInfo delegatorInfo = EntityConfigUtil.getDelegatorInfo(delegatorName); if (delegatorInfo == null) { Debug.logError( "BAD ERROR: Could not find delegator config with name: " + delegatorName, module); return null; } return delegatorInfo.entityEcaReader; } protected static void readConfig( String entityEcaReaderName, Map<String, Map<String, List<EntityEcaRule>>> ecaCache) { EntityEcaReaderInfo entityEcaReaderInfo = EntityConfigUtil.getEntityEcaReaderInfo(entityEcaReaderName); if (entityEcaReaderInfo == null) { Debug.logError( "BAD ERROR: Could not find entity-eca-reader config with name: " + entityEcaReaderName, module); return; } for (Element eecaResourceElement : entityEcaReaderInfo.resourceElements) { ResourceHandler handler = new MainResourceHandler(EntityConfigUtil.ENTITY_ENGINE_XML_FILENAME, eecaResourceElement); addEcaDefinitions(handler, ecaCache); } // get all of the component resource eca stuff, ie specified in each ofbiz-component.xml file for (ComponentConfig.EntityResourceInfo componentResourceInfo : ComponentConfig.getAllEntityResourceInfos("eca")) { if (entityEcaReaderName.equals(componentResourceInfo.readerName)) { addEcaDefinitions(componentResourceInfo.createResourceHandler(), ecaCache); } } } protected static void addEcaDefinitions( ResourceHandler handler, Map<String, Map<String, List<EntityEcaRule>>> ecaCache) { Element rootElement = null; try { rootElement = handler.getDocument().getDocumentElement(); } catch (GenericConfigException e) { Debug.logError(e, module); return; } int numDefs = 0; for (Element e : UtilXml.childElementList(rootElement, "eca")) { String entityName = e.getAttribute("entity"); String eventName = e.getAttribute("event"); Map<String, List<EntityEcaRule>> eventMap = ecaCache.get(entityName); List<EntityEcaRule> rules = null; if (eventMap == null) { eventMap = FastMap.newInstance(); rules = FastList.newInstance(); ecaCache.put(entityName, eventMap); eventMap.put(eventName, rules); } else { rules = eventMap.get(eventName); if (rules == null) { rules = FastList.newInstance(); eventMap.put(eventName, rules); } } rules.add(new EntityEcaRule(e)); numDefs++; } try { Debug.logImportant( "Loaded [" + numDefs + "] Entity ECA definitions from " + handler.getFullLocation() + " in loader " + handler.getLoaderName(), module); } catch (GenericConfigException e) { Debug.logError(e, module); return; } } public static Collection<EntityEcaRule> getEntityEcaRules( Delegator delegator, String entityName, String event) { Map<String, Map<String, List<EntityEcaRule>>> ecaCache = EntityEcaUtil.getEntityEcaCache( EntityEcaUtil.getEntityEcaReaderName(delegator.getDelegatorName())); Map<String, List<EntityEcaRule>> eventMap = ecaCache.get(entityName); if (eventMap != null) { if (event != null) { return eventMap.get(event); } } return null; } }
/** Common Services */ public class CommonEvents { public static final String module = CommonEvents.class.getName(); public static UtilCache<String, Map<String, String>> appletSessions = UtilCache.createUtilCache("AppletSessions", 0, 600000, true); public static String checkAppletRequest( HttpServletRequest request, HttpServletResponse response) { Delegator delegator = (Delegator) request.getAttribute("delegator"); String sessionId = request.getParameter("sessionId"); String visitId = request.getParameter("visitId"); sessionId = sessionId.trim(); visitId = visitId.trim(); String responseString = ""; GenericValue visit = null; try { visit = delegator.findOne("Visit", false, "visitId", visitId); } catch (GenericEntityException e) { Debug.logError(e, "Cannot Visit Object", module); } if (visit != null && visit.getString("sessionId").equals(sessionId) && appletSessions.containsKey(sessionId)) { Map<String, String> sessionMap = appletSessions.get(sessionId); if (sessionMap != null && sessionMap.containsKey("followPage")) responseString = sessionMap.remove("followPage"); } try { PrintWriter out = response.getWriter(); response.setContentType("text/plain"); out.println(responseString); out.close(); } catch (IOException e) { Debug.logError(e, "Problems writing servlet output!", module); } return "success"; } public static String receiveAppletRequest( HttpServletRequest request, HttpServletResponse response) { Delegator delegator = (Delegator) request.getAttribute("delegator"); String sessionId = request.getParameter("sessionId"); String visitId = request.getParameter("visitId"); sessionId = sessionId.trim(); visitId = visitId.trim(); String responseString = "ERROR"; GenericValue visit = null; try { visit = delegator.findOne("Visit", false, "visitId", visitId); } catch (GenericEntityException e) { Debug.logError(e, "Cannot Visit Object", module); } if (visit.getString("sessionId").equals(sessionId)) { String currentPage = request.getParameter("currentPage"); if (appletSessions.containsKey(sessionId)) { Map<String, String> sessionMap = appletSessions.get(sessionId); String followers = sessionMap.get("followers"); List<String> folList = StringUtil.split(followers, ","); for (String follower : folList) { Map<String, String> folSesMap = UtilMisc.toMap("followPage", currentPage); appletSessions.put(follower, folSesMap); } } responseString = "OK"; } try { PrintWriter out = response.getWriter(); response.setContentType("text/plain"); out.println(responseString); out.close(); } catch (IOException e) { Debug.logError(e, "Problems writing servlet output!", module); } return "success"; } public static String setAppletFollower(HttpServletRequest request, HttpServletResponse response) { Security security = (Security) request.getAttribute("security"); GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); String visitId = request.getParameter("visitId"); if (visitId != null) request.setAttribute("visitId", visitId); if (security.hasPermission("SEND_CONTROL_APPLET", userLogin)) { String followerSessionId = request.getParameter("followerSid"); String followSessionId = request.getParameter("followSid"); Map<String, String> follow = appletSessions.get(followSessionId); if (follow == null) follow = FastMap.newInstance(); String followerListStr = follow.get("followers"); if (followerListStr == null) { followerListStr = followerSessionId; } else { followerListStr = followerListStr + "," + followerSessionId; } appletSessions.put(followSessionId, follow); appletSessions.put(followerSessionId, null); } return "success"; } public static String setFollowerPage(HttpServletRequest request, HttpServletResponse response) { Security security = (Security) request.getAttribute("security"); GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); String visitId = request.getParameter("visitId"); if (visitId != null) request.setAttribute("visitId", visitId); if (security.hasPermission("SEND_CONTROL_APPLET", userLogin)) { String followerSessionId = request.getParameter("followerSid"); String pageUrl = request.getParameter("pageUrl"); Map<String, String> follow = appletSessions.get(followerSessionId); if (follow == null) follow = FastMap.newInstance(); follow.put("followPage", pageUrl); appletSessions.put(followerSessionId, follow); } return "success"; } /** * Simple event to set the users per-session locale setting. The user's locale setting should be * passed as a "newLocale" request parameter. */ public static String setSessionLocale(HttpServletRequest request, HttpServletResponse response) { String localeString = request.getParameter("newLocale"); if (UtilValidate.isNotEmpty(localeString)) { UtilHttp.setLocale(request, localeString); // update the UserLogin object GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); if (userLogin == null) { userLogin = (GenericValue) request.getSession().getAttribute("autoUserLogin"); } if (userLogin != null) { GenericValue ulUpdate = GenericValue.create(userLogin); ulUpdate.set("lastLocale", localeString); try { ulUpdate.store(); userLogin.refreshFromCache(); } catch (GenericEntityException e) { Debug.logWarning(e, module); } } } return "success"; } /** Simple event to set the user's per-session time zone setting. */ public static String setSessionTimeZone( HttpServletRequest request, HttpServletResponse response) { String tzString = request.getParameter("tzId"); if (UtilValidate.isNotEmpty(tzString)) { UtilHttp.setTimeZone(request, tzString); // update the UserLogin object GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); if (userLogin == null) { userLogin = (GenericValue) request.getSession().getAttribute("autoUserLogin"); } if (userLogin != null) { GenericValue ulUpdate = GenericValue.create(userLogin); ulUpdate.set("lastTimeZone", tzString); try { ulUpdate.store(); userLogin.refreshFromCache(); } catch (GenericEntityException e) { Debug.logWarning(e, module); } } } return "success"; } /** Simple event to set the users per-session currency uom value */ public static String setSessionCurrencyUom( HttpServletRequest request, HttpServletResponse response) { String currencyUom = request.getParameter("currencyUom"); if (UtilValidate.isNotEmpty(currencyUom)) { // update the session UtilHttp.setCurrencyUom(request.getSession(), currencyUom); // update the UserLogin object GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); if (userLogin == null) { userLogin = (GenericValue) request.getSession().getAttribute("autoUserLogin"); } if (userLogin != null) { GenericValue ulUpdate = GenericValue.create(userLogin); ulUpdate.set("lastCurrencyUom", currencyUom); try { ulUpdate.store(); userLogin.refreshFromCache(); } catch (GenericEntityException e) { Debug.logWarning(e, module); } } } return "success"; } public static String jsonResponseFromRequestAttributes( HttpServletRequest request, HttpServletResponse response) { // pull out the service response from the request attribute Map<String, Object> attrMap = UtilHttp.getJSONAttributeMap(request); // create a JSON Object for return JSONObject json = JSONObject.fromObject(attrMap); writeJSONtoResponse(json, response); return "success"; } private static void writeJSONtoResponse(JSON json, HttpServletResponse response) { String jsonStr = json.toString(); if (jsonStr == null) { Debug.logError("JSON Object was empty; fatal error!", module); return; } // set the X-JSON content type response.setContentType("application/x-json"); // jsonStr.length is not reliable for unicode characters try { response.setContentLength(jsonStr.getBytes("UTF8").length); } catch (UnsupportedEncodingException e) { Debug.logError("Problems with Json encoding: " + e, module); } // return the JSON String Writer out; try { out = response.getWriter(); out.write(jsonStr); out.flush(); } catch (IOException e) { Debug.logError(e, module); } } public static String getJSONuiLabelArray( HttpServletRequest request, HttpServletResponse response) { String requiredLabels = request.getParameter("requiredLabels"); JSONObject uiLabelObject = null; if (UtilValidate.isNotEmpty(requiredLabels)) { // Transform JSON String to Object uiLabelObject = (JSONObject) JSONSerializer.toJSON(requiredLabels); } JSONObject jsonUiLabel = new JSONObject(); Locale locale = request.getLocale(); if (!uiLabelObject.isEmpty()) { Set<String> resourceSet = UtilGenerics.checkSet(uiLabelObject.keySet()); // Iterate over the resouce set for (String resource : resourceSet) { JSONArray labels = uiLabelObject.getJSONArray(resource); if (labels.isEmpty() || labels == null) { continue; } // Iterate over the uiLabel List Iterator<String> jsonLabelIterator = UtilGenerics.cast(labels.iterator()); JSONArray resourceLabelList = new JSONArray(); while (jsonLabelIterator.hasNext()) { String label = jsonLabelIterator.next(); String receivedLabel = UtilProperties.getMessage(resource, label, locale); if (UtilValidate.isNotEmpty(receivedLabel)) { resourceLabelList.add(receivedLabel); } } jsonUiLabel.element(resource, resourceLabelList); } } writeJSONtoResponse(jsonUiLabel, response); return "success"; } public static String getJSONuiLabel(HttpServletRequest request, HttpServletResponse response) { String requiredLabels = request.getParameter("requiredLabel"); JSONObject uiLabelObject = null; if (UtilValidate.isNotEmpty(requiredLabels)) { // Transform JSON String to Object uiLabelObject = (JSONObject) JSONSerializer.toJSON(requiredLabels); } JSONArray jsonUiLabel = new JSONArray(); Locale locale = request.getLocale(); if (!uiLabelObject.isEmpty()) { Set<String> resourceSet = UtilGenerics.checkSet(uiLabelObject.keySet()); // Iterate over the resource set // here we need a keySet because we don't now which label resource to load // the key set should have the size one, if greater or empty error should returned if (UtilValidate.isEmpty(resourceSet)) { Debug.logError("No resource and labels found", module); return "error"; } else if (resourceSet.size() > 1) { Debug.logError( "More than one resource found, please use the method: getJSONuiLabelArray", module); return "error"; } for (String resource : resourceSet) { String label = uiLabelObject.getString(resource); if (UtilValidate.isEmail(label)) { continue; } String receivedLabel = UtilProperties.getMessage(resource, label, locale); jsonUiLabel.add(receivedLabel); } } writeJSONtoResponse(jsonUiLabel, response); return "success"; } public static String getCaptcha(HttpServletRequest request, HttpServletResponse response) { try { final String captchaSizeConfigName = StringUtils.defaultIfEmpty(request.getParameter("captchaSize"), "default"); final String captchaSizeConfig = UtilProperties.getPropertyValue("captcha.properties", "captcha." + captchaSizeConfigName); final String[] captchaSizeConfigs = captchaSizeConfig.split("\\|"); final String captchaCodeId = StringUtils.defaultIfEmpty( request.getParameter("captchaCodeId"), ""); // this is used to uniquely identify in the user session the attribute where the // captcha code for the last captcha for the form is stored final int fontSize = Integer.parseInt(captchaSizeConfigs[0]); final int height = Integer.parseInt(captchaSizeConfigs[1]); final int width = Integer.parseInt(captchaSizeConfigs[2]); final int charsToPrint = UtilProperties.getPropertyAsInteger("captcha.properties", "captcha.code_length", 6); final char[] availableChars = UtilProperties.getPropertyValue("captcha.properties", "captcha.characters").toCharArray(); // It is possible to pass the font size, image width and height with the request as well Color backgroundColor = Color.gray; Color borderColor = Color.DARK_GRAY; Color textColor = Color.ORANGE; Color circleColor = new Color(160, 160, 160); Font textFont = new Font("Arial", Font.PLAIN, fontSize); int circlesToDraw = 6; float horizMargin = 20.0f; double rotationRange = 0.7; // in radians BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) bufferedImage.getGraphics(); g.setColor(backgroundColor); g.fillRect(0, 0, width, height); // Generating some circles for background noise g.setColor(circleColor); for (int i = 0; i < circlesToDraw; i++) { int circleRadius = (int) (Math.random() * height / 2.0); int circleX = (int) (Math.random() * width - circleRadius); int circleY = (int) (Math.random() * height - circleRadius); g.drawOval(circleX, circleY, circleRadius * 2, circleRadius * 2); } g.setColor(textColor); g.setFont(textFont); FontMetrics fontMetrics = g.getFontMetrics(); int maxAdvance = fontMetrics.getMaxAdvance(); int fontHeight = fontMetrics.getHeight(); String captchaCode = RandomStringUtils.random(6, availableChars); float spaceForLetters = -horizMargin * 2 + width; float spacePerChar = spaceForLetters / (charsToPrint - 1.0f); for (int i = 0; i < captchaCode.length(); i++) { // this is a separate canvas used for the character so that // we can rotate it independently int charWidth = fontMetrics.charWidth(captchaCode.charAt(i)); int charDim = Math.max(maxAdvance, fontHeight); int halfCharDim = (charDim / 2); BufferedImage charImage = new BufferedImage(charDim, charDim, BufferedImage.TYPE_INT_ARGB); Graphics2D charGraphics = charImage.createGraphics(); charGraphics.translate(halfCharDim, halfCharDim); double angle = (Math.random() - 0.5) * rotationRange; charGraphics.transform(AffineTransform.getRotateInstance(angle)); charGraphics.translate(-halfCharDim, -halfCharDim); charGraphics.setColor(textColor); charGraphics.setFont(textFont); int charX = (int) (0.5 * charDim - 0.5 * charWidth); charGraphics.drawString( "" + captchaCode.charAt(i), charX, ((charDim - fontMetrics.getAscent()) / 2 + fontMetrics.getAscent())); float x = horizMargin + spacePerChar * (i) - charDim / 2.0f; int y = ((height - charDim) / 2); g.drawImage(charImage, (int) x, y, charDim, charDim, null, null); charGraphics.dispose(); } // Drawing the image border g.setColor(borderColor); g.drawRect(0, 0, width - 1, height - 1); g.dispose(); response.setContentType("image/jpeg"); ImageIO.write(bufferedImage, "jpg", response.getOutputStream()); HttpSession session = request.getSession(); Map captchaCodeMap = (Map) session.getAttribute("_CAPTCHA_CODE_"); if (captchaCodeMap == null) { captchaCodeMap = new HashMap(); session.setAttribute("_CAPTCHA_CODE_", captchaCodeMap); } captchaCodeMap.put(captchaCodeId, captchaCode); } catch (Exception ioe) { Debug.logError(ioe.getMessage(), module); } return "success"; } }