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.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.concurrent.ConcurrentHashMap; 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:bs@nuxeo.com">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<>(); 053 map = new HashMap<>(); // remove any previous data 054 fields = new HashMap<>(); // remove any previous data 055 // TODO when implementing file upload - remove here any previously created file 056 } 057 058 @Override 059 public Collection<String> unknownKeys() { 060 return unknownKeys; 061 } 062 063 @Override 064 public Map<String, String[]> fields() { 065 return fields; 066 } 067 068 @Override 069 @SuppressWarnings("unchecked") 070 public void load(FormDataProvider data, Form proxy) throws ValidationException { 071 ValidationException ve = null; 072 Set<String> reqs = (Set<String>) fd.requiredFields.clone(); 073 for (String key : data.getKeys()) { 074 String[] values = data.getList(key); 075 if (values != null) { 076 int k = 0; 077 for (String v : values) { 078 if (v.length() == 0) { 079 k++; 080 } 081 } 082 if (k == values.length) { 083 values = null; 084 } 085 } 086 if (values != null) { 087 fields.put(key, values); 088 reqs.remove(key); 089 } 090 FormDescriptor.Field f = fd.fields.get(key); 091 if (f != null) { 092 Object o = null; 093 try { 094 if (f.isArray) { 095 if (values != null) { 096 o = f.validateArray(values); 097 } 098 } else { 099 String v = values != null && values.length > 0 ? values[0] : null; 100 if (v != null && v.length() > 0) { 101 102 o = f.validate(v); 103 } 104 } 105 } catch (ValidationException e) { 106 if (ve == null) { 107 ve = e; 108 } 109 ve.addInvalidField(key); 110 } 111 map.put(key, o); 112 } else { 113 unknownKeys.add(key); 114 } 115 } 116 if (!reqs.isEmpty()) { 117 if (ve == null) { 118 ve = new ValidationException(); 119 } 120 for (String req : reqs) { 121 ve.addRequiredField(req); 122 } 123 } 124 if (ve != null) { 125 throw ve; 126 } 127 if (fd.validator != null) { 128 fd.validator.validate(data, proxy); 129 } 130 } 131 132 @Override 133 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 134 if (method.getDeclaringClass() == Form.class) { 135 try { 136 return method.invoke(this, args); 137 } catch (InvocationTargetException e) { 138 throw e.getCause(); 139 } 140 } else { 141 String name = method.getName(); 142 int len = name.length(); 143 if (len > 3) { 144 if (name.startsWith("get")) { 145 name = FormDescriptor.getFieldName(name, len); 146 return map.get(name); 147 } 148 } 149 } 150 throw new UnsupportedOperationException("Method unsupported: " + method); 151 } 152 153 protected static Map<Class<?>, FormDescriptor> forms = new ConcurrentHashMap<>(); 154 155 @SuppressWarnings("unchecked") 156 public static <T> T newProxy(Class<T> type) { 157 WebEngine we = Framework.getService(WebEngine.class); 158 ClassLoader cl = we != null ? we.getWebLoader().getClassLoader() : FormManager.class.getClassLoader(); 159 return (T) Proxy.newProxyInstance(cl, new Class<?>[] { type }, new FormManager(getDescriptor(type))); 160 } 161 162 public void flushCache() { 163 forms.clear(); 164 } 165 166 static FormDescriptor getDescriptor(Class<?> type) { 167 FormDescriptor fd = forms.get(type); 168 if (fd == null) { 169 try { 170 fd = new FormDescriptor(type); 171 forms.put(type, fd); 172 } catch (ReflectiveOperationException e) { 173 throw new RuntimeException("Failed to build form descriptor", e); 174 } 175 } 176 return fd; 177 } 178 179}