Permalink
Browse files

old hot-reloading classloader

  • Loading branch information...
1 parent 6470047 commit 353bed7b8bfd91a910b65d2d9b6b02bef60bf422 @ashigeru committed Jul 3, 2010
View
@@ -0,0 +1,4 @@
+/.settings
+/target
+/.classpath
+/.project
View
@@ -0,0 +1,91 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.ashigeru.appengine</groupId>
+ <artifactId>hot-reload</artifactId>
+ <packaging>jar</packaging>
+ <version>0.1.0-SNAPSHOT</version>
+ <properties>
+ <appengine.version>1.3.4</appengine.version>
+ </properties>
+ <repositories>
+ <repository>
+ <id>maven.seasar.org</id>
+ <name>The Seasar Foundation Maven2 Repository</name>
+ <url>dav:https://www.seasar.org/maven/maven2</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <updatePolicy>never</updatePolicy>
+ </releases>
+ </repository>
+ <repository>
+ <id>jboss.org</id>
+ <name>JBoss Maven Repository</name>
+ <url>http://repository.jboss.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.appengine</groupId>
+ <artifactId>appengine-api-1.0-sdk</artifactId>
+ <version>${appengine.version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.appengine</groupId>
+ <artifactId>appengine-api-labs</artifactId>
+ <version>${appengine.version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.11.0.GA</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.appengine</groupId>
+ <artifactId>appengine-api-stubs</artifactId>
+ <version>${appengine.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.appengine</groupId>
+ <artifactId>appengine-local-runtime</artifactId>
+ <version>${appengine.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.appengine</groupId>
+ <artifactId>appengine-testing</artifactId>
+ <version>${appengine.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <encoding>utf-8</encoding>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2010 @ashigeru.
+ *
+ * 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 com.ashigeru.appengine.tools.classload;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * {@link InterceptClassLoader}から委譲されるクラスローダが実際にリソースを読み出す処理。
+ * <p>
+ * この実装では、次のような連鎖が行われているため、必要に応じてメソッドをオーバーライドすること。
+ * </p>
+ * <ol>
+ * <li>
+ * {@link #findClass(String)} → バイナリ名に対応するパスを計算し、
+ * {@link #findResourceAsStream(String)}を利用してバイナリを取得する
+ * </li>
+ * <li>
+ * {@link #findResourceAsStream(String)} → 対応するリソースの位置を
+ * {@link #findResource(String)}で探し、ストリームを開く
+ * </li>
+ * <li>
+ * {@link #findResource(String)} → 関連するすべての位置を
+ * {@link #findAllResources(String)}で探し、先頭の要素を返す
+ * </li>
+ * <li>
+ * {@link #findAllResources(String)} → 空の要素を返す
+ * </li>
+ * </ol>
+ */
+public abstract class ClassLoaderDelegate {
+
+ /**
+ * {@link InterceptClassLoader#loadClass(String, boolean)}から呼び出され、
+ * 対応するクラスのバイナリ表現を返す。
+ * <p>
+ * 委譲元の{@link InterceptClassLoader}が当該クラス名のクラスを対象としない場合、
+ * このメソッドは呼び出されない。
+ * </p>
+ * <p>
+ * このメソッドが{@code null}を返す(見つからない)場合、次の委譲先に問い合わせる。
+ * すべての委譲先が{@code null}を返す場合、クラスの探索は失敗する。
+ * </p>
+ * @param binaryName ロードするクラスのバイナリ名
+ * @return 対応するクラスのバイナリ、発見できない場合は{@code null}
+ * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
+ */
+ protected byte[] findClass(String binaryName) {
+ InputStream stream = findResourceAsStream(InterceptClassLoader.toClassFilePath(binaryName));
+ if (stream == null) {
+ return null;
+ }
+ try {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1000];
+ while (true) {
+ int read = stream.read(buffer);
+ if (read < 0) {
+ break;
+ }
+ result.write(buffer, 0, read);
+ }
+ return result.toByteArray();
+ }
+ catch (IOException e) {
+ return null;
+ }
+ finally {
+ try {
+ stream.close();
+ }
+ catch (IOException e) {
+ // ignored.
+ }
+ }
+ }
+
+ /**
+ * {@link InterceptClassLoader#getResource(String)}から呼び出され、
+ * 対応するクラスパス上のリソースへのURLを返す。
+ * <p>
+ * 委譲元の{@link InterceptClassLoader}が当該リソースを対象としない場合、
+ * このメソッドは呼び出されない。
+ * </p>
+ * <p>
+ * このメソッドが{@code null}を返す(見つからない)場合、次の委譲先に問い合わせる。
+ * すべての委譲先が{@code null}を返す場合、リソースの探索は失敗する。
+ * </p>
+ * @param path 探索するリソースへのパス
+ * @return 対応するリソースのURL、発見できない場合やURLで表現できない場合は{@code null}
+ * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
+ */
+ protected URL findResource(String path) {
+ Iterator<URL> found = findAllResources(path).iterator();
+ if (found.hasNext()) {
+ return found.next();
+ }
+ return null;
+ }
+
+ /**
+ * {@link InterceptClassLoader#getResources(String)}から呼び出され、
+ * 対応するクラスパス上のリソースへのURL一覧を返す。
+ * <p>
+ * 委譲元の{@link InterceptClassLoader}が当該リソースを対象としない場合、
+ * このメソッドは呼び出されない。
+ * </p>
+ * @param path 探索するリソースへのパス
+ * @return 対応するリソースのURL一覧、発見できない場合やURLで表現できない場合は空
+ * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
+ */
+ protected Iterable<URL> findAllResources(String path) {
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@link InterceptClassLoader#getResourceAsStream(String)}から呼び出され、
+ * 対応するクラスパス上のリソースの内容を返す。
+ * <p>
+ * 委譲元の{@link InterceptClassLoader}が当該リソースを対象としない場合、
+ * このメソッドは呼び出されない。
+ * </p>
+ * <p>
+ * このメソッドが{@code null}を返す(見つからない)場合、次の委譲先に問い合わせる。
+ * すべての委譲先が{@code null}を返す場合、リソースの探索は失敗する。
+ * </p>
+ * @param path 探索するリソースへのパス
+ * @return 対応するリソースの内容を返すストリーム、
+ * 発見できない場合やURLで表現できない場合は{@code null}
+ * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
+ */
+ protected InputStream findResourceAsStream(String path) {
+ URL location = findResource(path);
+ if (location == null) {
+ return null;
+ }
+ try {
+ return location.openStream();
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+}
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 @ashigeru.
+ *
+ * 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 com.ashigeru.appengine.tools.classload;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * データストアからクラスパス上の情報を取得する。
+ */
+public class DatastoreClassLoaderDelegate extends ClassLoaderDelegate {
+
+ private ResourceStore datastore;
+
+ /**
+ * インスタンスを生成する。
+ * @param datastore リソースファイルを参照する
+ * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
+ */
+ public DatastoreClassLoaderDelegate(ResourceStore datastore) {
+ if (datastore == null) {
+ throw new IllegalArgumentException("datastore must not be null"); //$NON-NLS-1$
+ }
+ this.datastore = datastore;
+ }
+
+ @Override
+ public byte[] findClass(String binaryName) {
+ if (binaryName == null) {
+ throw new IllegalArgumentException("name must not be null"); //$NON-NLS-1$
+ }
+ String path = InterceptClassLoader.toClassFilePath(binaryName);
+ return datastore.get(path);
+ }
+
+ @Override
+ public InputStream findResourceAsStream(String path) {
+ if (path == null) {
+ throw new IllegalArgumentException("path must not be null"); //$NON-NLS-1$
+ }
+ byte[] bytes = datastore.get(path);
+ if (bytes != null) {
+ return new ByteArrayInputStream(bytes);
+ }
+ return null;
+ }
+}
Oops, something went wrong.

0 comments on commit 353bed7

Please sign in to comment.