/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.web.taglib; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.TagSupport; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.api.context.Context; import org.openmrs.util.OpenmrsUtil; import org.openmrs.web.taglib.fieldgen.FieldGenHandler; import org.openmrs.web.taglib.fieldgen.FieldGenHandlerFactory; import org.openmrs.web.taglib.fieldgen.LocationHandler; public class FieldGenTag extends TagSupport { public static final long serialVersionUID = 21132L; private final Log log = LogFactory.getLog(getClass()); public static final String DEFAULT_INPUT_TEXT_LENGTH = "20"; public static final String DEFAULT_INPUT_INT_LENGTH = "8"; public static final String DEFAULT_INPUT_FLOAT_LENGTH = "12"; public static final String DEFAULT_INPUT_CHAR_LENGTH = "2"; private String type; private String formFieldName; private Object val; private String url; private String parameters = ""; private Map<String, Object> parameterMap = null; private Boolean allowUserDefault = Boolean.FALSE; // should not be reset each time private FieldGenHandlerFactory factory = null; //private String fieldLength; //private String forceInputType; //private String isNullable; //private String hasLabelBefore; //private String trueLabel; //private String falseLabel; //private String unknownLabel; //private String emptySelectMessage; //private String additionalArgs; //private Map<String,String> args; public PageContext getPageContext() { return this.pageContext; } @SuppressWarnings("unchecked") public int doStartTag() throws JspException { if (type == null) type = ""; if (formFieldName == null) formFieldName = ""; if (formFieldName.length() > 0) { FieldGenHandler handler = getHandlerByClassName(type); if (handler != null) { handler.setFieldGenTag(this); handler.run(); } else { String output = "Cannot handle type [" + type + "]. Please add a module to handle this type."; if (type.equals("char") || type.indexOf("java.lang.Character") >= 0) { String startVal = ""; if (val != null) { startVal = val.toString(); } startVal = (startVal == null) ? "" : startVal; if (startVal.length() > 1) startVal = startVal.substring(0, 1); String fieldLength = this.parameterMap != null ? (String) this.parameterMap.get("fieldLength") : null; fieldLength = (fieldLength == null) ? DEFAULT_INPUT_CHAR_LENGTH : fieldLength; output = "<input type=\"text\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "\" value=\"" + startVal + "\" size=\"" + fieldLength + "\" maxlength=\"1\" />"; } else if (type.equals("int") || type.indexOf("java.lang.Integer") >= 0 || type.equals("long") || type.indexOf("java.lang.Long") >= 0) { String startVal = ""; if (val != null) { startVal = val.toString(); } startVal = (startVal == null) ? "" : startVal; String fieldLength = this.parameterMap != null ? (String) this.parameterMap.get("fieldLength") : null; fieldLength = (fieldLength == null) ? DEFAULT_INPUT_INT_LENGTH : fieldLength; output = "<input type=\"text\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "\" value=\"" + startVal + "\" size=\"" + fieldLength + "\" />"; } else if (type.equals("float") || type.indexOf("java.lang.Float") >= 0 || type.equals("double") || type.indexOf("java.lang.Double") >= 0 || type.indexOf("java.lang.Number") >= 0) { String startVal = ""; if (val != null) { startVal = val.toString(); } startVal = (startVal == null) ? "" : startVal; String fieldLength = this.parameterMap != null ? (String) this.parameterMap.get("fieldLength") : null; fieldLength = (fieldLength == null) ? DEFAULT_INPUT_FLOAT_LENGTH : fieldLength; output = "<input type=\"text\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "\" value=\"" + startVal + "\" size=\"" + fieldLength + "\" />"; } else if (type.equals("boolean") || type.indexOf("java.lang.Boolean") >= 0) { String startVal = ""; if (val != null) { startVal = val.toString(); } startVal = (startVal == null) ? "" : startVal.toLowerCase(); if ("false".equals(startVal) || "0".equals(startVal)) startVal = "false"; if ("true".equals(startVal) || "1".equals(startVal)) startVal = "true"; if ("unknown".equals(startVal) || "?".equals(startVal)) startVal = "unknown"; String forceInputType = this.parameterMap != null ? (String) this.parameterMap.get("forceInputType") : null; String isNullable = this.parameterMap != null ? (String) this.parameterMap.get("isNullable") : null; String trueLabel = this.parameterMap != null ? (String) this.parameterMap.get("trueLabel") : null; String falseLabel = this.parameterMap != null ? (String) this.parameterMap.get("falseLabel") : null; String unknownLabel = this.parameterMap != null ? (String) this.parameterMap.get("unknownLabel") : null; if (forceInputType == null) forceInputType = ""; if ("checkbox".equals(forceInputType)) { output = "<input type=\"checkbox\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "\" value=\"true\"" + ("true".equals(startVal) ? " checked" : "") + "/> "; } else { if (isNullable == null) isNullable = ""; if (trueLabel == null) trueLabel = Context.getMessageSourceService().getMessage("general.yes"); if (falseLabel == null) falseLabel = Context.getMessageSourceService().getMessage("general.no"); if (unknownLabel == null) unknownLabel = Context.getMessageSourceService().getMessage("general.unknown"); if ("false".equalsIgnoreCase(isNullable) || "f".equalsIgnoreCase(isNullable) || "0".equals(isNullable)) { output = "<input type=\"radio\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "_f\" value=\"false\"" + ("false".equals(startVal) ? " checked" : "") + "/> "; output += falseLabel; output += "      "; output += "<input type=\"radio\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "_t\" value=\"true\"" + ("true".equals(startVal) ? " checked" : "") + "/> "; output += trueLabel; } else { output = "<input type=\"radio\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "_f\" value=\"false\"" + ("false".equals(startVal) ? " checked" : "") + "/> "; output += falseLabel; output += "      "; output += "<input type=\"radio\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "_t\" value=\"true\"" + ("true".equals(startVal) ? " checked" : "") + "/> "; output += trueLabel; output += "      "; output += "<input type=\"radio\" name=\"" + formFieldName + "\" id=\"" + formFieldName + "_u\" value=\"unknown\"" + ("unknown".equals(startVal) ? " checked" : "") + "/> "; output += unknownLabel; } } } else if (type.indexOf("$") >= 0) { // this could be an enum - if so, let's display it String className = type; Class cls = null; try { cls = Class.forName(className); } catch (Throwable t) { cls = null; log.error("Could not instantiate class for this enum of class name [" + className + "] in FieldGenTag"); } if (cls != null) { if (cls.isEnum()) { Object[] enumConstants = cls.getEnumConstants(); if (enumConstants != null) { if (enumConstants.length > 0) { String startVal = ""; if (val != null) startVal = val.toString(); log.debug("val is " + val); log.debug("val.toString is " + startVal); if (startVal == null) startVal = ""; output = "<select name=\"" + formFieldName + "\" id=\"" + formFieldName + "\">"; for (int i = 0; i < enumConstants.length; i++) { output += "<option value=\"" + enumConstants[i].toString() + "\"" + (startVal.equals(enumConstants[i].toString()) ? " selected" : "") + ">"; output += enumConstants[i].toString(); output += "</option>"; } output += "</select> "; } } } } } // end checking different built-in types try { pageContext.getOut().write(output); } catch (IOException e) { log.error(e); } } } if (url == null) url = "default.field"; // all fieldGens are contained in the /WEB-INF/view/fieldGen/ folder and end with .field if (!url.endsWith("field")) url += ".field"; url = "/fieldGen/" + url; // add attrs to request so that the controller (and field jsp) can see/use them pageContext.getRequest().setAttribute("org.openmrs.fieldGen.type", type); pageContext.getRequest().setAttribute("org.openmrs.fieldGen.formFieldName", formFieldName); pageContext.getRequest().setAttribute("org.openmrs.fieldGen.parameters", OpenmrsUtil.parseParameterList(parameters)); HashMap<String, Object> hmParamMap = (HashMap<String, Object>) pageContext.getRequest().getAttribute( "org.openmrs.fieldGen.parameterMap"); if (hmParamMap == null) hmParamMap = new HashMap<String, Object>(); if (this.parameterMap != null) hmParamMap.putAll(this.parameterMap); pageContext.getRequest().setAttribute("org.openmrs.fieldGen.parameterMap", hmParamMap); pageContext.getRequest().setAttribute("org.openmrs.fieldGen.object", val); pageContext.getRequest().setAttribute("org.openmrs.fieldGen.request", pageContext.getRequest()); try { pageContext.include(this.url); } catch (ServletException e) { log.error("ServletException while trying to include a file in FieldGenTag", e); } catch (IOException e) { log.error("IOException while trying to include a file in FieldGenTag", e); } /* log.debug("FieldGenTag has reqest of " + pageContext.getRequest().toString()); pageContext.getRequest().setAttribute("javax.servlet.include.servlet_path.fieldGen", url); FieldGenController fgc = new FieldGenController(); try { fgc.handleRequest((HttpServletRequest)pageContext.getRequest(), (HttpServletResponse)pageContext.getResponse()); } catch (ServletException e) { log.error("ServletException while attempting to pass control to FieldGenController in FieldGenTag"); } catch (IOException e) { log.error("IOException while attempting to pass control to FieldGenController in FieldGenTag"); } */ resetValues(); return SKIP_BODY; } private void resetValues() { this.type = null; this.formFieldName = null; this.val = null; this.url = null; this.parameters = null; this.parameterMap = null; } public String getType() { return type; } public void setType(String type) { if (type.startsWith("class ")) { this.type = type.substring("class ".length()); } else { this.type = type; } } /** * @return Returns the formFieldName. */ public String getFormFieldName() { return formFieldName; } /** * @param formFieldName The formFieldName to set. */ public void setFormFieldName(String formFieldName) { this.formFieldName = formFieldName; } /** * This is the initial value or the stored value for this tag. * * @return Returns the startVal. */ public Object getVal() { return val; } /** * @param startVal The startVal to set. */ public void setVal(Object startVal) { this.val = startVal; } public void setUrl(String url) { this.url = url; } /** * @return Returns the parameterMap. */ public Map<String, Object> getParameterMap() { return parameterMap; } /** * @param parameterMap The parameterMap to set. */ public void setParameterMap(Map<String, Object> parameterMap) { this.parameterMap = parameterMap; } /** * @return Returns the parameters. */ public String getParameters() { return parameters; } /** * @param parameters The parameters to set. */ public void setParameters(String parameters) { this.parameters = parameters; String delimiter = "\\|"; // pipe is a special char in regex, so need to escape it... /* if ( parameters.indexOf(delimiter) < 0 ) { delimiter = ";"; } */ String[] nvPairs = parameters.split(delimiter); try { for (String nvPair : nvPairs) { String[] nameValue = nvPair.split("="); String name = ""; if (nameValue.length > 0) name = nameValue[0]; String val = ""; if (nameValue.length > 1) val = nameValue[1]; if (this.parameterMap == null) this.parameterMap = new HashMap<String, Object>(); this.parameterMap.put(name, val); } } catch (ArrayIndexOutOfBoundsException ae) { log.error("Out of bounds while trying to parse " + parameters + " with delimiter " + delimiter); } } /** * @return the allowUserDefault */ public Boolean getAllowUserDefault() { return allowUserDefault; } /** * If this is set to true, the user's stored default value for this value will be used if the * {@link #getVal()} is null. <br/> * <br/> * Usage of this is up to the individual handlers. See {@link LocationHandler} for an example. <br/> * <br/> * An example of when the dev doesn't want a default value is if location is set to null by a * previous user and the current user is only editing. Therefore, the * FieldGenTag.java#setAllowUserDefault() should only be set to true if creating an object for * the first time) * * @param allowUserDefault the allowUserDefault to set */ public void setAllowUserDefault(Boolean allowUserDefault) { this.allowUserDefault = allowUserDefault; } public FieldGenHandler getHandlerByClassName(String className) { String handlerClassName = null; try { //Resource beanDefinition = new ClassPathResource("/web/WEB-INF/openmrs-servlet.xml"); //XmlBeanFactory beanFactory = new XmlBeanFactory( beanDefinition ); //factory = (FieldGenHandlerFactory)beanFactory.getBean("fieldGenHandlerFactory"); //ApplicationContext context = new FileSystemXmlApplicationContext("file:/**/WEB-INF/openmrs-servlet.xml"); //if ( context == null ) context = WebApplicationContextUtils.getWebApplicationContext(this.pageContext.getServletContext()); //if ( context == null ) context = new FileSystemXmlApplicationContext("file:/**/WEB-INF/openmrs-servlet.xml"); /* if ( context != null ) { if ( factory == null ) factory = (FieldGenHandlerFactory)Context.getBean("fieldGenHandlerFactory"); } else log.error("Could not get handle on BeanFactory from FieldGen module"); */ factory = FieldGenHandlerFactory.getSingletonInstance(); } catch (Exception e) { factory = null; e.printStackTrace(); } if (factory != null) { handlerClassName = factory.getHandlerByClassName(className); if (handlerClassName != null) { try { Class<?> cls = Context.loadClass(handlerClassName); Constructor<?> ct = cls.getConstructor(); FieldGenHandler handler = (FieldGenHandler) ct.newInstance(); return handler; } catch (Exception e) { log.error("Unable to handle type [" + className + "] with handler [" + handlerClassName + "]. " + e); return null; } } else { return null; } } else { return null; } } }