[Jiemamy-notify] commit [1914] ChangeSupportの自動生成を実装

Back to archive index

svnno****@sourc***** svnno****@sourc*****
2008年 9月 12日 (金) 06:50:08 JST


Revision: 1914
          http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=jiemamy&view=rev&rev=1914
Author:   shin1
Date:     2008-09-12 06:50:08 +0900 (Fri, 12 Sep 2008)

Log Message:
-----------
ChangeSupportの自動生成を実装
テンプレートの微調整等

Modified Paths:
--------------
    sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java
    sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java
    sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeListener.vm
    sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupport.vm

Removed Paths:
-------------
    sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/App.java


-------------- next part --------------
Deleted: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/App.java
===================================================================
--- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/App.java	2008-09-11 17:43:24 UTC (rev 1913)
+++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/App.java	2008-09-11 21:50:08 UTC (rev 1914)
@@ -1,106 +0,0 @@
-package org.jiemamy.core.eventcodegen;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.Writer;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.Velocity;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.jiemamy.core.model.AbstractModel;
-
-public class App {
-	static String SRC_ROOT = "../org.jiemamy.core/src/main/java";
-
-	public static void main(String[] args) throws Exception {
-		setupVelocity();
-		SRC_ROOT = new File(".").getAbsoluteFile().getParent() + "/" + SRC_ROOT;
-		if (!SRC_ROOT.endsWith("/")) {
-			SRC_ROOT = SRC_ROOT + "/";
-		}
-		processDirectory(new File(SRC_ROOT));
-	}
-
-	/**
-	 * Velocityの初期化を行う。
-	 * 
-	 * @throws Exception
-	 */
-	public static void setupVelocity() throws Exception {
-		Properties p = new Properties();
-		p.setProperty("resource.loader", "class");
-		p.setProperty("class.resource.loader.class",
-				"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
-		p.setProperty("input.encoding", "UTF-8");
-		Velocity.init(p);
-	}
-
-	/**
-	 * org.jiemamy.coreのJavaソースディレクトリ配下を辿ってModelクラスのソースを探す。
-	 * org.jiemamy.core.modelパッケージ内のソースを発見した場合はそのClassをLoadし、
-	 * AbstractModelのサブクラスだった時は{@link #processModel(AbstractModel)}にそのインスタンスを渡す。
-	 * 
-	 * @param dir
-	 *            org.jiemamy.coreプロジェクトのJavaソースディレクトリ。
-	 */
-	public static void processDirectory(File dir) {
-		if (dir.isDirectory()) {
-			for (File f : dir.listFiles()) {
-				if (f.isDirectory() && !f.getName().startsWith(".")) {
-					processDirectory(f);
-				} else if (f.isFile() && f.getAbsolutePath().indexOf("org/jiemamy/core/model/") >= 0) {
-					String modelJava = f.getAbsolutePath().replaceFirst(SRC_ROOT, "");
-					modelJava = modelJava.replaceFirst(".java", "");
-					modelJava = modelJava.replace("/", ".");
-					try {
-						Class<?> clazz = Class.forName(modelJava);
-						// Instance化出来ないものはInstantialtionExceptionを発生させて弾く。
-						clazz.newInstance();
-						// AbstractModelのサブクラスでないものはClassCastExceptionを発生させて弾く。
-						Class<? extends AbstractModel> modelClass = clazz.asSubclass(AbstractModel.class);
-						processModel(modelClass);
-					} catch (Exception ex) {
-						// 無視する。
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * AbstractModelに対応するChangeListenerとChangeSupportのソースを生成する。
-	 * 
-	 * @param model
-	 * @throws Exception
-	 * @throws ParseErrorException
-	 * @throws ResourceNotFoundException
-	 */
-	public static void processModel(Class<? extends AbstractModel> modelClass) throws ResourceNotFoundException,
-			ParseErrorException, Exception {
-		System.out.println(modelClass);
-		Field[] fields = modelClass.getDeclaredFields();
-		// TODO Collection用Fieldを拾って、List<CollectionProperty>を作成する。
-		List<CollectionProperty> properties = new ArrayList<CollectionProperty>();
-		for (Field field : fields) {
-			System.out.println("  #" + field.getName() + ":" + field.getType().getName());
-			properties.add(new CollectionProperty(field.getName(), field.getType(), null));
-		}
-
-		//
-		VelocityContext velocityContext = new VelocityContext();
-		Template listenerTemplate = Velocity.getTemplate("ChangeListener.vm");
-		Writer writer = new FileWriter("target/" + modelClass.getPackage().getName() + "." + modelClass.getSimpleName()
-				+ "ChangeListener.java");
-		velocityContext.put("modelClassName", modelClass.getSimpleName());
-		velocityContext.put("properties", properties);
-		listenerTemplate.merge(velocityContext, writer);
-		writer.flush();
-		writer.close();
-	}
-}

Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java
===================================================================
--- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java	2008-09-11 17:43:24 UTC (rev 1913)
+++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java	2008-09-11 21:50:08 UTC (rev 1914)
@@ -1,16 +1,51 @@
 package org.jiemamy.core.eventcodegen;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.jiemamy.core.utils.collectionimpl.ObservableList;
+import org.jiemamy.core.utils.collectionimpl.ObservableMap;
+import org.jiemamy.core.utils.collectionimpl.ObservableSet;
+
 public class CollectionProperty {
 	private String name;
+	private String nameUpper;
+	private String nameSingle;
 	private Class<?> collectionClass;
+	private Class<?> observableCollectionClass;
 	private Class<?> elementClass;
 
-	public CollectionProperty(String name, Class<?> collectionClass, Class<?> elementClass) {
+	public CollectionProperty(String name, Class<?> collectionClass,
+			Class<?> elementClass) {
 		this.name = name;
+		this.nameUpper = name.substring(0, 1).toUpperCase() + name.substring(1);
+		this.nameSingle = toSingle(name);
 		this.collectionClass = collectionClass;
 		this.elementClass = elementClass;
+		if (collectionClass.equals(List.class)) {
+			observableCollectionClass = ObservableList.class;
+		} else if (collectionClass.equals(Set.class)) {
+			observableCollectionClass = ObservableSet.class;
+		} else if (collectionClass.equals(Map.class)) {
+			observableCollectionClass = ObservableMap.class;
+		}
 	}
 
+	/**
+	 * 複数形を単数系に変換する.
+	 * 
+	 * @param plural
+	 * @return
+	 */
+	private String toSingle(String plural) {
+		if (plural.endsWith("es")) {
+			return plural.substring(0, name.length() - 2);
+		} else {
+			return plural.substring(0, name.length() - 1);
+		}
+	}
+
 	public Class<?> getCollectionClass() {
 		return collectionClass;
 	}
@@ -34,4 +69,28 @@
 	public void setElementClass(Class<?> elementClass) {
 		this.elementClass = elementClass;
 	}
+
+	public String getNameUpper() {
+		return nameUpper;
+	}
+
+	public void setNameUpper(String nameUpper) {
+		this.nameUpper = nameUpper;
+	}
+
+	public Class<?> getObservableCollectionClass() {
+		return observableCollectionClass;
+	}
+
+	public void setObservableCollectionClass(Class<?> observableCollectionClass) {
+		this.observableCollectionClass = observableCollectionClass;
+	}
+
+	public String getNameSingle() {
+		return nameSingle;
+	}
+
+	public void setNameSingle(String nameSingle) {
+		this.nameSingle = nameSingle;
+	}
 }

Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java
===================================================================
--- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java	2008-09-11 17:43:24 UTC (rev 1913)
+++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java	2008-09-11 21:50:08 UTC (rev 1914)
@@ -4,11 +4,11 @@
 import java.io.FileWriter;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
 
 import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
@@ -109,35 +109,30 @@
 			throws ResourceNotFoundException, ParseErrorException, Exception {
 		System.out.println(classDoc.qualifiedTypeName() + ":"
 				+ getPackageName(classDoc));
-
+		List<String> importClasses = new ArrayList<String>();
+		importClasses.add(classDoc.qualifiedTypeName());
+		importClasses.add("org.jiemamy.core.event.ModelChangeListener");
+		importClasses
+				.add("org.jiemamy.core.event.ObservableCollectionChangeEvent");
 		List<CollectionProperty> properties = new ArrayList<CollectionProperty>();
 		FieldDoc[] fields = classDoc.fields();
 		for (FieldDoc fieldDoc : fields) {
 			String fieldTypeName = fieldDoc.type().qualifiedTypeName();
 			Class<?> fieldType = Class.forName(fieldTypeName);
-			try {
-				// ListのサブクラスでないものはClassCastExceptionを発生させて弾く。
-				fieldType.asSubclass(List.class);
-				properties.add(new CollectionProperty(fieldDoc.name(),
-						Class.forName(fieldDoc.type().qualifiedTypeName()
-								.toString()), Class
-								.forName(getParameterClassName(fieldDoc))));
-				continue;
-			} catch (Exception ex) {
-				// 
+			if (isSubClass(fieldType, List.class)
+					|| isSubClass(fieldType, List.class)) {
+				// ListまたはSetのサブクラス
+				String parameterClassName = getParameterClassName(fieldDoc);
+				duplicateCheckAndAddToList(importClasses, fieldTypeName);
+				duplicateCheckAndAddToList(importClasses, parameterClassName);
+				properties
+						.add(new CollectionProperty(fieldDoc.name(), Class
+								.forName(fieldDoc.type().qualifiedTypeName()
+										.toString()), Class
+								.forName(parameterClassName)));
 			}
-			try {
-				// SetのサブクラスでないものはClassCastExceptionを発生させて弾く。
-				fieldType.asSubclass(Set.class);
-				properties.add(new CollectionProperty(fieldDoc.name(),
-						Class.forName(fieldDoc.type().qualifiedTypeName()
-								.toString()), Class
-								.forName(getParameterClassName(fieldDoc))));
-				continue;
-			} catch (Exception ex) {
-				// 
-			}
 		}
+		Collections.sort(importClasses);
 		// Templateからjavaファイルを生成する。
 		try {
 			String packageName = getPackageName(classDoc).replaceAll(
@@ -146,25 +141,63 @@
 			if (!dir.exists()) {
 				dir.mkdirs();
 			}
+			VelocityContext velocityContext = new VelocityContext();
+			velocityContext.put("package", packageName);
+			velocityContext.put("importClasses", importClasses);
+			velocityContext.put("modelClassName", classDoc.name().toString());
+			velocityContext.put("modelClassNameLower", classDoc.name()
+					.toString().substring(0, 1).toLowerCase()
+					+ classDoc.name().toString().substring(1));
+			velocityContext.put("properties", properties);
+			Template listenerTemplate = Velocity
+					.getTemplate("ChangeListener.vm");
 			File file = new File(dir.getAbsolutePath() + "/"
 					+ classDoc.name().toString() + "ChangeListener.java");
 			System.out.println(file.getAbsolutePath());
-			VelocityContext velocityContext = new VelocityContext();
-			Template listenerTemplate = Velocity
-					.getTemplate("ChangeListener.vm");
 			Writer writer = new FileWriter(file);
-			velocityContext.put("package", packageName);
-			velocityContext.put("modelClassName", classDoc.name().toString());
-			velocityContext.put("properties", properties);
 			listenerTemplate.merge(velocityContext, writer);
 			writer.flush();
 			writer.close();
+
+			importClasses.add("java.util.ArrayList");
+			importClasses.add("org.jiemamy.core.event.ModelChangeEvent");
+			importClasses
+					.add("org.jiemamy.core.event.ObservableCollectionChangeListener");
+			for (CollectionProperty property : properties) {
+				duplicateCheckAndAddToList(importClasses, property
+						.getObservableCollectionClass().getName());
+			}
+			Collections.sort(importClasses);
+			Template supportTemplate = Velocity.getTemplate("ChangeSupport.vm");
+			file = new File(dir.getAbsolutePath() + "/"
+					+ classDoc.name().toString() + "ChangeSupport.java");
+			System.out.println(file.getAbsolutePath());
+			writer = new FileWriter(file);
+			supportTemplate.merge(velocityContext, writer);
+			writer.flush();
+			writer.close();
 		} catch (Exception ex) {
 			ex.printStackTrace();
 		}
 	}
 
 	/**
+	 * あるクラスがあるクラスのサブクラスかどうか。
+	 * 
+	 * @param subClass
+	 * @param superClass
+	 * @return
+	 */
+	private static boolean isSubClass(Class<?> subClass, Class<?> superClass) {
+		try {
+			subClass.asSubclass(superClass);
+			return true;
+		} catch (Exception ex) {
+			return false;
+		}
+	}
+
+	/**
 	 * パッケージ名を取得する。
 	 * 
 	 * @param classDoc
@@ -188,4 +221,24 @@
 		int index2 = parameterizedType.lastIndexOf('>');
 		return parameterizedType.substring(index1 + 1, index2);
 	}
+
+	/**
+	 * List内の要素に存在しない時のみListに追加する。
+	 * 
+	 * @param <E>
+	 * @param list
+	 * @param element
+	 */
+	private static <E> void duplicateCheckAndAddToList(List<E> list, E element) {
+		boolean exist = false;
+		for (E e : list) {
+			if (e.equals(element)) {
+				exist = true;
+				break;
+			}
+		}
+		if (!exist) {
+			list.add(element);
+		}
+	}
 }

Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeListener.vm
===================================================================
--- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeListener.vm	2008-09-11 17:43:24 UTC (rev 1913)
+++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeListener.vm	2008-09-11 21:50:08 UTC (rev 1914)
@@ -18,10 +18,6 @@
  */
 package ${package};
 
-import java.util.List;
-
-import org.jiemamy.core.event.ModelChangeListener;
-import org.jiemamy.core.event.ObservableCollectionChangeEvent;
 #foreach(${importClass} in ${importClasses})
 import ${importClass.toString()};
 #end
@@ -33,12 +29,12 @@
  */
 public interface ${modelClassName}ChangeListener extends ModelChangeListener {
 
-	#foreach($property in $properties)
+#foreach($property in $properties)
 	
 	/**
-	 * {@link ${modelClassName}}が保持する{@link ${property.name}}のCollectionに対する変更を処理する。
+	 * {@link ${modelClassName}}が保持する{@link ${property.elementClass.name}}のCollectionに対する変更を処理する。
 	 * @param event
 	 */
-	void ${property.name}CollectionChange(ObservableCollectionChangeEvent<${property.collectionClass.name}<${property.elementClass.name}>, ${property.elementClass.name}> event);
-	#end
+	void ${property.nameSingle}CollectionChange(ObservableCollectionChangeEvent<${property.collectionClass.simpleName}<${property.elementClass.simpleName}>, ${property.elementClass.simpleName}> event);
+#end
 }

Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupport.vm
===================================================================
--- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupport.vm	2008-09-11 17:43:24 UTC (rev 1913)
+++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupport.vm	2008-09-11 21:50:08 UTC (rev 1914)
@@ -18,19 +18,13 @@
  */
 package org.jiemamy.core.event.model;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jiemamy.core.event.ModelChangeEvent;
-import org.jiemamy.core.event.ModelChangeListener;
-import org.jiemamy.core.event.ObservableCollectionChangeEvent;
-import org.jiemamy.core.event.ObservableCollectionChangeListener;
 #foreach($importClass in $importClasses)
 import $importClass;
 #end
 
 /**
  * Event関連の処理をModel内に直接記述するとModelのSourceの可読性が低くなるため、${modelClassName}からそれらを引き受ける。
+ * 
  * @author shin1ogawa
  */
 public class ${modelClassName}ChangeSupport {
@@ -38,25 +32,39 @@
 	/** ${modelClassName}自身のEventを監視するListenerのリスト */
 	private List<${modelClassName}ChangeListener> listeners = new ArrayList<${modelClassName}ChangeListener>();
 	
-	#foreach($property in $properties)
+#foreach($property in $properties)
+	
 	/** 
 	 * ${property.name}のリストを監視するListener 
 	 * @see ObservableCollectionChangeListener
-	 * @see #fireColumnsCollectionChangeEvent(ObservableCollectionChangeEvent)
+	 * @see #fire${property.nameUpper}CollectionChangeEvent(ObservableCollectionChangeEvent)
 	 */
-	private ObservableCollectionChangeListener<List<${property.elementClass.name}>, ${property.elementClass.name}> ${property.name}CollectionChangeListener =
-			new ObservableCollectionChangeListener<List<${property.elementClass.name}>, ${property.elementClass.name}>() {
+	private ObservableCollectionChangeListener<${property.collectionClass.simpleName}<${property.elementClass.simpleName}>, ${property.elementClass.simpleName}> ${property.name}CollectionChangeListener =
+			new ObservableCollectionChangeListener<${property.collectionClass.simpleName}<${property.elementClass.simpleName}>, ${property.elementClass.simpleName}>() {
 				
 				/**
 				 * {@inheritDoc}
 				 */
-				public void collectionChanged(ObservableCollectionChangeEvent<List<${property.elementClass.name}>, ${property.elementClass.name}> event) {
-					fireColumnsCollectionChangeEvent(event);
+				public void collectionChanged(ObservableCollectionChangeEvent<${property.collectionClass.simpleName}<${property.elementClass.simpleName}>, ${property.elementClass.simpleName}> event) {
+					fire${property.nameUpper}CollectionChangeEvent(event);
 				}
 			};
-	#end
+#end
+	
+	/**
+	 * ${modelClassName}の属性の変更Eventを処理するListener
+	 * @see #fireModelChange(ModelChangeEvent)
+	 */
+	private ModelChangeListener ${modelClassNameLower}ChangeListener = new ModelChangeListener() {
+		
+		/**
+		 * {@inheritDoc}
+		 */
+		public void modelChanged(ModelChangeEvent event) {
+			fireModelChange(event);
+		}
+	};
 
-
 	/**
 	 * コンストラクタ。
 	 * @param source {@link ${modelClassName}}
@@ -64,9 +72,9 @@
 	 */
 	public ${modelClassName}ChangeSupport(${modelClassName} source) {
 		source.addModelChangeListener(${modelClassNameLower}ChangeListener);
-		#foreach($property in $properties)
-		((ObservableList<ColumnModel>) source.get${property.nameUpper}()).addListener(${property.name}CollectionChangeListener);
-		#end
+#foreach($property in $properties)
+		((${property.observableCollectionClass.simpleName}<${property.elementClass.simpleName}>) source.get${property.nameUpper}()).addListener(${property.name}CollectionChangeListener);
+#end
 	}
 	
 	/**
@@ -78,18 +86,18 @@
 		listeners.add(l);
 	}
 	
-	#foreach($property in $properties)
+#foreach($property in $properties)
 	/**
 	 * ${property.name}のcollectionを監視するListenerに通知されたEventを${modelClassName}の監視Listenerへ通知する。
 	 * @param event {@link ObservableCollectionChangeEvent}
 	 */
-	public void fireChecksCollectionChangeEvent(
-			ObservableCollectionChangeEvent<List<${property.elementClass.name}>, ${property.elementClass.name}> event) {
+	public void fire${property.nameUpper}CollectionChangeEvent(
+			ObservableCollectionChangeEvent<${property.collectionClass.simpleName}<${property.elementClass.simpleName}>, ${property.elementClass.simpleName}> event) {
 		for (TableModelChangeListener l : listeners) {
-			l.${property.name}CollectionChange(event);
+			l.${property.nameSingle}CollectionChange(event);
 		}
 	}
-	#end
+#end
 	
 	/**
 	 * ${modelClassName}自身を監視するListenerに通知されたEventを${modelClassName}の監視Listenerへ通知する。


Jiemamy-notify メーリングリストの案内
Back to archive index