/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.seasar.extension.jdbc.gen.internal.meta; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import javax.persistence.Entity; import org.seasar.extension.jdbc.EntityMeta; import org.seasar.extension.jdbc.EntityMetaFactory; import org.seasar.extension.jdbc.gen.internal.exception.DocletUnavailableRuntimeException; import org.seasar.extension.jdbc.gen.internal.exception.EntityClassNotFoundRuntimeException; import org.seasar.extension.jdbc.gen.internal.util.FileUtil; import org.seasar.extension.jdbc.gen.meta.EntityMetaReader; import org.seasar.framework.log.Logger; import org.seasar.framework.util.ClassTraversal; import org.seasar.framework.util.ClassUtil; import org.seasar.framework.util.ClassTraversal.ClassHandler; import com.sun.javadoc.Doclet; /** * {@link EntityMetaReader}の実装クラスです。 * * @author taedium */ public class EntityMetaReaderImpl implements EntityMetaReader { /** ロガー */ protected static Logger logger = Logger .getLogger(EntityMetaReaderImpl.class); /** {@link Doclet}が使用可能な場合{@code true} */ protected static boolean docletAvailable; static { try { Class.forName("com.sun.javadoc.Doclet"); // tools.jar docletAvailable = true; } catch (final Throwable ignore) { } } /** ルートディレクトリ */ protected File classpathDir; /** 読み取り対象とするパッケージ名 */ protected String packageName; /** エンティティメタデータのファクトリ */ protected EntityMetaFactory entityMetaFactory; /** 読み取り対象とするエンティティクラス名のパターン */ protected Pattern shortClassNamePattern; /** 読み取り非対象とするエンティティクラス名のパターン */ protected Pattern ignoreShortClassNamePattern; /** コメントを読む場合 {@code true} */ protected boolean readComment; /** * javaファイルが存在するディレクトリのリスト、{@code useComment}が{@code true}の場合{@code null} * であってはならない */ protected List<File> javaFileSrcDirList = new ArrayList<File>(); /** * javaファイルのエンコーディング、{@code useComment}が{@code true}の場合{@code null} * であってはならない */ protected String javaFileEncoding; /** * インタスタンスを構築します。 * * @param classpathDir * ルートディレクトリ * @param packageName * パッケージ名、パッケージ名を指定しない場合は{@code null} * @param entityMetaFactory * エンティティメタデータのファクトリ * @param shortClassNamePattern * 対象とするエンティティクラス名の正規表現 * @param ignoreShortClassNamePattern * 対象としないエンティティクラス名の正規表現 * @param readComment * エンティティのコメントを使用する場合 {@code true} * @param javaFileSrcDirList * javaファイルが存在するディレクトリのリスト、{@code readComment}が{@code true}の場合 * {@code null}であってはならない * @param javaFileEncoding * javaファイルのエンコーディング、{@code readComment}が{@code true}の場合{@code * null}であってはならない */ public EntityMetaReaderImpl(File classpathDir, String packageName, EntityMetaFactory entityMetaFactory, String shortClassNamePattern, String ignoreShortClassNamePattern, boolean readComment, List<File> javaFileSrcDirList, String javaFileEncoding) { if (classpathDir == null) { throw new NullPointerException("classpathDir"); } if (entityMetaFactory == null) { throw new NullPointerException("entityMetaFactory"); } if (shortClassNamePattern == null) { throw new NullPointerException("shortClassNamePattern"); } if (ignoreShortClassNamePattern == null) { throw new NullPointerException("ignoreShortClassNamePattern"); } if (readComment) { if (javaFileSrcDirList == null) { throw new NullPointerException("javaFileSrcDirList"); } if (javaFileSrcDirList.isEmpty()) { throw new IllegalArgumentException("javaFileSrcDirList"); } if (javaFileEncoding == null) { throw new NullPointerException("javaFileEncoding"); } } this.classpathDir = classpathDir; this.packageName = packageName; this.entityMetaFactory = entityMetaFactory; this.shortClassNamePattern = Pattern.compile(shortClassNamePattern); this.ignoreShortClassNamePattern = Pattern .compile(ignoreShortClassNamePattern); this.readComment = readComment; if (javaFileSrcDirList != null) { this.javaFileSrcDirList.addAll(javaFileSrcDirList); } this.javaFileEncoding = javaFileEncoding; } public List<EntityMeta> read() { final List<EntityMeta> entityMetaList = new ArrayList<EntityMeta>(); ClassTraversal.forEach(classpathDir, new ClassHandler() { public void processClass(String packageName, String shortClassName) { if (isTargetPackage(packageName) && isTargetClass(shortClassName)) { String className = ClassUtil.concatName(packageName, shortClassName); Class<?> clazz = ClassUtil.forName(className); if (clazz.isAnnotationPresent(Entity.class)) { EntityMeta entityMeta = entityMetaFactory .getEntityMeta(clazz); entityMetaList.add(entityMeta); } } } }); if (entityMetaList.isEmpty()) { throw new EntityClassNotFoundRuntimeException(classpathDir, packageName, shortClassNamePattern.pattern(), ignoreShortClassNamePattern.pattern()); } if (readComment) { readComment(entityMetaList); } return entityMetaList; } /** * 読み取りの対象パッケージの場合{@code true}を返します。 * * @param packageName * パッケージ名 * @return 読み取りの対象パッケージの場合{@code true} */ protected boolean isTargetPackage(String packageName) { if (packageName == null) { return true; } if (packageName.equals(this.packageName)) { return true; } if (packageName.startsWith(this.packageName + ".")) { return true; } return false; } /** * 読み取りの対象クラスの場合{@code true}を返します。 * * @param shortClassName * クラスの単純名 * @return 読み取りの対象クラスの場合{@code true} */ protected boolean isTargetClass(String shortClassName) { if (!shortClassNamePattern.matcher(shortClassName).matches()) { return false; } if (ignoreShortClassNamePattern.matcher(shortClassName).matches()) { return false; } return true; } /** * コメントを読みコメントをメタデータに設定します。 * * @param entityMetaList * エンティティメタデータのリスト */ protected void readComment(List<EntityMeta> entityMetaList) { if (!docletAvailable) { throw new DocletUnavailableRuntimeException(); } String[] args = createDocletArgs(); StringBuilder buf = new StringBuilder(); for (String arg : args) { buf.append(arg).append(" "); } logger.log("DS2JDBCGen0019", new Object[] { buf.toString() }); CommentDocletContext.setEntityMetaList(entityMetaList); try { com.sun.tools.javadoc.Main.execute(args); } finally { CommentDocletContext.setEntityMetaList(null); } } /** * {@link Doclet}の引数の配列を作成します。 * * @return {@link Doclet}の引数の配列 */ protected String[] createDocletArgs() { StringBuilder srcDirListBuf = new StringBuilder(); for (File dir : javaFileSrcDirList) { srcDirListBuf.append(FileUtil.getCanonicalPath(dir)); srcDirListBuf.append(File.pathSeparator); } srcDirListBuf.setLength(srcDirListBuf.length() - File.pathSeparator.length()); List<String> args = new ArrayList<String>(); args.add("-doclet"); args.add(CommentDoclet.class.getName()); args.add("-sourcepath"); args.add(srcDirListBuf.toString()); args.add("-encoding"); args.add(javaFileEncoding); args.add("-subpackages"); args.add(packageName); if (logger.isDebugEnabled()) { args.add("-verbose"); } return args.toArray(new String[args.size()]); } public boolean isFiltered() { return !shortClassNamePattern.pattern().equals(".*") || !ignoreShortClassNamePattern.pattern().equals(""); } }