001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kns.kim.type; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.CoreApiServiceLocator; 020import org.kuali.rice.core.api.uif.RemotableControlContract; 021import org.kuali.rice.core.api.uif.RemotableAbstractControl; 022import org.kuali.rice.core.api.uif.RemotableAbstractWidget; 023import org.kuali.rice.core.api.uif.RemotableAttributeField; 024import org.kuali.rice.core.api.uif.RemotableCheckbox; 025import org.kuali.rice.core.api.uif.RemotableCheckboxGroup; 026import org.kuali.rice.core.api.uif.RemotableDatepicker; 027import org.kuali.rice.core.api.uif.RemotableHiddenInput; 028import org.kuali.rice.core.api.uif.RemotableQuickFinder; 029import org.kuali.rice.core.api.uif.RemotableRadioButtonGroup; 030import org.kuali.rice.core.api.uif.RemotableSelect; 031import org.kuali.rice.core.api.uif.RemotableTextExpand; 032import org.kuali.rice.core.api.uif.RemotableTextInput; 033import org.kuali.rice.core.api.uif.RemotableTextarea; 034import org.kuali.rice.kim.api.KimConstants; 035import org.kuali.rice.kim.api.type.KimAttributeField; 036import org.kuali.rice.kns.datadictionary.control.CheckboxControlDefinition; 037import org.kuali.rice.kns.datadictionary.control.HiddenControlDefinition; 038import org.kuali.rice.kns.datadictionary.control.MultiselectControlDefinition; 039import org.kuali.rice.kns.datadictionary.control.RadioControlDefinition; 040import org.kuali.rice.kns.datadictionary.control.SelectControlDefinition; 041import org.kuali.rice.kns.datadictionary.control.TextControlDefinition; 042import org.kuali.rice.kns.datadictionary.control.TextareaControlDefinition; 043import org.kuali.rice.krad.datadictionary.AttributeDefinition; 044import org.kuali.rice.krad.datadictionary.control.ControlDefinition; 045import org.kuali.rice.krad.datadictionary.exporter.ExportMap; 046import org.kuali.rice.krad.datadictionary.validation.ValidationPattern; 047import org.kuali.rice.krad.keyvalues.KeyValuesFinder; 048import org.kuali.rice.krad.keyvalues.KeyValuesFinderFactory; 049import org.kuali.rice.krad.util.ObjectUtils; 050 051import java.util.ArrayList; 052import java.util.Collection; 053import java.util.Collections; 054import java.util.List; 055import java.util.Map; 056import java.util.regex.Pattern; 057 058/** 059 * @deprecated A krad integrated type service base class will be provided in the future. 060 * This is only used for the legacy {@link DataDictionaryTypeServiceBase}. 061 */ 062@Deprecated 063public final class DataDictionaryTypeServiceHelper { 064 065 private DataDictionaryTypeServiceHelper() { 066 throw new UnsupportedOperationException("do not call"); 067 } 068 069 public static String getKimBasePath(){ 070 String kimBaseUrl = CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString(KimConstants.KimUIConstants.KIM_URL_KEY); 071 if (!kimBaseUrl.endsWith(KimConstants.KimUIConstants.URL_SEPARATOR)) { 072 kimBaseUrl = kimBaseUrl + KimConstants.KimUIConstants.URL_SEPARATOR; 073 } 074 return kimBaseUrl; 075 } 076 077 public static RemotableAbstractControl.Builder toRemotableAbstractControlBuilder(AttributeDefinition attr) { 078 ControlDefinition control = attr.getControl(); 079 if (ObjectUtils.isNotNull(control)) { 080 if (control.isCheckbox()) { 081 return RemotableCheckbox.Builder.create(); 082 } else if (control.isHidden()) { 083 return RemotableHiddenInput.Builder.create(); 084 } else if (control.isMultiselect()) { 085 RemotableSelect.Builder b = RemotableSelect.Builder.create(getValues(attr)); 086 b.setMultiple(true); 087 b.setSize(control.getSize()); 088 } else if (control.isRadio()) { 089 return RemotableRadioButtonGroup.Builder.create(getValues(attr)); 090 } else if (control.isSelect()) { 091 RemotableSelect.Builder b = RemotableSelect.Builder.create(getValues(attr)); 092 b.setMultiple(false); 093 b.setSize(control.getSize()); 094 return b; 095 } else if (control.isText() || control.isCurrency()) { 096 final RemotableTextInput.Builder b = RemotableTextInput.Builder.create(); 097 b.setSize(control.getSize()); 098 return b; 099 } else if (control.isTextarea()) { 100 final RemotableTextarea.Builder b = RemotableTextarea.Builder.create(); 101 b.setCols(control.getCols()); 102 b.setRows(control.getRows()); 103 return b; 104 } 105 } 106 return null; 107 } 108 109 /** 110 * will first try to execute the values finder. If that doesn't return any values then will try to use the optionfinder 111 * on the AttributeDefinition. 112 * 113 * @param attr AttributeDefinition 114 * @return a Map of key value pairs 115 */ 116 private static Map<String, String> getValues(AttributeDefinition attr) { 117 ControlDefinition control = attr.getControl(); 118 119 try { 120 final Class<KeyValuesFinder> clazz = (Class<KeyValuesFinder>) Class.forName(control.getValuesFinderClass()); 121 final KeyValuesFinder finder = clazz.newInstance(); 122 final Map<String, String> values = finder.getKeyLabelMap(); 123 if ((values != null) && !values.isEmpty()) { 124 return values; 125 } 126 else if (attr.getOptionsFinder() != null) { 127 return attr.getOptionsFinder().getKeyLabelMap(); 128 } 129 } catch (ClassNotFoundException e) { 130 throw new RuntimeException(e); 131 } catch (InstantiationException e) { 132 throw new RuntimeException(e); 133 } catch (IllegalAccessException e) { 134 throw new RuntimeException(e); 135 } 136 return Collections.emptyMap(); 137 } 138 139 public static List<KimAttributeDefinition> toKimAttributeDefinitions(List<KimAttributeField> fields) { 140 if (fields == null) { 141 throw new IllegalArgumentException("fields was null"); 142 } 143 144 final List<KimAttributeDefinition> defns = new ArrayList<KimAttributeDefinition>(); 145 for (KimAttributeField field : fields) { 146 defns.add(toKimAttributeDefinition(field)); 147 } 148 149 return Collections.unmodifiableList(defns); 150 } 151 152 public static KimAttributeDefinition toKimAttributeDefinition(KimAttributeField field) { 153 if (field == null) { 154 throw new IllegalArgumentException("field is null"); 155 } 156 157 KimAttributeDefinition ad = new KimAttributeDefinition(); 158 ad.setKimAttrDefnId(field.getId()); 159 ad.setUnique(field.isUnique()); 160 161 final RemotableAttributeField attr = field.getAttributeField(); 162 ad.setName(attr.getName()); 163 ad.setDataType(attr.getDataType()); 164 ad.setShortLabel(attr.getShortLabel()); 165 ad.setLabel(attr.getLongLabel()); 166 ad.setSummary(attr.getHelpSummary()); 167 ad.setConstraintText(attr.getConstraintText()); 168 ad.setDescription(attr.getHelpDescription()); 169 ad.setForceUppercase(attr.isForceUpperCase()); 170 ad.setMinLength(attr.getMinLength()); 171 ad.setMaxLength(attr.getMaxLength()); 172 ad.setExclusiveMin(attr.getMinValue() != null ? attr.getMinValue().toString() : null); 173 ad.setInclusiveMax(attr.getMaxValue() != null ? attr.getMaxValue().toString() : null); 174 if (StringUtils.isNotBlank(attr.getRegexConstraint())) { 175 ValidationPattern pattern = new ValidationPattern() { 176 177 @Override 178 public Pattern getRegexPattern() { 179 return Pattern.compile(getRegexString()); 180 } 181 182 @Override 183 protected String getRegexString() { 184 return attr.getRegexConstraint(); 185 } 186 187 @Override 188 public ExportMap buildExportMap(String exportKey) { 189 ExportMap exportMap = new ExportMap(exportKey); 190 exportMap.set("type", "regex"); 191 exportMap.set("pattern", getRegexString()); 192 193 return exportMap; 194 } 195 196 @Override 197 public String getValidationErrorMessageKey() { 198 return attr.getRegexContraintMsg(); 199 } 200 }; 201 ad.setValidationPattern(pattern); 202 } 203 ad.setRequired(attr.isRequired()); 204 205 final RemotableControlContract control = field.getAttributeField().getControl(); 206 207 if (control != null) { 208 ControlDefinition d = toControlDefinition(control, ad); 209 for (RemotableAbstractWidget widget : field.getAttributeField().getWidgets()) { 210 if(widget instanceof RemotableQuickFinder) { 211 ad.setLookupBoClass(((RemotableQuickFinder) widget).getDataObjectClass()); 212 ad.setLookupInputPropertyConversions(((RemotableQuickFinder) widget).getLookupParameters()); 213 ad.setLookupReturnPropertyConversions(((RemotableQuickFinder) widget).getFieldConversions()); 214 } else if (widget instanceof RemotableDatepicker && d != null) { 215 d.setDatePicker(true); 216 } else if (widget instanceof RemotableTextExpand && d != null) { 217 d.setExpandedTextArea(true); 218 } 219 } 220 ad.setControl(d); 221 } 222 223 return ad; 224 } 225 226 /** WARNING HACK! this may set the OptionsFinder instance on the passed in KimAttributeDefinition! */ 227 private static ControlDefinition toControlDefinition(RemotableControlContract control, KimAttributeDefinition containingAttribute) { 228 if (control instanceof RemotableCheckboxGroup) { 229 containingAttribute.setOptionsFinder(KeyValuesFinderFactory.fromMap(((RemotableCheckboxGroup) control).getKeyLabels())); 230 CheckboxControlDefinition checkbox = new CheckboxControlDefinition(); 231 return checkbox; 232 } else if (control instanceof RemotableCheckbox) { 233 CheckboxControlDefinition checkbox = new CheckboxControlDefinition(); 234 return checkbox; 235 } else if (control instanceof RemotableHiddenInput) { 236 HiddenControlDefinition hidden = new HiddenControlDefinition(); 237 return hidden; 238 } else if (control instanceof RemotableRadioButtonGroup) { 239 containingAttribute.setOptionsFinder(KeyValuesFinderFactory.fromMap(((RemotableRadioButtonGroup) control).getKeyLabels())); 240 RadioControlDefinition radio = new RadioControlDefinition(); 241 return radio; 242 243 } else if (control instanceof RemotableSelect) { 244 containingAttribute.setOptionsFinder(KeyValuesFinderFactory.fromMap(((RemotableSelect) control).getKeyLabels())); 245 if (((RemotableSelect) control).isMultiple()) { 246 MultiselectControlDefinition multiSelect = new MultiselectControlDefinition(); 247 multiSelect.setSize(((RemotableSelect) control).getSize()); 248 return multiSelect; 249 } else { 250 SelectControlDefinition select = new SelectControlDefinition(); 251 select.setSize(((RemotableSelect) control).getSize()); 252 return select; 253 } 254 } else if (control instanceof RemotableTextarea) { 255 TextareaControlDefinition textarea = new TextareaControlDefinition(); 256 textarea.setRows(((RemotableTextarea) control).getRows()); 257 textarea.setCols(((RemotableTextarea) control).getCols()); 258 return textarea; 259 } else if (control instanceof RemotableTextInput) { 260 TextControlDefinition text = new TextControlDefinition(); 261 text.setSize(((RemotableTextInput) control).getSize()); 262 return text; 263 } 264 return null; 265 } 266 267 /** 268 * Utility method to search a collection of attribute fields and returns 269 * a field for a give attribute name. 270 * 271 * @param attributeName the name of the attribute to search for. Cannot be blank or null. 272 * @param fields cannot be null. 273 * 274 * @return the attribute field or null if not found. 275 */ 276 public static <T extends KimAttributeField> T findAttributeField(String attributeName, Collection<? extends T> fields) { 277 if (StringUtils.isBlank(attributeName)) { 278 throw new IllegalArgumentException("attributeName is blank"); 279 } 280 281 if (fields == null) { 282 throw new IllegalArgumentException("fields is null"); 283 } 284 285 for (T field : fields) { 286 if (attributeName.equals(field.getAttributeField().getName())) { 287 return field; 288 } 289 } 290 return null; 291 } 292 293 public static String createErrorString(KimAttributeField definition) { 294 return definition.getAttributeField().getRegexContraintMsg(); 295 } 296 297 /** will create a string like the following: 298 * errorKey:param1;param2;param3; 299 * 300 * @param errorKey the errorKey 301 * @param params the error params 302 * @return error string 303 */ 304 public static String createErrorString(String errorKey, String... params) { 305 final StringBuilder s = new StringBuilder(errorKey).append(':'); 306 if (params != null) { 307 for (String p : params) { 308 if (p != null) { 309 s.append(p); 310 s.append(';'); 311 } 312 } 313 } 314 return s.toString(); 315 } 316 317 public static String getAttributeErrorLabel(KimAttributeField definition) { 318 String longAttributeLabel = definition.getAttributeField().getLongLabel(); 319 String shortAttributeLabel = definition.getAttributeField().getShortLabel(); 320 return longAttributeLabel + " (" + shortAttributeLabel + ")"; 321 } 322}