001 package org.apache.tapestry.annotations; 002 003 import java.util.ArrayList; 004 import java.util.Collections; 005 import java.util.List; 006 007 import org.apache.hivemind.ApplicationRuntimeException; 008 import org.apache.hivemind.Location; 009 import org.apache.tapestry.enhance.EnhancementOperation; 010 import org.apache.tapestry.spec.IComponentSpecification; 011 012 /** 013 * Recognizes the {@link org.apache.tapestry.annotations.Meta} annotation, and converts it into 014 * properties on the specification. It is desirable to have meta data in base classes be "merged" 015 * with meta data from sub classes, with the sub classes overriding any conflicting elements from 016 * the base class. What we do is work our way up the inheritance tree to java.lang.Object and work 017 * with each Meta annotation we find. 018 * 019 * @author Howard M. Lewis Ship 020 * @since 4.0 021 */ 022 public class MetaAnnotationWorker implements ClassAnnotationEnhancementWorker 023 { 024 025 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec, 026 Class baseClass, Location location) 027 { 028 List<Meta> metas = assembleMetas(baseClass); 029 030 for (Meta meta : metas) 031 applyPropertiesFromMeta(meta, spec, location); 032 } 033 034 private List<Meta> assembleMetas(Class baseClass) 035 { 036 Class searchClass = baseClass; 037 List<Meta> result = new ArrayList<Meta>(); 038 Meta lastMeta = null; 039 040 while (true) 041 { 042 Meta meta = (Meta) searchClass.getAnnotation(Meta.class); 043 044 // When reach a class that doesn't define or inherit a @Meta, we're done 045 if (meta == null) 046 break; 047 048 // Cheap approach, based on annotation inheritance, for determining 049 // whether a meta is already in the result list 050 051 if (meta != lastMeta) 052 result.add(meta); 053 054 searchClass = searchClass.getSuperclass(); 055 } 056 057 Collections.reverse(result); 058 059 return result; 060 } 061 062 private void applyPropertiesFromMeta(Meta meta, IComponentSpecification spec, Location location) 063 { 064 String[] pairs = meta.value(); 065 066 for (String pair : pairs) 067 { 068 int equalx = pair.indexOf('='); 069 070 // The only big problem is that the location will be the location of the @Meta in 071 // the subclass, even if the @Meta with a problem is from a base class. 072 073 if (equalx < 0) 074 throw new ApplicationRuntimeException(AnnotationMessages.missingEqualsInMeta(pair), 075 location, null); 076 077 String key = pair.substring(0, equalx); 078 String value = pair.substring(equalx + 1); 079 080 spec.setProperty(key, value); 081 } 082 } 083 }