001/* 002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0 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 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.ecm.webengine.forms.validation; 020 021import java.lang.reflect.InvocationHandler; 022import java.lang.reflect.InvocationTargetException; 023import java.lang.reflect.Method; 024import java.lang.reflect.Proxy; 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.HashMap; 028import java.util.Hashtable; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033import org.nuxeo.ecm.webengine.WebEngine; 034import org.nuxeo.ecm.webengine.forms.FormDataProvider; 035import org.nuxeo.runtime.api.Framework; 036 037/** 038 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 039 */ 040public class FormManager implements InvocationHandler, Form { 041 042 protected Map<String, Object> map; 043 044 protected Map<String, String[]> fields; 045 046 protected List<String> unknownKeys; 047 048 protected FormDescriptor fd; 049 050 public FormManager(FormDescriptor fd) { 051 this.fd = fd; 052 unknownKeys = new ArrayList<String>(); 053 map = new HashMap<String, Object>(); // remove any previous data 054 fields = new HashMap<String, String[]>(); // remove any previous data 055 // TODO when implementing file upload - remove here any previously created file 056 } 057 058 public Collection<String> unknownKeys() { 059 return unknownKeys; 060 } 061 062 public Map<String, String[]> fields() { 063 return fields; 064 } 065 066 @SuppressWarnings("unchecked") 067 public void load(FormDataProvider data, Form proxy) throws ValidationException { 068 ValidationException ve = null; 069 Set<String> reqs = (Set<String>) fd.requiredFields.clone(); 070 for (String key : data.getKeys()) { 071 String[] values = data.getList(key); 072 if (values != null) { 073 int k = 0; 074 for (String v : values) { 075 if (v.length() == 0) { 076 k++; 077 } 078 } 079 if (k == values.length) { 080 values = null; 081 } 082 } 083 if (values != null) { 084 fields.put(key, values); 085 reqs.remove(key); 086 } 087 FormDescriptor.Field f = fd.fields.get(key); 088 if (f != null) { 089 Object o = null; 090 try { 091 if (f.isArray) { 092 if (values != null) { 093 o = f.validateArray(values); 094 } 095 } else { 096 String v = values != null && values.length > 0 ? values[0] : null; 097 if (v != null && v.length() > 0) { 098 099 o = f.validate(v); 100 } 101 } 102 } catch (ValidationException e) { 103 if (ve == null) { 104 ve = e; 105 } 106 ve.addInvalidField(key); 107 } 108 map.put(key, o); 109 } else { 110 unknownKeys.add(key); 111 } 112 } 113 if (!reqs.isEmpty()) { 114 if (ve == null) { 115 ve = new ValidationException(); 116 } 117 for (String req : reqs) { 118 ve.addRequiredField(req); 119 } 120 } 121 if (ve != null) { 122 throw ve; 123 } 124 if (fd.validator != null) { 125 fd.validator.validate(data, proxy); 126 } 127 } 128 129 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 130 if (method.getDeclaringClass() == Form.class) { 131 try { 132 return method.invoke(this, args); 133 } catch (InvocationTargetException e) { 134 throw e.getCause(); 135 } 136 } else { 137 String name = method.getName(); 138 int len = name.length(); 139 if (len > 3) { 140 if (name.startsWith("get")) { 141 name = FormDescriptor.getFieldName(name, len); 142 return map.get(name); 143 } 144 } 145 } 146 throw new UnsupportedOperationException("Method unsupported: " + method); 147 } 148 149 protected static Map<Class<?>, FormDescriptor> forms = new Hashtable<Class<?>, FormDescriptor>(); 150 151 @SuppressWarnings("unchecked") 152 public static <T> T newProxy(Class<T> type) { 153 WebEngine we = Framework.getService(WebEngine.class); 154 ClassLoader cl = we != null ? we.getWebLoader().getClassLoader() : FormManager.class.getClassLoader(); 155 return (T) Proxy.newProxyInstance(cl, new Class<?>[] { type }, new FormManager(getDescriptor(type))); 156 } 157 158 public void flushCache() { 159 forms = new Hashtable<Class<?>, FormDescriptor>(); 160 } 161 162 static FormDescriptor getDescriptor(Class<?> type) { 163 FormDescriptor fd = forms.get(type); 164 if (fd == null) { 165 try { 166 fd = new FormDescriptor(type); 167 forms.put(type, fd); 168 } catch (ReflectiveOperationException e) { 169 throw new RuntimeException("Failed to build form descriptor", e); 170 } 171 } 172 return fd; 173 } 174 175}