001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.config.rules;
017:
018: import org.apache.openejb.OpenEJBException;
019: import org.apache.openejb.jee.EnterpriseBean;
020: import org.apache.openejb.jee.RemoteBean;
021: import org.apache.openejb.jee.EntityBean;
022: import org.apache.openejb.jee.SessionBean;
023: import org.apache.openejb.jee.Interceptor;
024: import org.apache.openejb.config.EjbModule;
025: import org.apache.openejb.util.SafeToolkit;
026: import org.apache.xbean.finder.ClassFinder;
027:
028: import javax.ejb.EJBLocalHome;
029: import javax.ejb.EJBLocalObject;
030: import javax.ejb.EJBHome;
031: import javax.ejb.EJBObject;
032: import javax.jws.WebService;
033: import static java.lang.reflect.Modifier.isAbstract;
034: import java.lang.reflect.Method;
035: import java.lang.annotation.Annotation;
036: import java.util.ArrayList;
037: import java.util.List;
038:
039: public class CheckClasses extends ValidationBase {
040:
041: private static final List<Class<? extends Annotation>> beanOnlyAnnotations = new ArrayList<Class<? extends Annotation>>();
042:
043: static {
044: beanOnlyAnnotations.add(javax.annotation.PostConstruct.class);
045: beanOnlyAnnotations.add(javax.annotation.PreDestroy.class);
046: beanOnlyAnnotations.add(javax.annotation.Resource.class);
047: beanOnlyAnnotations.add(javax.annotation.Resources.class);
048: beanOnlyAnnotations
049: .add(javax.annotation.security.DeclareRoles.class);
050: beanOnlyAnnotations
051: .add(javax.annotation.security.DenyAll.class);
052: beanOnlyAnnotations
053: .add(javax.annotation.security.PermitAll.class);
054: beanOnlyAnnotations
055: .add(javax.annotation.security.RolesAllowed.class);
056: beanOnlyAnnotations.add(javax.annotation.security.RunAs.class);
057:
058: beanOnlyAnnotations.add(javax.ejb.EJB.class);
059: beanOnlyAnnotations.add(javax.ejb.EJBs.class);
060: beanOnlyAnnotations.add(javax.ejb.Init.class);
061: beanOnlyAnnotations.add(javax.ejb.PostActivate.class);
062: beanOnlyAnnotations.add(javax.ejb.PrePassivate.class);
063: beanOnlyAnnotations.add(javax.ejb.Remove.class);
064: beanOnlyAnnotations.add(javax.ejb.Timeout.class);
065: beanOnlyAnnotations.add(javax.ejb.TransactionAttribute.class);
066: beanOnlyAnnotations.add(javax.ejb.TransactionManagement.class);
067: }
068:
069: public void validate(EjbModule ejbModule) {
070: for (EnterpriseBean bean : ejbModule.getEjbJar()
071: .getEnterpriseBeans()) {
072: try {
073: check_hasEjbClass(bean);
074:
075: if (!(bean instanceof RemoteBean))
076: continue;
077: RemoteBean b = (RemoteBean) bean;
078:
079: check_isEjbClass(b);
080: check_hasDependentClasses(b, b.getEjbClass(),
081: "<ejb-class>");
082: check_hasInterface(b);
083: if (b.getHome() != null) {
084: check_hasHomeClass(b);
085: check_hasRemoteClass(b);
086: check_isHomeInterface(b);
087: check_isRemoteInterface(b);
088: check_hasDependentClasses(b, b.getHome(), "<home>");
089: check_hasDependentClasses(b, b.getRemote(),
090: "<remote>");
091: }
092: if (b.getLocalHome() != null) {
093: check_hasLocalHomeClass(b);
094: check_hasLocalClass(b);
095: check_isLocalHomeInterface(b);
096: check_isLocalInterface(b);
097: check_hasDependentClasses(b, b.getLocalHome(),
098: "<local-home>");
099: check_hasDependentClasses(b, b.getLocal(),
100: "<local>");
101: }
102:
103: if (b instanceof SessionBean) {
104: SessionBean sessionBean = (SessionBean) b;
105: for (String interfce : sessionBean
106: .getBusinessLocal()) {
107: check_businessInterface(sessionBean, interfce,
108: "<business-local>");
109: }
110: for (String interfce : sessionBean
111: .getBusinessRemote()) {
112: check_businessInterface(sessionBean, interfce,
113: "<business-remote>");
114: }
115: }
116: } catch (RuntimeException e) {
117: throw new RuntimeException(bean.getEjbName(), e);
118: }
119: }
120:
121: for (Interceptor interceptor : ejbModule.getEjbJar()
122: .getInterceptors()) {
123: check_hasInterceptorClass(interceptor);
124: }
125: }
126:
127: private void check_businessInterface(SessionBean b,
128: String interfaceName, String tagName) {
129: String ejbName = b.getEjbName();
130: Class interfce = lookForClass(interfaceName, tagName, b
131: .getEjbName());
132:
133: if (!interfce.isInterface()) {
134: fail(b, "notAnInterface", interfce.getName(), tagName);
135: }
136:
137: ClassFinder finder = new ClassFinder(interfce);
138:
139: for (Class<? extends Annotation> annotation : beanOnlyAnnotations) {
140: if (interfce.getAnnotation(annotation) != null) {
141: warn(b, "interface.beanOnlyAnnotation", annotation
142: .getSimpleName(), interfce.getName(), b
143: .getEjbClass());
144: }
145: for (Method method : finder
146: .findAnnotatedMethods(annotation)) {
147: warn(b, "interfaceMethod.beanOnlyAnnotation",
148: annotation.getSimpleName(), interfce.getName(),
149: method.getName(), b.getEjbClass());
150: }
151: }
152:
153: if (EJBHome.class.isAssignableFrom(interfce)) {
154: fail(ejbName, "xml.remoteOrLocal.ejbHome", tagName,
155: interfce.getName());
156: } else if (EJBObject.class.isAssignableFrom(interfce)) {
157: fail(ejbName, "xml.remoteOrLocal.ejbObject", tagName,
158: interfce.getName());
159: } else if (EJBLocalHome.class.isAssignableFrom(interfce)) {
160: fail(ejbName, "xml.remoteOrLocal.ejbLocalHome", tagName,
161: interfce.getName());
162: } else if (EJBLocalObject.class.isAssignableFrom(interfce)) {
163: fail(ejbName, "xml.remoteOrLocal.ejbLocalObject", tagName,
164: interfce.getName());
165: }
166:
167: }
168:
169: private void check_hasInterface(RemoteBean b) {
170: if (b.getRemote() != null)
171: return;
172: if (b.getLocal() != null)
173: return;
174:
175: Class beanClass = null;
176: try {
177: beanClass = loadClass(b.getEjbClass());
178: } catch (OpenEJBException e) {
179: }
180:
181: if (b instanceof EntityBean) {
182: fail(b, "noInterfaceDeclared.entity", beanClass
183: .getSimpleName());
184: return;
185: }
186:
187: if (b.getBusinessLocal().size() > 0)
188: return;
189: if (b.getBusinessRemote().size() > 0)
190: return;
191:
192: if (((SessionBean) b).getServiceEndpoint() != null)
193: return;
194:
195: if (beanClass.getAnnotation(WebService.class) != null)
196: return;
197:
198: fail(b, "noInterfaceDeclared.session");
199: }
200:
201: private void check_hasDependentClasses(RemoteBean b,
202: String className, String type) {
203: try {
204: ClassLoader cl = module.getClassLoader();
205: Class clazz = cl.loadClass(className);
206: for (Object item : clazz.getFields()) {
207: item.toString();
208: }
209: for (Object item : clazz.getMethods()) {
210: item.toString();
211: }
212: for (Object item : clazz.getConstructors()) {
213: item.toString();
214: }
215: for (Object item : clazz.getAnnotations()) {
216: item.toString();
217: }
218: for (Object item : clazz.getEnumConstants()) {
219: item.toString();
220: }
221: } catch (NullPointerException e) {
222: // Don't know why I get these from clazz.getEnumConstants()
223: } catch (ClassNotFoundException e) {
224: /*
225: # 0 - Referring Class name
226: # 1 - Dependent Class name
227: # 2 - Element (home, ejb-class, remote)
228: # 3 - Bean name
229: */
230: fail(b, "missing.dependent.class", className, e
231: .getMessage(), type, b.getEjbName());
232: } catch (NoClassDefFoundError e) {
233: /*
234: # 0 - Referring Class name
235: # 1 - Dependent Class name
236: # 2 - Element (home, ejb-class, remote)
237: # 3 - Bean name
238: */
239: fail(b, "missing.dependent.class", className, e
240: .getMessage(), type, b.getEjbName());
241: }
242: }
243:
244: private void check_hasLocalClass(RemoteBean b) {
245: lookForClass(b.getLocal(), "<local>", b.getEjbName());
246: }
247:
248: private void check_hasLocalHomeClass(RemoteBean b) {
249: lookForClass(b.getLocalHome(), "<local-home>", b.getEjbName());
250: }
251:
252: public void check_hasEjbClass(EnterpriseBean b) {
253:
254: String ejbName = b.getEjbName();
255:
256: Class beanClass = lookForClass(b.getEjbClass(), "<ejb-class>",
257: ejbName);
258:
259: if (beanClass.isInterface()) {
260: fail(ejbName, "interfaceDeclaredAsBean", beanClass
261: .getName());
262: }
263:
264: if (isCmp(b))
265: return;
266:
267: if (isAbstract(beanClass.getModifiers())) {
268: fail(ejbName, "abstractDeclaredAsBean", beanClass.getName());
269: }
270: }
271:
272: public void check_hasInterceptorClass(Interceptor i) {
273:
274: lookForClass(i.getInterceptorClass(), "<interceptor-class>",
275: "Interceptor");
276:
277: }
278:
279: public void check_hasHomeClass(RemoteBean b) {
280:
281: lookForClass(b.getHome(), "<home>", b.getEjbName());
282:
283: }
284:
285: public void check_hasRemoteClass(RemoteBean b) {
286:
287: lookForClass(b.getRemote(), "<remote>", b.getEjbName());
288:
289: }
290:
291: public void check_isEjbClass(RemoteBean b) {
292:
293: if (b instanceof SessionBean) {
294:
295: // DMB: Beans in ejb 3 are not required to implement javax.ejb.SessionBean
296: // but it would still be nice to think of some sort of check to do here.
297: // compareTypes(b, b.getEjbClass(), javax.ejb.SessionBean.class);
298:
299: } else if (b instanceof EntityBean) {
300:
301: compareTypes(b, b.getEjbClass(), javax.ejb.EntityBean.class);
302:
303: }
304:
305: }
306:
307: private void check_isLocalInterface(RemoteBean b) {
308: compareTypes(b, b.getLocal(), EJBLocalObject.class);
309: }
310:
311: private void check_isLocalHomeInterface(RemoteBean b) {
312: compareTypes(b, b.getLocalHome(), EJBLocalHome.class);
313: }
314:
315: public void check_isHomeInterface(RemoteBean b) {
316:
317: compareTypes(b, b.getHome(), javax.ejb.EJBHome.class);
318:
319: }
320:
321: public void check_isRemoteInterface(RemoteBean b) {
322:
323: compareTypes(b, b.getRemote(), javax.ejb.EJBObject.class);
324:
325: }
326:
327: private Class lookForClass(String clazz, String type, String ejbName) {
328: try {
329: return loadClass(clazz);
330: } catch (OpenEJBException e) {
331: /*
332: # 0 - Class name
333: # 1 - Element (home, ejb-class, remote)
334: # 2 - Bean name
335: */
336:
337: fail(ejbName, "missing.class", clazz, type, ejbName);
338:
339: } catch (NoClassDefFoundError e) {
340: /*
341: # 0 - Class name
342: # 1 - Element (home, ejb-class, remote)
343: # 2 - Bean name
344: # 3 - Misslocated Class name
345: */
346: fail(ejbName, "misslocated.class", clazz, type, ejbName, e
347: .getMessage());
348:
349: throw e;
350: }
351:
352: return null;
353: }
354:
355: private void compareTypes(RemoteBean b, String clazz1, Class class2) {
356: Class class1 = null;
357: try {
358: class1 = loadClass(clazz1);
359: } catch (OpenEJBException e) {
360: return;
361: }
362:
363: if (class1 != null && !class2.isAssignableFrom(class1)) {
364: fail(b, "wrong.class.type", clazz1, class2.getName());
365: }
366: }
367:
368: protected Class loadClass(String clazz) throws OpenEJBException {
369: ClassLoader cl = module.getClassLoader();
370: try {
371: return Class.forName(clazz, false, cl);
372: } catch (ClassNotFoundException cnfe) {
373: throw new OpenEJBException(SafeToolkit.messages.format(
374: "cl0007", clazz, module.getJarLocation()), cnfe);
375: }
376: }
377: }
|