merge with revision 1294 where issues with SHIFT operations on Long were detected
1.1 --- a/.hgtags Wed Feb 27 17:50:47 2013 +0100
1.2 +++ b/.hgtags Mon Oct 07 14:20:58 2013 +0200
1.3 @@ -1,1 +1,13 @@
1.4 0a115f1c6f3c70458fc479ae82b4d7fcdeb7e95a jdk7-b147_base
1.5 +7367a296a9ec4a88e0292a41244c96283818e563 bck2brwsr-0.3
1.6 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-${releaseVersion}
1.7 +30e9ac29654fba6f67d0921e7e3aa21133442592 release-0.5
1.8 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-0.4
1.9 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-${releaseVersion}
1.10 +0000000000000000000000000000000000000000 release-${releaseVersion}
1.11 +52a4a5f868bccc67d50ad17f793b9ebabdf75d88 release-0.6
1.12 +6792dc0bafb9c76a099e45bfc9e967d6a2823827 release-0.7
1.13 +623816269b75e53fffb4b19960df7040a3c20056 release-0.7
1.14 +23572dc719bd630817d11eaabdee4565f63ef8e1 release-0.7.1
1.15 +56abd247f421febd8b2c5e59d666968692e11555 release-0.7.2
1.16 +a83e16b8b825399bb21461e578c32d86982e4ed3 release-0.8
2.1 --- a/benchmarks/matrix-multiplication/pom.xml Wed Feb 27 17:50:47 2013 +0100
2.2 +++ b/benchmarks/matrix-multiplication/pom.xml Mon Oct 07 14:20:58 2013 +0200
2.3 @@ -1,16 +1,15 @@
2.4 <?xml version="1.0"?>
2.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2.6 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2.7 +<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/xsd/maven-4.0.0.xsd">
2.8 <modelVersion>4.0.0</modelVersion>
2.9
2.10 <groupId>org.apidesign.bck2brwsr</groupId>
2.11 <artifactId>matrix.multiplication</artifactId>
2.12 - <version>0.3-SNAPSHOT</version>
2.13 + <version>0.9-SNAPSHOT</version>
2.14 <packaging>jar</packaging>
2.15 <parent>
2.16 <artifactId>benchmarks</artifactId>
2.17 <groupId>org.apidesign.bck2brwsr</groupId>
2.18 - <version>0.3-SNAPSHOT</version>
2.19 + <version>0.9-SNAPSHOT</version>
2.20 </parent>
2.21
2.22 <name>Matrix multiplication</name>
2.23 @@ -38,6 +37,36 @@
2.24 <skip>true</skip>
2.25 </configuration>
2.26 </plugin>
2.27 + <plugin>
2.28 + <groupId>org.codehaus.mojo</groupId>
2.29 + <artifactId>xml-maven-plugin</artifactId>
2.30 + <version>1.0</version>
2.31 + <executions>
2.32 + <execution>
2.33 + <goals>
2.34 + <goal>transform</goal>
2.35 + </goals>
2.36 + <phase>install</phase>
2.37 + </execution>
2.38 + </executions>
2.39 + <configuration>
2.40 + <transformationSets>
2.41 + <transformationSet>
2.42 + <dir>target/surefire-reports</dir>
2.43 + <outputDir>target/surefire-reports</outputDir>
2.44 + <includes>
2.45 + <include>TEST*.xml</include>
2.46 + </includes>
2.47 + <stylesheet>src/main/select-time.xsl</stylesheet>
2.48 + <fileMappers>
2.49 + <fileMapper implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
2.50 + <targetExtension>.csv</targetExtension>
2.51 + </fileMapper>
2.52 + </fileMappers>
2.53 + </transformationSet>
2.54 + </transformationSets>
2.55 + </configuration>
2.56 + </plugin>
2.57 </plugins>
2.58 </build>
2.59
2.60 @@ -45,7 +74,7 @@
2.61 <dependency>
2.62 <groupId>org.apidesign.bck2brwsr</groupId>
2.63 <artifactId>emul.mini</artifactId>
2.64 - <version>0.3-SNAPSHOT</version>
2.65 + <version>0.9-SNAPSHOT</version>
2.66 </dependency>
2.67 <dependency>
2.68 <groupId>org.testng</groupId>
2.69 @@ -62,7 +91,13 @@
2.70 <dependency>
2.71 <groupId>org.apidesign.bck2brwsr</groupId>
2.72 <artifactId>vmtest</artifactId>
2.73 - <version>0.3-SNAPSHOT</version>
2.74 + <version>0.9-SNAPSHOT</version>
2.75 + <scope>test</scope>
2.76 + </dependency>
2.77 + <dependency>
2.78 + <groupId>org.apidesign.bck2brwsr</groupId>
2.79 + <artifactId>launcher.http</artifactId>
2.80 + <version>0.9-SNAPSHOT</version>
2.81 <scope>test</scope>
2.82 </dependency>
2.83 </dependencies>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/benchmarks/matrix-multiplication/src/main/select-time.xsl Mon Oct 07 14:20:58 2013 +0200
3.3 @@ -0,0 +1,55 @@
3.4 +<?xml version="1.0" encoding="UTF-8"?>
3.5 +<!--
3.6 +
3.7 + Back 2 Browser Bytecode Translator
3.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.9 +
3.10 + This program is free software: you can redistribute it and/or modify
3.11 + it under the terms of the GNU General Public License as published by
3.12 + the Free Software Foundation, version 2 of the License.
3.13 +
3.14 + This program is distributed in the hope that it will be useful,
3.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + GNU General Public License for more details.
3.18 +
3.19 + You should have received a copy of the GNU General Public License
3.20 + along with this program. Look for COPYING file in the top folder.
3.21 + If not, see http://opensource.org/licenses/GPL-2.0.
3.22 +
3.23 +-->
3.24 +
3.25 +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
3.26 + <xsl:output method="text"/>
3.27 +
3.28 + <xsl:template match="/">
3.29 + <xsl:apply-templates mode="header" select="testsuite/testcase"/><xsl:text>End
3.30 +</xsl:text>
3.31 + <xsl:apply-templates mode="value" select="testsuite/testcase"/><xsl:text>NaN
3.32 +</xsl:text>
3.33 + </xsl:template>
3.34 +
3.35 +
3.36 + <xsl:template match="testcase" mode="header">
3.37 + <xsl:if test="contains(@name,'tenThousand')">
3.38 + <xsl:if test="not(contains(@name, '[Java]'))">
3.39 + <xsl:if test="not(contains(@name, '[Compare'))">
3.40 + <xsl:value-of select="@name"/>
3.41 + <xsl:text>,</xsl:text>
3.42 + </xsl:if>
3.43 + </xsl:if>
3.44 + </xsl:if>
3.45 + </xsl:template>
3.46 +
3.47 + <xsl:template match="testcase" mode="value">
3.48 + <xsl:if test="contains(@name,'tenThousand')">
3.49 + <xsl:if test="not(contains(@name, '[Java]'))">
3.50 + <xsl:if test="not(contains(@name, '[Compare'))">
3.51 + <xsl:value-of select="@time"/>
3.52 + <xsl:text>,</xsl:text>
3.53 + </xsl:if>
3.54 + </xsl:if>
3.55 + </xsl:if>
3.56 + </xsl:template>
3.57 +
3.58 +</xsl:stylesheet>
4.1 --- a/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Wed Feb 27 17:50:47 2013 +0100
4.2 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Mon Oct 07 14:20:58 2013 +0200
4.3 @@ -31,6 +31,22 @@
4.4 }
4.5
4.6 @Compare(scripting = false)
4.7 + public String oneIteration() throws IOException {
4.8 +
4.9 + Matrix m1 = new Matrix(5);
4.10 + Matrix m2 = new Matrix(5);
4.11 +
4.12 + m1.generateData();
4.13 + m2.generateData();
4.14 +
4.15 + Matrix res = m1.multiply(m2);
4.16 +
4.17 + StringBuilder sb = new StringBuilder();
4.18 + res.printOn(sb);
4.19 + return sb.toString();
4.20 + }
4.21 +
4.22 + @Compare(scripting = false)
4.23 public String tenThousandIterations() throws IOException {
4.24
4.25 Matrix m1 = new Matrix(5);
4.26 @@ -50,6 +66,27 @@
4.27 return sb.toString();
4.28 }
4.29
4.30 + @Compare(scripting = false)
4.31 + public String tenUselessIterations() throws IOException {
4.32 +
4.33 + Matrix m1 = new Matrix(5);
4.34 + Matrix m2 = new Matrix(5);
4.35 +
4.36 + m1.generateData();
4.37 + m2.generateData();
4.38 +
4.39 + Matrix res = null;
4.40 + for (int i = 0; i < 10; i++) {
4.41 + res = m1.multiply(m2);
4.42 + m1 = res;
4.43 + }
4.44 +
4.45 + StringBuilder sb = new StringBuilder();
4.46 + res.printOn(sb);
4.47 + return sb.toString();
4.48 + }
4.49 +
4.50 +
4.51 @Factory
4.52 public static Object[] create() {
4.53 return VMTest.create(MatrixTest.class);
5.1 --- a/benchmarks/pom.xml Wed Feb 27 17:50:47 2013 +0100
5.2 +++ b/benchmarks/pom.xml Mon Oct 07 14:20:58 2013 +0200
5.3 @@ -4,11 +4,11 @@
5.4 <parent>
5.5 <artifactId>bck2brwsr</artifactId>
5.6 <groupId>org.apidesign</groupId>
5.7 - <version>0.3-SNAPSHOT</version>
5.8 + <version>0.9-SNAPSHOT</version>
5.9 </parent>
5.10 <groupId>org.apidesign.bck2brwsr</groupId>
5.11 <artifactId>benchmarks</artifactId>
5.12 - <version>0.3-SNAPSHOT</version>
5.13 + <version>0.9-SNAPSHOT</version>
5.14 <packaging>pom</packaging>
5.15 <name>Performance benchmarks</name>
5.16 <modules>
6.1 --- a/dew/pom.xml Wed Feb 27 17:50:47 2013 +0100
6.2 +++ b/dew/pom.xml Mon Oct 07 14:20:58 2013 +0200
6.3 @@ -1,15 +1,14 @@
6.4 <?xml version="1.0"?>
6.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
6.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
6.7 +<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/xsd/maven-4.0.0.xsd">
6.8 <modelVersion>4.0.0</modelVersion>
6.9 <parent>
6.10 <groupId>org.apidesign</groupId>
6.11 <artifactId>bck2brwsr</artifactId>
6.12 - <version>0.3-SNAPSHOT</version>
6.13 + <version>0.9-SNAPSHOT</version>
6.14 </parent>
6.15 <groupId>org.apidesign.bck2brwsr</groupId>
6.16 <artifactId>dew</artifactId>
6.17 - <version>0.3-SNAPSHOT</version>
6.18 + <version>0.9-SNAPSHOT</version>
6.19 <name>Development Environment for Web</name>
6.20 <url>http://maven.apache.org</url>
6.21 <build>
6.22 @@ -38,11 +37,19 @@
6.23 <executable>java</executable>
6.24 <arguments>
6.25 <argument>-classpath</argument>
6.26 - <classpath/>
6.27 + <classpath />
6.28 <argument>org.apidesign.bck2brwsr.dew.Dew</argument>
6.29 </arguments>
6.30 </configuration>
6.31 </plugin>
6.32 + <plugin>
6.33 + <groupId>org.apache.maven.plugins</groupId>
6.34 + <artifactId>maven-deploy-plugin</artifactId>
6.35 + <version>2.7</version>
6.36 + <configuration>
6.37 + <skip>true</skip>
6.38 + </configuration>
6.39 + </plugin>
6.40 </plugins>
6.41 </build>
6.42 <properties>
7.1 --- a/ide/editor/pom.xml Wed Feb 27 17:50:47 2013 +0100
7.2 +++ b/ide/editor/pom.xml Mon Oct 07 14:20:58 2013 +0200
7.3 @@ -4,19 +4,18 @@
7.4 <parent>
7.5 <artifactId>ide</artifactId>
7.6 <groupId>org.apidesign.bck2brwsr</groupId>
7.7 - <version>0.3-SNAPSHOT</version>
7.8 + <version>0.9-SNAPSHOT</version>
7.9 </parent>
7.10
7.11 - <groupId>org.apidesign.bck2brwsr.ide.editor</groupId>
7.12 + <groupId>org.apidesign.bck2brwsr.ide</groupId>
7.13 <artifactId>editor</artifactId>
7.14 - <version>0.3-SNAPSHOT</version>
7.15 + <version>0.9-SNAPSHOT</version>
7.16 <packaging>nbm</packaging>
7.17
7.18 <name>Editor Support for Bck2Brwsr</name>
7.19
7.20 <properties>
7.21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
7.22 - <netbeans.version>RELEASE72</netbeans.version>
7.23 <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
7.24 </properties>
7.25
7.26 @@ -40,71 +39,59 @@
7.27 <dependency>
7.28 <groupId>org.netbeans.api</groupId>
7.29 <artifactId>org-netbeans-api-annotations-common</artifactId>
7.30 - <version>${netbeans.version}</version>
7.31 </dependency>
7.32 <dependency>
7.33 <groupId>org.netbeans.api</groupId>
7.34 <artifactId>org-netbeans-modules-java-source</artifactId>
7.35 - <version>${netbeans.version}</version>
7.36 </dependency>
7.37 <dependency>
7.38 <groupId>org.netbeans.api</groupId>
7.39 <artifactId>org-netbeans-libs-javacapi</artifactId>
7.40 - <version>${netbeans.version}</version>
7.41 </dependency>
7.42 <dependency>
7.43 <groupId>org.netbeans.api</groupId>
7.44 <artifactId>org-netbeans-spi-java-hints</artifactId>
7.45 - <version>${netbeans.version}</version>
7.46 </dependency>
7.47 <dependency>
7.48 <groupId>org.netbeans.api</groupId>
7.49 <artifactId>org-netbeans-modules-parsing-api</artifactId>
7.50 - <version>${netbeans.version}</version>
7.51 </dependency>
7.52 <dependency>
7.53 <groupId>org.netbeans.api</groupId>
7.54 <artifactId>org-netbeans-spi-editor-hints</artifactId>
7.55 - <version>${netbeans.version}</version>
7.56 </dependency>
7.57 <dependency>
7.58 <groupId>org.netbeans.api</groupId>
7.59 <artifactId>org-openide-util</artifactId>
7.60 - <version>${netbeans.version}</version>
7.61 </dependency>
7.62 <dependency>
7.63 <groupId>org.netbeans.api</groupId>
7.64 <artifactId>org-netbeans-modules-java-lexer</artifactId>
7.65 - <version>${netbeans.version}</version>
7.66 </dependency>
7.67 <dependency>
7.68 <groupId>org.netbeans.api</groupId>
7.69 <artifactId>org-netbeans-modules-lexer</artifactId>
7.70 - <version>${netbeans.version}</version>
7.71 </dependency>
7.72 <dependency>
7.73 <groupId>org.apidesign.bck2brwsr</groupId>
7.74 <artifactId>core</artifactId>
7.75 - <version>0.3-SNAPSHOT</version>
7.76 + <version>0.9-SNAPSHOT</version>
7.77 <type>jar</type>
7.78 <scope>test</scope>
7.79 </dependency>
7.80 <dependency>
7.81 <groupId>org.netbeans.api</groupId>
7.82 <artifactId>org-netbeans-modules-java-hints-test</artifactId>
7.83 - <version>${netbeans.version}</version>
7.84 <scope>test</scope>
7.85 </dependency>
7.86 <dependency>
7.87 <groupId>org.netbeans.api</groupId>
7.88 <artifactId>org-netbeans-libs-junit4</artifactId>
7.89 - <version>${netbeans.version}</version>
7.90 <scope>test</scope>
7.91 </dependency>
7.92 <dependency>
7.93 <groupId>org.netbeans.modules</groupId>
7.94 <artifactId>org-netbeans-lib-nbjavac</artifactId>
7.95 - <version>${netbeans.version}</version>
7.96 <scope>test</scope>
7.97 </dependency>
7.98 <dependency>
8.1 --- a/ide/pom.xml Wed Feb 27 17:50:47 2013 +0100
8.2 +++ b/ide/pom.xml Mon Oct 07 14:20:58 2013 +0200
8.3 @@ -4,14 +4,26 @@
8.4 <parent>
8.5 <artifactId>bck2brwsr</artifactId>
8.6 <groupId>org.apidesign</groupId>
8.7 - <version>0.3-SNAPSHOT</version>
8.8 + <version>0.9-SNAPSHOT</version>
8.9 </parent>
8.10 <groupId>org.apidesign.bck2brwsr</groupId>
8.11 <artifactId>ide</artifactId>
8.12 - <version>0.3-SNAPSHOT</version>
8.13 + <version>0.9-SNAPSHOT</version>
8.14 <packaging>pom</packaging>
8.15 <name>IDE Support</name>
8.16 <modules>
8.17 <module>editor</module>
8.18 </modules>
8.19 + <build>
8.20 + <plugins>
8.21 + <plugin>
8.22 + <groupId>org.apache.maven.plugins</groupId>
8.23 + <artifactId>maven-deploy-plugin</artifactId>
8.24 + <version>2.7</version>
8.25 + <configuration>
8.26 + <skip>true</skip>
8.27 + </configuration>
8.28 + </plugin>
8.29 + </plugins>
8.30 + </build>
8.31 </project>
9.1 --- a/javaquery/api/pom.xml Wed Feb 27 17:50:47 2013 +0100
9.2 +++ b/javaquery/api/pom.xml Mon Oct 07 14:20:58 2013 +0200
9.3 @@ -1,15 +1,14 @@
9.4 <?xml version="1.0"?>
9.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
9.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
9.7 +<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/xsd/maven-4.0.0.xsd">
9.8 <modelVersion>4.0.0</modelVersion>
9.9 <parent>
9.10 <groupId>org.apidesign.bck2brwsr</groupId>
9.11 <artifactId>javaquery</artifactId>
9.12 - <version>0.3-SNAPSHOT</version>
9.13 + <version>0.9-SNAPSHOT</version>
9.14 </parent>
9.15 <groupId>org.apidesign.bck2brwsr</groupId>
9.16 <artifactId>javaquery.api</artifactId>
9.17 - <version>0.3-SNAPSHOT</version>
9.18 + <version>0.9-SNAPSHOT</version>
9.19 <name>JavaQuery API</name>
9.20 <url>http://maven.apache.org</url>
9.21 <build>
9.22 @@ -19,8 +18,16 @@
9.23 <artifactId>maven-compiler-plugin</artifactId>
9.24 <version>2.3.2</version>
9.25 <configuration>
9.26 - <source>1.6</source>
9.27 - <target>1.6</target>
9.28 + <source>1.7</source>
9.29 + <target>1.7</target>
9.30 + </configuration>
9.31 + </plugin>
9.32 + <plugin>
9.33 + <groupId>org.apache.maven.plugins</groupId>
9.34 + <artifactId>maven-javadoc-plugin</artifactId>
9.35 + <configuration>
9.36 + <subpackages>org.apidesign.bck2brwsr.htmlpage.api</subpackages>
9.37 + <skip>false</skip>
9.38 </configuration>
9.39 </plugin>
9.40 </plugins>
9.41 @@ -66,5 +73,11 @@
9.42 <version>${project.version}</version>
9.43 <scope>test</scope>
9.44 </dependency>
9.45 + <dependency>
9.46 + <groupId>${project.groupId}</groupId>
9.47 + <artifactId>launcher.http</artifactId>
9.48 + <version>${project.version}</version>
9.49 + <scope>test</scope>
9.50 + </dependency>
9.51 </dependencies>
9.52 </project>
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Mon Oct 07 14:20:58 2013 +0200
10.3 @@ -0,0 +1,155 @@
10.4 +/**
10.5 + * Back 2 Browser Bytecode Translator
10.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
10.7 + *
10.8 + * This program is free software: you can redistribute it and/or modify
10.9 + * it under the terms of the GNU General Public License as published by
10.10 + * the Free Software Foundation, version 2 of the License.
10.11 + *
10.12 + * This program is distributed in the hope that it will be useful,
10.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.15 + * GNU General Public License for more details.
10.16 + *
10.17 + * You should have received a copy of the GNU General Public License
10.18 + * along with this program. Look for COPYING file in the top folder.
10.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
10.20 + */
10.21 +package org.apidesign.bck2brwsr.htmlpage;
10.22 +
10.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
10.24 +
10.25 +/**
10.26 + *
10.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
10.28 + */
10.29 +public final class ConvertTypes {
10.30 + ConvertTypes() {
10.31 + }
10.32 +
10.33 + public static String toString(Object object, String property) {
10.34 + Object ret = getProperty(object, property);
10.35 + return ret == null ? null : ret.toString();
10.36 + }
10.37 +
10.38 + public static double toDouble(Object object, String property) {
10.39 + Object ret = getProperty(object, property);
10.40 + return ret instanceof Number ? ((Number)ret).doubleValue() : Double.NaN;
10.41 + }
10.42 +
10.43 + public static int toInt(Object object, String property) {
10.44 + Object ret = getProperty(object, property);
10.45 + return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE;
10.46 + }
10.47 +
10.48 + public static <T> T toModel(Class<T> modelClass, Object object, String property) {
10.49 + Object ret = getProperty(object, property);
10.50 + if (ret == null || modelClass.isInstance(ret)) {
10.51 + return modelClass.cast(ret);
10.52 + }
10.53 + throw new IllegalStateException("Value " + ret + " is not of type " + modelClass);
10.54 + }
10.55 +
10.56 + public static String toJSON(Object value) {
10.57 + if (value == null) {
10.58 + return "null";
10.59 + }
10.60 + if (value instanceof Enum) {
10.61 + value = value.toString();
10.62 + }
10.63 + if (value instanceof String) {
10.64 + return '"' +
10.65 + ((String)value).
10.66 + replace("\"", "\\\"").
10.67 + replace("\n", "\\n").
10.68 + replace("\r", "\\r").
10.69 + replace("\t", "\\t")
10.70 + + '"';
10.71 + }
10.72 + return value.toString();
10.73 + }
10.74 +
10.75 + @JavaScriptBody(args = { "object", "property" },
10.76 + body = "if (property === null) return object;\n"
10.77 + + "var p = object[property]; return p ? p : null;"
10.78 + )
10.79 + private static Object getProperty(Object object, String property) {
10.80 + return null;
10.81 + }
10.82 +
10.83 + public static String createJSONP(Object[] jsonResult, Runnable whenDone) {
10.84 + int h = whenDone.hashCode();
10.85 + String name;
10.86 + for (;;) {
10.87 + name = "jsonp" + Integer.toHexString(h);
10.88 + if (defineIfUnused(name, jsonResult, whenDone)) {
10.89 + return name;
10.90 + }
10.91 + h++;
10.92 + }
10.93 + }
10.94 +
10.95 + @JavaScriptBody(args = { "name", "arr", "run" }, body =
10.96 + "if (window[name]) return false;\n "
10.97 + + "window[name] = function(data) {\n "
10.98 + + " delete window[name];\n"
10.99 + + " var el = window.document.getElementById(name);\n"
10.100 + + " el.parentNode.removeChild(el);\n"
10.101 + + " arr[0] = data;\n"
10.102 + + " run.run__V();\n"
10.103 + + "};\n"
10.104 + + "return true;\n"
10.105 + )
10.106 + private static boolean defineIfUnused(String name, Object[] arr, Runnable run) {
10.107 + return true;
10.108 + }
10.109 +
10.110 + @JavaScriptBody(args = { "url", "arr", "callback" }, body = ""
10.111 + + "var request = new XMLHttpRequest();\n"
10.112 + + "request.open('GET', url, true);\n"
10.113 + + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n"
10.114 + + "request.onreadystatechange = function() {\n"
10.115 + + " if (this.readyState!==4) return;\n"
10.116 + + " try {\n"
10.117 + + " arr[0] = eval('(' + this.response + ')');\n"
10.118 + + " } catch (error) {;\n"
10.119 + + " throw 'Cannot parse' + error + ':' + this.response;\n"
10.120 + + " };\n"
10.121 + + " callback.run__V();\n"
10.122 + + "};"
10.123 + + "request.send();"
10.124 + )
10.125 + private static void loadJSON(
10.126 + String url, Object[] jsonResult, Runnable whenDone
10.127 + ) {
10.128 + }
10.129 +
10.130 + public static void loadJSON(
10.131 + String url, Object[] jsonResult, Runnable whenDone, String jsonp
10.132 + ) {
10.133 + if (jsonp == null) {
10.134 + loadJSON(url, jsonResult, whenDone);
10.135 + } else {
10.136 + loadJSONP(url, jsonp);
10.137 + }
10.138 + }
10.139 +
10.140 + @JavaScriptBody(args = { "url", "jsonp" }, body =
10.141 + "var scrpt = window.document.createElement('script');\n "
10.142 + + "scrpt.setAttribute('src', url);\n "
10.143 + + "scrpt.setAttribute('id', jsonp);\n "
10.144 + + "scrpt.setAttribute('type', 'text/javascript');\n "
10.145 + + "var body = document.getElementsByTagName('body')[0];\n "
10.146 + + "body.appendChild(scrpt);\n"
10.147 + )
10.148 + private static void loadJSONP(String url, String jsonp) {
10.149 +
10.150 + }
10.151 +
10.152 + public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
10.153 + for (int i = 0; i < props.length; i++) {
10.154 + values[i] = getProperty(jsonObject, props[i]);
10.155 + }
10.156 + }
10.157 +
10.158 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/KOList.java Mon Oct 07 14:20:58 2013 +0200
11.3 @@ -0,0 +1,167 @@
11.4 +/**
11.5 + * Back 2 Browser Bytecode Translator
11.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
11.7 + *
11.8 + * This program is free software: you can redistribute it and/or modify
11.9 + * it under the terms of the GNU General Public License as published by
11.10 + * the Free Software Foundation, version 2 of the License.
11.11 + *
11.12 + * This program is distributed in the hope that it will be useful,
11.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11.15 + * GNU General Public License for more details.
11.16 + *
11.17 + * You should have received a copy of the GNU General Public License
11.18 + * along with this program. Look for COPYING file in the top folder.
11.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
11.20 + */
11.21 +package org.apidesign.bck2brwsr.htmlpage;
11.22 +
11.23 +import java.util.ArrayList;
11.24 +import java.util.Collection;
11.25 +import java.util.Iterator;
11.26 +import org.apidesign.bck2brwsr.core.JavaScriptOnly;
11.27 +
11.28 +/**
11.29 + *
11.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
11.31 + */
11.32 +public final class KOList<T> extends ArrayList<T> {
11.33 + private final String name;
11.34 + private final String[] deps;
11.35 + private Knockout model;
11.36 + private Runnable onchange;
11.37 +
11.38 + public KOList(String name, String... deps) {
11.39 + this.name = name;
11.40 + this.deps = deps;
11.41 + }
11.42 +
11.43 + public void assign(Knockout model) {
11.44 + if (this.model != model) {
11.45 + this.model = model;
11.46 + notifyChange();
11.47 + }
11.48 + }
11.49 +
11.50 + public KOList<T> onChange(Runnable r) {
11.51 + if (this.onchange != null) {
11.52 + throw new IllegalStateException();
11.53 + }
11.54 + this.onchange = r;
11.55 + return this;
11.56 + }
11.57 +
11.58 + @Override
11.59 + public boolean add(T e) {
11.60 + boolean ret = super.add(e);
11.61 + notifyChange();
11.62 + return ret;
11.63 + }
11.64 +
11.65 + @Override
11.66 + public boolean addAll(Collection<? extends T> c) {
11.67 + boolean ret = super.addAll(c);
11.68 + notifyChange();
11.69 + return ret;
11.70 + }
11.71 +
11.72 + @Override
11.73 + public boolean addAll(int index, Collection<? extends T> c) {
11.74 + boolean ret = super.addAll(index, c);
11.75 + notifyChange();
11.76 + return ret;
11.77 + }
11.78 +
11.79 + @Override
11.80 + public boolean remove(Object o) {
11.81 + boolean ret = super.remove(o);
11.82 + notifyChange();
11.83 + return ret;
11.84 + }
11.85 +
11.86 + @Override
11.87 + public void clear() {
11.88 + super.clear();
11.89 + notifyChange();
11.90 + }
11.91 +
11.92 + @Override
11.93 + public boolean removeAll(Collection<?> c) {
11.94 + boolean ret = super.removeAll(c);
11.95 + notifyChange();
11.96 + return ret;
11.97 + }
11.98 +
11.99 + @Override
11.100 + public boolean retainAll(Collection<?> c) {
11.101 + boolean ret = super.retainAll(c);
11.102 + notifyChange();
11.103 + return ret;
11.104 + }
11.105 +
11.106 + @Override
11.107 + public T set(int index, T element) {
11.108 + T ret = super.set(index, element);
11.109 + notifyChange();
11.110 + return ret;
11.111 + }
11.112 +
11.113 + @Override
11.114 + public void add(int index, T element) {
11.115 + super.add(index, element);
11.116 + notifyChange();
11.117 + }
11.118 +
11.119 + @Override
11.120 + public T remove(int index) {
11.121 + T ret = super.remove(index);
11.122 + notifyChange();
11.123 + return ret;
11.124 + }
11.125 +
11.126 + @Override
11.127 + public String toString() {
11.128 + Iterator<T> it = iterator();
11.129 + if (!it.hasNext()) {
11.130 + return "[]";
11.131 + }
11.132 + String sep = "";
11.133 + StringBuilder sb = new StringBuilder();
11.134 + sb.append('[');
11.135 + while (it.hasNext()) {
11.136 + T t = it.next();
11.137 + sb.append(sep);
11.138 + sb.append(ConvertTypes.toJSON(t));
11.139 + sep = ",";
11.140 + }
11.141 + sb.append(']');
11.142 + return sb.toString();
11.143 + }
11.144 +
11.145 +
11.146 + @JavaScriptOnly(name = "koArray", value = "function() { return this.toArray___3Ljava_lang_Object_2(); }")
11.147 + private static native int koArray();
11.148 +
11.149 + private void notifyChange() {
11.150 + Knockout m = model;
11.151 + if (m != null) {
11.152 + m.valueHasMutated(name);
11.153 + for (String dependant : deps) {
11.154 + m.valueHasMutated(dependant);
11.155 + }
11.156 + }
11.157 + Runnable r = onchange;
11.158 + if (r != null) {
11.159 + r.run();
11.160 + }
11.161 + }
11.162 +
11.163 + @Override
11.164 + public KOList clone() {
11.165 + KOList ko = (KOList)super.clone();
11.166 + ko.model = null;
11.167 + return ko;
11.168 + }
11.169 +
11.170 +}
12.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Wed Feb 27 17:50:47 2013 +0100
12.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Mon Oct 07 14:20:58 2013 +0200
12.3 @@ -18,6 +18,7 @@
12.4 package org.apidesign.bck2brwsr.htmlpage;
12.5
12.6 import java.lang.reflect.Method;
12.7 +import java.util.List;
12.8 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
12.9 import org.apidesign.bck2brwsr.core.JavaScriptBody;
12.10
12.11 @@ -29,38 +30,40 @@
12.12 public class Knockout {
12.13 /** used by tests */
12.14 static Knockout next;
12.15 -
12.16 - Knockout() {
12.17 + private final Object model;
12.18 +
12.19 + Knockout(Object model) {
12.20 + this.model = model == null ? this : model;
12.21 }
12.22
12.23 public static <M> Knockout applyBindings(
12.24 - Class<M> modelClass, M model, String[] propsGettersAndSetters
12.25 + Object model, String[] propsGettersAndSetters,
12.26 + String[] methodsAndSignatures
12.27 + ) {
12.28 + applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures);
12.29 + return new Knockout(model);
12.30 + }
12.31 + public static <M> Knockout applyBindings(
12.32 + Class<M> modelClass, M model, String[] propsGettersAndSetters,
12.33 + String[] methodsAndSignatures
12.34 ) {
12.35 Knockout bindings = next;
12.36 next = null;
12.37 if (bindings == null) {
12.38 - bindings = new Knockout();
12.39 + bindings = new Knockout(null);
12.40 }
12.41 - for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
12.42 - try {
12.43 - Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
12.44 - bind(bindings, model, propsGettersAndSetters[i],
12.45 - propsGettersAndSetters[i + 1],
12.46 - propsGettersAndSetters[i + 2],
12.47 - getter.getReturnType().isPrimitive()
12.48 - );
12.49 - } catch (NoSuchMethodException ex) {
12.50 - throw new IllegalStateException(ex.getMessage());
12.51 - }
12.52 - }
12.53 + applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures);
12.54 applyBindings(bindings);
12.55 return bindings;
12.56 }
12.57
12.58 - @JavaScriptBody(args = { "prop" }, body =
12.59 - "this[prop].valueHasMutated();"
12.60 + public void valueHasMutated(String prop) {
12.61 + valueHasMutated(model, prop);
12.62 + }
12.63 + @JavaScriptBody(args = { "self", "prop" }, body =
12.64 + "self[prop].valueHasMutated();"
12.65 )
12.66 - public void valueHasMutated(String prop) {
12.67 + public void valueHasMutated(Object self, String prop) {
12.68 }
12.69
12.70
12.71 @@ -68,26 +71,60 @@
12.72 public static void triggerEvent(String id, String ev) {
12.73 }
12.74
12.75 - @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body =
12.76 + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body =
12.77 "var bnd = {\n"
12.78 - + " read: function() {\n"
12.79 + + " 'read': function() {\n"
12.80 + " var v = model[getter]();\n"
12.81 + + " if (array) v = v.koArray();\n"
12.82 + " return v;\n"
12.83 + " },\n"
12.84 - + " owner: bindings\n"
12.85 + + " 'owner': bindings\n"
12.86 + "};\n"
12.87 + "if (setter != null) {\n"
12.88 - + " bnd.write = function(val) {\n"
12.89 + + " bnd['write'] = function(val) {\n"
12.90 + " model[setter](primitive ? new Number(val) : val);\n"
12.91 + " };\n"
12.92 + "}\n"
12.93 - + "bindings[prop] = ko.computed(bnd);"
12.94 + + "bindings[prop] = ko['computed'](bnd);"
12.95 )
12.96 private static void bind(
12.97 - Object bindings, Object model, String prop, String getter, String setter, boolean primitive
12.98 + Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array
12.99 + ) {
12.100 + }
12.101 +
12.102 + @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body =
12.103 + "bindings[prop] = function(data, ev) { model[sig](data, ev); };"
12.104 + )
12.105 + private static void expose(
12.106 + Object bindings, Object model, String prop, String sig
12.107 ) {
12.108 }
12.109
12.110 @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
12.111 private static void applyBindings(Object bindings) {}
12.112 +
12.113 + private static void applyImpl(
12.114 + String[] propsGettersAndSetters,
12.115 + Class<?> modelClass,
12.116 + Object bindings,
12.117 + Object model,
12.118 + String[] methodsAndSignatures
12.119 + ) throws IllegalStateException, SecurityException {
12.120 + for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
12.121 + try {
12.122 + Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
12.123 + bind(bindings, model, propsGettersAndSetters[i],
12.124 + propsGettersAndSetters[i + 1],
12.125 + propsGettersAndSetters[i + 2],
12.126 + getter.getReturnType().isPrimitive(),
12.127 + List.class.isAssignableFrom(getter.getReturnType()));
12.128 + } catch (NoSuchMethodException ex) {
12.129 + throw new IllegalStateException(ex.getMessage());
12.130 + }
12.131 + }
12.132 + for (int i = 0; i < methodsAndSignatures.length; i += 2) {
12.133 + expose(
12.134 + bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]);
12.135 + }
12.136 + }
12.137 }
13.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Wed Feb 27 17:50:47 2013 +0100
13.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Oct 07 14:20:58 2013 +0200
13.3 @@ -20,23 +20,30 @@
13.4 import java.io.IOException;
13.5 import java.io.InputStream;
13.6 import java.io.OutputStreamWriter;
13.7 +import java.io.StringWriter;
13.8 import java.io.Writer;
13.9 +import java.lang.annotation.AnnotationTypeMismatchException;
13.10 +import java.lang.annotation.IncompleteAnnotationException;
13.11 +import java.lang.reflect.Method;
13.12 import java.util.ArrayList;
13.13 import java.util.Collection;
13.14 import java.util.Collections;
13.15 import java.util.HashMap;
13.16 +import java.util.HashSet;
13.17 import java.util.LinkedHashSet;
13.18 import java.util.List;
13.19 -import java.util.Locale;
13.20 import java.util.Map;
13.21 import java.util.Set;
13.22 +import java.util.WeakHashMap;
13.23 import javax.annotation.processing.AbstractProcessor;
13.24 import javax.annotation.processing.Completion;
13.25 import javax.annotation.processing.Completions;
13.26 +import javax.annotation.processing.ProcessingEnvironment;
13.27 import javax.annotation.processing.Processor;
13.28 import javax.annotation.processing.RoundEnvironment;
13.29 import javax.annotation.processing.SupportedAnnotationTypes;
13.30 import javax.lang.model.element.AnnotationMirror;
13.31 +import javax.lang.model.element.AnnotationValue;
13.32 import javax.lang.model.element.Element;
13.33 import javax.lang.model.element.ElementKind;
13.34 import javax.lang.model.element.ExecutableElement;
13.35 @@ -44,13 +51,21 @@
13.36 import javax.lang.model.element.PackageElement;
13.37 import javax.lang.model.element.TypeElement;
13.38 import javax.lang.model.element.VariableElement;
13.39 +import javax.lang.model.type.ArrayType;
13.40 import javax.lang.model.type.MirroredTypeException;
13.41 +import javax.lang.model.type.TypeKind;
13.42 import javax.lang.model.type.TypeMirror;
13.43 +import javax.lang.model.util.Elements;
13.44 +import javax.lang.model.util.Types;
13.45 import javax.tools.Diagnostic;
13.46 import javax.tools.FileObject;
13.47 import javax.tools.StandardLocation;
13.48 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
13.49 +import org.apidesign.bck2brwsr.htmlpage.api.Model;
13.50 import org.apidesign.bck2brwsr.htmlpage.api.On;
13.51 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
13.52 +import org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange;
13.53 +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive;
13.54 import org.apidesign.bck2brwsr.htmlpage.api.Page;
13.55 import org.apidesign.bck2brwsr.htmlpage.api.Property;
13.56 import org.openide.util.lookup.ServiceProvider;
13.57 @@ -62,89 +77,70 @@
13.58 */
13.59 @ServiceProvider(service=Processor.class)
13.60 @SupportedAnnotationTypes({
13.61 + "org.apidesign.bck2brwsr.htmlpage.api.Model",
13.62 "org.apidesign.bck2brwsr.htmlpage.api.Page",
13.63 + "org.apidesign.bck2brwsr.htmlpage.api.OnFunction",
13.64 + "org.apidesign.bck2brwsr.htmlpage.api.OnReceive",
13.65 + "org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange",
13.66 + "org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty",
13.67 "org.apidesign.bck2brwsr.htmlpage.api.On"
13.68 })
13.69 public final class PageProcessor extends AbstractProcessor {
13.70 + private final Map<Element,String> models = new WeakHashMap<>();
13.71 + private final Map<Element,Prprt[]> verify = new WeakHashMap<>();
13.72 @Override
13.73 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
13.74 - for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) {
13.75 - Page p = e.getAnnotation(Page.class);
13.76 - if (p == null) {
13.77 - continue;
13.78 - }
13.79 - PackageElement pe = (PackageElement)e.getEnclosingElement();
13.80 - String pkg = pe.getQualifiedName().toString();
13.81 -
13.82 - ProcessPage pp;
13.83 - try {
13.84 - InputStream is = openStream(pkg, p.xhtml());
13.85 - pp = ProcessPage.readPage(is);
13.86 - is.close();
13.87 - } catch (IOException iOException) {
13.88 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't read " + p.xhtml(), e);
13.89 - return false;
13.90 - }
13.91 - Writer w;
13.92 - String className = p.className();
13.93 - if (className.isEmpty()) {
13.94 - int indx = p.xhtml().indexOf('.');
13.95 - className = p.xhtml().substring(0, indx);
13.96 - }
13.97 - try {
13.98 - FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
13.99 - w = new OutputStreamWriter(java.openOutputStream());
13.100 - try {
13.101 - w.append("package " + pkg + ";\n");
13.102 - w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
13.103 - w.append("final class ").append(className).append(" {\n");
13.104 - w.append(" private boolean locked;\n");
13.105 - if (!initializeOnClick(className, (TypeElement) e, w, pp)) {
13.106 - return false;
13.107 - }
13.108 - for (String id : pp.ids()) {
13.109 - String tag = pp.tagNameForId(id);
13.110 - String type = type(tag);
13.111 - w.append(" ").append("public final ").
13.112 - append(type).append(' ').append(cnstnt(id)).append(" = new ").
13.113 - append(type).append("(\"").append(id).append("\");\n");
13.114 - }
13.115 - List<String> propsGetSet = new ArrayList<String>();
13.116 - Map<String,Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
13.117 - generateComputedProperties(w, e.getEnclosedElements(), propsGetSet, propsDeps);
13.118 - generateProperties(w, p.properties(), propsGetSet, propsDeps);
13.119 - w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
13.120 - if (!propsGetSet.isEmpty()) {
13.121 - w.write("public " + className + " applyBindings() {\n");
13.122 - w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(");
13.123 - w.write(className + ".class, this, ");
13.124 - w.write("new String[] {\n");
13.125 - String sep = "";
13.126 - for (String n : propsGetSet) {
13.127 - w.write(sep);
13.128 - if (n == null) {
13.129 - w.write(" null");
13.130 - } else {
13.131 - w.write(" \"" + n + "\"");
13.132 - }
13.133 - sep = ",\n";
13.134 - }
13.135 - w.write("\n });\n return this;\n}\n");
13.136 -
13.137 - w.write("public void triggerEvent(Element e, OnEvent ev) {\n");
13.138 - w.write(" org.apidesign.bck2brwsr.htmlpage.Knockout.triggerEvent(e.getId(), ev.getElementPropertyName());\n");
13.139 - w.write("}\n");
13.140 - }
13.141 - w.append("}\n");
13.142 - } finally {
13.143 - w.close();
13.144 - }
13.145 - } catch (IOException ex) {
13.146 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e);
13.147 - return false;
13.148 + boolean ok = true;
13.149 + for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
13.150 + if (!processModel(e)) {
13.151 + ok = false;
13.152 }
13.153 }
13.154 - return true;
13.155 + for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) {
13.156 + if (!processPage(e)) {
13.157 + ok = false;
13.158 + }
13.159 + }
13.160 + if (roundEnv.processingOver()) {
13.161 + models.clear();
13.162 + for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
13.163 + TypeElement te = (TypeElement)entry.getKey();
13.164 + String fqn = processingEnv.getElementUtils().getBinaryName(te).toString();
13.165 + Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
13.166 + if (finalElem == null) {
13.167 + continue;
13.168 + }
13.169 + Prprt[] props;
13.170 + Model m = finalElem.getAnnotation(Model.class);
13.171 + if (m != null) {
13.172 + props = Prprt.wrap(processingEnv, finalElem, m.properties());
13.173 + } else {
13.174 + Page p = finalElem.getAnnotation(Page.class);
13.175 + props = Prprt.wrap(processingEnv, finalElem, p.properties());
13.176 + }
13.177 + for (Prprt p : props) {
13.178 + boolean[] isModel = { false };
13.179 + boolean[] isEnum = { false };
13.180 + boolean[] isPrimitive = { false };
13.181 + String t = checkType(p, isModel, isEnum, isPrimitive);
13.182 + if (isEnum[0]) {
13.183 + continue;
13.184 + }
13.185 + if (isPrimitive[0]) {
13.186 + continue;
13.187 + }
13.188 + if (isModel[0]) {
13.189 + continue;
13.190 + }
13.191 + if ("java.lang.String".equals(t)) {
13.192 + continue;
13.193 + }
13.194 + error("The type " + t + " should be defined by @Model annotation", entry.getKey());
13.195 + }
13.196 + }
13.197 + verify.clear();
13.198 + }
13.199 + return ok;
13.200 }
13.201
13.202 private InputStream openStream(String pkg, String name) throws IOException {
13.203 @@ -157,6 +153,236 @@
13.204 }
13.205 }
13.206
13.207 + private void error(String msg, Element e) {
13.208 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
13.209 + }
13.210 +
13.211 + private boolean processModel(Element e) {
13.212 + boolean ok = true;
13.213 + Model m = e.getAnnotation(Model.class);
13.214 + if (m == null) {
13.215 + return true;
13.216 + }
13.217 + String pkg = findPkgName(e);
13.218 + Writer w;
13.219 + String className = m.className();
13.220 + models.put(e, className);
13.221 + try {
13.222 + StringWriter body = new StringWriter();
13.223 + List<String> propsGetSet = new ArrayList<>();
13.224 + List<String> functions = new ArrayList<>();
13.225 + Map<String, Collection<String>> propsDeps = new HashMap<>();
13.226 + Map<String, Collection<String>> functionDeps = new HashMap<>();
13.227 + Prprt[] props = createProps(e, m.properties());
13.228 +
13.229 + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
13.230 + ok = false;
13.231 + }
13.232 + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
13.233 + ok = false;
13.234 + }
13.235 + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) {
13.236 + ok = false;
13.237 + }
13.238 + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
13.239 + ok = false;
13.240 + }
13.241 + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
13.242 + w = new OutputStreamWriter(java.openOutputStream());
13.243 + try {
13.244 + w.append("package " + pkg + ";\n");
13.245 + w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
13.246 + w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n");
13.247 + w.append("import org.apidesign.bck2brwsr.core.JavaScriptOnly;\n");
13.248 + w.append("final class ").append(className).append(" implements Cloneable {\n");
13.249 + w.append(" private boolean locked;\n");
13.250 + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
13.251 + w.append(body.toString());
13.252 + w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
13.253 + w.append(" public ").append(className).append("() {\n");
13.254 + w.append(" intKnckt();\n");
13.255 + w.append(" };\n");
13.256 + w.append(" private void intKnckt() {\n");
13.257 + w.append(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(this, ");
13.258 + writeStringArray(propsGetSet, w);
13.259 + w.append(", ");
13.260 + writeStringArray(functions, w);
13.261 + w.append(" );\n");
13.262 + w.append(" };\n");
13.263 + w.append(" ").append(className).append("(Object json) {\n");
13.264 + int values = 0;
13.265 + for (int i = 0; i < propsGetSet.size(); i += 4) {
13.266 + Prprt p = findPrprt(props, propsGetSet.get(i));
13.267 + if (p == null) {
13.268 + continue;
13.269 + }
13.270 + values++;
13.271 + }
13.272 + w.append(" Object[] ret = new Object[" + values + "];\n");
13.273 + w.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.extractJSON(json, new String[] {\n");
13.274 + for (int i = 0; i < propsGetSet.size(); i += 4) {
13.275 + Prprt p = findPrprt(props, propsGetSet.get(i));
13.276 + if (p == null) {
13.277 + continue;
13.278 + }
13.279 + w.append(" \"").append(propsGetSet.get(i)).append("\",\n");
13.280 + }
13.281 + w.append(" }, ret);\n");
13.282 + for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 4) {
13.283 + final String pn = propsGetSet.get(i);
13.284 + Prprt p = findPrprt(props, pn);
13.285 + if (p == null) {
13.286 + continue;
13.287 + }
13.288 + boolean[] isModel = { false };
13.289 + boolean[] isEnum = { false };
13.290 + boolean isPrimitive[] = { false };
13.291 + String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
13.292 + if (p.array()) {
13.293 + w.append("if (ret[" + cnt + "] instanceof Object[]) {\n");
13.294 + w.append(" for (Object e : ((Object[])ret[" + cnt + "])) {\n");
13.295 + if (isModel[0]) {
13.296 + w.append(" this.prop_").append(pn).append(".add(new ");
13.297 + w.append(type).append("(e));\n");
13.298 + } else if (isEnum[0]) {
13.299 + w.append(" this.prop_").append(pn);
13.300 + w.append(".add(e == null ? null : ");
13.301 + w.append(type).append(".valueOf((String)e));\n");
13.302 + } else {
13.303 + if (isPrimitive(type)) {
13.304 + w.append(" this.prop_").append(pn).append(".add(((Number)e).");
13.305 + w.append(type).append("Value());\n");
13.306 + } else {
13.307 + w.append(" this.prop_").append(pn).append(".add((");
13.308 + w.append(type).append(")e);\n");
13.309 + }
13.310 + }
13.311 + w.append(" }\n");
13.312 + w.append("}\n");
13.313 + } else {
13.314 + if (isEnum[0]) {
13.315 + w.append(" this.prop_").append(pn);
13.316 + w.append(" = ret[" + cnt + "] == null ? null : ");
13.317 + w.append(type).append(".valueOf((String)ret[" + cnt + "]);\n");
13.318 + } else if (isPrimitive(type)) {
13.319 + w.append(" this.prop_").append(pn);
13.320 + w.append(" = ((Number)").append("ret[" + cnt + "]).");
13.321 + w.append(type).append("Value();\n");
13.322 + } else {
13.323 + w.append(" this.prop_").append(pn);
13.324 + w.append(" = (").append(type).append(')');
13.325 + w.append("ret[" + cnt + "];\n");
13.326 + }
13.327 + }
13.328 + cnt++;
13.329 + }
13.330 + w.append(" intKnckt();\n");
13.331 + w.append(" };\n");
13.332 + writeToString(props, w);
13.333 + writeClone(className, props, w);
13.334 + w.append("}\n");
13.335 + } finally {
13.336 + w.close();
13.337 + }
13.338 + } catch (IOException ex) {
13.339 + error("Can't create " + className + ".java", e);
13.340 + return false;
13.341 + }
13.342 + return ok;
13.343 + }
13.344 +
13.345 + private boolean processPage(Element e) {
13.346 + boolean ok = true;
13.347 + Page p = e.getAnnotation(Page.class);
13.348 + if (p == null) {
13.349 + return true;
13.350 + }
13.351 + String pkg = findPkgName(e);
13.352 +
13.353 + ProcessPage pp;
13.354 + try (InputStream is = openStream(pkg, p.xhtml())) {
13.355 + pp = ProcessPage.readPage(is);
13.356 + is.close();
13.357 + } catch (IOException iOException) {
13.358 + error("Can't read " + p.xhtml() + " as " + iOException.getMessage(), e);
13.359 + ok = false;
13.360 + pp = null;
13.361 + }
13.362 + Writer w;
13.363 + String className = p.className();
13.364 + if (className.isEmpty()) {
13.365 + int indx = p.xhtml().indexOf('.');
13.366 + className = p.xhtml().substring(0, indx);
13.367 + }
13.368 + try {
13.369 + StringWriter body = new StringWriter();
13.370 + List<String> propsGetSet = new ArrayList<>();
13.371 + List<String> functions = new ArrayList<>();
13.372 + Map<String, Collection<String>> propsDeps = new HashMap<>();
13.373 + Map<String, Collection<String>> functionDeps = new HashMap<>();
13.374 +
13.375 + Prprt[] props = createProps(e, p.properties());
13.376 + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
13.377 + ok = false;
13.378 + }
13.379 + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
13.380 + ok = false;
13.381 + }
13.382 + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) {
13.383 + ok = false;
13.384 + }
13.385 + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
13.386 + ok = false;
13.387 + }
13.388 + if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) {
13.389 + ok = false;
13.390 + }
13.391 +
13.392 + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
13.393 + w = new OutputStreamWriter(java.openOutputStream());
13.394 + try {
13.395 + w.append("package " + pkg + ";\n");
13.396 + w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
13.397 + w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n");
13.398 + w.append("final class ").append(className).append(" {\n");
13.399 + w.append(" private boolean locked;\n");
13.400 + if (!initializeOnClick(className, (TypeElement) e, w, pp)) {
13.401 + ok = false;
13.402 + } else {
13.403 + if (pp != null) for (String id : pp.ids()) {
13.404 + String tag = pp.tagNameForId(id);
13.405 + String type = type(tag);
13.406 + w.append(" ").append("public final ").
13.407 + append(type).append(' ').append(cnstnt(id)).append(" = new ").
13.408 + append(type).append("(\"").append(id).append("\");\n");
13.409 + }
13.410 + }
13.411 + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
13.412 + w.append(body.toString());
13.413 + if (!propsGetSet.isEmpty()) {
13.414 + w.write("public " + className + " applyBindings() {\n");
13.415 + w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(");
13.416 + w.write(className + ".class, this, ");
13.417 + writeStringArray(propsGetSet, w);
13.418 + w.append(", ");
13.419 + writeStringArray(functions, w);
13.420 + w.write(");\n return this;\n}\n");
13.421 +
13.422 + w.write("public void triggerEvent(Element e, OnEvent ev) {\n");
13.423 + w.write(" org.apidesign.bck2brwsr.htmlpage.Knockout.triggerEvent(e.getId(), ev.getElementPropertyName());\n");
13.424 + w.write("}\n");
13.425 + }
13.426 + w.append("}\n");
13.427 + } finally {
13.428 + w.close();
13.429 + }
13.430 + } catch (IOException ex) {
13.431 + error("Can't create " + className + ".java", e);
13.432 + return false;
13.433 + }
13.434 + return ok;
13.435 + }
13.436 +
13.437 private static String type(String tag) {
13.438 if (tag.equals("title")) {
13.439 return "Title";
13.440 @@ -177,12 +403,13 @@
13.441 }
13.442
13.443 private static String cnstnt(String id) {
13.444 - return id.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_');
13.445 + return id.replace('.', '_').replace('-', '_');
13.446 }
13.447
13.448 private boolean initializeOnClick(
13.449 String className, TypeElement type, Writer w, ProcessPage pp
13.450 ) throws IOException {
13.451 + boolean ok = true;
13.452 TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
13.453 { //for (Element clazz : pe.getEnclosedElements()) {
13.454 // if (clazz.getKind() != ElementKind.CLASS) {
13.455 @@ -195,46 +422,27 @@
13.456 On oc = method.getAnnotation(On.class);
13.457 if (oc != null) {
13.458 for (String id : oc.id()) {
13.459 + if (pp == null) {
13.460 + error("id = " + id + " not found in HTML page.", method);
13.461 + ok = false;
13.462 + continue;
13.463 + }
13.464 if (pp.tagNameForId(id) == null) {
13.465 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method);
13.466 - return false;
13.467 + error("id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method);
13.468 + ok = false;
13.469 + continue;
13.470 }
13.471 ExecutableElement ee = (ExecutableElement)method;
13.472 - StringBuilder params = new StringBuilder();
13.473 - {
13.474 - boolean first = true;
13.475 - for (VariableElement ve : ee.getParameters()) {
13.476 - if (!first) {
13.477 - params.append(", ");
13.478 - }
13.479 - first = false;
13.480 - if (ve.asType() == stringType) {
13.481 - params.append('"').append(id).append('"');
13.482 - continue;
13.483 - }
13.484 - String rn = ve.asType().toString();
13.485 - int last = rn.lastIndexOf('.');
13.486 - if (last >= 0) {
13.487 - rn = rn.substring(last + 1);
13.488 - }
13.489 - if (rn.equals(className)) {
13.490 - params.append(className).append(".this");
13.491 - continue;
13.492 - }
13.493 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
13.494 - "@On method can only accept String or " + className + " arguments",
13.495 - ee
13.496 - );
13.497 - return false;
13.498 - }
13.499 - }
13.500 + CharSequence params = wrapParams(ee, id, className, "ev", null);
13.501 if (!ee.getModifiers().contains(Modifier.STATIC)) {
13.502 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee);
13.503 - return false;
13.504 + error("@On method has to be static", ee);
13.505 + ok = false;
13.506 + continue;
13.507 }
13.508 if (ee.getModifiers().contains(Modifier.PRIVATE)) {
13.509 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method can't be private", ee);
13.510 - return false;
13.511 + error("@On method can't be private", ee);
13.512 + ok = false;
13.513 + continue;
13.514 }
13.515 w.append(" OnEvent." + oc.event()).append(".of(").append(cnstnt(id)).
13.516 append(").perform(new OnDispatch(" + dispatchCnt + "));\n");
13.517 @@ -252,10 +460,10 @@
13.518 }
13.519 w.append(" }\n");
13.520 if (dispatchCnt > 0) {
13.521 - w.append("class OnDispatch implements Runnable {\n");
13.522 + w.append("class OnDispatch implements OnHandler {\n");
13.523 w.append(" private final int dispatch;\n");
13.524 w.append(" OnDispatch(int d) { dispatch = d; }\n");
13.525 - w.append(" public void run() {\n");
13.526 + w.append(" public void onEvent(Object ev) {\n");
13.527 w.append(" switch (dispatch) {\n");
13.528 w.append(dispatch);
13.529 w.append(" }\n");
13.530 @@ -265,7 +473,7 @@
13.531
13.532
13.533 }
13.534 - return true;
13.535 + return ok;
13.536 }
13.537
13.538 @Override
13.539 @@ -279,8 +487,7 @@
13.540
13.541 Element cls = findClass(element);
13.542 Page p = cls.getAnnotation(Page.class);
13.543 - PackageElement pe = (PackageElement) cls.getEnclosingElement();
13.544 - String pkg = pe.getQualifiedName().toString();
13.545 + String pkg = findPkgName(cls);
13.546 ProcessPage pp;
13.547 try {
13.548 InputStream is = openStream(pkg, p.xhtml());
13.549 @@ -290,7 +497,7 @@
13.550 return Collections.emptyList();
13.551 }
13.552
13.553 - List<Completion> cc = new ArrayList<Completion>();
13.554 + List<Completion> cc = new ArrayList<>();
13.555 userText = userText.substring(1);
13.556 for (String id : pp.ids()) {
13.557 if (id.startsWith(userText)) {
13.558 @@ -311,44 +518,89 @@
13.559 return e.getEnclosingElement();
13.560 }
13.561
13.562 - private static void generateProperties(
13.563 - Writer w, Property[] properties, Collection<String> props,
13.564 - Map<String,Collection<String>> deps
13.565 + private boolean generateProperties(
13.566 + Element where,
13.567 + Writer w, Prprt[] properties,
13.568 + Collection<String> props,
13.569 + Map<String,Collection<String>> deps,
13.570 + Map<String,Collection<String>> functionDeps
13.571 ) throws IOException {
13.572 - for (Property p : properties) {
13.573 - final String tn = typeName(p);
13.574 - String[] gs = toGetSet(p.name(), tn);
13.575 + boolean ok = true;
13.576 + for (Prprt p : properties) {
13.577 + final String tn;
13.578 + tn = typeName(where, p);
13.579 + String[] gs = toGetSet(p.name(), tn, p.array());
13.580
13.581 - w.write("private " + tn + " prop_" + p.name() + ";\n");
13.582 - w.write("public " + tn + " " + gs[0] + "() {\n");
13.583 - w.write(" if (locked) throw new IllegalStateException();\n");
13.584 - w.write(" return prop_" + p.name() + ";\n");
13.585 - w.write("}\n");
13.586 - w.write("public void " + gs[1] + "(" + tn + " v) {\n");
13.587 - w.write(" if (locked) throw new IllegalStateException();\n");
13.588 - w.write(" prop_" + p.name() + " = v;\n");
13.589 - w.write(" if (ko != null) {\n");
13.590 - w.write(" ko.valueHasMutated(\"" + p.name() + "\");\n");
13.591 - final Collection<String> dependants = deps.get(p.name());
13.592 - if (dependants != null) {
13.593 - for (String depProp : dependants) {
13.594 - w.write(" ko.valueHasMutated(\"" + depProp + "\");\n");
13.595 + if (p.array()) {
13.596 + w.write("private KOList<" + tn + "> prop_" + p.name() + " = new KOList<" + tn + ">(\""
13.597 + + p.name() + "\"");
13.598 + Collection<String> dependants = deps.get(p.name());
13.599 + if (dependants != null) {
13.600 + for (String depProp : dependants) {
13.601 + w.write(", ");
13.602 + w.write('\"');
13.603 + w.write(depProp);
13.604 + w.write('\"');
13.605 + }
13.606 }
13.607 + w.write(")");
13.608 +
13.609 + dependants = functionDeps.get(p.name());
13.610 + if (dependants != null) {
13.611 + w.write(".onChange(new Runnable() { public void run() {\n");
13.612 + for (String call : dependants) {
13.613 + w.append(call);
13.614 + }
13.615 + w.write("}})");
13.616 + }
13.617 + w.write(";\n");
13.618 +
13.619 + w.write("public java.util.List<" + tn + "> " + gs[0] + "() {\n");
13.620 + w.write(" if (locked) throw new IllegalStateException();\n");
13.621 + w.write(" prop_" + p.name() + ".assign(ko);\n");
13.622 + w.write(" return prop_" + p.name() + ";\n");
13.623 + w.write("}\n");
13.624 + } else {
13.625 + w.write("private " + tn + " prop_" + p.name() + ";\n");
13.626 + w.write("public " + tn + " " + gs[0] + "() {\n");
13.627 + w.write(" if (locked) throw new IllegalStateException();\n");
13.628 + w.write(" return prop_" + p.name() + ";\n");
13.629 + w.write("}\n");
13.630 + w.write("public void " + gs[1] + "(" + tn + " v) {\n");
13.631 + w.write(" if (locked) throw new IllegalStateException();\n");
13.632 + w.write(" prop_" + p.name() + " = v;\n");
13.633 + w.write(" if (ko != null) {\n");
13.634 + w.write(" ko.valueHasMutated(\"" + p.name() + "\");\n");
13.635 + Collection<String> dependants = deps.get(p.name());
13.636 + if (dependants != null) {
13.637 + for (String depProp : dependants) {
13.638 + w.write(" ko.valueHasMutated(\"" + depProp + "\");\n");
13.639 + }
13.640 + }
13.641 + w.write(" }\n");
13.642 + dependants = functionDeps.get(p.name());
13.643 + if (dependants != null) {
13.644 + for (String call : dependants) {
13.645 + w.append(call);
13.646 + }
13.647 + }
13.648 + w.write("}\n");
13.649 }
13.650 - w.write(" }\n");
13.651 - w.write("}\n");
13.652
13.653 props.add(p.name());
13.654 props.add(gs[2]);
13.655 props.add(gs[3]);
13.656 props.add(gs[0]);
13.657 }
13.658 + return ok;
13.659 }
13.660
13.661 private boolean generateComputedProperties(
13.662 - Writer w, Collection<? extends Element> arr, Collection<String> props,
13.663 + Writer w, Prprt[] fixedProps,
13.664 + Collection<? extends Element> arr, Collection<String> props,
13.665 Map<String,Collection<String>> deps
13.666 ) throws IOException {
13.667 + boolean ok = true;
13.668 for (Element e : arr) {
13.669 if (e.getKind() != ElementKind.METHOD) {
13.670 continue;
13.671 @@ -357,30 +609,43 @@
13.672 continue;
13.673 }
13.674 ExecutableElement ee = (ExecutableElement)e;
13.675 - final String tn = ee.getReturnType().toString();
13.676 + final TypeMirror rt = ee.getReturnType();
13.677 + final Types tu = processingEnv.getTypeUtils();
13.678 + TypeMirror ert = tu.erasure(rt);
13.679 + String tn = fqn(ert, ee);
13.680 + boolean array = false;
13.681 + if (tn.equals("java.util.List")) {
13.682 + array = true;
13.683 + }
13.684 +
13.685 final String sn = ee.getSimpleName().toString();
13.686 - String[] gs = toGetSet(sn, tn);
13.687 + String[] gs = toGetSet(sn, tn, array);
13.688
13.689 w.write("public " + tn + " " + gs[0] + "() {\n");
13.690 w.write(" if (locked) throw new IllegalStateException();\n");
13.691 int arg = 0;
13.692 for (VariableElement pe : ee.getParameters()) {
13.693 final String dn = pe.getSimpleName().toString();
13.694 - final String dt = pe.asType().toString();
13.695 - String[] call = toGetSet(dn, dt);
13.696 +
13.697 + if (!verifyPropName(pe, dn, fixedProps)) {
13.698 + ok = false;
13.699 + }
13.700 +
13.701 + final String dt = fqn(pe.asType(), ee);
13.702 + String[] call = toGetSet(dn, dt, false);
13.703 w.write(" " + dt + " arg" + (++arg) + " = ");
13.704 w.write(call[0] + "();\n");
13.705
13.706 Collection<String> depends = deps.get(dn);
13.707 if (depends == null) {
13.708 - depends = new LinkedHashSet<String>();
13.709 + depends = new LinkedHashSet<>();
13.710 deps.put(dn, depends);
13.711 }
13.712 depends.add(sn);
13.713 }
13.714 w.write(" try {\n");
13.715 w.write(" locked = true;\n");
13.716 - w.write(" return " + e.getEnclosingElement().getSimpleName() + '.' + e.getSimpleName() + "(");
13.717 + w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
13.718 String sep = "";
13.719 for (int i = 1; i <= arg; i++) {
13.720 w.write(sep);
13.721 @@ -392,17 +657,17 @@
13.722 w.write(" locked = false;\n");
13.723 w.write(" }\n");
13.724 w.write("}\n");
13.725 -
13.726 +
13.727 props.add(e.getSimpleName().toString());
13.728 props.add(gs[2]);
13.729 props.add(null);
13.730 props.add(gs[0]);
13.731 }
13.732
13.733 - return true;
13.734 + return ok;
13.735 }
13.736
13.737 - private static String[] toGetSet(String name, String type) {
13.738 + private static String[] toGetSet(String name, String type, boolean array) {
13.739 String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
13.740 String bck2brwsrType = "L" + type.replace('.', '_') + "_2";
13.741 if ("int".equals(type)) {
13.742 @@ -417,6 +682,14 @@
13.743 bck2brwsrType = "Z";
13.744 }
13.745 final String nu = n.replace('.', '_');
13.746 + if (array) {
13.747 + return new String[] {
13.748 + "get" + n,
13.749 + null,
13.750 + "get" + nu + "__Ljava_util_List_2",
13.751 + null
13.752 + };
13.753 + }
13.754 return new String[]{
13.755 pref + n,
13.756 "set" + n,
13.757 @@ -425,11 +698,702 @@
13.758 };
13.759 }
13.760
13.761 - private static String typeName(Property p) {
13.762 - try {
13.763 - return p.type().getName();
13.764 - } catch (MirroredTypeException ex) {
13.765 - return ex.getTypeMirror().toString();
13.766 + private String typeName(Element where, Prprt p) {
13.767 + String ret;
13.768 + boolean[] isModel = { false };
13.769 + boolean[] isEnum = { false };
13.770 + boolean isPrimitive[] = { false };
13.771 + ret = checkType(p, isModel, isEnum, isPrimitive);
13.772 + if (p.array()) {
13.773 + String bt = findBoxedType(ret);
13.774 + if (bt != null) {
13.775 + return bt;
13.776 + }
13.777 + }
13.778 + return ret;
13.779 + }
13.780 +
13.781 + private static String findBoxedType(String ret) {
13.782 + if (ret.equals("boolean")) {
13.783 + return Boolean.class.getName();
13.784 + }
13.785 + if (ret.equals("byte")) {
13.786 + return Byte.class.getName();
13.787 + }
13.788 + if (ret.equals("short")) {
13.789 + return Short.class.getName();
13.790 + }
13.791 + if (ret.equals("char")) {
13.792 + return Character.class.getName();
13.793 + }
13.794 + if (ret.equals("int")) {
13.795 + return Integer.class.getName();
13.796 + }
13.797 + if (ret.equals("long")) {
13.798 + return Long.class.getName();
13.799 + }
13.800 + if (ret.equals("float")) {
13.801 + return Float.class.getName();
13.802 + }
13.803 + if (ret.equals("double")) {
13.804 + return Double.class.getName();
13.805 + }
13.806 + return null;
13.807 + }
13.808 +
13.809 + private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) {
13.810 + StringBuilder sb = new StringBuilder();
13.811 + String sep = "";
13.812 + for (Prprt Prprt : existingProps) {
13.813 + if (Prprt.name().equals(propName)) {
13.814 + return true;
13.815 + }
13.816 + sb.append(sep);
13.817 + sb.append('"');
13.818 + sb.append(Prprt.name());
13.819 + sb.append('"');
13.820 + sep = ", ";
13.821 + }
13.822 + error(
13.823 + propName + " is not one of known properties: " + sb
13.824 + , e
13.825 + );
13.826 + return false;
13.827 + }
13.828 +
13.829 + private static String findPkgName(Element e) {
13.830 + for (;;) {
13.831 + if (e.getKind() == ElementKind.PACKAGE) {
13.832 + return ((PackageElement)e).getQualifiedName().toString();
13.833 + }
13.834 + e = e.getEnclosingElement();
13.835 }
13.836 }
13.837 +
13.838 + private boolean generateFunctions(
13.839 + Element clazz, StringWriter body, String className,
13.840 + List<? extends Element> enclosedElements, List<String> functions
13.841 + ) {
13.842 + for (Element m : enclosedElements) {
13.843 + if (m.getKind() != ElementKind.METHOD) {
13.844 + continue;
13.845 + }
13.846 + ExecutableElement e = (ExecutableElement)m;
13.847 + OnFunction onF = e.getAnnotation(OnFunction.class);
13.848 + if (onF == null) {
13.849 + continue;
13.850 + }
13.851 + if (!e.getModifiers().contains(Modifier.STATIC)) {
13.852 + error("@OnFunction method needs to be static", e);
13.853 + return false;
13.854 + }
13.855 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
13.856 + error("@OnFunction method cannot be private", e);
13.857 + return false;
13.858 + }
13.859 + if (e.getReturnType().getKind() != TypeKind.VOID) {
13.860 + error("@OnFunction method should return void", e);
13.861 + return false;
13.862 + }
13.863 + String n = e.getSimpleName().toString();
13.864 + body.append("private void ").append(n).append("(Object data, Object ev) {\n");
13.865 + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
13.866 + body.append(wrapParams(e, null, className, "ev", "data"));
13.867 + body.append(");\n");
13.868 + body.append("}\n");
13.869 +
13.870 + functions.add(n);
13.871 + functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2");
13.872 + }
13.873 + return true;
13.874 + }
13.875 +
13.876 + private boolean generateOnChange(Element clazz, Map<String,Collection<String>> propDeps,
13.877 + Prprt[] properties, String className,
13.878 + Map<String, Collection<String>> functionDeps
13.879 + ) {
13.880 + for (Element m : clazz.getEnclosedElements()) {
13.881 + if (m.getKind() != ElementKind.METHOD) {
13.882 + continue;
13.883 + }
13.884 + ExecutableElement e = (ExecutableElement) m;
13.885 + OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class);
13.886 + if (onPC == null) {
13.887 + continue;
13.888 + }
13.889 + for (String pn : onPC.value()) {
13.890 + if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) {
13.891 + error("No Prprt named '" + pn + "' in the model", clazz);
13.892 + return false;
13.893 + }
13.894 + }
13.895 + if (!e.getModifiers().contains(Modifier.STATIC)) {
13.896 + error("@OnPrprtChange method needs to be static", e);
13.897 + return false;
13.898 + }
13.899 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
13.900 + error("@OnPrprtChange method cannot be private", e);
13.901 + return false;
13.902 + }
13.903 + if (e.getReturnType().getKind() != TypeKind.VOID) {
13.904 + error("@OnPrprtChange method should return void", e);
13.905 + return false;
13.906 + }
13.907 + String n = e.getSimpleName().toString();
13.908 +
13.909 +
13.910 + for (String pn : onPC.value()) {
13.911 + StringBuilder call = new StringBuilder();
13.912 + call.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
13.913 + call.append(wrapPropName(e, className, "name", pn));
13.914 + call.append(");\n");
13.915 +
13.916 + Collection<String> change = functionDeps.get(pn);
13.917 + if (change == null) {
13.918 + change = new ArrayList<>();
13.919 + functionDeps.put(pn, change);
13.920 + }
13.921 + change.add(call.toString());
13.922 + for (String dpn : findDerivedFrom(propDeps, pn)) {
13.923 + change = functionDeps.get(dpn);
13.924 + if (change == null) {
13.925 + change = new ArrayList<>();
13.926 + functionDeps.put(dpn, change);
13.927 + }
13.928 + change.add(call.toString());
13.929 + }
13.930 + }
13.931 + }
13.932 + return true;
13.933 + }
13.934 +
13.935 + private boolean generateReceive(
13.936 + Element clazz, StringWriter body, String className,
13.937 + List<? extends Element> enclosedElements, List<String> functions
13.938 + ) {
13.939 + for (Element m : enclosedElements) {
13.940 + if (m.getKind() != ElementKind.METHOD) {
13.941 + continue;
13.942 + }
13.943 + ExecutableElement e = (ExecutableElement)m;
13.944 + OnReceive onR = e.getAnnotation(OnReceive.class);
13.945 + if (onR == null) {
13.946 + continue;
13.947 + }
13.948 + if (!e.getModifiers().contains(Modifier.STATIC)) {
13.949 + error("@OnReceive method needs to be static", e);
13.950 + return false;
13.951 + }
13.952 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
13.953 + error("@OnReceive method cannot be private", e);
13.954 + return false;
13.955 + }
13.956 + if (e.getReturnType().getKind() != TypeKind.VOID) {
13.957 + error("@OnReceive method should return void", e);
13.958 + return false;
13.959 + }
13.960 + String modelClass = null;
13.961 + boolean expectsList = false;
13.962 + List<String> args = new ArrayList<>();
13.963 + {
13.964 + for (VariableElement ve : e.getParameters()) {
13.965 + TypeMirror modelType = null;
13.966 + if (ve.asType().toString().equals(className)) {
13.967 + args.add(className + ".this");
13.968 + } else if (isModel(ve.asType())) {
13.969 + modelType = ve.asType();
13.970 + } else if (ve.asType().getKind() == TypeKind.ARRAY) {
13.971 + modelType = ((ArrayType)ve.asType()).getComponentType();
13.972 + expectsList = true;
13.973 + }
13.974 + if (modelType != null) {
13.975 + if (modelClass != null) {
13.976 + error("There can be only one model class among arguments", e);
13.977 + } else {
13.978 + modelClass = modelType.toString();
13.979 + if (expectsList) {
13.980 + args.add("arr");
13.981 + } else {
13.982 + args.add("arr[0]");
13.983 + }
13.984 + }
13.985 + }
13.986 + }
13.987 + }
13.988 + if (modelClass == null) {
13.989 + error("The method needs to have one @Model class as parameter", e);
13.990 + }
13.991 + String n = e.getSimpleName().toString();
13.992 + body.append("public void ").append(n).append("(");
13.993 + StringBuilder assembleURL = new StringBuilder();
13.994 + String jsonpVarName = null;
13.995 + {
13.996 + String sep = "";
13.997 + boolean skipJSONP = onR.jsonp().isEmpty();
13.998 + for (String p : findParamNames(e, onR.url(), assembleURL)) {
13.999 + if (!skipJSONP && p.equals(onR.jsonp())) {
13.1000 + skipJSONP = true;
13.1001 + jsonpVarName = p;
13.1002 + continue;
13.1003 + }
13.1004 + body.append(sep);
13.1005 + body.append("String ").append(p);
13.1006 + sep = ", ";
13.1007 + }
13.1008 + if (!skipJSONP) {
13.1009 + error(
13.1010 + "Name of jsonp attribute ('" + onR.jsonp() +
13.1011 + "') is not used in url attribute '" + onR.url() + "'", e
13.1012 + );
13.1013 + }
13.1014 + }
13.1015 + body.append(") {\n");
13.1016 + body.append(" final Object[] result = { null };\n");
13.1017 + body.append(
13.1018 + " class ProcessResult implements Runnable {\n" +
13.1019 + " @Override\n" +
13.1020 + " public void run() {\n" +
13.1021 + " Object value = result[0];\n");
13.1022 + body.append(
13.1023 + " " + modelClass + "[] arr;\n");
13.1024 + body.append(
13.1025 + " if (value instanceof Object[]) {\n" +
13.1026 + " Object[] data = ((Object[])value);\n" +
13.1027 + " arr = new " + modelClass + "[data.length];\n" +
13.1028 + " for (int i = 0; i < data.length; i++) {\n" +
13.1029 + " arr[i] = new " + modelClass + "(data[i]);\n" +
13.1030 + " }\n" +
13.1031 + " } else {\n" +
13.1032 + " arr = new " + modelClass + "[1];\n" +
13.1033 + " arr[0] = new " + modelClass + "(value);\n" +
13.1034 + " }\n"
13.1035 + );
13.1036 + {
13.1037 + body.append(clazz.getSimpleName()).append(".").append(n).append("(");
13.1038 + String sep = "";
13.1039 + for (String arg : args) {
13.1040 + body.append(sep);
13.1041 + body.append(arg);
13.1042 + sep = ", ";
13.1043 + }
13.1044 + body.append(");\n");
13.1045 + }
13.1046 + body.append(
13.1047 + " }\n" +
13.1048 + " }\n"
13.1049 + );
13.1050 + body.append(" ProcessResult pr = new ProcessResult();\n");
13.1051 + if (jsonpVarName != null) {
13.1052 + body.append(" String ").append(jsonpVarName).
13.1053 + append(" = org.apidesign.bck2brwsr.htmlpage.ConvertTypes.createJSONP(result, pr);\n");
13.1054 + }
13.1055 + body.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.loadJSON(\n ");
13.1056 + body.append(assembleURL);
13.1057 + body.append(", result, pr, ").append(jsonpVarName).append("\n );\n");
13.1058 +// body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
13.1059 +// body.append(wrapParams(e, null, className, "ev", "data"));
13.1060 +// body.append(");\n");
13.1061 + body.append("}\n");
13.1062 + }
13.1063 + return true;
13.1064 + }
13.1065 +
13.1066 + private CharSequence wrapParams(
13.1067 + ExecutableElement ee, String id, String className, String evName, String dataName
13.1068 + ) {
13.1069 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
13.1070 + StringBuilder params = new StringBuilder();
13.1071 + boolean first = true;
13.1072 + for (VariableElement ve : ee.getParameters()) {
13.1073 + if (!first) {
13.1074 + params.append(", ");
13.1075 + }
13.1076 + first = false;
13.1077 + String toCall = null;
13.1078 + if (ve.asType() == stringType) {
13.1079 + if (ve.getSimpleName().contentEquals("id")) {
13.1080 + params.append('"').append(id).append('"');
13.1081 + continue;
13.1082 + }
13.1083 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString(";
13.1084 + }
13.1085 + if (ve.asType().getKind() == TypeKind.DOUBLE) {
13.1086 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble(";
13.1087 + }
13.1088 + if (ve.asType().getKind() == TypeKind.INT) {
13.1089 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt(";
13.1090 + }
13.1091 + if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
13.1092 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toModel(" + ve.asType() + ".class, ";
13.1093 + }
13.1094 +
13.1095 + if (toCall != null) {
13.1096 + params.append(toCall);
13.1097 + if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
13.1098 + params.append(dataName);
13.1099 + params.append(", null");
13.1100 + } else {
13.1101 + if (evName == null) {
13.1102 + final StringBuilder sb = new StringBuilder();
13.1103 + sb.append("Unexpected string parameter name.");
13.1104 + if (dataName != null) {
13.1105 + sb.append(" Try \"").append(dataName).append("\"");
13.1106 + }
13.1107 + error(sb.toString(), ee);
13.1108 + }
13.1109 + params.append(evName);
13.1110 + params.append(", \"");
13.1111 + params.append(ve.getSimpleName().toString());
13.1112 + params.append("\"");
13.1113 + }
13.1114 + params.append(")");
13.1115 + continue;
13.1116 + }
13.1117 + String rn = fqn(ve.asType(), ee);
13.1118 + int last = rn.lastIndexOf('.');
13.1119 + if (last >= 0) {
13.1120 + rn = rn.substring(last + 1);
13.1121 + }
13.1122 + if (rn.equals(className)) {
13.1123 + params.append(className).append(".this");
13.1124 + continue;
13.1125 + }
13.1126 + error(
13.1127 + "@On method can only accept String named 'id' or " + className + " arguments",
13.1128 + ee
13.1129 + );
13.1130 + }
13.1131 + return params;
13.1132 + }
13.1133 +
13.1134 +
13.1135 + private CharSequence wrapPropName(
13.1136 + ExecutableElement ee, String className, String propName, String propValue
13.1137 + ) {
13.1138 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
13.1139 + StringBuilder params = new StringBuilder();
13.1140 + boolean first = true;
13.1141 + for (VariableElement ve : ee.getParameters()) {
13.1142 + if (!first) {
13.1143 + params.append(", ");
13.1144 + }
13.1145 + first = false;
13.1146 + if (ve.asType() == stringType) {
13.1147 + if (propName != null && ve.getSimpleName().contentEquals(propName)) {
13.1148 + params.append('"').append(propValue).append('"');
13.1149 + } else {
13.1150 + error("Unexpected string parameter name. Try \"" + propName + "\".", ee);
13.1151 + }
13.1152 + continue;
13.1153 + }
13.1154 + String rn = fqn(ve.asType(), ee);
13.1155 + int last = rn.lastIndexOf('.');
13.1156 + if (last >= 0) {
13.1157 + rn = rn.substring(last + 1);
13.1158 + }
13.1159 + if (rn.equals(className)) {
13.1160 + params.append(className).append(".this");
13.1161 + continue;
13.1162 + }
13.1163 + error(
13.1164 + "@OnPrprtChange method can only accept String or " + className + " arguments",
13.1165 + ee);
13.1166 + }
13.1167 + return params;
13.1168 + }
13.1169 +
13.1170 + private boolean isModel(TypeMirror tm) {
13.1171 + final Element e = processingEnv.getTypeUtils().asElement(tm);
13.1172 + if (e == null) {
13.1173 + return false;
13.1174 + }
13.1175 + for (Element ch : e.getEnclosedElements()) {
13.1176 + if (ch.getKind() == ElementKind.METHOD) {
13.1177 + ExecutableElement ee = (ExecutableElement)ch;
13.1178 + if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
13.1179 + return true;
13.1180 + }
13.1181 + }
13.1182 + }
13.1183 + return models.values().contains(e.getSimpleName().toString());
13.1184 + }
13.1185 +
13.1186 + private void writeStringArray(List<String> strings, Writer w) throws IOException {
13.1187 + w.write("new String[] {\n");
13.1188 + String sep = "";
13.1189 + for (String n : strings) {
13.1190 + w.write(sep);
13.1191 + if (n == null) {
13.1192 + w.write(" null");
13.1193 + } else {
13.1194 + w.write(" \"" + n + "\"");
13.1195 + }
13.1196 + sep = ",\n";
13.1197 + }
13.1198 + w.write("\n }");
13.1199 + }
13.1200 +
13.1201 + private void writeToString(Prprt[] props, Writer w) throws IOException {
13.1202 + w.write(" public String toString() {\n");
13.1203 + w.write(" StringBuilder sb = new StringBuilder();\n");
13.1204 + w.write(" sb.append('{');\n");
13.1205 + String sep = "";
13.1206 + for (Prprt p : props) {
13.1207 + w.write(sep);
13.1208 + w.append(" sb.append('\"').append(\"" + p.name() + "\")");
13.1209 + w.append(".append('\"').append(\":\");\n");
13.1210 + w.append(" sb.append(org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toJSON(prop_");
13.1211 + w.append(p.name()).append("));\n");
13.1212 + sep = " sb.append(',');\n";
13.1213 + }
13.1214 + w.write(" sb.append('}');\n");
13.1215 + w.write(" return sb.toString();\n");
13.1216 + w.write(" }\n");
13.1217 + }
13.1218 + private void writeClone(String className, Prprt[] props, Writer w) throws IOException {
13.1219 + w.write(" public " + className + " clone() {\n");
13.1220 + w.write(" " + className + " ret = new " + className + "();\n");
13.1221 + for (Prprt p : props) {
13.1222 + if (!p.array()) {
13.1223 + boolean isModel[] = { false };
13.1224 + boolean isEnum[] = { false };
13.1225 + boolean isPrimitive[] = { false };
13.1226 + checkType(p, isModel, isEnum, isPrimitive);
13.1227 + if (!isModel[0]) {
13.1228 + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ";\n");
13.1229 + continue;
13.1230 + }
13.1231 + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ".clone();\n");
13.1232 + } else {
13.1233 + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ".clone();\n");
13.1234 + }
13.1235 + }
13.1236 +
13.1237 + w.write(" return ret;\n");
13.1238 + w.write(" }\n");
13.1239 + }
13.1240 +
13.1241 + private String inPckName(Element e) {
13.1242 + StringBuilder sb = new StringBuilder();
13.1243 + while (e.getKind() != ElementKind.PACKAGE) {
13.1244 + if (sb.length() == 0) {
13.1245 + sb.append(e.getSimpleName());
13.1246 + } else {
13.1247 + sb.insert(0, '.');
13.1248 + sb.insert(0, e.getSimpleName());
13.1249 + }
13.1250 + e = e.getEnclosingElement();
13.1251 + }
13.1252 + return sb.toString();
13.1253 + }
13.1254 +
13.1255 + private String fqn(TypeMirror pt, Element relative) {
13.1256 + if (pt.getKind() == TypeKind.ERROR) {
13.1257 + final Elements eu = processingEnv.getElementUtils();
13.1258 + PackageElement pckg = eu.getPackageOf(relative);
13.1259 + return pckg.getQualifiedName() + "." + pt.toString();
13.1260 + }
13.1261 + return pt.toString();
13.1262 + }
13.1263 +
13.1264 + private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) {
13.1265 + TypeMirror tm;
13.1266 + try {
13.1267 + String ret = p.typeName(processingEnv);
13.1268 + TypeElement e = processingEnv.getElementUtils().getTypeElement(ret);
13.1269 + if (e == null) {
13.1270 + isModel[0] = true;
13.1271 + isEnum[0] = false;
13.1272 + isPrimitive[0] = false;
13.1273 + return ret;
13.1274 + }
13.1275 + tm = e.asType();
13.1276 + } catch (MirroredTypeException ex) {
13.1277 + tm = ex.getTypeMirror();
13.1278 + }
13.1279 + tm = processingEnv.getTypeUtils().erasure(tm);
13.1280 + isPrimitive[0] = tm.getKind().isPrimitive();
13.1281 + final Element e = processingEnv.getTypeUtils().asElement(tm);
13.1282 + final Model m = e == null ? null : e.getAnnotation(Model.class);
13.1283 +
13.1284 + String ret;
13.1285 + if (m != null) {
13.1286 + ret = findPkgName(e) + '.' + m.className();
13.1287 + isModel[0] = true;
13.1288 + models.put(e, m.className());
13.1289 + } else if (findModelForMthd(e)) {
13.1290 + ret = ((TypeElement)e).getQualifiedName().toString();
13.1291 + isModel[0] = true;
13.1292 + } else {
13.1293 + ret = tm.toString();
13.1294 + }
13.1295 + TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
13.1296 + enm = processingEnv.getTypeUtils().erasure(enm);
13.1297 + isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm);
13.1298 + return ret;
13.1299 + }
13.1300 +
13.1301 + private static boolean findModelForMthd(Element clazz) {
13.1302 + if (clazz == null) {
13.1303 + return false;
13.1304 + }
13.1305 + for (Element e : clazz.getEnclosedElements()) {
13.1306 + if (e.getKind() == ElementKind.METHOD) {
13.1307 + ExecutableElement ee = (ExecutableElement)e;
13.1308 + if (
13.1309 + ee.getSimpleName().contentEquals("modelFor") &&
13.1310 + ee.getParameters().isEmpty()
13.1311 + ) {
13.1312 + return true;
13.1313 + }
13.1314 + }
13.1315 + }
13.1316 + return false;
13.1317 + }
13.1318 +
13.1319 + private Iterable<String> findParamNames(Element e, String url, StringBuilder assembleURL) {
13.1320 + List<String> params = new ArrayList<>();
13.1321 +
13.1322 + for (int pos = 0; ;) {
13.1323 + int next = url.indexOf('{', pos);
13.1324 + if (next == -1) {
13.1325 + assembleURL.append('"')
13.1326 + .append(url.substring(pos))
13.1327 + .append('"');
13.1328 + return params;
13.1329 + }
13.1330 + int close = url.indexOf('}', next);
13.1331 + if (close == -1) {
13.1332 + error("Unbalanced '{' and '}' in " + url, e);
13.1333 + return params;
13.1334 + }
13.1335 + final String paramName = url.substring(next + 1, close);
13.1336 + params.add(paramName);
13.1337 + assembleURL.append('"')
13.1338 + .append(url.substring(pos, next))
13.1339 + .append("\" + ").append(paramName).append(" + ");
13.1340 + pos = close + 1;
13.1341 + }
13.1342 + }
13.1343 +
13.1344 + private static Prprt findPrprt(Prprt[] properties, String propName) {
13.1345 + for (Prprt p : properties) {
13.1346 + if (propName.equals(p.name())) {
13.1347 + return p;
13.1348 + }
13.1349 + }
13.1350 + return null;
13.1351 + }
13.1352 +
13.1353 + private boolean isPrimitive(String type) {
13.1354 + return
13.1355 + "int".equals(type) ||
13.1356 + "double".equals(type) ||
13.1357 + "long".equals(type) ||
13.1358 + "short".equals(type) ||
13.1359 + "byte".equals(type) ||
13.1360 + "float".equals(type);
13.1361 + }
13.1362 +
13.1363 + private static Collection<String> findDerivedFrom(Map<String, Collection<String>> propsDeps, String derivedProp) {
13.1364 + Set<String> names = new HashSet<>();
13.1365 + for (Map.Entry<String, Collection<String>> e : propsDeps.entrySet()) {
13.1366 + if (e.getValue().contains(derivedProp)) {
13.1367 + names.add(e.getKey());
13.1368 + }
13.1369 + }
13.1370 + return names;
13.1371 + }
13.1372 +
13.1373 + private Prprt[] createProps(Element e, Property[] arr) {
13.1374 + Prprt[] ret = Prprt.wrap(processingEnv, e, arr);
13.1375 + Prprt[] prev = verify.put(e, ret);
13.1376 + if (prev != null) {
13.1377 + error("Two sets of properties for ", e);
13.1378 + }
13.1379 + return ret;
13.1380 + }
13.1381 +
13.1382 + private static class Prprt {
13.1383 + private final Element e;
13.1384 + private final AnnotationMirror tm;
13.1385 + private final Property p;
13.1386 +
13.1387 + public Prprt(Element e, AnnotationMirror tm, Property p) {
13.1388 + this.e = e;
13.1389 + this.tm = tm;
13.1390 + this.p = p;
13.1391 + }
13.1392 +
13.1393 + String name() {
13.1394 + return p.name();
13.1395 + }
13.1396 +
13.1397 + boolean array() {
13.1398 + return p.array();
13.1399 + }
13.1400 +
13.1401 + String typeName(ProcessingEnvironment env) {
13.1402 + try {
13.1403 + return p.type().getName();
13.1404 + } catch (IncompleteAnnotationException | AnnotationTypeMismatchException ex) {
13.1405 + for (Object v : getAnnoValues(env)) {
13.1406 + String s = v.toString().replace(" ", "");
13.1407 + if (s.startsWith("type=") && s.endsWith(".class")) {
13.1408 + return s.substring(5, s.length() - 6);
13.1409 + }
13.1410 + }
13.1411 + throw ex;
13.1412 + }
13.1413 + }
13.1414 +
13.1415 +
13.1416 + static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) {
13.1417 + if (arr.length == 0) {
13.1418 + return new Prprt[0];
13.1419 + }
13.1420 +
13.1421 + if (e.getKind() != ElementKind.CLASS) {
13.1422 + throw new IllegalStateException("" + e.getKind());
13.1423 + }
13.1424 + TypeElement te = (TypeElement)e;
13.1425 + List<? extends AnnotationValue> val = null;
13.1426 + for (AnnotationMirror an : te.getAnnotationMirrors()) {
13.1427 + for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : an.getElementValues().entrySet()) {
13.1428 + if (entry.getKey().getSimpleName().contentEquals("properties")) {
13.1429 + val = (List)entry.getValue().getValue();
13.1430 + break;
13.1431 + }
13.1432 + }
13.1433 + }
13.1434 + if (val == null || val.size() != arr.length) {
13.1435 + pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e);
13.1436 + return new Prprt[0];
13.1437 + }
13.1438 + Prprt[] ret = new Prprt[arr.length];
13.1439 + BIG: for (int i = 0; i < ret.length; i++) {
13.1440 + AnnotationMirror am = (AnnotationMirror)val.get(i).getValue();
13.1441 + ret[i] = new Prprt(e, am, arr[i]);
13.1442 +
13.1443 + }
13.1444 + return ret;
13.1445 + }
13.1446 +
13.1447 + private List<? extends Object> getAnnoValues(ProcessingEnvironment pe) {
13.1448 + try {
13.1449 + Class<?> trees = Class.forName("com.sun.tools.javac.api.JavacTrees");
13.1450 + Method m = trees.getMethod("instance", ProcessingEnvironment.class);
13.1451 + Object instance = m.invoke(null, pe);
13.1452 + m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class);
13.1453 + Object path = m.invoke(instance, e, tm);
13.1454 + m = path.getClass().getMethod("getLeaf");
13.1455 + Object leaf = m.invoke(path);
13.1456 + m = leaf.getClass().getMethod("getArguments");
13.1457 + return (List)m.invoke(leaf);
13.1458 + } catch (Exception ex) {
13.1459 + return Collections.emptyList();
13.1460 + }
13.1461 + }
13.1462 + }
13.1463 +
13.1464 }
14.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Wed Feb 27 17:50:47 2013 +0100
14.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Mon Oct 07 14:20:58 2013 +0200
14.3 @@ -18,6 +18,7 @@
14.4 package org.apidesign.bck2brwsr.htmlpage.api;
14.5
14.6 import org.apidesign.bck2brwsr.core.JavaScriptBody;
14.7 +import static org.apidesign.bck2brwsr.htmlpage.api.Element.getAttribute;
14.8
14.9 /**
14.10 *
14.11 @@ -34,7 +35,8 @@
14.12 }
14.13
14.14 public int getHeight() {
14.15 - return (Integer) getAttribute(this, "height");
14.16 + Object ret = getAttribute(this, "height");
14.17 + return (ret instanceof Number) ? ((Number)ret).intValue(): Integer.MIN_VALUE;
14.18 }
14.19
14.20 public void setWidth(int width) {
14.21 @@ -42,7 +44,8 @@
14.22 }
14.23
14.24 public int getWidth() {
14.25 - return (Integer) getAttribute(this, "width");
14.26 + Object ret = getAttribute(this, "width");
14.27 + return (ret instanceof Number) ? ((Number)ret).intValue(): Integer.MIN_VALUE;
14.28 }
14.29
14.30 @JavaScriptBody(
15.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Wed Feb 27 17:50:47 2013 +0100
15.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Mon Oct 07 14:20:58 2013 +0200
15.3 @@ -22,16 +22,11 @@
15.4 import java.lang.annotation.RetentionPolicy;
15.5 import java.lang.annotation.Target;
15.6
15.7 -/** Can be used in classes annotated with {@link Page} annotation to
15.8 - * define a derived property. Value of derived property is based on values
15.9 - * of {@link Property} as enumerated by {@link Page#properties()}.
15.10 - * <p>
15.11 - * The name of the derived property is the name of the method. The arguments
15.12 - * of the method define the property names (from {@link Page#properties()} list)
15.13 - * the value of property depends on.
15.14 - *
15.15 +/**
15.16 + * @deprecated Replaced by new {@link net.java.html.json.ComputedProperty net.java.html.json} API.
15.17 * @author Jaroslav Tulach <jtulach@netbeans.org>
15.18 */
15.19 +@Deprecated
15.20 @Retention(RetentionPolicy.SOURCE)
15.21 @Target(ElementType.METHOD)
15.22 public @interface ComputedProperty {
16.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Wed Feb 27 17:50:47 2013 +0100
16.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Mon Oct 07 14:20:58 2013 +0200
16.3 @@ -61,14 +61,18 @@
16.4
16.5 /** Executes given runnable when user performs a "click" on the given
16.6 * element.
16.7 + * @param data an array of one element to fill with event parameter (if any)
16.8 * @param r the runnable to execute, never null
16.9 */
16.10 @JavaScriptBody(
16.11 args={ "ev", "r" },
16.12 body="var e = window.document.getElementById(this._id());\n"
16.13 - + "e[ev._id()] = function() { r.run__V(); };\n"
16.14 + + "e[ev._id()] = function(ev) {\n"
16.15 + + " var d = ev ? ev : null;\n"
16.16 + + " r.onEvent__VLjava_lang_Object_2(d);\n"
16.17 + + "};\n"
16.18 )
16.19 - final void on(OnEvent ev, Runnable r) {
16.20 + final void on(OnEvent ev, OnHandler r) {
16.21 }
16.22
16.23 /** Shows alert message dialog in a browser.
17.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/GraphicsContext.java Wed Feb 27 17:50:47 2013 +0100
17.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/GraphicsContext.java Mon Oct 07 14:20:58 2013 +0200
17.3 @@ -134,7 +134,7 @@
17.4 @JavaScriptBody(args = {"ctx", "img", "x", "y"}, body = "ctx.drawImage(img,x,y);")
17.5 private native static void drawImageImpl(Object ctx, Object img, double x, double y);
17.6
17.7 - @JavaScriptBody(args = {"style"}, body = "this._context().fillStyle=style;")
17.8 + @JavaScriptBody(args = {"style"}, body = "this._context().fillStyle=style.valueOf();")
17.9 public native void setFillStyle(String style);
17.10
17.11 @JavaScriptBody(args = {}, body = "return this._context().fillStyle;")
17.12 @@ -155,7 +155,7 @@
17.13 @JavaScriptBody(args = {"context","obj"}, body = "context.fillStyle=obj;")
17.14 private native void setFillStyleImpl(Object context, Object obj);
17.15
17.16 - @JavaScriptBody(args = {"style"}, body = "this._context().strokeStyle=style;")
17.17 + @JavaScriptBody(args = {"style"}, body = "this._context().strokeStyle=style.valueOf();")
17.18 public native void setStrokeStyle(String style);
17.19
17.20 public void setStrokeStyle(LinearGradient style) {
17.21 @@ -174,7 +174,7 @@
17.22 @JavaScriptBody(args = {"context","obj"}, body = "context.strokeStyle=obj;")
17.23 private native void setStrokeStyleImpl(Object context, Object obj);
17.24
17.25 - @JavaScriptBody(args = {"color"}, body = "this._context().shadowColor=color;")
17.26 + @JavaScriptBody(args = {"color"}, body = "this._context().shadowColor=color.valueOf();")
17.27 public native void setShadowColor(String color);
17.28
17.29 @JavaScriptBody(args = {"blur"}, body = "this._context().shadowBlur=blur;")
17.30 @@ -204,19 +204,19 @@
17.31 @JavaScriptBody(args = {}, body = "return this._context().lineCap;")
17.32 public native String getLineCap();
17.33
17.34 - @JavaScriptBody(args = {"style"}, body = "this._context().lineCap=style;")
17.35 + @JavaScriptBody(args = {"style"}, body = "this._context().lineCap=style.valueOf();")
17.36 public native void setLineCap(String style);
17.37
17.38 @JavaScriptBody(args = {}, body = "return this._context().lineJoin;")
17.39 public native String getLineJoin();
17.40
17.41 - @JavaScriptBody(args = {"style"}, body = "this._context().lineJoin=style;")
17.42 + @JavaScriptBody(args = {"style"}, body = "this._context().lineJoin=style.valueOf();")
17.43 public native void setLineJoin(String style) ;
17.44
17.45 @JavaScriptBody(args = {}, body = "return this._context().lineWidth;")
17.46 public native double getLineWidth();
17.47
17.48 - @JavaScriptBody(args = {"width"}, body = "this._context().lineJoin=width;")
17.49 + @JavaScriptBody(args = {"width"}, body = "this._context().lineWidth=width;")
17.50 public native void setLineWidth(double width);
17.51
17.52 @JavaScriptBody(args = {}, body = "return this._context().miterLimit;")
17.53 @@ -228,19 +228,19 @@
17.54 @JavaScriptBody(args = {}, body = "return this._context().font;")
17.55 public native String getFont();
17.56
17.57 - @JavaScriptBody(args = {"font"}, body = "this._context().font=font;")
17.58 + @JavaScriptBody(args = {"font"}, body = "this._context().font=font.valueOf();")
17.59 public native void setFont(String font);
17.60
17.61 @JavaScriptBody(args = {}, body = "return this._context().textAlign;")
17.62 public native String getTextAlign();
17.63
17.64 - @JavaScriptBody(args = {"textalign"}, body = "this._context().textAlign=textalign;")
17.65 + @JavaScriptBody(args = {"textalign"}, body = "this._context().textAlign=textalign.valueOf();")
17.66 public native void setTextAlign(String textAlign);
17.67
17.68 @JavaScriptBody(args = {}, body = "return this._context().textBaseline;")
17.69 public native String getTextBaseline();
17.70
17.71 - @JavaScriptBody(args = {"textbaseline"}, body = "this._context().textBaseline=textbaseline;")
17.72 + @JavaScriptBody(args = {"textbaseline"}, body = "this._context().textBaseline=textbaseline.valueOf();")
17.73 public native void setTextBaseline(String textbaseline);
17.74
17.75 @JavaScriptBody(args = {"text", "x", "y"}, body = "this._context().fillText(text,x,y);")
17.76 @@ -306,7 +306,7 @@
17.77 @JavaScriptBody(args = {}, body = "return this._context().globalAlpha;")
17.78 public native double getGlobalAlpha();
17.79
17.80 - @JavaScriptBody(args = {"operation"}, body = "this._context().globalCompositeOperation=operation;")
17.81 + @JavaScriptBody(args = {"operation"}, body = "this._context().globalCompositeOperation=operation.valueOf();")
17.82 public native void setGlobalCompositeOperation(String operation);
17.83
17.84 @JavaScriptBody(args = {}, body = "return this._context().globalCompositeOperation;")
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Model.java Mon Oct 07 14:20:58 2013 +0200
18.3 @@ -0,0 +1,38 @@
18.4 +/**
18.5 + * Back 2 Browser Bytecode Translator
18.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
18.7 + *
18.8 + * This program is free software: you can redistribute it and/or modify
18.9 + * it under the terms of the GNU General Public License as published by
18.10 + * the Free Software Foundation, version 2 of the License.
18.11 + *
18.12 + * This program is distributed in the hope that it will be useful,
18.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
18.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18.15 + * GNU General Public License for more details.
18.16 + *
18.17 + * You should have received a copy of the GNU General Public License
18.18 + * along with this program. Look for COPYING file in the top folder.
18.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
18.20 + */
18.21 +package org.apidesign.bck2brwsr.htmlpage.api;
18.22 +
18.23 +import java.lang.annotation.ElementType;
18.24 +import java.lang.annotation.Retention;
18.25 +import java.lang.annotation.RetentionPolicy;
18.26 +import java.lang.annotation.Target;
18.27 +
18.28 +/**
18.29 + * @deprecated Replaced by new {@link net.java.html.json.Model net.java.html.json} API.
18.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
18.31 + */
18.32 +@Retention(RetentionPolicy.SOURCE)
18.33 +@Target(ElementType.TYPE)
18.34 +@Deprecated
18.35 +public @interface Model {
18.36 + /** Name of the model class */
18.37 + String className();
18.38 + /** List of properties in the model.
18.39 + */
18.40 + Property[] properties();
18.41 +}
19.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java Wed Feb 27 17:50:47 2013 +0100
19.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java Mon Oct 07 14:20:58 2013 +0200
19.3 @@ -30,14 +30,33 @@
19.4 this.arr = arr;
19.5 }
19.6
19.7 + /** Registers an event handler on associated {@link OnEvent}
19.8 + * and {@link Element}
19.9 + *
19.10 + * @param handler the handler to be called when the event occurs
19.11 + */
19.12 + public void perform(final OnHandler handler) {
19.13 + for (Element e : arr) {
19.14 + e.on(event, handler);
19.15 + }
19.16 + }
19.17 +
19.18 /** Registers a runnable to be performed on associated {@link OnEvent}
19.19 * and {@link Element}.
19.20 *
19.21 * @see OnEvent#of
19.22 */
19.23 - public void perform(Runnable r) {
19.24 + public void perform(final Runnable r) {
19.25 + class W implements OnHandler {
19.26 + @Override
19.27 + public void onEvent(Object event) throws Exception {
19.28 + r.run();
19.29 + }
19.30 + }
19.31 + perform(new W());
19.32 + OnHandler w = new W();
19.33 for (Element e : arr) {
19.34 - e.on(event, r);
19.35 + e.on(event, w);
19.36 }
19.37 }
19.38 }
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnFunction.java Mon Oct 07 14:20:58 2013 +0200
20.3 @@ -0,0 +1,33 @@
20.4 +/**
20.5 + * Back 2 Browser Bytecode Translator
20.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
20.7 + *
20.8 + * This program is free software: you can redistribute it and/or modify
20.9 + * it under the terms of the GNU General Public License as published by
20.10 + * the Free Software Foundation, version 2 of the License.
20.11 + *
20.12 + * This program is distributed in the hope that it will be useful,
20.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
20.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20.15 + * GNU General Public License for more details.
20.16 + *
20.17 + * You should have received a copy of the GNU General Public License
20.18 + * along with this program. Look for COPYING file in the top folder.
20.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
20.20 + */
20.21 +package org.apidesign.bck2brwsr.htmlpage.api;
20.22 +
20.23 +import java.lang.annotation.ElementType;
20.24 +import java.lang.annotation.Retention;
20.25 +import java.lang.annotation.RetentionPolicy;
20.26 +import java.lang.annotation.Target;
20.27 +
20.28 +/**
20.29 + * @deprecated Replaced by new {@link net.java.html.json.Function net.java.html.json} API.
20.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
20.31 + */
20.32 +@Target(ElementType.METHOD)
20.33 +@Retention(RetentionPolicy.SOURCE)
20.34 +@Deprecated
20.35 +public @interface OnFunction {
20.36 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnHandler.java Mon Oct 07 14:20:58 2013 +0200
21.3 @@ -0,0 +1,33 @@
21.4 +/**
21.5 + * Back 2 Browser Bytecode Translator
21.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
21.7 + *
21.8 + * This program is free software: you can redistribute it and/or modify
21.9 + * it under the terms of the GNU General Public License as published by
21.10 + * the Free Software Foundation, version 2 of the License.
21.11 + *
21.12 + * This program is distributed in the hope that it will be useful,
21.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
21.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21.15 + * GNU General Public License for more details.
21.16 + *
21.17 + * You should have received a copy of the GNU General Public License
21.18 + * along with this program. Look for COPYING file in the top folder.
21.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
21.20 + */
21.21 +package org.apidesign.bck2brwsr.htmlpage.api;
21.22 +
21.23 +/** Handler to be called when an event in an HTML {@link Page} appears.
21.24 + * @see OnEvent
21.25 + * @see OnController
21.26 + *
21.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
21.28 + */
21.29 +public interface OnHandler {
21.30 + /** Called when a DOM event appears
21.31 + *
21.32 + * @param event the event as produced by the browser
21.33 + * @throws Exception execution can throw exception
21.34 + */
21.35 + public void onEvent(Object event) throws Exception;
21.36 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnPropertyChange.java Mon Oct 07 14:20:58 2013 +0200
22.3 @@ -0,0 +1,38 @@
22.4 +/**
22.5 + * Back 2 Browser Bytecode Translator
22.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
22.7 + *
22.8 + * This program is free software: you can redistribute it and/or modify
22.9 + * it under the terms of the GNU General Public License as published by
22.10 + * the Free Software Foundation, version 2 of the License.
22.11 + *
22.12 + * This program is distributed in the hope that it will be useful,
22.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
22.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22.15 + * GNU General Public License for more details.
22.16 + *
22.17 + * You should have received a copy of the GNU General Public License
22.18 + * along with this program. Look for COPYING file in the top folder.
22.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
22.20 + */
22.21 +package org.apidesign.bck2brwsr.htmlpage.api;
22.22 +
22.23 +import java.lang.annotation.ElementType;
22.24 +import java.lang.annotation.Retention;
22.25 +import java.lang.annotation.RetentionPolicy;
22.26 +import java.lang.annotation.Target;
22.27 +
22.28 +/**
22.29 + * @deprecated Replaced by new {@link net.java.html.json.OnPropertyChange net.java.html.json} API.
22.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
22.31 + */
22.32 +@Retention(RetentionPolicy.SOURCE)
22.33 +@Target(ElementType.METHOD)
22.34 +@Deprecated
22.35 +public @interface OnPropertyChange {
22.36 + /** Name(s) of the properties. One wishes to observe.
22.37 + *
22.38 + * @return valid java identifier
22.39 + */
22.40 + String[] value();
22.41 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnReceive.java Mon Oct 07 14:20:58 2013 +0200
23.3 @@ -0,0 +1,53 @@
23.4 +/**
23.5 + * Back 2 Browser Bytecode Translator
23.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
23.7 + *
23.8 + * This program is free software: you can redistribute it and/or modify
23.9 + * it under the terms of the GNU General Public License as published by
23.10 + * the Free Software Foundation, version 2 of the License.
23.11 + *
23.12 + * This program is distributed in the hope that it will be useful,
23.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
23.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23.15 + * GNU General Public License for more details.
23.16 + *
23.17 + * You should have received a copy of the GNU General Public License
23.18 + * along with this program. Look for COPYING file in the top folder.
23.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
23.20 + */
23.21 +package org.apidesign.bck2brwsr.htmlpage.api;
23.22 +
23.23 +import java.lang.annotation.ElementType;
23.24 +import java.lang.annotation.Retention;
23.25 +import java.lang.annotation.RetentionPolicy;
23.26 +import java.lang.annotation.Target;
23.27 +
23.28 +/**
23.29 + * @deprecated Replaced by new {@link net.java.html.json.OnReceive net.java.html.json} API.
23.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
23.31 + * @since 0.6
23.32 + */
23.33 +@Retention(RetentionPolicy.SOURCE)
23.34 +@Target(ElementType.METHOD)
23.35 +@Deprecated
23.36 +public @interface OnReceive {
23.37 + /** The URL to connect to. Can contain variable names surrounded by '{' and '}'.
23.38 + * Those parameters will then become variables of the associated method.
23.39 + *
23.40 + * @return the (possibly parametrized) url to connect to
23.41 + */
23.42 + String url();
23.43 +
23.44 + /** Support for <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> requires
23.45 + * a callback from the server generated page to a function defined in the
23.46 + * system. The name of such function is usually specified as a property
23.47 + * (of possibly different names). By defining the <code>jsonp</code> attribute
23.48 + * one turns on the <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>
23.49 + * transmission and specifies the name of the property. The property should
23.50 + * also be used in the {@link #url()} attribute on appropriate place.
23.51 + *
23.52 + * @return name of a property to carry the name of <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>
23.53 + * callback function.
23.54 + */
23.55 + String jsonp() default "";
23.56 +}
24.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Wed Feb 27 17:50:47 2013 +0100
24.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Mon Oct 07 14:20:58 2013 +0200
24.3 @@ -20,15 +20,36 @@
24.4 import java.lang.annotation.Retention;
24.5 import java.lang.annotation.RetentionPolicy;
24.6 import java.lang.annotation.Target;
24.7 +import java.util.List;
24.8
24.9 -/** Represents a property in a generated model of an HTML
24.10 - * {@link Page}.
24.11 - *
24.12 +/**
24.13 + * @deprecated Replaced by new {@link net.java.html.json.Property net.java.html.json} API.
24.14 * @author Jaroslav Tulach <jtulach@netbeans.org>
24.15 */
24.16 @Retention(RetentionPolicy.SOURCE)
24.17 @Target({})
24.18 +@Deprecated
24.19 public @interface Property {
24.20 + /** Name of the property. Will be used to define proper getter and setter
24.21 + * in the associated class.
24.22 + *
24.23 + * @return valid java identifier
24.24 + */
24.25 String name();
24.26 +
24.27 + /** Type of the property. Can either be primitive type (like <code>int.class</code>,
24.28 + * <code>double.class</code>, etc.), {@link String} or complex model
24.29 + * class (defined by {@link Model} property).
24.30 + *
24.31 + * @return the class of the property
24.32 + */
24.33 Class<?> type();
24.34 +
24.35 + /** Is this property an array of the {@link #type()} or a single value?
24.36 + * If the property is an array, only its getter (returning mutable {@link List} of
24.37 + * the boxed {@link #type()}).
24.38 + *
24.39 + * @return true, if this is supposed to be an array of values.
24.40 + */
24.41 + boolean array() default false;
24.42 }
25.1 --- a/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Wed Feb 27 17:50:47 2013 +0100
25.2 +++ b/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Mon Oct 07 14:20:58 2013 +0200
25.3 @@ -2193,7 +2193,14 @@
25.4 else
25.5 element[attrName] = attrValue;
25.6 } else if (!toRemove) {
25.7 - element.setAttribute(attrName, attrValue.toString());
25.8 + try {
25.9 + element.setAttribute(attrName, attrValue.toString());
25.10 + } catch (err) {
25.11 + // ignore for now
25.12 + if (console) {
25.13 + console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
25.14 + }
25.15 + }
25.16 }
25.17
25.18 // Treat "name" specially - although you can think of it as an attribute, it also needs
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java Mon Oct 07 14:20:58 2013 +0200
26.3 @@ -0,0 +1,203 @@
26.4 +/**
26.5 + * Back 2 Browser Bytecode Translator
26.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
26.7 + *
26.8 + * This program is free software: you can redistribute it and/or modify
26.9 + * it under the terms of the GNU General Public License as published by
26.10 + * the Free Software Foundation, version 2 of the License.
26.11 + *
26.12 + * This program is distributed in the hope that it will be useful,
26.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
26.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26.15 + * GNU General Public License for more details.
26.16 + *
26.17 + * You should have received a copy of the GNU General Public License
26.18 + * along with this program. Look for COPYING file in the top folder.
26.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
26.20 + */
26.21 +package org.apidesign.bck2brwsr.htmlpage;
26.22 +
26.23 +import java.io.ByteArrayInputStream;
26.24 +import java.io.ByteArrayOutputStream;
26.25 +import java.io.IOException;
26.26 +import java.io.InputStream;
26.27 +import java.io.OutputStream;
26.28 +import java.net.URI;
26.29 +import java.net.URISyntaxException;
26.30 +import java.util.ArrayList;
26.31 +import java.util.Arrays;
26.32 +import java.util.HashMap;
26.33 +import java.util.List;
26.34 +import java.util.Map;
26.35 +import java.util.regex.Matcher;
26.36 +import java.util.regex.Pattern;
26.37 +import javax.tools.Diagnostic;
26.38 +import javax.tools.DiagnosticListener;
26.39 +import javax.tools.FileObject;
26.40 +import javax.tools.ForwardingJavaFileManager;
26.41 +import javax.tools.JavaFileManager;
26.42 +import javax.tools.JavaFileObject;
26.43 +import javax.tools.JavaFileObject.Kind;
26.44 +import javax.tools.SimpleJavaFileObject;
26.45 +import javax.tools.StandardJavaFileManager;
26.46 +import javax.tools.StandardLocation;
26.47 +import javax.tools.ToolProvider;
26.48 +
26.49 +/**
26.50 + *
26.51 + * @author Jaroslav Tulach <jtulach@netbeans.org>
26.52 + */
26.53 +final class Compile implements DiagnosticListener<JavaFileObject> {
26.54 + private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
26.55 + private final Map<String, byte[]> classes;
26.56 + private final String pkg;
26.57 + private final String cls;
26.58 + private final String html;
26.59 +
26.60 + private Compile(String html, String code) throws IOException {
26.61 + this.pkg = findPkg(code);
26.62 + this.cls = findCls(code);
26.63 + this.html = html;
26.64 + classes = compile(html, code);
26.65 + }
26.66 +
26.67 + /** Performs compilation of given HTML page and associated Java code
26.68 + */
26.69 + public static Compile create(String html, String code) throws IOException {
26.70 + return new Compile(html, code);
26.71 + }
26.72 +
26.73 + /** Checks for given class among compiled resources */
26.74 + public byte[] get(String res) {
26.75 + return classes.get(res);
26.76 + }
26.77 +
26.78 + /** Obtains errors created during compilation.
26.79 + */
26.80 + public List<Diagnostic<? extends JavaFileObject>> getErrors() {
26.81 + List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
26.82 + for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
26.83 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
26.84 + err.add(diagnostic);
26.85 + }
26.86 + }
26.87 + return err;
26.88 + }
26.89 +
26.90 + private Map<String, byte[]> compile(final String html, final String code) throws IOException {
26.91 + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
26.92 +
26.93 + final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
26.94 +
26.95 + JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
26.96 + @Override
26.97 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
26.98 + return code;
26.99 + }
26.100 + };
26.101 + final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
26.102 + @Override
26.103 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
26.104 + return html;
26.105 + }
26.106 +
26.107 + @Override
26.108 + public InputStream openInputStream() throws IOException {
26.109 + return new ByteArrayInputStream(html.getBytes());
26.110 + }
26.111 + };
26.112 +
26.113 + final URI scratch;
26.114 + try {
26.115 + scratch = new URI("mem://mem3");
26.116 + } catch (URISyntaxException ex) {
26.117 + throw new IOException(ex);
26.118 + }
26.119 +
26.120 + JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
26.121 + @Override
26.122 + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
26.123 + if (kind == Kind.CLASS) {
26.124 + final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
26.125 +
26.126 + class2BAOS.put(className.replace('.', '/') + ".class", buffer);
26.127 + return new SimpleJavaFileObject(sibling.toUri(), kind) {
26.128 + @Override
26.129 + public OutputStream openOutputStream() throws IOException {
26.130 + return buffer;
26.131 + }
26.132 + };
26.133 + }
26.134 +
26.135 + if (kind == Kind.SOURCE) {
26.136 + return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
26.137 + private final ByteArrayOutputStream data = new ByteArrayOutputStream();
26.138 + @Override
26.139 + public OutputStream openOutputStream() throws IOException {
26.140 + return data;
26.141 + }
26.142 +
26.143 + @Override
26.144 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
26.145 + data.close();
26.146 + return new String(data.toByteArray());
26.147 + }
26.148 + };
26.149 + }
26.150 +
26.151 + throw new IllegalStateException();
26.152 + }
26.153 +
26.154 + @Override
26.155 + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
26.156 + if (location == StandardLocation.SOURCE_PATH) {
26.157 + if (packageName.equals(pkg)) {
26.158 + return htmlFile;
26.159 + }
26.160 + }
26.161 +
26.162 + return null;
26.163 + }
26.164 +
26.165 + };
26.166 +
26.167 + ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
26.168 +
26.169 + Map<String, byte[]> result = new HashMap<>();
26.170 +
26.171 + for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
26.172 + result.put(e.getKey(), e.getValue().toByteArray());
26.173 + }
26.174 +
26.175 + return result;
26.176 + }
26.177 +
26.178 +
26.179 + @Override
26.180 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
26.181 + errors.add(diagnostic);
26.182 + }
26.183 + private static String findPkg(String java) throws IOException {
26.184 + Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
26.185 + Matcher m = p.matcher(java);
26.186 + if (!m.find()) {
26.187 + throw new IOException("Can't find package declaration in the java file");
26.188 + }
26.189 + String pkg = m.group(1);
26.190 + return pkg;
26.191 + }
26.192 + private static String findCls(String java) throws IOException {
26.193 + Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
26.194 + Matcher m = p.matcher(java);
26.195 + if (!m.find()) {
26.196 + throw new IOException("Can't find package declaration in the java file");
26.197 + }
26.198 + String cls = m.group(1);
26.199 + return cls;
26.200 + }
26.201 +
26.202 + String getHtml() {
26.203 + String fqn = "'" + pkg + '.' + cls + "'";
26.204 + return html.replace("'${fqn}'", fqn);
26.205 + }
26.206 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypesTest.java Mon Oct 07 14:20:58 2013 +0200
27.3 @@ -0,0 +1,63 @@
27.4 +/**
27.5 + * Back 2 Browser Bytecode Translator
27.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
27.7 + *
27.8 + * This program is free software: you can redistribute it and/or modify
27.9 + * it under the terms of the GNU General Public License as published by
27.10 + * the Free Software Foundation, version 2 of the License.
27.11 + *
27.12 + * This program is distributed in the hope that it will be useful,
27.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.15 + * GNU General Public License for more details.
27.16 + *
27.17 + * You should have received a copy of the GNU General Public License
27.18 + * along with this program. Look for COPYING file in the top folder.
27.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
27.20 + */
27.21 +package org.apidesign.bck2brwsr.htmlpage;
27.22 +
27.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
27.24 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
27.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
27.26 +import org.testng.annotations.Factory;
27.27 +
27.28 +/**
27.29 + *
27.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
27.31 + */
27.32 +public class ConvertTypesTest {
27.33 + @JavaScriptBody(args = { "includeSex" }, body = "var json = new Object();"
27.34 + + "json.firstName = 'son';\n"
27.35 + + "json.lastName = 'dj';\n"
27.36 + + "if (includeSex) json.sex = 'MALE';\n"
27.37 + + "return json;"
27.38 + )
27.39 + private static native Object createJSON(boolean includeSex);
27.40 +
27.41 + @BrwsrTest
27.42 + public void testConvertToPeople() throws Exception {
27.43 + final Object o = createJSON(true);
27.44 +
27.45 + Person p = new Person(o);
27.46 +
27.47 + assert "son".equals(p.getFirstName()) : "First name: " + p.getFirstName();
27.48 + assert "dj".equals(p.getLastName()) : "Last name: " + p.getLastName();
27.49 + assert Sex.MALE.equals(p.getSex()) : "Sex: " + p.getSex();
27.50 + }
27.51 +
27.52 + @BrwsrTest
27.53 + public void testConvertToPeopleWithoutSex() throws Exception {
27.54 + final Object o = createJSON(false);
27.55 +
27.56 + Person p = new Person(o);
27.57 +
27.58 + assert "son".equals(p.getFirstName()) : "First name: " + p.getFirstName();
27.59 + assert "dj".equals(p.getLastName()) : "Last name: " + p.getLastName();
27.60 + assert p.getSex() == null : "No sex: " + p.getSex();
27.61 + }
27.62 +
27.63 + @Factory public static Object[] create() {
27.64 + return VMTest.create(ConvertTypesTest.class);
27.65 + }
27.66 +}
27.67 \ No newline at end of file
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java Mon Oct 07 14:20:58 2013 +0200
28.3 @@ -0,0 +1,392 @@
28.4 +/**
28.5 + * Back 2 Browser Bytecode Translator
28.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
28.7 + *
28.8 + * This program is free software: you can redistribute it and/or modify
28.9 + * it under the terms of the GNU General Public License as published by
28.10 + * the Free Software Foundation, version 2 of the License.
28.11 + *
28.12 + * This program is distributed in the hope that it will be useful,
28.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
28.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.15 + * GNU General Public License for more details.
28.16 + *
28.17 + * You should have received a copy of the GNU General Public License
28.18 + * along with this program. Look for COPYING file in the top folder.
28.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
28.20 + */
28.21 +package org.apidesign.bck2brwsr.htmlpage;
28.22 +
28.23 +import java.util.Arrays;
28.24 +import java.util.Iterator;
28.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
28.26 +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive;
28.27 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
28.28 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
28.29 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
28.30 +import org.apidesign.bck2brwsr.vmtest.Http;
28.31 +import org.apidesign.bck2brwsr.vmtest.VMTest;
28.32 +import org.json.JSONException;
28.33 +import org.json.JSONObject;
28.34 +import org.json.JSONTokener;
28.35 +import org.testng.annotations.Test;
28.36 +import static org.testng.Assert.*;
28.37 +import org.testng.annotations.Factory;
28.38 +
28.39 +/** Need to verify that models produce reasonable JSON objects.
28.40 + *
28.41 + * @author Jaroslav Tulach <jtulach@netbeans.org>
28.42 + */
28.43 +@Page(xhtml = "Empty.html", className = "JSONik", properties = {
28.44 + @Property(name = "fetched", type = PersonImpl.class),
28.45 + @Property(name = "fetchedCount", type = int.class),
28.46 + @Property(name = "fetchedSex", type = Sex.class, array = true)
28.47 +})
28.48 +public class JSONTest {
28.49 + private JSONik js;
28.50 + private Integer orig;
28.51 +
28.52 + @Test public void personToString() throws JSONException {
28.53 + Person p = new Person();
28.54 + p.setSex(Sex.MALE);
28.55 + p.setFirstName("Jarda");
28.56 + p.setLastName("Tulach");
28.57 +
28.58 + JSONTokener t = new JSONTokener(p.toString());
28.59 + JSONObject o;
28.60 + try {
28.61 + o = new JSONObject(t);
28.62 + } catch (JSONException ex) {
28.63 + throw new AssertionError("Can't parse " + p.toString(), ex);
28.64 + }
28.65 +
28.66 + Iterator it = o.sortedKeys();
28.67 + assertEquals(it.next(), "firstName");
28.68 + assertEquals(it.next(), "lastName");
28.69 + assertEquals(it.next(), "sex");
28.70 +
28.71 + assertEquals(o.getString("firstName"), "Jarda");
28.72 + assertEquals(o.getString("lastName"), "Tulach");
28.73 + assertEquals(o.getString("sex"), "MALE");
28.74 + }
28.75 +
28.76 + @BrwsrTest public void toJSONInABrowser() throws Throwable {
28.77 + Person p = new Person();
28.78 + p.setSex(Sex.MALE);
28.79 + p.setFirstName("Jarda");
28.80 + p.setLastName("Tulach");
28.81 +
28.82 + Object json;
28.83 + try {
28.84 + json = parseJSON(p.toString());
28.85 + } catch (Throwable ex) {
28.86 + throw new IllegalStateException("Can't parse " + p).initCause(ex);
28.87 + }
28.88 +
28.89 + Person p2 = new Person(json);
28.90 +
28.91 + assert p2.getFirstName().equals(p.getFirstName()) :
28.92 + "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
28.93 + }
28.94 +
28.95 + @Test public void personWithWildCharactersAndNulls() throws JSONException {
28.96 + Person p = new Person();
28.97 + p.setFirstName("'\"\n");
28.98 + p.setLastName("\t\r\u0002");
28.99 +
28.100 + JSONTokener t = new JSONTokener(p.toString());
28.101 + JSONObject o;
28.102 + try {
28.103 + o = new JSONObject(t);
28.104 + } catch (JSONException ex) {
28.105 + throw new AssertionError("Can't parse " + p.toString(), ex);
28.106 + }
28.107 +
28.108 + Iterator it = o.sortedKeys();
28.109 + assertEquals(it.next(), "firstName");
28.110 + assertEquals(it.next(), "lastName");
28.111 + assertEquals(it.next(), "sex");
28.112 +
28.113 + assertEquals(o.getString("firstName"), p.getFirstName());
28.114 + assertEquals(o.getString("lastName"), p.getLastName());
28.115 + assertEquals(o.get("sex"), JSONObject.NULL);
28.116 + }
28.117 +
28.118 + @Test public void personsInArray() throws JSONException {
28.119 + Person p1 = new Person();
28.120 + p1.setFirstName("One");
28.121 +
28.122 + Person p2 = new Person();
28.123 + p2.setFirstName("Two");
28.124 +
28.125 + People arr = new People();
28.126 + arr.getInfo().add(p1);
28.127 + arr.getInfo().add(p2);
28.128 + arr.getNicknames().add("Prvn\u00ed k\u016f\u0148");
28.129 + final String n2 = "Druh\u00fd hlem\u00fd\u017e\u010f, star\u0161\u00ed";
28.130 + arr.getNicknames().add(n2);
28.131 + arr.getAge().add(33);
28.132 + arr.getAge().add(73);
28.133 +
28.134 +
28.135 + final String json = arr.toString();
28.136 +
28.137 + JSONTokener t = new JSONTokener(json);
28.138 + JSONObject o;
28.139 + try {
28.140 + o = new JSONObject(t);
28.141 + } catch (JSONException ex) {
28.142 + throw new AssertionError("Can't parse " + json, ex);
28.143 + }
28.144 +
28.145 + assertEquals(o.getJSONArray("info").getJSONObject(0).getString("firstName"), "One");
28.146 + assertEquals(o.getJSONArray("nicknames").getString(1), n2);
28.147 + assertEquals(o.getJSONArray("age").getInt(1), 73);
28.148 + }
28.149 +
28.150 +
28.151 + @OnReceive(url="/{url}")
28.152 + static void fetch(Person p, JSONik model) {
28.153 + model.setFetched(p);
28.154 + }
28.155 +
28.156 + @OnReceive(url="/{url}")
28.157 + static void fetchArray(Person[] p, JSONik model) {
28.158 + model.setFetchedCount(p.length);
28.159 + model.setFetched(p[0]);
28.160 + }
28.161 +
28.162 + @OnReceive(url="/{url}")
28.163 + static void fetchPeople(People p, JSONik model) {
28.164 + model.setFetchedCount(p.getInfo().size());
28.165 + model.setFetched(p.getInfo().get(0));
28.166 + }
28.167 +
28.168 + @OnReceive(url="/{url}")
28.169 + static void fetchPeopleAge(People p, JSONik model) {
28.170 + int sum = 0;
28.171 + for (int a : p.getAge()) {
28.172 + sum += a;
28.173 + }
28.174 + model.setFetchedCount(sum);
28.175 + }
28.176 +
28.177 + @Http(@Http.Resource(
28.178 + content = "{'firstName': 'Sitar', 'sex': 'MALE'}",
28.179 + path="/person.json",
28.180 + mimeType = "application/json"
28.181 + ))
28.182 + @BrwsrTest public void loadAndParseJSON() throws InterruptedException {
28.183 + if (js == null) {
28.184 + js = new JSONik();
28.185 + js.applyBindings();
28.186 +
28.187 + js.fetch("person.json");
28.188 + }
28.189 +
28.190 + Person p = js.getFetched();
28.191 + if (p == null) {
28.192 + throw new InterruptedException();
28.193 + }
28.194 +
28.195 + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
28.196 + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
28.197 + }
28.198 +
28.199 + @OnReceive(url="/{url}?callme={me}", jsonp = "me")
28.200 + static void fetchViaJSONP(Person p, JSONik model) {
28.201 + model.setFetched(p);
28.202 + }
28.203 +
28.204 + @Http(@Http.Resource(
28.205 + content = "$0({'firstName': 'Mitar', 'sex': 'MALE'})",
28.206 + path="/person.json",
28.207 + mimeType = "application/javascript",
28.208 + parameters = { "callme" }
28.209 + ))
28.210 + @BrwsrTest public void loadAndParseJSONP() throws InterruptedException {
28.211 +
28.212 + if (js == null) {
28.213 + orig = scriptElements();
28.214 + assert orig > 0 : "There should be some scripts on the page";
28.215 +
28.216 + js = new JSONik();
28.217 + js.applyBindings();
28.218 +
28.219 + js.fetchViaJSONP("person.json");
28.220 + }
28.221 +
28.222 + Person p = js.getFetched();
28.223 + if (p == null) {
28.224 + throw new InterruptedException();
28.225 + }
28.226 +
28.227 + assert "Mitar".equals(p.getFirstName()) : "Unexpected: " + p.getFirstName();
28.228 + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
28.229 +
28.230 + int now = scriptElements();
28.231 +
28.232 + assert orig == now : "The set of elements is unchanged. Delta: " + (now - orig);
28.233 + }
28.234 +
28.235 + @JavaScriptBody(args = { }, body = "return window.document.getElementsByTagName('script').length;")
28.236 + private static native int scriptElements();
28.237 +
28.238 + @JavaScriptBody(args = { "s" }, body = "return window.JSON.parse(s);")
28.239 + private static native Object parseJSON(String s);
28.240 +
28.241 + @Http(@Http.Resource(
28.242 + content = "{'firstName': 'Sitar', 'sex': 'MALE'}",
28.243 + path="/person.json",
28.244 + mimeType = "application/json"
28.245 + ))
28.246 + @BrwsrTest public void loadAndParseJSONSentToArray() throws InterruptedException {
28.247 + if (js == null) {
28.248 + js = new JSONik();
28.249 + js.applyBindings();
28.250 +
28.251 + js.fetchArray("person.json");
28.252 + }
28.253 +
28.254 + Person p = js.getFetched();
28.255 + if (p == null) {
28.256 + throw new InterruptedException();
28.257 + }
28.258 +
28.259 + assert p != null : "We should get our person back: " + p;
28.260 + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
28.261 + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
28.262 + }
28.263 +
28.264 + @Http(@Http.Resource(
28.265 + content = "[{'firstName': 'Gitar', 'sex': 'FEMALE'}]",
28.266 + path="/person.json",
28.267 + mimeType = "application/json"
28.268 + ))
28.269 + @BrwsrTest public void loadAndParseJSONArraySingle() throws InterruptedException {
28.270 + if (js == null) {
28.271 + js = new JSONik();
28.272 + js.applyBindings();
28.273 +
28.274 + js.fetch("person.json");
28.275 + }
28.276 +
28.277 + Person p = js.getFetched();
28.278 + if (p == null) {
28.279 + throw new InterruptedException();
28.280 + }
28.281 +
28.282 + assert p != null : "We should get our person back: " + p;
28.283 + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
28.284 + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
28.285 + }
28.286 +
28.287 + @Http(@Http.Resource(
28.288 + content = "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}",
28.289 + path="/people.json",
28.290 + mimeType = "application/json"
28.291 + ))
28.292 + @BrwsrTest public void loadAndParseArrayInPeople() throws InterruptedException {
28.293 + if (js == null) {
28.294 + js = new JSONik();
28.295 + js.applyBindings();
28.296 +
28.297 + js.fetchPeople("people.json");
28.298 + }
28.299 +
28.300 + if (0 == js.getFetchedCount()) {
28.301 + throw new InterruptedException();
28.302 + }
28.303 +
28.304 + assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount();
28.305 +
28.306 + Person p = js.getFetched();
28.307 +
28.308 + assert p != null : "We should get our person back: " + p;
28.309 + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
28.310 + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
28.311 + }
28.312 +
28.313 + @Http(@Http.Resource(
28.314 + content = "{'age':[1, 2, 3]}",
28.315 + path="/people.json",
28.316 + mimeType = "application/json"
28.317 + ))
28.318 + @BrwsrTest public void loadAndParseArrayOfIntegers() throws InterruptedException {
28.319 + if (js == null) {
28.320 + js = new JSONik();
28.321 + js.applyBindings();
28.322 +
28.323 + js.fetchPeopleAge("people.json");
28.324 + }
28.325 +
28.326 + if (0 == js.getFetchedCount()) {
28.327 + throw new InterruptedException();
28.328 + }
28.329 +
28.330 + assert js.getFetchedCount() == 6 : "1 + 2 + 3 is " + js.getFetchedCount();
28.331 + }
28.332 +
28.333 + @OnReceive(url="/{url}")
28.334 + static void fetchPeopleSex(People p, JSONik model) {
28.335 + model.setFetchedCount(1);
28.336 + model.getFetchedSex().addAll(p.getSex());
28.337 + }
28.338 +
28.339 +
28.340 + @Http(@Http.Resource(
28.341 + content = "{'sex':['FEMALE', 'MALE', 'MALE']}",
28.342 + path="/people.json",
28.343 + mimeType = "application/json"
28.344 + ))
28.345 + @BrwsrTest public void loadAndParseArrayOfEnums() throws InterruptedException {
28.346 + if (js == null) {
28.347 + js = new JSONik();
28.348 + js.applyBindings();
28.349 +
28.350 + js.fetchPeopleSex("people.json");
28.351 + }
28.352 +
28.353 + if (0 == js.getFetchedCount()) {
28.354 + throw new InterruptedException();
28.355 + }
28.356 +
28.357 + assert js.getFetchedCount() == 1 : "Loaded";
28.358 +
28.359 + assert js.getFetchedSex().size() == 3 : "Three values " + js.getFetchedSex();
28.360 + assert js.getFetchedSex().get(0) == Sex.FEMALE : "Female first " + js.getFetchedSex();
28.361 + assert js.getFetchedSex().get(1) == Sex.MALE : "male 2nd " + js.getFetchedSex();
28.362 + assert js.getFetchedSex().get(2) == Sex.MALE : "male 3rd " + js.getFetchedSex();
28.363 + }
28.364 +
28.365 + @Http(@Http.Resource(
28.366 + content = "[{'firstName': 'Gitar', 'sex': 'FEMALE'},"
28.367 + + "{'firstName': 'Peter', 'sex': 'MALE'}"
28.368 + + "]",
28.369 + path="/person.json",
28.370 + mimeType = "application/json"
28.371 + ))
28.372 + @BrwsrTest public void loadAndParseJSONArray() throws InterruptedException {
28.373 + if (js == null) {
28.374 + js = new JSONik();
28.375 + js.applyBindings();
28.376 + js.fetchArray("person.json");
28.377 + }
28.378 +
28.379 +
28.380 + Person p = js.getFetched();
28.381 + if (p == null) {
28.382 + throw new InterruptedException();
28.383 + }
28.384 +
28.385 + assert js.getFetchedCount() == 2 : "We got two values: " + js.getFetchedCount();
28.386 + assert p != null : "We should get our person back: " + p;
28.387 + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
28.388 + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
28.389 + }
28.390 +
28.391 + @Factory public static Object[] create() {
28.392 + return VMTest.create(JSONTest.class);
28.393 + }
28.394 +
28.395 +}
29.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Wed Feb 27 17:50:47 2013 +0100
29.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Mon Oct 07 14:20:58 2013 +0200
29.3 @@ -17,21 +17,29 @@
29.4 */
29.5 package org.apidesign.bck2brwsr.htmlpage;
29.6
29.7 +import java.util.List;
29.8 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
29.9 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
29.10 import org.apidesign.bck2brwsr.htmlpage.api.OnEvent;
29.11 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
29.12 import org.apidesign.bck2brwsr.htmlpage.api.Page;
29.13 import org.apidesign.bck2brwsr.htmlpage.api.Property;
29.14 import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
29.15 import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
29.16 import org.apidesign.bck2brwsr.vmtest.VMTest;
29.17 +import static org.testng.Assert.assertEquals;
29.18 import org.testng.annotations.Factory;
29.19 +import org.testng.annotations.Test;
29.20
29.21 /**
29.22 *
29.23 * @author Jaroslav Tulach <jtulach@netbeans.org>
29.24 */
29.25 @Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={
29.26 - @Property(name="name", type=String.class)
29.27 + @Property(name="name", type=String.class),
29.28 + @Property(name="results", type=String.class, array = true),
29.29 + @Property(name="callbackCount", type=int.class),
29.30 + @Property(name="people", type=PersonImpl.class, array = true)
29.31 })
29.32 public class KnockoutTest {
29.33
29.34 @@ -44,19 +52,207 @@
29.35 KnockoutModel m = new KnockoutModel();
29.36 m.setName("Kukuc");
29.37 m.applyBindings();
29.38 - assert "Kukuc".equals(m.INPUT.getValue()) : "Value is really kukuc: " + m.INPUT.getValue();
29.39 - m.INPUT.setValue("Jardo");
29.40 - m.triggerEvent(m.INPUT, OnEvent.CHANGE);
29.41 + assert "Kukuc".equals(m.input.getValue()) : "Value is really kukuc: " + m.input.getValue();
29.42 + m.input.setValue("Jardo");
29.43 + m.triggerEvent(m.input, OnEvent.CHANGE);
29.44 assert "Jardo".equals(m.getName()) : "Name property updated: " + m.getName();
29.45 }
29.46
29.47 + @HtmlFragment(
29.48 + "<ul id='ul' data-bind='foreach: results'>\n"
29.49 + + " <li data-bind='text: $data, click: $root.call'/>\n"
29.50 + + "</ul>\n"
29.51 + )
29.52 + @BrwsrTest public void displayContentOfArray() {
29.53 + KnockoutModel m = new KnockoutModel();
29.54 + m.getResults().add("Ahoj");
29.55 + m.applyBindings();
29.56 +
29.57 + int cnt = countChildren("ul");
29.58 + assert cnt == 1 : "One child, but was " + cnt;
29.59 +
29.60 + m.getResults().add("Hi");
29.61 +
29.62 + cnt = countChildren("ul");
29.63 + assert cnt == 2 : "Two children now, but was " + cnt;
29.64 +
29.65 + triggerChildClick("ul", 1);
29.66 +
29.67 + assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
29.68 + assert "Hi".equals(m.getName()) : "We got callback from 2nd child " + m.getName();
29.69 + }
29.70 +
29.71 + @HtmlFragment(
29.72 + "<ul id='ul' data-bind='foreach: cmpResults'>\n"
29.73 + + " <li><b data-bind='text: $data'></b></li>\n"
29.74 + + "</ul>\n"
29.75 + )
29.76 + @BrwsrTest public void displayContentOfDerivedArray() {
29.77 + KnockoutModel m = new KnockoutModel();
29.78 + m.getResults().add("Ahoj");
29.79 + m.applyBindings();
29.80 +
29.81 + int cnt = countChildren("ul");
29.82 + assert cnt == 1 : "One child, but was " + cnt;
29.83 +
29.84 + m.getResults().add("hello");
29.85 +
29.86 + cnt = countChildren("ul");
29.87 + assert cnt == 2 : "Two children now, but was " + cnt;
29.88 + }
29.89 +
29.90 + @HtmlFragment(
29.91 + "<ul id='ul' data-bind='foreach: people'>\n"
29.92 + + " <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
29.93 + + "</ul>\n"
29.94 + )
29.95 + @BrwsrTest public void displayContentOfArrayOfPeople() {
29.96 + KnockoutModel m = new KnockoutModel();
29.97 +
29.98 + final Person first = new Person();
29.99 + first.setFirstName("first");
29.100 + m.getPeople().add(first);
29.101 +
29.102 + m.applyBindings();
29.103 +
29.104 + int cnt = countChildren("ul");
29.105 + assert cnt == 1 : "One child, but was " + cnt;
29.106 +
29.107 + final Person second = new Person();
29.108 + second.setFirstName("second");
29.109 + m.getPeople().add(second);
29.110 +
29.111 + cnt = countChildren("ul");
29.112 + assert cnt == 2 : "Two children now, but was " + cnt;
29.113 +
29.114 + triggerChildClick("ul", 1);
29.115 +
29.116 + assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
29.117 +
29.118 + cnt = countChildren("ul");
29.119 + assert cnt == 1 : "Again one child, but was " + cnt;
29.120 +
29.121 + String txt = childText("ul", 0);
29.122 + assert "first".equals(txt) : "Expecting 'first': " + txt;
29.123 +
29.124 + first.setFirstName("changed");
29.125 +
29.126 + txt = childText("ul", 0);
29.127 + assert "changed".equals(txt) : "Expecting 'changed': " + txt;
29.128 + }
29.129 +
29.130 + @ComputedProperty
29.131 + static Person firstPerson(List<Person> people) {
29.132 + return people.isEmpty() ? null : people.get(0);
29.133 + }
29.134 +
29.135 + @HtmlFragment(
29.136 + "<p id='ul' data-bind='with: firstPerson'>\n"
29.137 + + " <span data-bind='text: firstName, click: changeSex'></span>\n"
29.138 + + "</p>\n"
29.139 + )
29.140 + @BrwsrTest public void accessFirstPersonWithOnFunction() {
29.141 + trasfertToFemale();
29.142 + }
29.143 +
29.144 + @HtmlFragment(
29.145 + "<ul id='ul' data-bind='foreach: people'>\n"
29.146 + + " <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
29.147 + + "</ul>\n"
29.148 + )
29.149 + @BrwsrTest public void onPersonFunction() {
29.150 + trasfertToFemale();
29.151 + }
29.152 +
29.153 + private void trasfertToFemale() {
29.154 + KnockoutModel m = new KnockoutModel();
29.155 +
29.156 + final Person first = new Person();
29.157 + first.setFirstName("first");
29.158 + first.setSex(Sex.MALE);
29.159 + m.getPeople().add(first);
29.160 +
29.161 +
29.162 + m.applyBindings();
29.163 +
29.164 + int cnt = countChildren("ul");
29.165 + assert cnt == 1 : "One child, but was " + cnt;
29.166 +
29.167 +
29.168 + triggerChildClick("ul", 0);
29.169 +
29.170 + assert first.getSex() == Sex.FEMALE : "Transverted to female: " + first.getSex();
29.171 + }
29.172 +
29.173 + @Test public void cloneModel() {
29.174 + Person model = new Person();
29.175 +
29.176 + model.setFirstName("first");
29.177 + Person snd = model.clone();
29.178 + snd.setFirstName("clone");
29.179 + assertEquals("first", model.getFirstName(), "Value has not changed");
29.180 + assertEquals("clone", snd.getFirstName(), "Value has changed in clone");
29.181 + }
29.182 +
29.183 +
29.184 + @Test public void deepCopyOnClone() {
29.185 + People model = new People();
29.186 + model.getNicknames().add("Jarda");
29.187 + assertEquals(model.getNicknames().size(), 1, "One element");
29.188 + People snd = model.clone();
29.189 + snd.getNicknames().clear();
29.190 + assertEquals(snd.getNicknames().size(), 0, "Clone is empty");
29.191 + assertEquals(model.getNicknames().size(), 1, "Still one element");
29.192 + }
29.193 +
29.194 +
29.195 + @OnFunction
29.196 + static void call(KnockoutModel m, String data) {
29.197 + m.setName(data);
29.198 + m.setCallbackCount(m.getCallbackCount() + 1);
29.199 + }
29.200 +
29.201 + @OnFunction
29.202 + static void removePerson(KnockoutModel model, Person data) {
29.203 + model.setCallbackCount(model.getCallbackCount() + 1);
29.204 + model.getPeople().remove(data);
29.205 + }
29.206 +
29.207 +
29.208 @ComputedProperty
29.209 static String helloMessage(String name) {
29.210 return "Hello " + name + "!";
29.211 }
29.212
29.213 + @ComputedProperty
29.214 + static List<String> cmpResults(List<String> results) {
29.215 + return results;
29.216 + }
29.217 +
29.218 @Factory
29.219 public static Object[] create() {
29.220 return VMTest.create(KnockoutTest.class);
29.221 }
29.222 +
29.223 + @JavaScriptBody(args = { "id" }, body =
29.224 + "var e = window.document.getElementById(id);\n "
29.225 + + "if (typeof e === 'undefined') return -2;\n "
29.226 + + "return e.children.length;\n "
29.227 + )
29.228 + private static native int countChildren(String id);
29.229 +
29.230 + @JavaScriptBody(args = { "id", "pos" }, body =
29.231 + "var e = window.document.getElementById(id);\n "
29.232 + + "var ev = window.document.createEvent('MouseEvents');\n "
29.233 + + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
29.234 + + "e.children[pos].dispatchEvent(ev);\n "
29.235 + )
29.236 + private static native void triggerChildClick(String id, int pos);
29.237 +
29.238 + @JavaScriptBody(args = { "id", "pos" }, body =
29.239 + "var e = window.document.getElementById(id);\n "
29.240 + + "var t = e.children[pos].innerHTML;\n "
29.241 + + "return t ? t : null;"
29.242 + )
29.243 + private static native String childText(String id, int pos);
29.244 }
30.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Wed Feb 27 17:50:47 2013 +0100
30.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Oct 07 14:20:58 2013 +0200
30.3 @@ -18,8 +18,13 @@
30.4 package org.apidesign.bck2brwsr.htmlpage;
30.5
30.6 import java.util.ArrayList;
30.7 +import java.util.Collections;
30.8 +import java.util.Iterator;
30.9 import java.util.List;
30.10 +import java.util.ListIterator;
30.11 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
30.12 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
30.13 +import org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange;
30.14 import org.apidesign.bck2brwsr.htmlpage.api.Page;
30.15 import org.apidesign.bck2brwsr.htmlpage.api.Property;
30.16 import static org.testng.Assert.*;
30.17 @@ -30,17 +35,22 @@
30.18 *
30.19 * @author Jaroslav Tulach <jtulach@netbeans.org>
30.20 */
30.21 -@Page(xhtml = "Empty.html", className = "Model", properties = {
30.22 +@Page(xhtml = "Empty.html", className = "Modelik", properties = {
30.23 @Property(name = "value", type = int.class),
30.24 - @Property(name = "unrelated", type = long.class)
30.25 + @Property(name = "count", type = int.class),
30.26 + @Property(name = "unrelated", type = long.class),
30.27 + @Property(name = "names", type = String.class, array = true),
30.28 + @Property(name = "values", type = int.class, array = true),
30.29 + @Property(name = "people", type = PersonImpl.class, array = true),
30.30 + @Property(name = "changedProperty", type=String.class)
30.31 })
30.32 public class ModelTest {
30.33 - private Model model;
30.34 - private static Model leakedModel;
30.35 + private Modelik model;
30.36 + private static Modelik leakedModel;
30.37
30.38 @BeforeMethod
30.39 public void createModel() {
30.40 - model = new Model();
30.41 + model = new Modelik();
30.42 }
30.43
30.44 @Test public void classGeneratedWithSetterGetter() {
30.45 @@ -53,6 +63,75 @@
30.46 assertEquals(16, model.getPowerValue());
30.47 }
30.48
30.49 + @Test public void arrayIsMutable() {
30.50 + assertEquals(model.getNames().size(), 0, "Is empty");
30.51 + model.getNames().add("Jarda");
30.52 + assertEquals(model.getNames().size(), 1, "One element");
30.53 + }
30.54 +
30.55 + @Test public void arrayChangesNotified() {
30.56 + MockKnockout my = new MockKnockout();
30.57 + MockKnockout.next = my;
30.58 +
30.59 + model.applyBindings();
30.60 +
30.61 + model.getNames().add("Hello");
30.62 +
30.63 + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
30.64 + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
30.65 +
30.66 + my.mutated.clear();
30.67 +
30.68 + Iterator<String> it = model.getNames().iterator();
30.69 + assertEquals(it.next(), "Hello");
30.70 + it.remove();
30.71 +
30.72 + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
30.73 + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
30.74 +
30.75 + my.mutated.clear();
30.76 +
30.77 + ListIterator<String> lit = model.getNames().listIterator();
30.78 + lit.add("Jarda");
30.79 +
30.80 + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
30.81 + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
30.82 + }
30.83 +
30.84 + @Test public void autoboxedArray() {
30.85 + MockKnockout my = new MockKnockout();
30.86 + MockKnockout.next = my;
30.87 +
30.88 + model.applyBindings();
30.89 +
30.90 + model.getValues().add(10);
30.91 +
30.92 + assertEquals(model.getValues().get(0), Integer.valueOf(10), "Really ten");
30.93 + }
30.94 +
30.95 + @Test public void derivedArrayProp() {
30.96 + MockKnockout my = new MockKnockout();
30.97 + MockKnockout.next = my;
30.98 +
30.99 + model.applyBindings();
30.100 +
30.101 + model.setCount(10);
30.102 +
30.103 + List<String> arr = model.getRepeat();
30.104 + assertEquals(arr.size(), 10, "Ten items: " + arr);
30.105 +
30.106 + my.mutated.clear();
30.107 +
30.108 + model.setCount(5);
30.109 +
30.110 + arr = model.getRepeat();
30.111 + assertEquals(arr.size(), 5, "Five items: " + arr);
30.112 +
30.113 + assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
30.114 + assertTrue(my.mutated.contains("repeat"), "Array is in there: " + my.mutated);
30.115 + assertTrue(my.mutated.contains("count"), "Count is in there: " + my.mutated);
30.116 + }
30.117 +
30.118 @Test public void derivedPropertiesAreNotified() {
30.119 MockKnockout my = new MockKnockout();
30.120 MockKnockout.next = my;
30.121 @@ -61,6 +140,9 @@
30.122
30.123 model.setValue(33);
30.124
30.125 + // not interested in change of this property
30.126 + my.mutated.remove("changedProperty");
30.127 +
30.128 assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
30.129 assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated);
30.130 assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated);
30.131 @@ -68,7 +150,11 @@
30.132 my.mutated.clear();
30.133
30.134 model.setUnrelated(44);
30.135 - assertEquals(my.mutated.size(), 1, "One property changed");
30.136 +
30.137 +
30.138 + // not interested in change of this property
30.139 + my.mutated.remove("changedProperty");
30.140 + assertEquals(my.mutated.size(), 1, "One property changed: " + my.mutated);
30.141 assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated");
30.142 }
30.143
30.144 @@ -92,11 +178,43 @@
30.145 }
30.146 }
30.147
30.148 + @OnFunction
30.149 + static void doSomething() {
30.150 + }
30.151 +
30.152 @ComputedProperty
30.153 static int powerValue(int value) {
30.154 return value * value;
30.155 }
30.156
30.157 + @OnPropertyChange({ "powerValue", "unrelated" })
30.158 + static void aPropertyChanged(Modelik m, String name) {
30.159 + m.setChangedProperty(name);
30.160 + }
30.161 +
30.162 + @OnPropertyChange({ "values" })
30.163 + static void anArrayPropertyChanged(String name, Modelik m) {
30.164 + m.setChangedProperty(name);
30.165 + }
30.166 +
30.167 + @Test public void changeAnything() {
30.168 + model.setCount(44);
30.169 + assertNull(model.getChangedProperty(), "No observed value change");
30.170 + }
30.171 + @Test public void changeValue() {
30.172 + model.setValue(33);
30.173 + assertEquals(model.getChangedProperty(), "powerValue", "power property changed");
30.174 + }
30.175 + @Test public void changeUnrelated() {
30.176 + model.setUnrelated(333);
30.177 + assertEquals(model.getChangedProperty(), "unrelated", "unrelated changed");
30.178 + }
30.179 +
30.180 + @Test public void changeInArray() {
30.181 + model.getValues().add(10);
30.182 + assertEquals(model.getChangedProperty(), "values", "Something added into the array");
30.183 + }
30.184 +
30.185 @ComputedProperty
30.186 static String notAllowedRead() {
30.187 return "Not allowed callback: " + leakedModel.getUnrelated();
30.188 @@ -108,12 +226,31 @@
30.189 return "Not allowed callback!";
30.190 }
30.191
30.192 + @ComputedProperty
30.193 + static List<String> repeat(int count) {
30.194 + return Collections.nCopies(count, "Hello");
30.195 + }
30.196 +
30.197 static class MockKnockout extends Knockout {
30.198 - List<String> mutated = new ArrayList<String>();
30.199 + List<String> mutated = new ArrayList<>();
30.200 +
30.201 + MockKnockout() {
30.202 + super(null);
30.203 + }
30.204
30.205 @Override
30.206 public void valueHasMutated(String prop) {
30.207 mutated.add(prop);
30.208 }
30.209 }
30.210 +
30.211 + public @Test void hasPersonPropertyAndComputedFullName() {
30.212 + List<Person> arr = model.getPeople();
30.213 + assertEquals(arr.size(), 0, "By default empty");
30.214 + Person p = null;
30.215 + if (p != null) {
30.216 + String fullNameGenerated = p.getFullName();
30.217 + assertNotNull(fullNameGenerated);
30.218 + }
30.219 + }
30.220 }
31.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Wed Feb 27 17:50:47 2013 +0100
31.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Mon Oct 07 14:20:58 2013 +0200
31.3 @@ -50,7 +50,7 @@
31.4 if (PAGE != ref) {
31.5 throw new IllegalStateException("Both references should be the same. " + ref + " != " + PAGE);
31.6 }
31.7 - ref.PG_TITLE.setText("You want this window to be named " + ref.PG_TEXT.getValue());
31.8 + ref.pg_title.setText("You want this window to be named " + ref.pg_text.getValue());
31.9 }
31.10
31.11 @On(event = CLICK, id={ "pg.title", "pg.text" })
31.12 @@ -58,6 +58,11 @@
31.13 if (!id.equals("pg.title")) {
31.14 throw new IllegalStateException();
31.15 }
31.16 - PAGE.PG_TITLE.setText(id);
31.17 + PAGE.pg_title.setText(id);
31.18 + }
31.19 +
31.20 + @On(event = CLICK, id={ "pg.canvas" })
31.21 + static void clickCanvas(String id, double layerX) {
31.22 + PAGE.pg_canvas.setWidth((int) layerX);
31.23 }
31.24 }
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageTest.java Mon Oct 07 14:20:58 2013 +0200
32.3 @@ -0,0 +1,53 @@
32.4 +/**
32.5 + * Back 2 Browser Bytecode Translator
32.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
32.7 + *
32.8 + * This program is free software: you can redistribute it and/or modify
32.9 + * it under the terms of the GNU General Public License as published by
32.10 + * the Free Software Foundation, version 2 of the License.
32.11 + *
32.12 + * This program is distributed in the hope that it will be useful,
32.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
32.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.15 + * GNU General Public License for more details.
32.16 + *
32.17 + * You should have received a copy of the GNU General Public License
32.18 + * along with this program. Look for COPYING file in the top folder.
32.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
32.20 + */
32.21 +package org.apidesign.bck2brwsr.htmlpage;
32.22 +
32.23 +import java.io.IOException;
32.24 +import java.util.Locale;
32.25 +import javax.tools.Diagnostic;
32.26 +import javax.tools.JavaFileObject;
32.27 +import static org.testng.Assert.*;
32.28 +import org.testng.annotations.Test;
32.29 +
32.30 +/** Verify errors emitted by the processor.
32.31 + *
32.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
32.33 + */
32.34 +public class PageTest {
32.35 + @Test public void verifyWrongType() throws IOException {
32.36 + String html = "<html><body>"
32.37 + + "</body></html>";
32.38 + String code = "package x.y.z;\n"
32.39 + + "import org.apidesign.bck2brwsr.htmlpage.api.*;\n"
32.40 + + "@Page(xhtml=\"index.xhtml\", className=\"Model\", properties={\n"
32.41 + + " @Property(name=\"prop\", type=Runnable.class)\n"
32.42 + + "})\n"
32.43 + + "class X {\n"
32.44 + + "}\n";
32.45 +
32.46 + Compile c = Compile.create(html, code);
32.47 + assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
32.48 + for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
32.49 + String msg = e.getMessage(Locale.ENGLISH);
32.50 + if (!msg.contains("Runnable")) {
32.51 + fail("Should contain warning about Runnable: " + msg);
32.52 + }
32.53 + }
32.54 + }
32.55 +
32.56 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PersonImpl.java Mon Oct 07 14:20:58 2013 +0200
33.3 @@ -0,0 +1,62 @@
33.4 +/**
33.5 + * Back 2 Browser Bytecode Translator
33.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
33.7 + *
33.8 + * This program is free software: you can redistribute it and/or modify
33.9 + * it under the terms of the GNU General Public License as published by
33.10 + * the Free Software Foundation, version 2 of the License.
33.11 + *
33.12 + * This program is distributed in the hope that it will be useful,
33.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
33.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33.15 + * GNU General Public License for more details.
33.16 + *
33.17 + * You should have received a copy of the GNU General Public License
33.18 + * along with this program. Look for COPYING file in the top folder.
33.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
33.20 + */
33.21 +package org.apidesign.bck2brwsr.htmlpage;
33.22 +
33.23 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
33.24 +import org.apidesign.bck2brwsr.htmlpage.api.Model;
33.25 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
33.26 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
33.27 +
33.28 +/**
33.29 + *
33.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
33.31 + */
33.32 +@Model(className = "Person", properties = {
33.33 + @Property(name = "firstName", type = String.class),
33.34 + @Property(name = "lastName", type = String.class),
33.35 + @Property(name = "sex", type = Sex.class)
33.36 +})
33.37 +final class PersonImpl {
33.38 + @ComputedProperty
33.39 + public static String fullName(String firstName, String lastName) {
33.40 + return firstName + " " + lastName;
33.41 + }
33.42 +
33.43 + @ComputedProperty
33.44 + public static String sexType(Sex sex) {
33.45 + return sex == null ? "unknown" : sex.toString();
33.46 + }
33.47 +
33.48 + @OnFunction
33.49 + static void changeSex(Person p) {
33.50 + if (p.getSex() == Sex.MALE) {
33.51 + p.setSex(Sex.FEMALE);
33.52 + } else {
33.53 + p.setSex(Sex.MALE);
33.54 + }
33.55 + }
33.56 +
33.57 + @Model(className = "People", properties = {
33.58 + @Property(array = true, name = "info", type = Person.class),
33.59 + @Property(array = true, name = "nicknames", type = String.class),
33.60 + @Property(array = true, name = "age", type = int.class),
33.61 + @Property(array = true, name = "sex", type = Sex.class)
33.62 + })
33.63 + public class PeopleImpl {
33.64 + }
33.65 +}
34.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Wed Feb 27 17:50:47 2013 +0100
34.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Mon Oct 07 14:20:58 2013 +0200
34.3 @@ -36,11 +36,12 @@
34.4 assertNotNull(is, "Sample HTML page found");
34.5 ProcessPage res = ProcessPage.readPage(is);
34.6 final Set<String> ids = res.ids();
34.7 - assertEquals(ids.size(), 3, "Three ids found: " + ids);
34.8 + assertEquals(ids.size(), 4, "Four ids found: " + ids);
34.9
34.10 assertEquals(res.tagNameForId("pg.title"), "title");
34.11 assertEquals(res.tagNameForId("pg.button"), "button");
34.12 assertEquals(res.tagNameForId("pg.text"), "input");
34.13 + assertEquals(res.tagNameForId("pg.canvas"), "canvas");
34.14 }
34.15
34.16 @Test public void testCompileAndRunPageController() throws Exception {
34.17 @@ -53,11 +54,13 @@
34.18 + "doc.title.innerHTML = 'nothing';\n"
34.19 + "doc.text = new Object();\n"
34.20 + "doc.text.value = 'something';\n"
34.21 + + "doc.canvas = new Object();\n"
34.22 + "doc.getElementById = function(id) {\n"
34.23 + " switch(id) {\n"
34.24 + " case 'pg.button': return doc.button;\n"
34.25 + " case 'pg.title': return doc.title;\n"
34.26 + " case 'pg.text': return doc.text;\n"
34.27 + + " case 'pg.canvas': return doc.canvas;\n"
34.28 + " }\n"
34.29 + " throw id;\n"
34.30 + " }\n"
34.31 @@ -92,11 +95,13 @@
34.32 + "doc.title.innerHTML = 'nothing';\n"
34.33 + "doc.text = new Object();\n"
34.34 + "doc.text.value = 'something';\n"
34.35 + + "doc.canvas = new Object();\n"
34.36 + "doc.getElementById = function(id) {\n"
34.37 + " switch(id) {\n"
34.38 + " case 'pg.button': return doc.button;\n"
34.39 + " case 'pg.title': return doc.title;\n"
34.40 + " case 'pg.text': return doc.text;\n"
34.41 + + " case 'pg.canvas': return doc.canvas;\n"
34.42 + " }\n"
34.43 + " throw id;\n"
34.44 + " }\n"
34.45 @@ -123,12 +128,61 @@
34.46 assertEquals(ret, "pg.title", "Title has been passed to the method argument");
34.47 }
34.48
34.49 + @Test public void clickWithArgumentAndParameterCalled() throws Exception {
34.50 + StringBuilder sb = new StringBuilder();
34.51 + sb.append(
34.52 + "var window = new Object();\n"
34.53 + + "var doc = new Object();\n"
34.54 + + "var eventObject = new Object();\n"
34.55 + + "eventObject.layerX = 100;\n"
34.56 + + "doc.button = new Object();\n"
34.57 + + "doc.title = new Object();\n"
34.58 + + "doc.title.innerHTML = 'nothing';\n"
34.59 + + "doc.text = new Object();\n"
34.60 + + "doc.text.value = 'something';\n"
34.61 + + "doc.canvas = new Object();\n"
34.62 + + "doc.canvas.width = 200;\n"
34.63 + + "doc.getElementById = function(id) {\n"
34.64 + + " switch(id) {\n"
34.65 + + " case 'pg.button': return doc.button;\n"
34.66 + + " case 'pg.title': return doc.title;\n"
34.67 + + " case 'pg.text': return doc.text;\n"
34.68 + + " case 'pg.canvas': return doc.canvas;\n"
34.69 + + " }\n"
34.70 + + " throw id;\n"
34.71 + + " }\n"
34.72 + + "\n"
34.73 + + "function clickAndCheck() {\n"
34.74 + + " doc.canvas.onclick(eventObject);\n"
34.75 + + " return doc.canvas.width.toString();\n"
34.76 + + "};\n"
34.77 + + "\n"
34.78 + + "window.document = doc;\n"
34.79 + );
34.80 + Invocable i = compileClass(sb,
34.81 + "org/apidesign/bck2brwsr/htmlpage/PageController"
34.82 + );
34.83 +
34.84 + Object ret = null;
34.85 + try {
34.86 + ret = i.invokeFunction("clickAndCheck");
34.87 + } catch (ScriptException ex) {
34.88 + fail("Execution failed in " + sb, ex);
34.89 + } catch (NoSuchMethodException ex) {
34.90 + fail("Cannot find method in " + sb, ex);
34.91 + }
34.92 + assertEquals(ret, "100", "layerX has been passed to the method argument");
34.93 + }
34.94 +
34.95 static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException {
34.96 if (sb == null) {
34.97 sb = new StringBuilder();
34.98 }
34.99 Bck2Brwsr.generate(sb, ProcessPageTest.class.getClassLoader(), names);
34.100 sb.append("var vm = this.bck2brwsr();\n");
34.101 + for (String c : names) {
34.102 + sb.append("vm.loadClass('").append(c.replace('/', '.')).append("');\n");
34.103 + }
34.104
34.105 ScriptEngineManager sem = new ScriptEngineManager();
34.106 ScriptEngine js = sem.getEngineByExtension("js");
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Sex.java Mon Oct 07 14:20:58 2013 +0200
35.3 @@ -0,0 +1,26 @@
35.4 +/**
35.5 + * Back 2 Browser Bytecode Translator
35.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
35.7 + *
35.8 + * This program is free software: you can redistribute it and/or modify
35.9 + * it under the terms of the GNU General Public License as published by
35.10 + * the Free Software Foundation, version 2 of the License.
35.11 + *
35.12 + * This program is distributed in the hope that it will be useful,
35.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
35.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35.15 + * GNU General Public License for more details.
35.16 + *
35.17 + * You should have received a copy of the GNU General Public License
35.18 + * along with this program. Look for COPYING file in the top folder.
35.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
35.20 + */
35.21 +package org.apidesign.bck2brwsr.htmlpage;
35.22 +
35.23 +/**
35.24 + *
35.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
35.26 + */
35.27 +public enum Sex {
35.28 + MALE, FEMALE;
35.29 +}
36.1 --- a/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html Wed Feb 27 17:50:47 2013 +0100
36.2 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html Mon Oct 07 14:20:58 2013 +0200
36.3 @@ -26,5 +26,6 @@
36.4 <body>
36.5 New title: <input id="pg.text"/>
36.6 <button id="pg.button">Change title!</button>
36.7 + <canvas id="pg.canvas" width="100"/>
36.8 </body>
36.9 </html>
37.1 --- a/javaquery/demo-calculator-dynamic/nbactions.xml Wed Feb 27 17:50:47 2013 +0100
37.2 +++ b/javaquery/demo-calculator-dynamic/nbactions.xml Mon Oct 07 14:20:58 2013 +0200
37.3 @@ -23,7 +23,7 @@
37.4 <actionName>run</actionName>
37.5 <goals>
37.6 <goal>process-classes</goal>
37.7 - <goal>org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr</goal>
37.8 + <goal>bck2brwsr:brwsr</goal>
37.9 </goals>
37.10 </action>
37.11 </actions>
38.1 --- a/javaquery/demo-calculator-dynamic/pom.xml Wed Feb 27 17:50:47 2013 +0100
38.2 +++ b/javaquery/demo-calculator-dynamic/pom.xml Mon Oct 07 14:20:58 2013 +0200
38.3 @@ -1,11 +1,10 @@
38.4 <?xml version="1.0"?>
38.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38.6 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
38.7 +<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/xsd/maven-4.0.0.xsd">
38.8 <modelVersion>4.0.0</modelVersion>
38.9
38.10 <groupId>org.apidesign.bck2brwsr</groupId>
38.11 <artifactId>demo.calculator</artifactId>
38.12 - <version>0.3-SNAPSHOT</version>
38.13 + <version>0.9-SNAPSHOT</version>
38.14 <packaging>jar</packaging>
38.15
38.16 <name>JavaQuery Demo - Calculator</name>
38.17 @@ -18,8 +17,8 @@
38.18 <plugins>
38.19 <plugin>
38.20 <groupId>org.apidesign.bck2brwsr</groupId>
38.21 - <artifactId>mojo</artifactId>
38.22 - <version>0.3-SNAPSHOT</version>
38.23 + <artifactId>bck2brwsr-maven-plugin</artifactId>
38.24 + <version>${project.version}</version>
38.25 <executions>
38.26 <execution>
38.27 <goals>
38.28 @@ -62,6 +61,14 @@
38.29 </configuration>
38.30 </plugin>
38.31 <plugin>
38.32 + <groupId>org.apache.maven.plugins</groupId>
38.33 + <artifactId>maven-javadoc-plugin</artifactId>
38.34 + <version>2.9</version>
38.35 + <configuration>
38.36 + <skip>true</skip>
38.37 + </configuration>
38.38 + </plugin>
38.39 + <plugin>
38.40 <artifactId>maven-assembly-plugin</artifactId>
38.41 <version>2.4</version>
38.42 <executions>
38.43 @@ -86,13 +93,13 @@
38.44 <dependency>
38.45 <groupId>org.apidesign.bck2brwsr</groupId>
38.46 <artifactId>emul</artifactId>
38.47 - <version>0.3-SNAPSHOT</version>
38.48 + <version>${project.version}</version>
38.49 <classifier>rt</classifier>
38.50 </dependency>
38.51 <dependency>
38.52 <groupId>org.apidesign.bck2brwsr</groupId>
38.53 <artifactId>javaquery.api</artifactId>
38.54 - <version>0.3-SNAPSHOT</version>
38.55 + <version>${project.version}</version>
38.56 </dependency>
38.57 <dependency>
38.58 <groupId>org.testng</groupId>
38.59 @@ -105,7 +112,7 @@
38.60 <artifactId>vm4brwsr</artifactId>
38.61 <classifier>js</classifier>
38.62 <type>zip</type>
38.63 - <version>0.3-SNAPSHOT</version>
38.64 + <version>${project.version}</version>
38.65 <scope>provided</scope>
38.66 </dependency>
38.67 </dependencies>
39.1 --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Wed Feb 27 17:50:47 2013 +0100
39.2 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Mon Oct 07 14:20:58 2013 +0200
39.3 @@ -17,9 +17,11 @@
39.4 */
39.5 package org.apidesign.bck2brwsr.demo.calc;
39.6
39.7 +import java.util.List;
39.8 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
39.9 import org.apidesign.bck2brwsr.htmlpage.api.On;
39.10 import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
39.11 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
39.12 import org.apidesign.bck2brwsr.htmlpage.api.Page;
39.13 import org.apidesign.bck2brwsr.htmlpage.api.Property;
39.14
39.15 @@ -33,11 +35,12 @@
39.16 @Property(name = "memory", type = double.class),
39.17 @Property(name = "display", type = double.class),
39.18 @Property(name = "operation", type = String.class),
39.19 - @Property(name = "hover", type = boolean.class)
39.20 + @Property(name = "hover", type = boolean.class),
39.21 + @Property(name = "history", type = HistoryImpl.class, array = true)
39.22 })
39.23 public class Calc {
39.24 static {
39.25 - new Calculator().applyBindings();
39.26 + new Calculator().applyBindings().setOperation("plus");
39.27 }
39.28
39.29 @On(event = CLICK, id="clear")
39.30 @@ -48,31 +51,48 @@
39.31 }
39.32
39.33 @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
39.34 - static void applyOp(Calculator c, String op) {
39.35 + static void applyOp(Calculator c, String id) {
39.36 c.setMemory(c.getDisplay());
39.37 - c.setOperation(op);
39.38 + c.setOperation(id);
39.39 c.setDisplay(0);
39.40 }
39.41
39.42 @On(event = MOUSE_OVER, id= { "result" })
39.43 - static void attemptingIn(Calculator c, String op) {
39.44 + static void attemptingIn(Calculator c) {
39.45 c.setHover(true);
39.46 }
39.47 @On(event = MOUSE_OUT, id= { "result" })
39.48 - static void attemptingOut(Calculator c, String op) {
39.49 + static void attemptingOut(Calculator c) {
39.50 c.setHover(false);
39.51 }
39.52
39.53 @On(event = CLICK, id="result")
39.54 static void computeTheValue(Calculator c) {
39.55 - c.setDisplay(compute(
39.56 + final double newValue = compute(
39.57 c.getOperation(),
39.58 c.getMemory(),
39.59 c.getDisplay()
39.60 - ));
39.61 + );
39.62 + c.setDisplay(newValue);
39.63 + if (!containsValue(c.getHistory(), newValue)) {
39.64 + History h = new History();
39.65 + h.setValue(newValue);
39.66 + h.setOperation(c.getOperation());
39.67 + c.getHistory().add(h);
39.68 + }
39.69 c.setMemory(0);
39.70 }
39.71
39.72 + @OnFunction
39.73 + static void recoverMemory(Calculator c, History data) {
39.74 + c.setDisplay(data.getValue());
39.75 + }
39.76 +
39.77 + @OnFunction
39.78 + static void removeMemory(Calculator c, History data) {
39.79 + c.getHistory().remove(data);
39.80 + }
39.81 +
39.82 private static double compute(String op, double memory, double display) {
39.83 switch (op) {
39.84 case "plus": return memory + display;
39.85 @@ -84,18 +104,18 @@
39.86 }
39.87
39.88 @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
39.89 - static void addDigit(String digit, Calculator c) {
39.90 - digit = digit.substring(1);
39.91 + static void addDigit(String id, Calculator c) {
39.92 + id = id.substring(1);
39.93
39.94 double v = c.getDisplay();
39.95 if (v == 0.0) {
39.96 - c.setDisplay(Integer.parseInt(digit));
39.97 + c.setDisplay(Integer.parseInt(id));
39.98 } else {
39.99 String txt = Double.toString(v);
39.100 if (txt.endsWith(".0")) {
39.101 txt = txt.substring(0, txt.length() - 2);
39.102 }
39.103 - txt = txt + digit;
39.104 + txt = txt + id;
39.105 c.setDisplay(Double.parseDouble(txt));
39.106 }
39.107 }
39.108 @@ -109,4 +129,18 @@
39.109 }
39.110 return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display);
39.111 }
39.112 +
39.113 + @ComputedProperty
39.114 + static boolean emptyHistory(List<?> history) {
39.115 + return history.isEmpty();
39.116 + }
39.117 +
39.118 + private static boolean containsValue(List<History> arr, final double newValue) {
39.119 + for (History history : arr) {
39.120 + if (history.getValue() == newValue) {
39.121 + return true;
39.122 + }
39.123 + }
39.124 + return false;
39.125 + }
39.126 }
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/HistoryImpl.java Mon Oct 07 14:20:58 2013 +0200
40.3 @@ -0,0 +1,43 @@
40.4 +/**
40.5 + * Back 2 Browser Bytecode Translator
40.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
40.7 + *
40.8 + * This program is free software: you can redistribute it and/or modify
40.9 + * it under the terms of the GNU General Public License as published by
40.10 + * the Free Software Foundation, version 2 of the License.
40.11 + *
40.12 + * This program is distributed in the hope that it will be useful,
40.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
40.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40.15 + * GNU General Public License for more details.
40.16 + *
40.17 + * You should have received a copy of the GNU General Public License
40.18 + * along with this program. Look for COPYING file in the top folder.
40.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
40.20 + */
40.21 +package org.apidesign.bck2brwsr.demo.calc;
40.22 +
40.23 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
40.24 +import org.apidesign.bck2brwsr.htmlpage.api.Model;
40.25 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
40.26 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
40.27 +
40.28 +/**
40.29 + *
40.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
40.31 + */
40.32 +@Model(className = "History", properties = {
40.33 + @Property(name = "value", type = double.class),
40.34 + @Property(name = "operation", type = String.class)
40.35 +})
40.36 +public class HistoryImpl {
40.37 + @ComputedProperty
40.38 + static String resultOf(String operation) {
40.39 + return "result of " + operation;
40.40 + }
40.41 +
40.42 + @OnFunction
40.43 + static void twice(History data) {
40.44 + data.setValue(2.0 * data.getValue());
40.45 + }
40.46 +}
41.1 --- a/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Wed Feb 27 17:50:47 2013 +0100
41.2 +++ b/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Mon Oct 07 14:20:58 2013 +0200
41.3 @@ -78,82 +78,25 @@
41.4 </table>
41.5 <div data-bind="text: displayPreview"></div>
41.6
41.7 + <h4>Previous Results</h4>
41.8 +
41.9 + <div data-bind="if: emptyHistory">No results yet.</div>
41.10 + <ul data-bind="foreach: history">
41.11 + <li>
41.12 + <span data-bind="text: $data.value"></span> -
41.13 + <a href="#" data-bind="click: $root.recoverMemory">Use</a>
41.14 + <a href="#" data-bind="click: $root.removeMemory">Remove</a>
41.15 + <a href="#" data-bind="click: $data.twice">Double</a> -
41.16 + <span data-bind="text: $data.resultOf"></span>
41.17 + </li>
41.18 + </ul>
41.19 +
41.20 <script src="bck2brwsr.js"></script>
41.21 <script type="text/javascript">
41.22 - var vm = bck2brwsr('demo.calculator-0.3-SNAPSHOT.jar');
41.23 + var vm = bck2brwsr('demo.calculator-0.6.jar');
41.24 vm.loadClass('org.apidesign.bck2brwsr.demo.calc.Calc');
41.25 </script>
41.26
41.27 <hr/>
41.28 - <pre>
41.29 - <span class="keyword-directive">package</span> org.apidesign.bck2brwsr.mavenhtml;
41.30 -
41.31 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.OnClick;
41.32 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.Page;
41.33 -
41.34 - <span class="comment">/**</span> <span class="comment">HTML5</span><span class="comment"> & </span><span class="comment">Java</span> <span class="comment">demo</span> <span class="comment">showing</span> <span class="comment">the</span> <span class="comment">power</span> <span class="comment">of</span> <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
41.35 - <span class="comment"> * </span><span class="comment">as</span> <span class="comment">well</span> <span class="comment">as</span> <span class="comment">other</span> <span class="comment">goodies</span><span class="comment">, including type-safe association between</span>
41.36 - <span class="comment"> * </span><span class="comment">an XHTML page and Java.</span>
41.37 - <span class="comment"> * </span>
41.38 - <span class="comment"> * </span><span class="ST1">@author</span> <span class="comment">Jaroslav</span> <span class="comment">Tulach</span> <span class="ST0"><jaroslav.tulach@apidesign.org></span>
41.39 - <span class="comment">*/</span>
41.40 - @Page(xhtml=<span class="string">"</span><span class="string">Calculator.xhtml</span><span class="string">"</span>)
41.41 - <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> App {
41.42 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> memory;
41.43 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> String operation;
41.44 -
41.45 - @OnClick(id=<span class="string">"</span><span class="string">clear</span><span class="string">"</span>)
41.46 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> clear() {
41.47 - memory = <span class="number">0</span>;
41.48 - operation = <span class="keyword-directive">null</span>;
41.49 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
41.50 - }
41.51 -
41.52 - @OnClick(id= { <span class="string">"</span><span class="string">plus</span><span class="string">"</span>, <span class="string">"</span><span class="string">minus</span><span class="string">"</span>, <span class="string">"</span><span class="string">mul</span><span class="string">"</span>, <span class="string">"</span><span class="string">div</span><span class="string">"</span> })
41.53 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> applyOp(String op) {
41.54 - memory = getValue();
41.55 - operation = op;
41.56 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
41.57 - }
41.58 -
41.59 - @OnClick(id=<span class="string">"</span><span class="string">result</span><span class="string">"</span>)
41.60 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> computeTheValue() {
41.61 - <span class="keyword-directive">switch</span> (operation) {
41.62 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">plus</span><span class="string">"</span>: setValue(memory + getValue()); <span class="keyword-directive">break</span>;
41.63 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">minus</span><span class="string">"</span>: setValue(memory - getValue()); <span class="keyword-directive">break</span>;
41.64 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">mul</span><span class="string">"</span>: setValue(memory * getValue()); <span class="keyword-directive">break</span>;
41.65 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">div</span><span class="string">"</span>: setValue(memory / getValue()); <span class="keyword-directive">break</span>;
41.66 - <span class="keyword-directive">default</span>: <span class="keyword-directive">throw</span> <span class="keyword-directive">new</span> IllegalStateException(operation);
41.67 - }
41.68 - }
41.69 -
41.70 - @OnClick(id={<span class="string">"</span><span class="string">n0</span><span class="string">"</span>, <span class="string">"</span><span class="string">n1</span><span class="string">"</span>, <span class="string">"</span><span class="string">n2</span><span class="string">"</span>, <span class="string">"</span><span class="string">n3</span><span class="string">"</span>, <span class="string">"</span><span class="string">n4</span><span class="string">"</span>, <span class="string">"</span><span class="string">n5</span><span class="string">"</span>, <span class="string">"</span><span class="string">n6</span><span class="string">"</span>, <span class="string">"</span><span class="string">n7</span><span class="string">"</span>, <span class="string">"</span><span class="string">n8</span><span class="string">"</span>, <span class="string">"</span><span class="string">n9</span><span class="string">"</span>})
41.71 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> addDigit(String digit) {
41.72 - digit = digit.substring(<span class="number">1</span>);
41.73 - String v = Calculator.DISPLAY.getValue();
41.74 - <span class="keyword-directive">if</span> (getValue() == <span class="number">0.0</span>) {
41.75 - Calculator.DISPLAY.setValue(digit);
41.76 - } <span class="keyword-directive">else</span> {
41.77 - Calculator.DISPLAY.setValue(v + digit);
41.78 - }
41.79 - }
41.80 -
41.81 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> setValue(<span class="keyword-directive">double</span> v) {
41.82 - StringBuilder sb = <span class="keyword-directive">new</span> StringBuilder();
41.83 - sb.append(v);
41.84 - Calculator.DISPLAY.setValue(sb.toString());
41.85 - }
41.86 -
41.87 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> getValue() {
41.88 - <span class="keyword-directive">try</span> {
41.89 - <span class="keyword-directive">return</span> Double.parseDouble(Calculator.DISPLAY.getValue());
41.90 - } <span class="keyword-directive">catch</span> (NumberFormatException ex) {
41.91 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">err</span><span class="string">"</span>);
41.92 - <span class="keyword-directive">return</span> <span class="number">0.0</span>;
41.93 - }
41.94 - }
41.95 - }
41.96 -
41.97 - </pre>
41.98 </body>
41.99 </html>
42.1 --- a/javaquery/demo-calculator/nbactions.xml Wed Feb 27 17:50:47 2013 +0100
42.2 +++ b/javaquery/demo-calculator/nbactions.xml Mon Oct 07 14:20:58 2013 +0200
42.3 @@ -23,7 +23,7 @@
42.4 <actionName>run</actionName>
42.5 <goals>
42.6 <goal>package</goal>
42.7 - <goal>org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr</goal>
42.8 + <goal>bck2brwsr:brwsr</goal>
42.9 </goals>
42.10 <properties>
42.11 <skipTests>true</skipTests>
43.1 --- a/javaquery/demo-calculator/pom.xml Wed Feb 27 17:50:47 2013 +0100
43.2 +++ b/javaquery/demo-calculator/pom.xml Mon Oct 07 14:20:58 2013 +0200
43.3 @@ -1,11 +1,10 @@
43.4 <?xml version="1.0"?>
43.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
43.6 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
43.7 +<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/xsd/maven-4.0.0.xsd">
43.8 <modelVersion>4.0.0</modelVersion>
43.9
43.10 <groupId>org.apidesign.bck2brwsr</groupId>
43.11 <artifactId>demo.static.calculator</artifactId>
43.12 - <version>0.3-SNAPSHOT</version>
43.13 + <version>0.9-SNAPSHOT</version>
43.14 <packaging>jar</packaging>
43.15
43.16 <name>JavaQuery Demo - Calculator - Static Compilation</name>
43.17 @@ -13,16 +12,18 @@
43.18
43.19 <properties>
43.20 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
43.21 + <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
43.22 </properties>
43.23 <build>
43.24 <plugins>
43.25 <plugin>
43.26 <groupId>org.apidesign.bck2brwsr</groupId>
43.27 - <artifactId>mojo</artifactId>
43.28 - <version>0.3-SNAPSHOT</version>
43.29 + <artifactId>bck2brwsr-maven-plugin</artifactId>
43.30 + <version>${project.version}</version>
43.31 <executions>
43.32 <execution>
43.33 <goals>
43.34 + <goal>j2js</goal>
43.35 <goal>brwsr</goal>
43.36 </goals>
43.37 </execution>
43.38 @@ -30,6 +31,8 @@
43.39 <configuration>
43.40 <directory>${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/</directory>
43.41 <startpage>index.xhtml</startpage>
43.42 + <javascript>${project.build.directory}/bck2brwsr.js</javascript>
43.43 + <obfuscation>${bck2brwsr.obfuscationlevel}</obfuscation>
43.44 </configuration>
43.45 </plugin>
43.46 <plugin>
43.47 @@ -80,6 +83,14 @@
43.48 <skip>true</skip>
43.49 </configuration>
43.50 </plugin>
43.51 + <plugin>
43.52 + <groupId>org.apache.maven.plugins</groupId>
43.53 + <artifactId>maven-javadoc-plugin</artifactId>
43.54 + <version>2.9</version>
43.55 + <configuration>
43.56 + <skip>true</skip>
43.57 + </configuration>
43.58 + </plugin>
43.59 </plugins>
43.60 </build>
43.61
43.62 @@ -87,21 +98,13 @@
43.63 <dependency>
43.64 <groupId>org.apidesign.bck2brwsr</groupId>
43.65 <artifactId>emul</artifactId>
43.66 - <version>0.3-SNAPSHOT</version>
43.67 + <version>${project.version}</version>
43.68 <classifier>rt</classifier>
43.69 </dependency>
43.70 <dependency>
43.71 <groupId>org.apidesign.bck2brwsr</groupId>
43.72 <artifactId>javaquery.api</artifactId>
43.73 - <version>0.3-SNAPSHOT</version>
43.74 - </dependency>
43.75 - <dependency>
43.76 - <groupId>org.apidesign.bck2brwsr</groupId>
43.77 - <artifactId>vm4brwsr</artifactId>
43.78 - <classifier>js</classifier>
43.79 - <type>zip</type>
43.80 - <version>0.3-SNAPSHOT</version>
43.81 - <scope>provided</scope>
43.82 + <version>${project.version}</version>
43.83 </dependency>
43.84 </dependencies>
43.85 </project>
44.1 --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Wed Feb 27 17:50:47 2013 +0100
44.2 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Mon Oct 07 14:20:58 2013 +0200
44.3 @@ -37,15 +37,6 @@
44.4 <include>*:rt</include>
44.5 </includes>
44.6 </dependencySet>
44.7 - <dependencySet>
44.8 - <useProjectArtifact>false</useProjectArtifact>
44.9 - <scope>provided</scope>
44.10 - <includes>
44.11 - <include>*:js</include>
44.12 - </includes>
44.13 - <unpack>true</unpack>
44.14 - <outputDirectory>/</outputDirectory>
44.15 - </dependencySet>
44.16 </dependencySets>
44.17 <files>
44.18 <file>
44.19 @@ -53,6 +44,10 @@
44.20 <outputDirectory>/</outputDirectory>
44.21 </file>
44.22 <file>
44.23 + <source>${project.build.directory}/bck2brwsr.js</source>
44.24 + <outputDirectory>/</outputDirectory>
44.25 + </file>
44.26 + <file>
44.27 <source>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml</source>
44.28 <outputDirectory>/</outputDirectory>
44.29 <destName>index.xhtml</destName>
45.1 --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Wed Feb 27 17:50:47 2013 +0100
45.2 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Mon Oct 07 14:20:58 2013 +0200
45.3 @@ -17,9 +17,11 @@
45.4 */
45.5 package org.apidesign.bck2brwsr.demo.calc.staticcompilation;
45.6
45.7 +import java.util.List;
45.8 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
45.9 import org.apidesign.bck2brwsr.htmlpage.api.On;
45.10 import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
45.11 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
45.12 import org.apidesign.bck2brwsr.htmlpage.api.Page;
45.13 import org.apidesign.bck2brwsr.htmlpage.api.Property;
45.14
45.15 @@ -33,11 +35,12 @@
45.16 @Property(name = "memory", type = double.class),
45.17 @Property(name = "display", type = double.class),
45.18 @Property(name = "operation", type = String.class),
45.19 - @Property(name = "hover", type = boolean.class)
45.20 + @Property(name = "hover", type = boolean.class),
45.21 + @Property(name = "history", type = double.class, array = true)
45.22 })
45.23 public class Calc {
45.24 static {
45.25 - new Calculator().applyBindings();
45.26 + new Calculator().applyBindings().setOperation("plus");
45.27 }
45.28
45.29 @On(event = CLICK, id="clear")
45.30 @@ -48,31 +51,45 @@
45.31 }
45.32
45.33 @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
45.34 - static void applyOp(Calculator c, String op) {
45.35 + static void applyOp(Calculator c, String id) {
45.36 c.setMemory(c.getDisplay());
45.37 - c.setOperation(op);
45.38 + c.setOperation(id);
45.39 c.setDisplay(0);
45.40 }
45.41
45.42 @On(event = MOUSE_OVER, id= { "result" })
45.43 - static void attemptingIn(Calculator c, String op) {
45.44 + static void attemptingIn(Calculator c) {
45.45 c.setHover(true);
45.46 }
45.47 @On(event = MOUSE_OUT, id= { "result" })
45.48 - static void attemptingOut(Calculator c, String op) {
45.49 + static void attemptingOut(Calculator c) {
45.50 c.setHover(false);
45.51 }
45.52
45.53 @On(event = CLICK, id="result")
45.54 static void computeTheValue(Calculator c) {
45.55 - c.setDisplay(compute(
45.56 + final double newValue = compute(
45.57 c.getOperation(),
45.58 c.getMemory(),
45.59 c.getDisplay()
45.60 - ));
45.61 + );
45.62 + c.setDisplay(newValue);
45.63 + if (!c.getHistory().contains(newValue)) {
45.64 + c.getHistory().add(newValue);
45.65 + }
45.66 c.setMemory(0);
45.67 }
45.68
45.69 + @OnFunction
45.70 + static void recoverMemory(Calculator c, double data) {
45.71 + c.setDisplay(data);
45.72 + }
45.73 +
45.74 + @OnFunction
45.75 + static void removeMemory(Calculator c, double data) {
45.76 + c.getHistory().remove(data);
45.77 + }
45.78 +
45.79 private static double compute(String op, double memory, double display) {
45.80 switch (op) {
45.81 case "plus": return memory + display;
45.82 @@ -84,18 +101,18 @@
45.83 }
45.84
45.85 @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
45.86 - static void addDigit(String digit, Calculator c) {
45.87 - digit = digit.substring(1);
45.88 + static void addDigit(String id, Calculator c) {
45.89 + id = id.substring(1);
45.90
45.91 double v = c.getDisplay();
45.92 if (v == 0.0) {
45.93 - c.setDisplay(Integer.parseInt(digit));
45.94 + c.setDisplay(Integer.parseInt(id));
45.95 } else {
45.96 String txt = Double.toString(v);
45.97 if (txt.endsWith(".0")) {
45.98 txt = txt.substring(0, txt.length() - 2);
45.99 }
45.100 - txt = txt + digit;
45.101 + txt = txt + id;
45.102 c.setDisplay(Double.parseDouble(txt));
45.103 }
45.104 }
45.105 @@ -109,4 +126,9 @@
45.106 }
45.107 return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display);
45.108 }
45.109 +
45.110 + @ComputedProperty
45.111 + static boolean emptyHistory(List<?> history) {
45.112 + return history.isEmpty();
45.113 + }
45.114 }
46.1 --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Wed Feb 27 17:50:47 2013 +0100
46.2 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Mon Oct 07 14:20:58 2013 +0200
46.3 @@ -76,10 +76,22 @@
46.4 </tr>
46.5 </tbody>
46.6 </table>
46.7 +
46.8 + <h4>Previous Results</h4>
46.9 +
46.10 + <div data-bind="if: emptyHistory">No results yet.</div>
46.11 + <ul data-bind="foreach: history">
46.12 + <li>
46.13 + <span data-bind="text: $data"></span> -
46.14 + <a href="#" data-bind="click: $root.recoverMemory">Use</a>
46.15 + <a href="#" data-bind="click: $root.removeMemory">Remove</a>
46.16 + </li>
46.17 + </ul>
46.18 +
46.19 <div data-bind="text: displayPreview"></div>
46.20 - <script src="bck2brwsr.js"/>
46.21 + <script src="bck2brwsr.js"></script>
46.22 <script>
46.23 - var vm = bck2brwsr('demo.static.calculator-0.3-SNAPSHOT.jar');
46.24 + var vm = bck2brwsr('demo.static.calculator-0.6.jar');
46.25 vm.loadClass('org.apidesign.bck2brwsr.demo.calc.staticcompilation.Calc');
46.26 </script>
46.27 </body>
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/javaquery/demo-twitter/bck2brwsr-assembly.xml Mon Oct 07 14:20:58 2013 +0200
47.3 @@ -0,0 +1,62 @@
47.4 +<?xml version="1.0"?>
47.5 +<!--
47.6 +
47.7 + Back 2 Browser Bytecode Translator
47.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
47.9 +
47.10 + This program is free software: you can redistribute it and/or modify
47.11 + it under the terms of the GNU General Public License as published by
47.12 + the Free Software Foundation, version 2 of the License.
47.13 +
47.14 + This program is distributed in the hope that it will be useful,
47.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
47.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.17 + GNU General Public License for more details.
47.18 +
47.19 + You should have received a copy of the GNU General Public License
47.20 + along with this program. Look for COPYING file in the top folder.
47.21 + If not, see http://opensource.org/licenses/GPL-2.0.
47.22 +
47.23 +-->
47.24 +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
47.25 + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
47.26 +
47.27 + <id>bck2brwsr</id>
47.28 + <formats>
47.29 + <format>zip</format>
47.30 + </formats>
47.31 + <baseDirectory>public_html</baseDirectory>
47.32 + <dependencySets>
47.33 + <dependencySet>
47.34 + <useProjectArtifact>false</useProjectArtifact>
47.35 + <scope>runtime</scope>
47.36 + <outputDirectory>lib</outputDirectory>
47.37 + <includes>
47.38 + <include>*:jar</include>
47.39 + <include>*:rt</include>
47.40 + </includes>
47.41 + </dependencySet>
47.42 + </dependencySets>
47.43 + <fileSets>
47.44 + <fileSet>
47.45 + <directory>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/twitter/</directory>
47.46 + <includes>
47.47 + <include>**/*</include>
47.48 + </includes>
47.49 + <excludes>
47.50 + <exclude>**/*.class</exclude>
47.51 + </excludes>
47.52 + <outputDirectory>/</outputDirectory>
47.53 + </fileSet>
47.54 + </fileSets>
47.55 + <files>
47.56 + <file>
47.57 + <source>${project.build.directory}/${project.build.finalName}.jar</source>
47.58 + <outputDirectory>/</outputDirectory>
47.59 + </file>
47.60 + <file>
47.61 + <source>${project.build.directory}/bck2brwsr.js</source>
47.62 + <outputDirectory>/</outputDirectory>
47.63 + </file>
47.64 + </files>
47.65 +</assembly>
47.66 \ No newline at end of file
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/javaquery/demo-twitter/nb-configuration.xml Mon Oct 07 14:20:58 2013 +0200
48.3 @@ -0,0 +1,37 @@
48.4 +<?xml version="1.0" encoding="UTF-8"?>
48.5 +<!--
48.6 +
48.7 + Back 2 Browser Bytecode Translator
48.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
48.9 +
48.10 + This program is free software: you can redistribute it and/or modify
48.11 + it under the terms of the GNU General Public License as published by
48.12 + the Free Software Foundation, version 2 of the License.
48.13 +
48.14 + This program is distributed in the hope that it will be useful,
48.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
48.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48.17 + GNU General Public License for more details.
48.18 +
48.19 + You should have received a copy of the GNU General Public License
48.20 + along with this program. Look for COPYING file in the top folder.
48.21 + If not, see http://opensource.org/licenses/GPL-2.0.
48.22 +
48.23 +-->
48.24 +<project-shared-configuration>
48.25 + <!--
48.26 +This file contains additional configuration written by modules in the NetBeans IDE.
48.27 +The configuration is intended to be shared among all the users of project and
48.28 +therefore it is assumed to be part of version control checkout.
48.29 +Without this configuration present, some functionality in the IDE may be limited or fail altogether.
48.30 +-->
48.31 + <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
48.32 + <!--
48.33 +Properties that influence various parts of the IDE, especially code formatting and the like.
48.34 +You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
48.35 +That way multiple projects can share the same settings (useful for formatting rules for example).
48.36 +Any value defined here will override the pom.xml file value but is only applicable to the current project.
48.37 +-->
48.38 + <netbeans.compile.on.save>none</netbeans.compile.on.save>
48.39 + </properties>
48.40 +</project-shared-configuration>
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/javaquery/demo-twitter/nbactions.xml Mon Oct 07 14:20:58 2013 +0200
49.3 @@ -0,0 +1,29 @@
49.4 +<?xml version="1.0" encoding="UTF-8"?>
49.5 +<!--
49.6 +
49.7 + Back 2 Browser Bytecode Translator
49.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
49.9 +
49.10 + This program is free software: you can redistribute it and/or modify
49.11 + it under the terms of the GNU General Public License as published by
49.12 + the Free Software Foundation, version 2 of the License.
49.13 +
49.14 + This program is distributed in the hope that it will be useful,
49.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
49.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49.17 + GNU General Public License for more details.
49.18 +
49.19 + You should have received a copy of the GNU General Public License
49.20 + along with this program. Look for COPYING file in the top folder.
49.21 + If not, see http://opensource.org/licenses/GPL-2.0.
49.22 +
49.23 +-->
49.24 +<actions>
49.25 + <action>
49.26 + <actionName>run</actionName>
49.27 + <goals>
49.28 + <goal>process-classes</goal>
49.29 + <goal>bck2brwsr:brwsr</goal>
49.30 + </goals>
49.31 + </action>
49.32 +</actions>
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/javaquery/demo-twitter/pom.xml Mon Oct 07 14:20:58 2013 +0200
50.3 @@ -0,0 +1,151 @@
50.4 +<?xml version="1.0" encoding="UTF-8"?>
50.5 +<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/xsd/maven-4.0.0.xsd">
50.6 + <modelVersion>4.0.0</modelVersion>
50.7 + <parent>
50.8 + <artifactId>javaquery</artifactId>
50.9 + <groupId>org.apidesign.bck2brwsr</groupId>
50.10 + <version>0.9-SNAPSHOT</version>
50.11 + </parent>
50.12 +
50.13 + <groupId>org.apidesign.bck2brwsr</groupId>
50.14 + <artifactId>demo-twitter</artifactId>
50.15 + <version>0.9-SNAPSHOT</version>
50.16 + <packaging>jar</packaging>
50.17 +
50.18 + <name>Bck2Brwsr's Twttr</name>
50.19 + <description>
50.20 + Rewrite of knockoutjs example to use model written in Java and
50.21 + execute using Bck2Brwsr virtual machine.
50.22 + </description>
50.23 +
50.24 + <repositories>
50.25 + <repository>
50.26 + <id>java.net</id>
50.27 + <name>Java.net</name>
50.28 + <url>https://maven.java.net/content/repositories/releases/</url>
50.29 + <snapshots>
50.30 + </snapshots>
50.31 + </repository>
50.32 + <repository>
50.33 + <id>netbeans</id>
50.34 + <name>NetBeans</name>
50.35 + <url>http://bits.netbeans.org/maven2/</url>
50.36 + </repository>
50.37 + </repositories>
50.38 + <pluginRepositories>
50.39 + <pluginRepository>
50.40 + <id>java.net</id>
50.41 + <name>Java.net</name>
50.42 + <url>https://maven.java.net/content/repositories/releases/</url>
50.43 + <snapshots>
50.44 + </snapshots>
50.45 + </pluginRepository>
50.46 + </pluginRepositories>
50.47 +
50.48 + <properties>
50.49 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
50.50 + <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
50.51 + </properties>
50.52 + <build>
50.53 + <plugins>
50.54 + <plugin>
50.55 + <groupId>org.apidesign.bck2brwsr</groupId>
50.56 + <artifactId>bck2brwsr-maven-plugin</artifactId>
50.57 + <version>${project.version}</version>
50.58 + <executions>
50.59 + <execution>
50.60 + <goals>
50.61 + <goal>brwsr</goal>
50.62 + <goal>j2js</goal>
50.63 + </goals>
50.64 + </execution>
50.65 + </executions>
50.66 + <configuration>
50.67 + <startpage>org/apidesign/bck2brwsr/demo/twitter/index.html</startpage>
50.68 + <javascript>${project.build.directory}/bck2brwsr.js</javascript>
50.69 + <obfuscation>${bck2brwsr.obfuscationlevel}</obfuscation>
50.70 + </configuration>
50.71 + </plugin>
50.72 + <plugin>
50.73 + <groupId>org.apache.maven.plugins</groupId>
50.74 + <artifactId>maven-compiler-plugin</artifactId>
50.75 + <version>2.3.2</version>
50.76 + <configuration>
50.77 + <source>1.7</source>
50.78 + <target>1.7</target>
50.79 + </configuration>
50.80 + </plugin>
50.81 + <plugin>
50.82 + <groupId>org.apache.maven.plugins</groupId>
50.83 + <artifactId>maven-jar-plugin</artifactId>
50.84 + <version>2.4</version>
50.85 + <configuration>
50.86 + <archive>
50.87 + <manifest>
50.88 + <addClasspath>true</addClasspath>
50.89 + <classpathPrefix>lib/</classpathPrefix>
50.90 + </manifest>
50.91 + </archive>
50.92 + </configuration>
50.93 + </plugin>
50.94 + <plugin>
50.95 + <groupId>org.apache.maven.plugins</groupId>
50.96 + <artifactId>maven-deploy-plugin</artifactId>
50.97 + <version>2.7</version>
50.98 + <configuration>
50.99 + <skip>true</skip>
50.100 + </configuration>
50.101 + </plugin>
50.102 + <plugin>
50.103 + <artifactId>maven-assembly-plugin</artifactId>
50.104 + <version>2.4</version>
50.105 + <executions>
50.106 + <execution>
50.107 + <id>distro-assembly</id>
50.108 + <phase>package</phase>
50.109 + <goals>
50.110 + <goal>single</goal>
50.111 + </goals>
50.112 + <configuration>
50.113 + <descriptors>
50.114 + <descriptor>bck2brwsr-assembly.xml</descriptor>
50.115 + </descriptors>
50.116 + </configuration>
50.117 + </execution>
50.118 + </executions>
50.119 + </plugin>
50.120 + </plugins>
50.121 + </build>
50.122 +
50.123 + <dependencies>
50.124 + <dependency>
50.125 + <groupId>org.apidesign.bck2brwsr</groupId>
50.126 + <artifactId>emul</artifactId>
50.127 + <version>${project.version}</version>
50.128 + <classifier>rt</classifier>
50.129 + </dependency>
50.130 + <dependency>
50.131 + <groupId>org.apidesign.bck2brwsr</groupId>
50.132 + <artifactId>javaquery.api</artifactId>
50.133 + <version>${project.version}</version>
50.134 + </dependency>
50.135 + <dependency>
50.136 + <groupId>org.testng</groupId>
50.137 + <artifactId>testng</artifactId>
50.138 + <version>6.5.2</version>
50.139 + <scope>test</scope>
50.140 + </dependency>
50.141 + <dependency>
50.142 + <groupId>org.apidesign.bck2brwsr</groupId>
50.143 + <artifactId>vmtest</artifactId>
50.144 + <version>${project.version}</version>
50.145 + <scope>test</scope>
50.146 + </dependency>
50.147 + <dependency>
50.148 + <groupId>org.apidesign.bck2brwsr</groupId>
50.149 + <artifactId>launcher.http</artifactId>
50.150 + <version>${project.version}</version>
50.151 + <scope>runtime</scope>
50.152 + </dependency>
50.153 + </dependencies>
50.154 +</project>
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java Mon Oct 07 14:20:58 2013 +0200
51.3 @@ -0,0 +1,194 @@
51.4 +/**
51.5 + * Back 2 Browser Bytecode Translator
51.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
51.7 + *
51.8 + * This program is free software: you can redistribute it and/or modify
51.9 + * it under the terms of the GNU General Public License as published by
51.10 + * the Free Software Foundation, version 2 of the License.
51.11 + *
51.12 + * This program is distributed in the hope that it will be useful,
51.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
51.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51.15 + * GNU General Public License for more details.
51.16 + *
51.17 + * You should have received a copy of the GNU General Public License
51.18 + * along with this program. Look for COPYING file in the top folder.
51.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
51.20 + */
51.21 +package org.apidesign.bck2brwsr.demo.twitter;
51.22 +
51.23 +import java.util.Arrays;
51.24 +import java.util.List;
51.25 +import org.apidesign.bck2brwsr.htmlpage.api.*;
51.26 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
51.27 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
51.28 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
51.29 +
51.30 +/** Controller class for access to Twitter.
51.31 + *
51.32 + * @author Jaroslav Tulach
51.33 + */
51.34 +@Page(xhtml="index.html", className="TwitterModel", properties={
51.35 + @Property(name="savedLists", type=Tweeters.class, array = true),
51.36 + @Property(name="activeTweetersName", type=String.class),
51.37 + @Property(name="activeTweeters", type=String.class, array = true),
51.38 + @Property(name="userNameToAdd", type=String.class),
51.39 + @Property(name="currentTweets", type=Tweet.class, array = true)
51.40 +})
51.41 +public class TwitterClient {
51.42 + @Model(className = "Tweeters", properties = {
51.43 + @Property(name="name", type = String.class),
51.44 + @Property(name="userNames", type = String.class, array = true)
51.45 + })
51.46 + static class Twttrs {
51.47 + }
51.48 + @Model(className = "Tweet", properties = {
51.49 + @Property(name = "from_user", type = String.class),
51.50 + @Property(name = "from_user_id", type = int.class),
51.51 + @Property(name = "profile_image_url", type = String.class),
51.52 + @Property(name = "text", type = String.class),
51.53 + @Property(name = "created_at", type = String.class),
51.54 + })
51.55 + static final class Twt {
51.56 + @ComputedProperty static String html(String text) {
51.57 + StringBuilder sb = new StringBuilder(320);
51.58 + for (int pos = 0;;) {
51.59 + int http = text.indexOf("http", pos);
51.60 + if (http == -1) {
51.61 + sb.append(text.substring(pos));
51.62 + return sb.toString();
51.63 + }
51.64 + int spc = text.indexOf(' ', http);
51.65 + if (spc == -1) {
51.66 + spc = text.length();
51.67 + }
51.68 + sb.append(text.substring(pos, http));
51.69 + String url = text.substring(http, spc);
51.70 + sb.append("<a href='").append(url).append("'>").append(url).append("</a>");
51.71 + pos = spc;
51.72 + }
51.73 + }
51.74 +
51.75 + @ComputedProperty static String userUrl(String from_user) {
51.76 + return "http://twitter.com/" + from_user;
51.77 + }
51.78 + }
51.79 + @Model(className = "TwitterQuery", properties = {
51.80 + @Property(array = true, name = "results", type = Twt.class)
51.81 + })
51.82 + public static final class TwttrQr {
51.83 + }
51.84 +
51.85 + @OnReceive(url="{root}/search.json?{query}&callback={me}", jsonp="me")
51.86 + static void queryTweets(TwitterModel page, TwitterQuery q) {
51.87 + page.getCurrentTweets().clear();
51.88 + page.getCurrentTweets().addAll(q.getResults());
51.89 + }
51.90 +
51.91 + @OnPropertyChange("activeTweetersName")
51.92 + static void changeTweetersList(TwitterModel model) {
51.93 + Tweeters people = findByName(model.getSavedLists(), model.getActiveTweetersName());
51.94 + model.getActiveTweeters().clear();
51.95 + model.getActiveTweeters().addAll(people.getUserNames());
51.96 + }
51.97 +
51.98 + @OnPropertyChange({ "activeTweeters", "activeTweetersCount" })
51.99 + static void refreshTweets(TwitterModel model) {
51.100 + StringBuilder sb = new StringBuilder();
51.101 + sb.append("rpp=25&q=");
51.102 + String sep = "";
51.103 + for (String p : model.getActiveTweeters()) {
51.104 + sb.append(sep);
51.105 + sb.append("from:");
51.106 + sb.append(p);
51.107 + sep = " OR ";
51.108 + }
51.109 + model.queryTweets("http://search.twitter.com", sb.toString());
51.110 + }
51.111 +
51.112 + static {
51.113 + final TwitterModel model = new TwitterModel();
51.114 + final List<Tweeters> svdLst = model.getSavedLists();
51.115 + svdLst.add(newTweeters("API Design", "JaroslavTulach"));
51.116 + svdLst.add(newTweeters("Celebrities", "JohnCleese", "MCHammer", "StephenFry", "algore", "StevenSanderson"));
51.117 + svdLst.add(newTweeters("Microsoft people", "BillGates", "shanselman", "ScottGu"));
51.118 + svdLst.add(newTweeters("NetBeans", "GeertjanW","monacotoni", "NetBeans", "petrjiricka"));
51.119 + svdLst.add(newTweeters("Tech pundits", "Scobleizer", "LeoLaporte", "techcrunch", "BoingBoing", "timoreilly", "codinghorror"));
51.120 +
51.121 + model.setActiveTweetersName("NetBeans");
51.122 +
51.123 + model.applyBindings();
51.124 + }
51.125 +
51.126 + @ComputedProperty
51.127 + static boolean hasUnsavedChanges(List<String> activeTweeters, List<Tweeters> savedLists, String activeTweetersName) {
51.128 + Tweeters tw = findByName(savedLists, activeTweetersName);
51.129 + if (activeTweeters == null) {
51.130 + return false;
51.131 + }
51.132 + return !tw.getUserNames().equals(activeTweeters);
51.133 + }
51.134 +
51.135 + @ComputedProperty
51.136 + static int activeTweetersCount(List<String> activeTweeters) {
51.137 + return activeTweeters.size();
51.138 + }
51.139 +
51.140 + @ComputedProperty
51.141 + static boolean userNameToAddIsValid(
51.142 + String userNameToAdd, String activeTweetersName, List<Tweeters> savedLists, List<String> activeTweeters
51.143 + ) {
51.144 + return userNameToAdd != null &&
51.145 + userNameToAdd.matches("[a-zA-Z0-9_]{1,15}") &&
51.146 + !activeTweeters.contains(userNameToAdd);
51.147 + }
51.148 +
51.149 + @OnFunction
51.150 + static void deleteList(TwitterModel model) {
51.151 + final List<Tweeters> sl = model.getSavedLists();
51.152 + sl.remove(findByName(sl, model.getActiveTweetersName()));
51.153 + if (sl.isEmpty()) {
51.154 + final Tweeters t = new Tweeters();
51.155 + t.setName("New");
51.156 + sl.add(t);
51.157 + }
51.158 + model.setActiveTweetersName(sl.get(0).getName());
51.159 + }
51.160 +
51.161 + @OnFunction
51.162 + static void saveChanges(TwitterModel model) {
51.163 + Tweeters t = findByName(model.getSavedLists(), model.getActiveTweetersName());
51.164 + int indx = model.getSavedLists().indexOf(t);
51.165 + if (indx != -1) {
51.166 + t.setName(model.getActiveTweetersName());
51.167 + t.getUserNames().clear();
51.168 + t.getUserNames().addAll(model.getActiveTweeters());
51.169 + }
51.170 + }
51.171 +
51.172 + @OnFunction
51.173 + static void addUser(TwitterModel model) {
51.174 + String n = model.getUserNameToAdd();
51.175 + model.getActiveTweeters().add(n);
51.176 + }
51.177 + @OnFunction
51.178 + static void removeUser(String data, TwitterModel model) {
51.179 + model.getActiveTweeters().remove(data);
51.180 + }
51.181 +
51.182 + private static Tweeters findByName(List<Tweeters> list, String name) {
51.183 + for (Tweeters l : list) {
51.184 + if (l.getName() != null && l.getName().equals(name)) {
51.185 + return l;
51.186 + }
51.187 + }
51.188 + return list.isEmpty() ? new Tweeters() : list.get(0);
51.189 + }
51.190 +
51.191 + private static Tweeters newTweeters(String listName, String... userNames) {
51.192 + Tweeters t = new Tweeters();
51.193 + t.setName(listName);
51.194 + t.getUserNames().addAll(Arrays.asList(userNames));
51.195 + return t;
51.196 + }
51.197 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html Mon Oct 07 14:20:58 2013 +0200
52.3 @@ -0,0 +1,99 @@
52.4 +<?xml version="1.0" encoding="UTF-8"?>
52.5 +<!--
52.6 +
52.7 + Back 2 Browser Bytecode Translator
52.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
52.9 +
52.10 + This program is free software: you can redistribute it and/or modify
52.11 + it under the terms of the GNU General Public License as published by
52.12 + the Free Software Foundation, version 2 of the License.
52.13 +
52.14 + This program is distributed in the hope that it will be useful,
52.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
52.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52.17 + GNU General Public License for more details.
52.18 +
52.19 + You should have received a copy of the GNU General Public License
52.20 + along with this program. Look for COPYING file in the top folder.
52.21 + If not, see http://opensource.org/licenses/GPL-2.0.
52.22 +
52.23 +-->
52.24 +
52.25 +<!--
52.26 + Copied from knockout.js Twitter example:
52.27 + http://knockoutjs.com/examples/twitter.html
52.28 +-->
52.29 +
52.30 +<!DOCTYPE html>
52.31 +<html xmlns="http://www.w3.org/1999/xhtml">
52.32 + <head>
52.33 + <title>Bck2Brwsr's Twitter</title>
52.34 + </head>
52.35 + <body>
52.36 + <link href='twitterExample.css' rel='Stylesheet' ></link>
52.37 +
52.38 + <style type='text/css'>
52.39 + .liveExample select { height: 1.7em; }
52.40 + .liveExample button { height: 2em; }
52.41 + </style>
52.42 +
52.43 +
52.44 + <h2>Bck2Brwsr's Twitter</h2>
52.45 +
52.46 + <p>
52.47 + This code based on original <a href="http://knockoutjs.com/examples/twitter.html">knockout.js Twitter example</a> and
52.48 + uses almost unmodified HTML code. It just changes the model. It
52.49 + is written in Java language and it is executed using <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a>
52.50 + virtual machine. The Java source code has about 190 lines and is available
52.51 + <a href="http://source.apidesign.org/hg/bck2brwsr/file/7fc6b7e9c982/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java">here</a>
52.52 + - in fact it may even be more dense than the original JavaScript model.
52.53 + </p>
52.54 +
52.55 + <div class='liveExample'>
52.56 + <div class='configuration'>
52.57 + <div class='listChooser'>
52.58 + <button data-bind='click: deleteList, enable: activeTweetersName'>Delete</button>
52.59 + <button data-bind='click: saveChanges, enable: hasUnsavedChanges'>Save</button>
52.60 + <select data-bind='options: savedLists, optionsValue: "name", value: activeTweetersName'> </select>
52.61 + </div>
52.62 +
52.63 + <p>Currently viewing <span data-bind='text: activeTweetersCount'> </span> user(s):</p>
52.64 + <div class='currentUsers' >
52.65 + <ul data-bind='foreach: activeTweeters'>
52.66 + <li>
52.67 + <button data-bind='click: $root.removeUser'>Remove</button>
52.68 + <div data-bind='text: $data'> </div>
52.69 + </li>
52.70 + </ul>
52.71 + </div>
52.72 +
52.73 + <form data-bind='submit: addUser'>
52.74 + <label>Add user:</label>
52.75 + <input data-bind='value: userNameToAdd, valueUpdate: "keyup", css: { invalid: !userNameToAddIsValid() }' />
52.76 + <button data-bind='enable: userNameToAddIsValid' type='submit'>Add</button>
52.77 + </form>
52.78 + </div>
52.79 + <div class='tweets'>
52.80 + <div class='loadingIndicator'>Loading...</div>
52.81 + <table data-bind='foreach: currentTweets' width='100%'>
52.82 + <tr>
52.83 + <td><img data-bind='attr: { src: profile_image_url }' /></td>
52.84 + <td>
52.85 + <a class='twitterUser' data-bind='attr: { href: userUrl }, text: from_user'> </a>
52.86 + <span data-bind='html: html'> </span>
52.87 + <div class='tweetInfo' data-bind='text: created_at'> </div>
52.88 + </td>
52.89 + </tr>
52.90 + </table>
52.91 + </div>
52.92 + </div>
52.93 +
52.94 + <script src="bck2brwsr.js"></script>
52.95 + <script type="text/javascript">
52.96 + var vm = bck2brwsr('demo-twitter-0.8-SNAPSHOT.jar');
52.97 + vm.loadClass('org.apidesign.bck2brwsr.demo.twitter.TwitterClient');
52.98 + </script>
52.99 +
52.100 +
52.101 + </body>
52.102 +</html>
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css Mon Oct 07 14:20:58 2013 +0200
53.3 @@ -0,0 +1,50 @@
53.4 +/**
53.5 + * Back 2 Browser Bytecode Translator
53.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
53.7 + *
53.8 + * This program is free software: you can redistribute it and/or modify
53.9 + * it under the terms of the GNU General Public License as published by
53.10 + * the Free Software Foundation, version 2 of the License.
53.11 + *
53.12 + * This program is distributed in the hope that it will be useful,
53.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
53.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53.15 + * GNU General Public License for more details.
53.16 + *
53.17 + * You should have received a copy of the GNU General Public License
53.18 + * along with this program. Look for COPYING file in the top folder.
53.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
53.20 + */
53.21 +
53.22 +/*
53.23 + Copied from knockout.js Twitter example:
53.24 + http://knockoutjs.com/examples/twitter.html
53.25 +*/
53.26 +
53.27 +.configuration, .tweets, .tweets td { font-family: Verdana; font-size: 13px; }
53.28 +.configuration { background-color: #DEDEDE; border: 2px solid gray; float:left; height: 40em; width: 40%; padding: 0.5em; border-right-width:0; }
53.29 +.tweets { width: 55%; border: 2px solid gray; height: 40em; overflow: scroll; overflow-x: hidden; background-color: Black; color: White; padding: 0.5em; position: relative; }
53.30 +.tweets table { border-width: 0;}
53.31 +.tweets tr { vertical-align: top; }
53.32 +.tweets td { padding: 0.4em 0.3em 1em 0.4em; border-width: 0; }
53.33 +.tweets img { width: 4em; }
53.34 +.tweetInfo { color: Gray; font-size: 0.9em; }
53.35 +.twitterUser { color: #77AAFF; text-decoration: none; font-size: 1.1em; font-weight: bold; }
53.36 +input.invalid { border: 1px solid red !important; background-color: #FFAAAA !important; }
53.37 +
53.38 +.listChooser select, .listChooser button { vertical-align:top; }
53.39 +.listChooser select { width: 60%; font-size:1.2em; height:1.4em; }
53.40 +.listChooser button { width: 19%; height:1.68em; float:right; }
53.41 +
53.42 +.currentUsers { height: 28em; overflow-y: auto; overflow-x: hidden; }
53.43 +.currentUsers button { float: right; height: 2.5em; margin: 0.1em; padding-left: 1em; padding-right: 1em; }
53.44 +.currentUsers ul, .configuration li { list-style: none; margin: 0; padding: 0 }
53.45 +.currentUsers li { height: 2.4em; font-size: 1.2em; background-color: #A7D0E3; border: 1px solid gray; margin-bottom: 0.3em; -webkit-border-radius: 5px; -moz-border-radius: 5px; -webkit-box-shadow: 0 0.2em 0.5em gray; -moz-box-shadow: 0 0.2em 0.5em gray; }
53.46 +.currentUsers li div { padding: 0.6em; }
53.47 +.currentUsers li:hover { background-color: #EEC; }
53.48 +
53.49 +.configuration form label { width: 25%; display: inline-block; text-align:right; overflow: hidden; }
53.50 +.configuration form input { width:40%; font-size: 1.3em; border:1px solid silver; background-color: White; padding: 0.1em; }
53.51 +.configuration form button { width: 20%; margin-left: 0.3em; height: 2em; }
53.52 +
53.53 +.loadingIndicator { position: absolute; top: 0.1em; left: 0.1em; font: 0.8em Arial; background-color: #229; color: White; padding: 0.2em 0.5em 0.2em 0.5em; display: none; }
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54.2 +++ b/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java Mon Oct 07 14:20:58 2013 +0200
54.3 @@ -0,0 +1,67 @@
54.4 +/**
54.5 + * Back 2 Browser Bytecode Translator
54.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
54.7 + *
54.8 + * This program is free software: you can redistribute it and/or modify
54.9 + * it under the terms of the GNU General Public License as published by
54.10 + * the Free Software Foundation, version 2 of the License.
54.11 + *
54.12 + * This program is distributed in the hope that it will be useful,
54.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
54.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54.15 + * GNU General Public License for more details.
54.16 + *
54.17 + * You should have received a copy of the GNU General Public License
54.18 + * along with this program. Look for COPYING file in the top folder.
54.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
54.20 + */
54.21 +package org.apidesign.bck2brwsr.demo.twitter;
54.22 +
54.23 +import java.util.List;
54.24 +import static org.testng.Assert.*;
54.25 +import org.testng.annotations.BeforeMethod;
54.26 +import org.testng.annotations.Test;
54.27 +
54.28 +/** We can unit test the TwitterModel smoothly.
54.29 + *
54.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
54.31 + */
54.32 +public class TwitterClientTest {
54.33 + private TwitterModel model;
54.34 +
54.35 +
54.36 + @BeforeMethod
54.37 + public void initModel() {
54.38 + model = new TwitterModel().applyBindings();
54.39 + }
54.40 +
54.41 + @Test public void testIsValidToAdd() {
54.42 + model.setUserNameToAdd("Joe");
54.43 + Tweeters t = new Tweeters();
54.44 + t.setName("test");
54.45 + model.getSavedLists().add(t);
54.46 + model.setActiveTweetersName("test");
54.47 +
54.48 + assertTrue(model.isUserNameToAddIsValid(), "Joe is OK");
54.49 + TwitterClient.addUser(model);
54.50 + assertFalse(model.isUserNameToAddIsValid(), "Can't add Joe for the 2nd time");
54.51 + assertEquals(t.getUserNames().size(), 0, "Original tweeters list remains empty");
54.52 +
54.53 + List<String> mod = model.getActiveTweeters();
54.54 + assertTrue(model.isHasUnsavedChanges(), "We have modifications");
54.55 + assertEquals(mod.size(), 1, "One element in the list");
54.56 + assertEquals(mod.get(0), "Joe", "Its name is Joe");
54.57 +
54.58 + assertSame(model.getActiveTweeters(), mod, "Editing list is the modified one");
54.59 +
54.60 + TwitterClient.saveChanges(model);
54.61 + assertFalse(model.isHasUnsavedChanges(), "Does not have anything to save");
54.62 +
54.63 + assertSame(model.getActiveTweeters(), mod, "Still editing the old modified one");
54.64 + }
54.65 +
54.66 + @Test public void httpAtTheEnd() {
54.67 + String res = TwitterClient.Twt.html("Ahoj http://kuk");
54.68 + assertEquals(res, "Ahoj <a href='http://kuk'>http://kuk</a>");
54.69 + }
54.70 +}
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55.2 +++ b/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterProtocolTest.java Mon Oct 07 14:20:58 2013 +0200
55.3 @@ -0,0 +1,94 @@
55.4 +/**
55.5 + * Back 2 Browser Bytecode Translator
55.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
55.7 + *
55.8 + * This program is free software: you can redistribute it and/or modify
55.9 + * it under the terms of the GNU General Public License as published by
55.10 + * the Free Software Foundation, version 2 of the License.
55.11 + *
55.12 + * This program is distributed in the hope that it will be useful,
55.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
55.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55.15 + * GNU General Public License for more details.
55.16 + *
55.17 + * You should have received a copy of the GNU General Public License
55.18 + * along with this program. Look for COPYING file in the top folder.
55.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
55.20 + */
55.21 +package org.apidesign.bck2brwsr.demo.twitter;
55.22 +
55.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
55.24 +import org.apidesign.bck2brwsr.vmtest.Http;
55.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
55.26 +import org.testng.annotations.Factory;
55.27 +
55.28 +/**
55.29 + *
55.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
55.31 + */
55.32 +public class TwitterProtocolTest {
55.33 + private TwitterModel page;
55.34 + @Http(@Http.Resource(
55.35 + path = "/search.json",
55.36 + mimeType = "application/json",
55.37 + parameters = {"callback"},
55.38 + content = "$0({\"completed_in\":0.04,\"max_id\":320055706885689344,\"max_id_str\""
55.39 + + ":\"320055706885689344\",\"page\":1,\"query\":\"from%3AJaroslavTulach\",\"refresh_url\":"
55.40 + + "\"?since_id=320055706885689344&q=from%3AJaroslavTulach\","
55.41 + + "\"results\":[{\"created_at\":\"Fri, 05 Apr 2013 06:10:01 +0000\","
55.42 + + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":"
55.43 + + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":320055706885689344,"
55.44 + + "\"id_str\":\"320055706885689344\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":"
55.45 + + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.46 + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.47 + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":"
55.48 + + "\"@tom_enebo Amzng! Not that I would like #ruby, but I am really glad you guys stabilized the plugin + "
55.49 + + "made it work in #netbeans 7.3! Gd wrk.\",\"to_user\":\"tom_enebo\",\"to_user_id\":14498747,"
55.50 + + "\"to_user_id_str\":\"14498747\",\"to_user_name\":\"tom_enebo\",\"in_reply_to_status_id\":319832359509839872,"
55.51 + + "\"in_reply_to_status_id_str\":\"319832359509839872\"},{\"created_at\":\"Thu, 04 Apr 2013 07:33:06 +0000\","
55.52 + + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":"
55.53 + + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":319714227088678913,"
55.54 + + "\"id_str\":\"319714227088678913\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":"
55.55 + + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.56 + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.57 + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":"
55.58 + + "\"RT @drkrab: At #erlangfactory @joerl: Frameworks grow in complexity until nobody can use them.\"},"
55.59 + + "{\"created_at\":\"Tue, 02 Apr 2013 07:44:34 +0000\",\"from_user\":\"JaroslavTulach\","
55.60 + + "\"from_user_id\":420944648,\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\","
55.61 + + "\"geo\":null,\"id\":318992336145248256,\"id_str\":\"318992336145248256\",\"iso_language_code\":\"en\","
55.62 + + "\"metadata\":{\"result_type\":\"recent\"},\"profile_image_url\":"
55.63 + + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.64 + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.65 + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":"
55.66 + + "\"Twitter renamed to twttr http:\\/\\/t.co\\/tqaN4T1xlZ - good, I don't have to rename #bck2brwsr!\"},"
55.67 + + "{\"created_at\":\"Sun, 31 Mar 2013 03:52:04 +0000\",\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,"
55.68 + + "\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,"
55.69 + + "\"id\":318209051223789568,\"id_str\":\"318209051223789568\",\"iso_language_code\":\"en\",\"metadata\":"
55.70 + + "{\"result_type\":\"recent\"},\"profile_image_url\":"
55.71 + + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.72 + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
55.73 + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":"
55.74 + + "\"Math proofs without words. Ingenious: http:\\/\\/t.co\\/sz7yVbfpGw\"}],\"results_per_page\":100,"
55.75 + + "\"since_id\":0,\"since_id_str\":\"0\"})"
55.76 + ))
55.77 + @BrwsrTest public void readFromTwttr() throws InterruptedException {
55.78 + if (page == null) {
55.79 + page = new TwitterModel();
55.80 + page.applyBindings();
55.81 + page.queryTweets("", "q=xyz");
55.82 + }
55.83 +
55.84 + if (page.getCurrentTweets().isEmpty()) {
55.85 + throw new InterruptedException();
55.86 + }
55.87 +
55.88 + assert 4 == page.getCurrentTweets().size() : "Four tweets: " + page.getCurrentTweets();
55.89 +
55.90 + String firstDate = page.getCurrentTweets().get(0).getCreated_at();
55.91 + assert "Fri, 05 Apr 2013 06:10:01 +0000".equals(firstDate) : "Date is OK: " + firstDate;
55.92 + }
55.93 +
55.94 + @Factory public static Object[] create() {
55.95 + return VMTest.create(TwitterProtocolTest.class);
55.96 + }
55.97 +}
56.1 --- a/javaquery/pom.xml Wed Feb 27 17:50:47 2013 +0100
56.2 +++ b/javaquery/pom.xml Mon Oct 07 14:20:58 2013 +0200
56.3 @@ -4,16 +4,17 @@
56.4 <parent>
56.5 <artifactId>bck2brwsr</artifactId>
56.6 <groupId>org.apidesign</groupId>
56.7 - <version>0.3-SNAPSHOT</version>
56.8 + <version>0.9-SNAPSHOT</version>
56.9 </parent>
56.10 <groupId>org.apidesign.bck2brwsr</groupId>
56.11 <artifactId>javaquery</artifactId>
56.12 - <version>0.3-SNAPSHOT</version>
56.13 + <version>0.9-SNAPSHOT</version>
56.14 <packaging>pom</packaging>
56.15 <name>JavaQuery API and Demo</name>
56.16 <modules>
56.17 <module>api</module>
56.18 <module>demo-calculator</module>
56.19 <module>demo-calculator-dynamic</module>
56.20 - </modules>
56.21 -</project>
56.22 + <module>demo-twitter</module>
56.23 + </modules>
56.24 +</project>
56.25 \ No newline at end of file
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57.2 +++ b/ko/archetype-test/pom.xml Mon Oct 07 14:20:58 2013 +0200
57.3 @@ -0,0 +1,48 @@
57.4 +<?xml version="1.0"?>
57.5 +<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/xsd/maven-4.0.0.xsd">
57.6 + <modelVersion>4.0.0</modelVersion>
57.7 + <parent>
57.8 + <groupId>org.apidesign.bck2brwsr</groupId>
57.9 + <artifactId>ko</artifactId>
57.10 + <version>0.9-SNAPSHOT</version>
57.11 + </parent>
57.12 + <groupId>org.apidesign.bck2brwsr</groupId>
57.13 + <artifactId>ko-archetype-test</artifactId>
57.14 + <version>0.9-SNAPSHOT</version>
57.15 + <name>Knockout Bck2Brwsr Archetype Test</name>
57.16 + <url>http://maven.apache.org</url>
57.17 + <description>Verifies the Knockout & net.java.html.json archetype behaves properly.</description>
57.18 + <properties>
57.19 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
57.20 + </properties>
57.21 + <dependencies>
57.22 + <dependency>
57.23 + <groupId>${project.groupId}</groupId>
57.24 + <artifactId>knockout4j-archetype</artifactId>
57.25 + <version>${project.version}</version>
57.26 + </dependency>
57.27 + <dependency>
57.28 + <groupId>org.testng</groupId>
57.29 + <artifactId>testng</artifactId>
57.30 + <scope>test</scope>
57.31 + </dependency>
57.32 + <dependency>
57.33 + <groupId>org.apache.maven.shared</groupId>
57.34 + <artifactId>maven-verifier</artifactId>
57.35 + <version>1.4</version>
57.36 + <scope>test</scope>
57.37 + </dependency>
57.38 + <dependency>
57.39 + <groupId>${project.groupId}</groupId>
57.40 + <artifactId>ko-fx</artifactId>
57.41 + <version>${project.version}</version>
57.42 + <scope>provided</scope>
57.43 + </dependency>
57.44 + <dependency>
57.45 + <groupId>${project.groupId}</groupId>
57.46 + <artifactId>ko-bck2brwsr</artifactId>
57.47 + <version>${project.version}</version>
57.48 + <scope>provided</scope>
57.49 + </dependency>
57.50 + </dependencies>
57.51 +</project>
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58.2 +++ b/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/ArchetypeVersionTest.java Mon Oct 07 14:20:58 2013 +0200
58.3 @@ -0,0 +1,140 @@
58.4 +/**
58.5 + * Back 2 Browser Bytecode Translator
58.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
58.7 + *
58.8 + * This program is free software: you can redistribute it and/or modify
58.9 + * it under the terms of the GNU General Public License as published by
58.10 + * the Free Software Foundation, version 2 of the License.
58.11 + *
58.12 + * This program is distributed in the hope that it will be useful,
58.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
58.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58.15 + * GNU General Public License for more details.
58.16 + *
58.17 + * You should have received a copy of the GNU General Public License
58.18 + * along with this program. Look for COPYING file in the top folder.
58.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
58.20 + */
58.21 +package org.apidesign.bck2brwsr.ko.archetype.test;
58.22 +
58.23 +import java.io.IOException;
58.24 +import java.net.URL;
58.25 +import javax.xml.XMLConstants;
58.26 +import javax.xml.parsers.DocumentBuilderFactory;
58.27 +import javax.xml.parsers.ParserConfigurationException;
58.28 +import javax.xml.xpath.XPathConstants;
58.29 +import javax.xml.xpath.XPathExpression;
58.30 +import javax.xml.xpath.XPathExpressionException;
58.31 +import javax.xml.xpath.XPathFactory;
58.32 +import javax.xml.xpath.XPathFactoryConfigurationException;
58.33 +import org.testng.annotations.Test;
58.34 +import static org.testng.Assert.*;
58.35 +import org.testng.annotations.BeforeClass;
58.36 +import org.w3c.dom.Document;
58.37 +import org.w3c.dom.NodeList;
58.38 +import org.xml.sax.SAXException;
58.39 +
58.40 +/**
58.41 + *
58.42 + * @author Jaroslav Tulach <jtulach@netbeans.org>
58.43 + */
58.44 +public class ArchetypeVersionTest {
58.45 + private String version;
58.46 +
58.47 + public ArchetypeVersionTest() {
58.48 + }
58.49 +
58.50 + @BeforeClass public void readCurrentVersion() throws Exception {
58.51 + version = findCurrentVersion();
58.52 + assertFalse(version.isEmpty(), "There should be some version string");
58.53 + }
58.54 +
58.55 +
58.56 + @Test public void testComparePomDepsVersions() throws Exception {
58.57 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
58.58 + URL r = l.getResource("archetype-resources/pom.xml");
58.59 + assertNotNull(r, "Archetype pom found");
58.60 +
58.61 + final XPathFactory fact = XPathFactory.newInstance();
58.62 + XPathExpression xp2 = fact.newXPath().compile(
58.63 + "//properties/net.java.html.version/text()"
58.64 + );
58.65 +
58.66 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
58.67 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
58.68 +
58.69 + int snapshot = arch.indexOf("-SNAPSHOT");
58.70 + if (snapshot >= 0) {
58.71 + arch = arch.substring(0, snapshot);
58.72 + }
58.73 +
58.74 + assertTrue(arch.matches("[0-9\\.]+"), "net.java.html.json version seems valid: " + arch);
58.75 + }
58.76 +
58.77 + @Test public void testCheckLauncher() throws Exception {
58.78 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
58.79 + URL r = l.getResource("archetype-resources/pom.xml");
58.80 + assertNotNull(r, "Archetype pom found");
58.81 +
58.82 + final XPathFactory fact = XPathFactory.newInstance();
58.83 + XPathExpression xp2 = fact.newXPath().compile(
58.84 + "//properties/bck2brwsr.launcher.version/text()"
58.85 + );
58.86 +
58.87 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
58.88 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
58.89 +
58.90 + assertEquals(arch, version, "launcher dependency is on more recent version");
58.91 + }
58.92 +
58.93 + @Test public void testCheckBck2Brwsr() throws Exception {
58.94 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
58.95 + URL r = l.getResource("archetype-resources/pom.xml");
58.96 + assertNotNull(r, "Archetype pom found");
58.97 +
58.98 + final XPathFactory fact = XPathFactory.newInstance();
58.99 + XPathExpression xp2 = fact.newXPath().compile(
58.100 + "//properties/bck2brwsr.version/text()"
58.101 + );
58.102 +
58.103 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
58.104 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
58.105 +
58.106 + assertEquals(arch, version, "bck2brwsr dependency is on more recent version");
58.107 + }
58.108 +
58.109 + @Test public void testNbActions() throws Exception {
58.110 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
58.111 + URL r = l.getResource("archetype-resources/nbactions.xml");
58.112 + assertNotNull(r, "Archetype nb file found");
58.113 +
58.114 + final XPathFactory fact = XPathFactory.newInstance();
58.115 + XPathExpression xp2 = fact.newXPath().compile(
58.116 + "//goal/text()"
58.117 + );
58.118 +
58.119 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
58.120 + NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
58.121 +
58.122 + for (int i = 0; i < goals.getLength(); i++) {
58.123 + String s = goals.item(i).getTextContent();
58.124 + if (s.contains("apidesign")) {
58.125 + assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s);
58.126 + }
58.127 + }
58.128 + }
58.129 +
58.130 + static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException {
58.131 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
58.132 + URL u = l.getResource("META-INF/maven/org.apidesign.bck2brwsr/knockout4j-archetype/pom.xml");
58.133 + assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path"));
58.134 +
58.135 + final XPathFactory fact = XPathFactory.newInstance();
58.136 + fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
58.137 +
58.138 + XPathExpression xp = fact.newXPath().compile("project/version/text()");
58.139 +
58.140 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream());
58.141 + return xp.evaluate(dom);
58.142 + }
58.143 +}
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java Mon Oct 07 14:20:58 2013 +0200
59.3 @@ -0,0 +1,133 @@
59.4 +/**
59.5 + * Back 2 Browser Bytecode Translator
59.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
59.7 + *
59.8 + * This program is free software: you can redistribute it and/or modify
59.9 + * it under the terms of the GNU General Public License as published by
59.10 + * the Free Software Foundation, version 2 of the License.
59.11 + *
59.12 + * This program is distributed in the hope that it will be useful,
59.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
59.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59.15 + * GNU General Public License for more details.
59.16 + *
59.17 + * You should have received a copy of the GNU General Public License
59.18 + * along with this program. Look for COPYING file in the top folder.
59.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
59.20 + */
59.21 +package org.apidesign.bck2brwsr.ko.archetype.test;
59.22 +
59.23 +import java.io.File;
59.24 +import java.io.IOException;
59.25 +import java.io.InputStream;
59.26 +import java.util.Properties;
59.27 +import java.util.zip.ZipEntry;
59.28 +import java.util.zip.ZipFile;
59.29 +import org.apache.maven.it.Verifier;
59.30 +import org.testng.annotations.Test;
59.31 +import static org.testng.Assert.*;
59.32 +import org.testng.reporters.Files;
59.33 +
59.34 +/**
59.35 + *
59.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
59.37 + */
59.38 +public class VerifyArchetypeTest {
59.39 + @Test public void fxBrwsrCompiles() throws Exception {
59.40 + final File dir = new File("target/tests/fxcompile/").getAbsoluteFile();
59.41 + generateFromArchetype(dir);
59.42 +
59.43 + File created = new File(dir, "o-a-test");
59.44 + assertTrue(created.isDirectory(), "Project created");
59.45 + assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
59.46 +
59.47 + Verifier v = new Verifier(created.getAbsolutePath());
59.48 + v.executeGoal("verify");
59.49 +
59.50 + v.verifyErrorFreeLog();
59.51 +
59.52 + for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
59.53 + if (l.contains("j2js")) {
59.54 + fail("No pre-compilaton:\n" + l);
59.55 + }
59.56 + }
59.57 +
59.58 + v.verifyTextInLog("org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher");
59.59 + v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-fxbrwsr.zip");
59.60 + }
59.61 +
59.62 + @Test public void bck2BrwsrCompiles() throws Exception {
59.63 + final File dir = new File("target/tests/b2bcompile/").getAbsoluteFile();
59.64 + generateFromArchetype(dir);
59.65 +
59.66 + File created = new File(dir, "o-a-test");
59.67 + assertTrue(created.isDirectory(), "Project created");
59.68 + assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
59.69 +
59.70 + Verifier v = new Verifier(created.getAbsolutePath());
59.71 + Properties sysProp = v.getSystemProperties();
59.72 + if (Boolean.getBoolean("java.awt.headless")) {
59.73 + sysProp.put("java.awt.headless", "true");
59.74 + }
59.75 + v.addCliOption("-Pbck2brwsr");
59.76 + v.executeGoal("verify");
59.77 +
59.78 + v.verifyErrorFreeLog();
59.79 +
59.80 + // does pre-compilation to JavaScript
59.81 + v.verifyTextInLog("j2js");
59.82 + // uses Bck2BrwsrLauncher
59.83 + v.verifyTextInLog("BaseHTTPLauncher showBrwsr");
59.84 + // building zip:
59.85 + v.verifyTextInLog("b2bcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-bck2brwsr.zip");
59.86 +
59.87 + for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
59.88 + if (l.contains("fxbrwsr")) {
59.89 + fail("No fxbrwsr:\n" + l);
59.90 + }
59.91 + }
59.92 +
59.93 + File zip = new File(new File(created, "target"), "o-a-test-1.0-SNAPSHOT-bck2brwsr.zip");
59.94 + assertTrue(zip.isFile(), "Zip file with website was created");
59.95 +
59.96 + ZipFile zf = new ZipFile(zip);
59.97 + final ZipEntry index = zf.getEntry("public_html/index.html");
59.98 + assertNotNull(index, "index.html found");
59.99 +
59.100 + String txt = readText(zf.getInputStream(index));
59.101 + final int beg = txt.indexOf("${");
59.102 + if (beg >= 0) {
59.103 + int end = txt.indexOf("}", beg);
59.104 + if (end < beg) {
59.105 + end = txt.length();
59.106 + }
59.107 + fail("No substitutions in index.html. Found: " + txt.substring(beg, end));
59.108 + }
59.109 + }
59.110 +
59.111 + private Verifier generateFromArchetype(final File dir, String... params) throws Exception {
59.112 + Verifier v = new Verifier(dir.getAbsolutePath());
59.113 + v.setAutoclean(false);
59.114 + v.setLogFileName("generate.log");
59.115 + v.deleteDirectory("");
59.116 + dir.mkdirs();
59.117 + Properties sysProp = v.getSystemProperties();
59.118 + sysProp.put("groupId", "org.apidesign.test");
59.119 + sysProp.put("artifactId", "o-a-test");
59.120 + sysProp.put("package", "org.apidesign.test.oat");
59.121 + sysProp.put("archetypeGroupId", "org.apidesign.bck2brwsr");
59.122 + sysProp.put("archetypeArtifactId", "knockout4j-archetype");
59.123 + sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion());
59.124 +
59.125 + for (String p : params) {
59.126 + v.addCliOption(p);
59.127 + }
59.128 + v.executeGoal("archetype:generate");
59.129 + v.verifyErrorFreeLog();
59.130 + return v;
59.131 + }
59.132 +
59.133 + private static String readText(InputStream is) throws IOException {
59.134 + return Files.readFile(is);
59.135 + }
59.136 +}
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/ko/archetype/pom.xml Mon Oct 07 14:20:58 2013 +0200
60.3 @@ -0,0 +1,58 @@
60.4 +<?xml version="1.0" encoding="UTF-8"?>
60.5 +<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/xsd/maven-4.0.0.xsd">
60.6 + <modelVersion>4.0.0</modelVersion>
60.7 + <parent>
60.8 + <artifactId>ko</artifactId>
60.9 + <groupId>org.apidesign.bck2brwsr</groupId>
60.10 + <version>0.9-SNAPSHOT</version>
60.11 + </parent>
60.12 + <groupId>org.apidesign.bck2brwsr</groupId>
60.13 + <artifactId>knockout4j-archetype</artifactId>
60.14 + <version>0.9-SNAPSHOT</version>
60.15 + <packaging>jar</packaging>
60.16 + <name>Knockout Bck2Brwsr Maven Archetype</name>
60.17 + <description>
60.18 + HTML page with Knockout.js bindings driven by application model
60.19 + written in Java. Use your favorite language to code. Use
60.20 + HTML as a lightweight rendering toolkit. Deploy using JavaFX or
60.21 + bck2brwsr virtual machine.
60.22 + </description>
60.23 + <build>
60.24 + <resources>
60.25 + <resource>
60.26 + <directory>src/main/resources</directory>
60.27 + <filtering>true</filtering>
60.28 + <includes>
60.29 + <include>**/pom.xml</include>
60.30 + </includes>
60.31 + </resource>
60.32 + <resource>
60.33 + <directory>src/main/resources</directory>
60.34 + <filtering>false</filtering>
60.35 + <excludes>
60.36 + <exclude>**/pom.xml</exclude>
60.37 + </excludes>
60.38 + </resource>
60.39 + </resources>
60.40 + <plugins>
60.41 + <plugin>
60.42 + <groupId>org.apache.maven.plugins</groupId>
60.43 + <artifactId>maven-compiler-plugin</artifactId>
60.44 + <version>2.3.2</version>
60.45 + <configuration>
60.46 + <source>1.6</source>
60.47 + <target>1.6</target>
60.48 + </configuration>
60.49 + </plugin>
60.50 + <plugin>
60.51 + <groupId>org.apache.maven.plugins</groupId>
60.52 + <artifactId>maven-resources-plugin</artifactId>
60.53 + <version>2.6</version>
60.54 + <configuration>
60.55 + <escapeString>\</escapeString>
60.56 + <target>1.6</target>
60.57 + </configuration>
60.58 + </plugin>
60.59 + </plugins>
60.60 + </build>
60.61 +</project>
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/ko/archetype/src/main/java/org/apidesign/bck2brwsr/ko/archetype/package-info.java Mon Oct 07 14:20:58 2013 +0200
61.3 @@ -0,0 +1,18 @@
61.4 +/**
61.5 + * Back 2 Browser Bytecode Translator
61.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
61.7 + *
61.8 + * This program is free software: you can redistribute it and/or modify
61.9 + * it under the terms of the GNU General Public License as published by
61.10 + * the Free Software Foundation, version 2 of the License.
61.11 + *
61.12 + * This program is distributed in the hope that it will be useful,
61.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
61.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61.15 + * GNU General Public License for more details.
61.16 + *
61.17 + * You should have received a copy of the GNU General Public License
61.18 + * along with this program. Look for COPYING file in the top folder.
61.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
61.20 + */
61.21 +package org.apidesign.bck2brwsr.ko.archetype;
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/ko/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml Mon Oct 07 14:20:58 2013 +0200
62.3 @@ -0,0 +1,63 @@
62.4 +<?xml version="1.0" encoding="UTF-8"?>
62.5 +<!--
62.6 +
62.7 + Back 2 Browser Bytecode Translator
62.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
62.9 +
62.10 + This program is free software: you can redistribute it and/or modify
62.11 + it under the terms of the GNU General Public License as published by
62.12 + the Free Software Foundation, version 2 of the License.
62.13 +
62.14 + This program is distributed in the hope that it will be useful,
62.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
62.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62.17 + GNU General Public License for more details.
62.18 +
62.19 + You should have received a copy of the GNU General Public License
62.20 + along with this program. Look for COPYING file in the top folder.
62.21 + If not, see http://opensource.org/licenses/GPL-2.0.
62.22 +
62.23 +-->
62.24 +<archetype-descriptor name="FX/Bck2Brwsr Example">
62.25 + <fileSets>
62.26 + <fileSet filtered="true" packaged="true">
62.27 + <directory>src/main/java</directory>
62.28 + <includes>
62.29 + <include>**/*.java</include>
62.30 + </includes>
62.31 + </fileSet>
62.32 + <fileSet filtered="true" packaged="false">
62.33 + <directory>src/main/webapp/pages</directory>
62.34 + <includes>
62.35 + <include>**/*.xhtml</include>
62.36 + <include>**/*.html</include>
62.37 + <include>**/*.css</include>
62.38 + </includes>
62.39 + </fileSet>
62.40 + <fileSet filtered="true" packaged="true">
62.41 + <directory>src/test/java</directory>
62.42 + <includes>
62.43 + <include>**/*Test.java</include>
62.44 + </includes>
62.45 + </fileSet>
62.46 + <fileSet filtered="true" packaged="false">
62.47 + <directory>src/main/assembly</directory>
62.48 + <includes>
62.49 + <include>**/*.xml</include>
62.50 + </includes>
62.51 + </fileSet>
62.52 + <fileSet filtered="false" packaged="false">
62.53 + <directory></directory>
62.54 + <includes>
62.55 + <include>nbactions*.xml</include>
62.56 + </includes>
62.57 + </fileSet>
62.58 + <fileSet filtered="true" packaged="false">
62.59 + <directory>assembly</directory>
62.60 + <includes>
62.61 + <include>fxbrwsr-assembly.xml</include>
62.62 + <include>bck2brwsr-assembly.xml</include>
62.63 + </includes>
62.64 + </fileSet>
62.65 + </fileSets>
62.66 +</archetype-descriptor>
62.67 \ No newline at end of file
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions-bck2brwsr.xml Mon Oct 07 14:20:58 2013 +0200
63.3 @@ -0,0 +1,14 @@
63.4 +<?xml version="1.0" encoding="UTF-8"?>
63.5 +<actions>
63.6 + <action>
63.7 + <actionName>run</actionName>
63.8 + <goals>
63.9 + <goal>package</goal>
63.10 + <goal>bck2brwsr:brwsr</goal>
63.11 + </goals>
63.12 + <properties>
63.13 + <skipTests>true</skipTests>
63.14 + <bck2brwsr.obfuscationlevel>NONE</bck2brwsr.obfuscationlevel>
63.15 + </properties>
63.16 + </action>
63.17 +</actions>
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions-fxbrwsr.xml Mon Oct 07 14:20:58 2013 +0200
64.3 @@ -0,0 +1,20 @@
64.4 +<?xml version="1.0" encoding="UTF-8"?>
64.5 +<actions>
64.6 + <action>
64.7 + <actionName>run</actionName>
64.8 + <goals>
64.9 + <goal>process-classes</goal>
64.10 + <goal>bck2brwsr:brwsr</goal>
64.11 + </goals>
64.12 + </action>
64.13 + <action>
64.14 + <actionName>debug</actionName>
64.15 + <goals>
64.16 + <goal>process-classes</goal>
64.17 + <goal>bck2brwsr:brwsr</goal>
64.18 + </goals>
64.19 + <properties>
64.20 + <jpda.listen>maven</jpda.listen>
64.21 + </properties>
64.22 + </action>
64.23 +</actions>
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions.xml Mon Oct 07 14:20:58 2013 +0200
65.3 @@ -0,0 +1,20 @@
65.4 +<?xml version="1.0" encoding="UTF-8"?>
65.5 +<actions>
65.6 + <action>
65.7 + <actionName>run</actionName>
65.8 + <goals>
65.9 + <goal>process-classes</goal>
65.10 + <goal>bck2brwsr:brwsr</goal>
65.11 + </goals>
65.12 + </action>
65.13 + <action>
65.14 + <actionName>debug</actionName>
65.15 + <goals>
65.16 + <goal>process-classes</goal>
65.17 + <goal>bck2brwsr:brwsr</goal>
65.18 + </goals>
65.19 + <properties>
65.20 + <jpda.listen>maven</jpda.listen>
65.21 + </properties>
65.22 + </action>
65.23 +</actions>
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/ko/archetype/src/main/resources/archetype-resources/pom.xml Mon Oct 07 14:20:58 2013 +0200
66.3 @@ -0,0 +1,267 @@
66.4 +<?xml version="1.0"?>
66.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
66.6 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
66.7 + <modelVersion>4.0.0</modelVersion>
66.8 +
66.9 + <groupId>\${groupId}</groupId>
66.10 + <artifactId>\${artifactId}</artifactId>
66.11 + <version>\${version}</version>
66.12 + <packaging>jar</packaging>
66.13 +
66.14 + <name>\${artifactId}</name>
66.15 +
66.16 + <repositories>
66.17 + <repository>
66.18 + <id>java.net</id>
66.19 + <name>Java.net</name>
66.20 + <url>https://maven.java.net/content/repositories/releases/</url>
66.21 + <snapshots>
66.22 + <enabled>true</enabled>
66.23 + </snapshots>
66.24 + </repository>
66.25 + <repository>
66.26 + <id>netbeans</id>
66.27 + <name>NetBeans</name>
66.28 + <url>http://bits.netbeans.org/maven2/</url>
66.29 + </repository>
66.30 + </repositories>
66.31 + <pluginRepositories>
66.32 + <pluginRepository>
66.33 + <id>java.net</id>
66.34 + <name>Java.net</name>
66.35 + <url>https://maven.java.net/content/repositories/releases/</url>
66.36 + <snapshots>
66.37 + <enabled>true</enabled>
66.38 + </snapshots>
66.39 + </pluginRepository>
66.40 + </pluginRepositories>
66.41 +
66.42 + <properties>
66.43 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
66.44 + <net.java.html.version>${net.java.html.version}</net.java.html.version>
66.45 + <bck2brwsr.version>${project.version}</bck2brwsr.version>
66.46 + <bck2brwsr.launcher.version>${project.version}</bck2brwsr.launcher.version>
66.47 + <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
66.48 + <brwsr.startpage>pages/index.html</brwsr.startpage>
66.49 + </properties>
66.50 + <build>
66.51 + <plugins>
66.52 + <plugin>
66.53 + <groupId>org.apidesign.bck2brwsr</groupId>
66.54 + <artifactId>bck2brwsr-maven-plugin</artifactId>
66.55 + <version>\${bck2brwsr.launcher.version}</version>
66.56 + <executions>
66.57 + <execution>
66.58 + <goals>
66.59 + <goal>brwsr</goal>
66.60 + </goals>
66.61 + </execution>
66.62 + </executions>
66.63 + <configuration>
66.64 + <directory>\${basedir}/src/main/webapp/</directory>
66.65 + <startpage>${brwsr.startpage}</startpage>
66.66 + <launcher>${brwsr}</launcher>
66.67 + </configuration>
66.68 + </plugin>
66.69 + <plugin>
66.70 + <groupId>org.apache.maven.plugins</groupId>
66.71 + <artifactId>maven-compiler-plugin</artifactId>
66.72 + <version>2.3.2</version>
66.73 + <configuration>
66.74 + <source>1.7</source>
66.75 + <target>1.7</target>
66.76 + </configuration>
66.77 + </plugin>
66.78 + <plugin>
66.79 + <groupId>org.apache.maven.plugins</groupId>
66.80 + <artifactId>maven-surefire-plugin</artifactId>
66.81 + <version>2.14.1</version>
66.82 + <configuration>
66.83 + <systemPropertyVariables>
66.84 + <vmtest.brwsrs>\${brwsr}</vmtest.brwsrs>
66.85 + </systemPropertyVariables>
66.86 + </configuration>
66.87 + </plugin>
66.88 + <plugin>
66.89 + <groupId>org.apache.maven.plugins</groupId>
66.90 + <artifactId>maven-jar-plugin</artifactId>
66.91 + <version>2.4</version>
66.92 + <configuration>
66.93 + <archive>
66.94 + <manifest>
66.95 + <addClasspath>true</addClasspath>
66.96 + <classpathPrefix>lib/</classpathPrefix>
66.97 + </manifest>
66.98 + </archive>
66.99 + </configuration>
66.100 + </plugin>
66.101 + <plugin>
66.102 + <groupId>org.apache.maven.plugins</groupId>
66.103 + <artifactId>maven-deploy-plugin</artifactId>
66.104 + <version>2.7</version>
66.105 + <configuration>
66.106 + <skip>true</skip>
66.107 + </configuration>
66.108 + </plugin>
66.109 + </plugins>
66.110 + </build>
66.111 +
66.112 + <dependencies>
66.113 + <dependency>
66.114 + <groupId>org.testng</groupId>
66.115 + <artifactId>testng</artifactId>
66.116 + <version>6.5.2</version>
66.117 + <scope>test</scope>
66.118 + </dependency>
66.119 + <dependency>
66.120 + <groupId>org.apidesign.bck2brwsr</groupId>
66.121 + <artifactId>launcher.http</artifactId>
66.122 + <version>\${bck2brwsr.launcher.version}</version>
66.123 + <scope>test</scope>
66.124 + </dependency>
66.125 + <dependency>
66.126 + <groupId>org.apidesign.bck2brwsr</groupId>
66.127 + <artifactId>vmtest</artifactId>
66.128 + <version>\${bck2brwsr.version}</version>
66.129 + <scope>test</scope>
66.130 + </dependency>
66.131 + <dependency>
66.132 + <groupId>org.apidesign.html</groupId>
66.133 + <artifactId>net.java.html.json</artifactId>
66.134 + <version>\${net.java.html.version}</version>
66.135 + <type>jar</type>
66.136 + </dependency>
66.137 + </dependencies>
66.138 + <profiles>
66.139 + <profile>
66.140 + <id>fxbrwsr</id>
66.141 + <activation>
66.142 + <activeByDefault>true</activeByDefault>
66.143 + </activation>
66.144 + <properties>
66.145 + <brwsr>fxbrwsr</brwsr>
66.146 + </properties>
66.147 + <build>
66.148 + <plugins>
66.149 + <plugin>
66.150 + <groupId>org.apache.maven.plugins</groupId>
66.151 + <artifactId>maven-jar-plugin</artifactId>
66.152 + <version>2.4</version>
66.153 + <configuration>
66.154 + <archive>
66.155 + <manifest>
66.156 + <mainClass>org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher</mainClass>
66.157 + <addClasspath>true</addClasspath>
66.158 + <classpathPrefix>lib/</classpathPrefix>
66.159 + </manifest>
66.160 + <manifestEntries>
66.161 + <StartPage>\${brwsr.startpage}</StartPage>
66.162 + </manifestEntries>
66.163 + </archive>
66.164 + </configuration>
66.165 + </plugin>
66.166 + <plugin>
66.167 + <artifactId>maven-assembly-plugin</artifactId>
66.168 + <version>2.4</version>
66.169 + <executions>
66.170 + <execution>
66.171 + <id>distro-assembly</id>
66.172 + <phase>package</phase>
66.173 + <goals>
66.174 + <goal>single</goal>
66.175 + </goals>
66.176 + <configuration>
66.177 + <descriptors>
66.178 + <descriptor>src/main/assembly/fxbrwsr.xml</descriptor>
66.179 + </descriptors>
66.180 + </configuration>
66.181 + </execution>
66.182 + </executions>
66.183 + </plugin>
66.184 + </plugins>
66.185 + </build>
66.186 + <dependencies>
66.187 + <dependency>
66.188 + <groupId>org.apidesign.html</groupId>
66.189 + <artifactId>ko-fx</artifactId>
66.190 + <version>\${net.java.html.version}</version>
66.191 + </dependency>
66.192 + <dependency>
66.193 + <groupId>org.apidesign.bck2brwsr</groupId>
66.194 + <artifactId>launcher.fx</artifactId>
66.195 + <version>\${bck2brwsr.launcher.version}</version>
66.196 + <scope>runtime</scope>
66.197 + </dependency>
66.198 + </dependencies>
66.199 + </profile>
66.200 + <profile>
66.201 + <id>bck2brwsr</id>
66.202 + <activation>
66.203 + <property>
66.204 + <name>brwsr</name>
66.205 + <value>bck2brwsr</value>
66.206 + </property>
66.207 + </activation>
66.208 + <build>
66.209 + <plugins>
66.210 + <plugin>
66.211 + <groupId>org.apidesign.bck2brwsr</groupId>
66.212 + <artifactId>bck2brwsr-maven-plugin</artifactId>
66.213 + <executions>
66.214 + <execution>
66.215 + <goals>
66.216 + <goal>j2js</goal>
66.217 + </goals>
66.218 + </execution>
66.219 + </executions>
66.220 + <configuration>
66.221 + <javascript>\${project.build.directory}/bck2brwsr.js</javascript>
66.222 + <obfuscation>\${bck2brwsr.obfuscationlevel}</obfuscation>
66.223 + </configuration>
66.224 + </plugin>
66.225 + <plugin>
66.226 + <groupId>org.apache.maven.plugins</groupId>
66.227 + <artifactId>maven-compiler-plugin</artifactId>
66.228 + <configuration>
66.229 + <compilerArguments>
66.230 + <bootclasspath>netbeans.ignore.jdk.bootclasspath</bootclasspath>
66.231 + </compilerArguments>
66.232 + </configuration>
66.233 + </plugin>
66.234 + <plugin>
66.235 + <artifactId>maven-assembly-plugin</artifactId>
66.236 + <version>2.4</version>
66.237 + <executions>
66.238 + <execution>
66.239 + <id>distro-assembly</id>
66.240 + <phase>package</phase>
66.241 + <goals>
66.242 + <goal>single</goal>
66.243 + </goals>
66.244 + <configuration>
66.245 + <descriptors>
66.246 + <descriptor>src/main/assembly/bck2brwsr.xml</descriptor>
66.247 + </descriptors>
66.248 + </configuration>
66.249 + </execution>
66.250 + </executions>
66.251 + </plugin>
66.252 + </plugins>
66.253 + </build>
66.254 + <dependencies>
66.255 + <dependency>
66.256 + <groupId>org.apidesign.bck2brwsr</groupId>
66.257 + <artifactId>emul</artifactId>
66.258 + <version>\${bck2brwsr.version}</version>
66.259 + <classifier>rt</classifier>
66.260 + </dependency>
66.261 + <dependency>
66.262 + <groupId>org.apidesign.bck2brwsr</groupId>
66.263 + <artifactId>ko-bck2brwsr</artifactId>
66.264 + <version>\${bck2brwsr.version}</version>
66.265 + <scope>runtime</scope>
66.266 + </dependency>
66.267 + </dependencies>
66.268 + </profile>
66.269 + </profiles>
66.270 +</project>
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml Mon Oct 07 14:20:58 2013 +0200
67.3 @@ -0,0 +1,48 @@
67.4 +<?xml version="1.0"?>
67.5 +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
67.6 + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
67.7 +
67.8 + <id>bck2brwsr</id>
67.9 + <formats>
67.10 + <format>zip</format>
67.11 + </formats>
67.12 + <baseDirectory>public_html</baseDirectory>
67.13 + <dependencySets>
67.14 + <dependencySet>
67.15 + <useProjectArtifact>false</useProjectArtifact>
67.16 + <scope>runtime</scope>
67.17 + <outputDirectory>lib</outputDirectory>
67.18 + <includes>
67.19 + <include>*:jar</include>
67.20 + <include>*:rt</include>
67.21 + </includes>
67.22 + </dependencySet>
67.23 + </dependencySets>
67.24 + <fileSets>
67.25 + <fileSet>
67.26 + <directory>${project.build.directory}/classes/${package.replace('.','/')}/</directory>
67.27 + <includes>
67.28 + <include>**/*</include>
67.29 + </includes>
67.30 + <excludes>
67.31 + <exclude>**/*.class</exclude>
67.32 + </excludes>
67.33 + <outputDirectory>/</outputDirectory>
67.34 + </fileSet>
67.35 + <fileSet>
67.36 + <directory>src/main/webapp/pages</directory>
67.37 + <outputDirectory>/</outputDirectory>
67.38 + <filtered>true</filtered>
67.39 + </fileSet>
67.40 + </fileSets>
67.41 + <files>
67.42 + <file>
67.43 + <source>${project.build.directory}/${project.build.finalName}.jar</source>
67.44 + <outputDirectory>/</outputDirectory>
67.45 + </file>
67.46 + <file>
67.47 + <source>${project.build.directory}/bck2brwsr.js</source>
67.48 + <outputDirectory>/</outputDirectory>
67.49 + </file>
67.50 + </files>
67.51 +</assembly>
67.52 \ No newline at end of file
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/fxbrwsr.xml Mon Oct 07 14:20:58 2013 +0200
68.3 @@ -0,0 +1,33 @@
68.4 +<?xml version="1.0"?>
68.5 +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
68.6 + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
68.7 +
68.8 + <id>fxbrwsr</id>
68.9 + <formats>
68.10 + <format>zip</format>
68.11 + </formats>
68.12 + <baseDirectory>${project.build.finalName}-fxbrwsr</baseDirectory>
68.13 + <dependencySets>
68.14 + <dependencySet>
68.15 + <useProjectArtifact>false</useProjectArtifact>
68.16 + <scope>runtime</scope>
68.17 + <outputDirectory>lib</outputDirectory>
68.18 + </dependencySet>
68.19 + </dependencySets>
68.20 + <files>
68.21 + <file>
68.22 + <source>${project.build.directory}/${project.build.finalName}.jar</source>
68.23 + <outputDirectory>/</outputDirectory>
68.24 + </file>
68.25 + </files>
68.26 + <fileSets>
68.27 + <fileSet>
68.28 + <directory>src/main/webapp/</directory>
68.29 + <outputDirectory>/</outputDirectory>
68.30 + <includes>
68.31 + <include>pages/**</include>
68.32 + </includes>
68.33 + <filtered>true</filtered>
68.34 + </fileSet>
68.35 + </fileSets>
68.36 +</assembly>
68.37 \ No newline at end of file
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java Mon Oct 07 14:20:58 2013 +0200
69.3 @@ -0,0 +1,31 @@
69.4 +package ${package};
69.5 +
69.6 +import net.java.html.json.ComputedProperty;
69.7 +import net.java.html.json.Function;
69.8 +import net.java.html.json.Model;
69.9 +import net.java.html.json.Property;
69.10 +
69.11 +/** Model annotation generates class Data with
69.12 + * one message property, boolean property and read only words property
69.13 + */
69.14 +@Model(className = "Data", properties = {
69.15 + @Property(name = "message", type = String.class),
69.16 + @Property(name = "on", type = boolean.class)
69.17 +})
69.18 +final class DataModel {
69.19 + @ComputedProperty static java.util.List<String> words(String message) {
69.20 + String[] arr = new String[6];
69.21 + String[] words = message == null ? new String[0] : message.split(" ", 6);
69.22 + for (int i = 0; i < 6; i++) {
69.23 + arr[i] = words.length > i ? words[i] : "!";
69.24 + }
69.25 + return java.util.Arrays.asList(arr);
69.26 + }
69.27 +
69.28 + @Function static void turnOn(Data model) {
69.29 + model.setOn(true);
69.30 + }
69.31 + @Function static void turnOff(Data model) {
69.32 + model.setOn(false);
69.33 + }
69.34 +}
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/Main.java Mon Oct 07 14:20:58 2013 +0200
70.3 @@ -0,0 +1,15 @@
70.4 +package ${package};
70.5 +
70.6 +public final class Main {
70.7 + private Main() {
70.8 + }
70.9 +
70.10 + /**
70.11 + * Called when the page is ready.
70.12 + */
70.13 + static {
70.14 + Data d = new Data();
70.15 + d.setMessage("Hello World from HTML and Java!");
70.16 + d.applyBindings();
70.17 + }
70.18 +}
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html Mon Oct 07 14:20:58 2013 +0200
71.3 @@ -0,0 +1,63 @@
71.4 +<!DOCTYPE html>
71.5 +<html>
71.6 + <head>
71.7 + <title></title>
71.8 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
71.9 +
71.10 + <style type="text/css">
71.11 + @-webkit-keyframes spin {
71.12 + 0% { -webkit-transform: rotate(0deg); }
71.13 + 100% { -webkit-transform: rotate(360deg); }
71.14 + }
71.15 +
71.16 + .rotate {
71.17 + -webkit-animation-name: spin;
71.18 + -webkit-animation-duration: 3s;
71.19 + -webkit-animation-iteration-count: infinite;
71.20 + -webkit-animation-direction: alternate;
71.21 + }
71.22 +
71.23 + #scene {
71.24 + position: relative;
71.25 + top: 60px;
71.26 + text-align: center;
71.27 + }
71.28 +
71.29 + #words span {
71.30 + border: 1px solid #ccc;
71.31 + background: rgba(255,255,155,0.8);
71.32 + text-align: center;
71.33 + font-size: 30px;
71.34 + -webkit-box-shadow: inset 0 0 40px rgba(0,0,0,0.4);
71.35 + position: absolute;
71.36 + }
71.37 +
71.38 + #words span:nth-child(1) { left: 45%; top: 0px; }
71.39 + #words span:nth-child(2) { left: 25%; top: 100px; }
71.40 + #words span:nth-child(3) { left: 65%; top: 100px; }
71.41 + #words span:nth-child(4) { left: 10%; top: 200px; }
71.42 + #words span:nth-child(5) { left: 45%; top: 200px; }
71.43 + #words span:nth-child(6) { left: 80%; top: 200px; }
71.44 +
71.45 + </style>
71.46 +
71.47 + </head>
71.48 + <body>
71.49 + <h1>Words Demo</h1>
71.50 + <input data-bind="value: message, valueUpdate: 'afterkeydown'" size="80">
71.51 + <br>
71.52 + <button data-bind="enable: !on(), click: $root.turnOn">Start</button>
71.53 + <button data-bind="enable: on, click: $root.turnOff">Stop</button>
71.54 +
71.55 + <div id="scene">
71.56 + <span id="words" data-bind="foreach: words">
71.57 + <span data-bind="text: $data, css: { 'rotate' : $root.on } "></span>
71.58 + </span>
71.59 + </div>
71.60 + <script type="text/javascript" src="bck2brwsr.js"></script>
71.61 + <script>
71.62 + var vm = bck2brwsr('${project.build.finalName}.jar');
71.63 + vm.loadClass('${package}.Main');
71.64 + </script>
71.65 + </body>
71.66 +</html>
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/DataModelTest.java Mon Oct 07 14:20:58 2013 +0200
72.3 @@ -0,0 +1,16 @@
72.4 +package ${package};
72.5 +
72.6 +import static org.testng.Assert.*;
72.7 +import org.testng.annotations.Test;
72.8 +
72.9 +public class DataModelTest {
72.10 + @Test public void areHelloWorldTwoWords() {
72.11 + Data model = new Data();
72.12 + model.setMessage("Hello World!");
72.13 +
72.14 + java.util.List<String> arr = model.getWords();
72.15 + assertEquals(arr.size(), 6, "Six words always");
72.16 + assertEquals("Hello", arr.get(0), "Hello is the first word");
72.17 + assertEquals("World!", arr.get(1), "World is the second word");
72.18 + }
72.19 +}
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Mon Oct 07 14:20:58 2013 +0200
73.3 @@ -0,0 +1,38 @@
73.4 +package ${package};
73.5 +
73.6 +import org.apidesign.bck2brwsr.vmtest.Compare;
73.7 +import org.apidesign.bck2brwsr.vmtest.VMTest;
73.8 +import org.testng.annotations.Factory;
73.9 +
73.10 +/** Bck2brwsr cares about compatibility with real Java. Whatever API is
73.11 + * supported by bck2brwsr, it needs to behave the same way as when running
73.12 + * in HotSpot VM.
73.13 + * <p>
73.14 + * There can be bugs, however. To help us fix them, we kindly ask you to
73.15 + * write an "inconsistency" test. A test that compares behavior of the API
73.16 + * between real VM and bck2brwsr VM. This class is skeleton of such test.
73.17 + */
73.18 +public class InconsistencyTest {
73.19 + /** A method to demonstrate inconsistency between bck2brwsr and HotSpot.
73.20 + * Make calls to an API that behaves strangely, return some result at
73.21 + * the end. No need to use any <code>assert</code>.
73.22 + *
73.23 + * @return value to compare between HotSpot and bck2brwsr
73.24 + */
73.25 + @Compare
73.26 + public int checkStringHashCode() throws Exception {
73.27 + return "Is string hashCode the same?".hashCode();
73.28 + }
73.29 +
73.30 + /** Factory method that creates a three tests for each method annotated with
73.31 + * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in
73.32 + * HotSpot, one in Rhino and the last one compares the results.
73.33 + *
73.34 + * @see org.apidesign.bck2brwsr.vmtest.VMTest
73.35 + */
73.36 + @Factory
73.37 + public static Object[] create() {
73.38 + return VMTest.create(InconsistencyTest.class);
73.39 + }
73.40 +
73.41 +}
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
74.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Mon Oct 07 14:20:58 2013 +0200
74.3 @@ -0,0 +1,31 @@
74.4 +package ${package};
74.5 +
74.6 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
74.7 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
74.8 +import org.apidesign.bck2brwsr.vmtest.VMTest;
74.9 +import org.testng.annotations.Factory;
74.10 +
74.11 +/** Sometimes it is useful to run tests inside of the real browser.
74.12 + * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest}
74.13 + * and that is it. If your code references elements on the HTML page,
74.14 + * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which
74.15 + * will be made available on the page before your test starts.
74.16 + */
74.17 +public class IntegrationTest {
74.18 +
74.19 + /** Write to testing code here. Use <code>assert</code> (but not TestNG's
74.20 + * Assert, as TestNG is not compiled with target 1.6 yet).
74.21 + */
74.22 + @HtmlFragment(
74.23 + "<h1>Put this snippet on the HTML page</h1>\n"
74.24 + )
74.25 + @BrwsrTest
74.26 + public void runThisTestInABrowser() {
74.27 + }
74.28 +
74.29 + @Factory
74.30 + public static Object[] create() {
74.31 + return VMTest.create(IntegrationTest.class);
74.32 + }
74.33 +
74.34 +}
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75.2 +++ b/ko/bck2brwsr/pom.xml Mon Oct 07 14:20:58 2013 +0200
75.3 @@ -0,0 +1,102 @@
75.4 +<?xml version="1.0"?>
75.5 +<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/xsd/maven-4.0.0.xsd">
75.6 + <modelVersion>4.0.0</modelVersion>
75.7 + <parent>
75.8 + <groupId>org.apidesign.bck2brwsr</groupId>
75.9 + <artifactId>ko</artifactId>
75.10 + <version>0.9-SNAPSHOT</version>
75.11 + </parent>
75.12 + <groupId>org.apidesign.bck2brwsr</groupId>
75.13 + <artifactId>ko-bck2brwsr</artifactId>
75.14 + <version>0.9-SNAPSHOT</version>
75.15 + <name>Knockout.b2b</name>
75.16 + <url>http://maven.apache.org</url>
75.17 + <build>
75.18 + <plugins>
75.19 + <plugin>
75.20 + <groupId>org.apache.maven.plugins</groupId>
75.21 + <artifactId>maven-compiler-plugin</artifactId>
75.22 + <version>2.3.2</version>
75.23 + <configuration>
75.24 + <source>1.7</source>
75.25 + <target>1.7</target>
75.26 + </configuration>
75.27 + </plugin>
75.28 + <plugin>
75.29 + <groupId>org.apache.maven.plugins</groupId>
75.30 + <artifactId>maven-javadoc-plugin</artifactId>
75.31 + <configuration>
75.32 + <skip>false</skip>
75.33 + </configuration>
75.34 + </plugin>
75.35 + </plugins>
75.36 + </build>
75.37 + <dependencies>
75.38 + <dependency>
75.39 + <groupId>org.testng</groupId>
75.40 + <artifactId>testng</artifactId>
75.41 + <scope>test</scope>
75.42 + <exclusions>
75.43 + <exclusion>
75.44 + <artifactId>junit</artifactId>
75.45 + <groupId>junit</groupId>
75.46 + </exclusion>
75.47 + </exclusions>
75.48 + </dependency>
75.49 + <dependency>
75.50 + <groupId>org.netbeans.api</groupId>
75.51 + <artifactId>org-openide-util-lookup</artifactId>
75.52 + <scope>provided</scope>
75.53 + </dependency>
75.54 + <dependency>
75.55 + <groupId>org.apidesign.bck2brwsr</groupId>
75.56 + <artifactId>emul</artifactId>
75.57 + <version>${project.version}</version>
75.58 + <classifier>rt</classifier>
75.59 + <type>jar</type>
75.60 + <scope>compile</scope>
75.61 + </dependency>
75.62 + <dependency>
75.63 + <groupId>org.apidesign.bck2brwsr</groupId>
75.64 + <artifactId>vm4brwsr</artifactId>
75.65 + <version>${project.version}</version>
75.66 + <type>jar</type>
75.67 + <scope>test</scope>
75.68 + </dependency>
75.69 + <dependency>
75.70 + <groupId>org.apidesign.bck2brwsr</groupId>
75.71 + <artifactId>vmtest</artifactId>
75.72 + <version>${project.version}</version>
75.73 + <scope>test</scope>
75.74 + </dependency>
75.75 + <dependency>
75.76 + <groupId>org.apidesign.bck2brwsr</groupId>
75.77 + <artifactId>launcher.http</artifactId>
75.78 + <version>${project.version}</version>
75.79 + <scope>test</scope>
75.80 + </dependency>
75.81 + <dependency>
75.82 + <groupId>org.apidesign.html</groupId>
75.83 + <artifactId>net.java.html.json</artifactId>
75.84 + <version>${net.java.html.version}</version>
75.85 + </dependency>
75.86 + <dependency>
75.87 + <groupId>org.apidesign.html</groupId>
75.88 + <artifactId>net.java.html.json.tck</artifactId>
75.89 + <version>${net.java.html.version}</version>
75.90 + <scope>test</scope>
75.91 + </dependency>
75.92 + <dependency>
75.93 + <groupId>org.apidesign.bck2brwsr</groupId>
75.94 + <artifactId>core</artifactId>
75.95 + <version>${project.version}</version>
75.96 + <type>jar</type>
75.97 + </dependency>
75.98 + <dependency>
75.99 + <groupId>org.apidesign.html</groupId>
75.100 + <artifactId>net.java.html.boot</artifactId>
75.101 + <version>0.5</version>
75.102 + <type>jar</type>
75.103 + </dependency>
75.104 + </dependencies>
75.105 +</project>
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxImpl.java Mon Oct 07 14:20:58 2013 +0200
76.3 @@ -0,0 +1,166 @@
76.4 +/**
76.5 + * Back 2 Browser Bytecode Translator
76.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
76.7 + *
76.8 + * This program is free software: you can redistribute it and/or modify
76.9 + * it under the terms of the GNU General Public License as published by
76.10 + * the Free Software Foundation, version 2 of the License.
76.11 + *
76.12 + * This program is distributed in the hope that it will be useful,
76.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
76.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76.15 + * GNU General Public License for more details.
76.16 + *
76.17 + * You should have received a copy of the GNU General Public License
76.18 + * along with this program. Look for COPYING file in the top folder.
76.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
76.20 + */
76.21 +package org.apidesign.bck2brwsr.ko2brwsr;
76.22 +
76.23 +import java.io.ByteArrayOutputStream;
76.24 +import java.io.IOException;
76.25 +import java.io.InputStream;
76.26 +import java.io.InputStreamReader;
76.27 +import org.apidesign.html.json.spi.FunctionBinding;
76.28 +import org.apidesign.html.json.spi.JSONCall;
76.29 +import org.apidesign.html.json.spi.PropertyBinding;
76.30 +import org.apidesign.html.json.spi.Technology;
76.31 +import org.apidesign.html.json.spi.Transfer;
76.32 +import org.apidesign.html.json.spi.WSTransfer;
76.33 +
76.34 +/**
76.35 + *
76.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
76.37 + */
76.38 +final class BrwsrCtxImpl implements Technology<Object>, Transfer, WSTransfer<LoadWS> {
76.39 + private BrwsrCtxImpl() {}
76.40 +
76.41 + public static final BrwsrCtxImpl DEFAULT = new BrwsrCtxImpl();
76.42 +
76.43 + @Override
76.44 + public void extract(Object obj, String[] props, Object[] values) {
76.45 + ConvertTypes.extractJSON(obj, props, values);
76.46 + }
76.47 +
76.48 + @Override
76.49 + public void loadJSON(final JSONCall call) {
76.50 + class R implements Runnable {
76.51 + final boolean success;
76.52 +
76.53 + public R(boolean success) {
76.54 + this.success = success;
76.55 + }
76.56 +
76.57 + Object[] arr = { null };
76.58 + @Override
76.59 + public void run() {
76.60 + if (success) {
76.61 + call.notifySuccess(arr[0]);
76.62 + } else {
76.63 + Throwable t;
76.64 + if (arr[0] instanceof Throwable) {
76.65 + t = (Throwable) arr[0];
76.66 + } else {
76.67 + if (arr[0] == null) {
76.68 + t = new IOException();
76.69 + } else {
76.70 + t = new IOException(arr[0].toString());
76.71 + }
76.72 + }
76.73 + call.notifyError(t);
76.74 + }
76.75 + }
76.76 + }
76.77 + R success = new R(true);
76.78 + R failure = new R(false);
76.79 + if (call.isJSONP()) {
76.80 + String me = ConvertTypes.createJSONP(success.arr, success);
76.81 + ConvertTypes.loadJSONP(call.composeURL(me), me);
76.82 + } else {
76.83 + String data = null;
76.84 + if (call.isDoOutput()) {
76.85 + try {
76.86 + ByteArrayOutputStream bos = new ByteArrayOutputStream();
76.87 + call.writeData(bos);
76.88 + data = new String(bos.toByteArray(), "UTF-8");
76.89 + } catch (IOException ex) {
76.90 + call.notifyError(ex);
76.91 + }
76.92 + }
76.93 + ConvertTypes.loadJSON(call.composeURL(null), success.arr, success, failure, call.getMethod(), data);
76.94 + }
76.95 + }
76.96 +
76.97 + @Override
76.98 + public Object wrapModel(Object model) {
76.99 + return model;
76.100 + }
76.101 +
76.102 + @Override
76.103 + public void bind(PropertyBinding b, Object model, Object data) {
76.104 + Knockout.bind(data, b, b.getPropertyName(),
76.105 + "getValue__Ljava_lang_Object_2",
76.106 + b.isReadOnly() ? null : "setValue__VLjava_lang_Object_2",
76.107 + false, false
76.108 + );
76.109 + }
76.110 +
76.111 + @Override
76.112 + public void valueHasMutated(Object data, String propertyName) {
76.113 + Knockout.valueHasMutated(data, propertyName);
76.114 + }
76.115 +
76.116 + @Override
76.117 + public void expose(FunctionBinding fb, Object model, Object d) {
76.118 + Knockout.expose(d, fb, fb.getFunctionName(), "call__VLjava_lang_Object_2Ljava_lang_Object_2");
76.119 + }
76.120 +
76.121 + @Override
76.122 + public void applyBindings(Object data) {
76.123 + Knockout.applyBindings(data);
76.124 + }
76.125 +
76.126 + @Override
76.127 + public Object wrapArray(Object[] arr) {
76.128 + return arr;
76.129 + }
76.130 +
76.131 + @Override
76.132 + public <M> M toModel(Class<M> modelClass, Object data) {
76.133 + return modelClass.cast(data);
76.134 + }
76.135 +
76.136 + @Override
76.137 + public Object toJSON(InputStream is) throws IOException {
76.138 + StringBuilder sb = new StringBuilder();
76.139 + InputStreamReader r = new InputStreamReader(is);
76.140 + for (;;) {
76.141 + int ch = r.read();
76.142 + if (ch == -1) {
76.143 + break;
76.144 + }
76.145 + sb.append((char)ch);
76.146 + }
76.147 + return ConvertTypes.parse(sb.toString());
76.148 + }
76.149 +
76.150 + @Override
76.151 + public void runSafe(Runnable r) {
76.152 + r.run();
76.153 + }
76.154 +
76.155 + @Override
76.156 + public LoadWS open(String url, JSONCall callback) {
76.157 + return new LoadWS(callback, url);
76.158 + }
76.159 +
76.160 + @Override
76.161 + public void send(LoadWS socket, JSONCall data) {
76.162 + socket.send(data);
76.163 + }
76.164 +
76.165 + @Override
76.166 + public void close(LoadWS socket) {
76.167 + socket.close();
76.168 + }
76.169 +}
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxPrvdr.java Mon Oct 07 14:20:58 2013 +0200
77.3 @@ -0,0 +1,53 @@
77.4 +/**
77.5 + * Back 2 Browser Bytecode Translator
77.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
77.7 + *
77.8 + * This program is free software: you can redistribute it and/or modify
77.9 + * it under the terms of the GNU General Public License as published by
77.10 + * the Free Software Foundation, version 2 of the License.
77.11 + *
77.12 + * This program is distributed in the hope that it will be useful,
77.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
77.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77.15 + * GNU General Public License for more details.
77.16 + *
77.17 + * You should have received a copy of the GNU General Public License
77.18 + * along with this program. Look for COPYING file in the top folder.
77.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
77.20 + */
77.21 +package org.apidesign.bck2brwsr.ko2brwsr;
77.22 +
77.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
77.24 +import org.apidesign.html.context.spi.Contexts;
77.25 +import org.apidesign.html.json.spi.Technology;
77.26 +import org.apidesign.html.json.spi.Transfer;
77.27 +import org.apidesign.html.json.spi.WSTransfer;
77.28 +import org.openide.util.lookup.ServiceProvider;
77.29 +
77.30 +/** This is an implementation package - just
77.31 + * include its JAR on classpath and use official {@link Context} API
77.32 + * to access the functionality.
77.33 + * <p>
77.34 + * Provides binding between models and <a href="http://bck2brwsr.apidesign.org">
77.35 + * Bck2Brwsr</a> VM.
77.36 + * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it.
77.37 + *
77.38 + * @author Jaroslav Tulach <jtulach@netbeans.org>
77.39 + */
77.40 +@ServiceProvider(service = Contexts.Provider.class)
77.41 +public final class BrwsrCtxPrvdr implements Contexts.Provider {
77.42 +
77.43 + @Override
77.44 + public void fillContext(Contexts.Builder context, Class<?> requestor) {
77.45 + if (bck2BrwsrVM()) {
77.46 + context.register(Technology.class, BrwsrCtxImpl.DEFAULT, 50).
77.47 + register(Transfer.class, BrwsrCtxImpl.DEFAULT, 50).
77.48 + register(WSTransfer.class, BrwsrCtxImpl.DEFAULT, 50);
77.49 + }
77.50 + }
77.51 +
77.52 + @JavaScriptBody(args = { }, body = "return true;")
77.53 + private static boolean bck2BrwsrVM() {
77.54 + return false;
77.55 + }
77.56 +}
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/ConvertTypes.java Mon Oct 07 14:20:58 2013 +0200
78.3 @@ -0,0 +1,157 @@
78.4 +/**
78.5 + * Back 2 Browser Bytecode Translator
78.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
78.7 + *
78.8 + * This program is free software: you can redistribute it and/or modify
78.9 + * it under the terms of the GNU General Public License as published by
78.10 + * the Free Software Foundation, version 2 of the License.
78.11 + *
78.12 + * This program is distributed in the hope that it will be useful,
78.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
78.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
78.15 + * GNU General Public License for more details.
78.16 + *
78.17 + * You should have received a copy of the GNU General Public License
78.18 + * along with this program. Look for COPYING file in the top folder.
78.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
78.20 + */
78.21 +package org.apidesign.bck2brwsr.ko2brwsr;
78.22 +
78.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
78.24 +
78.25 +/**
78.26 + *
78.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
78.28 + */
78.29 +final class ConvertTypes {
78.30 + ConvertTypes() {
78.31 + }
78.32 +
78.33 + public static String toString(Object object, String property) {
78.34 + Object ret = getProperty(object, property);
78.35 + return ret == null ? null : ret.toString();
78.36 + }
78.37 +
78.38 + public static double toDouble(Object object, String property) {
78.39 + Object ret = getProperty(object, property);
78.40 + return ret instanceof Number ? ((Number)ret).doubleValue() : Double.NaN;
78.41 + }
78.42 +
78.43 + public static int toInt(Object object, String property) {
78.44 + Object ret = getProperty(object, property);
78.45 + return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE;
78.46 + }
78.47 +
78.48 + public static <T> T toModel(Class<T> modelClass, Object object, String property) {
78.49 + Object ret = getProperty(object, property);
78.50 + if (ret == null || modelClass.isInstance(ret)) {
78.51 + return modelClass.cast(ret);
78.52 + }
78.53 + throw new IllegalStateException("Value " + ret + " is not of type " + modelClass);
78.54 + }
78.55 +
78.56 + public static String toJSON(Object value) {
78.57 + if (value == null) {
78.58 + return "null";
78.59 + }
78.60 + if (value instanceof Enum) {
78.61 + value = value.toString();
78.62 + }
78.63 + if (value instanceof String) {
78.64 + return '"' +
78.65 + ((String)value).
78.66 + replace("\"", "\\\"").
78.67 + replace("\n", "\\n").
78.68 + replace("\r", "\\r").
78.69 + replace("\t", "\\t")
78.70 + + '"';
78.71 + }
78.72 + return value.toString();
78.73 + }
78.74 +
78.75 + @JavaScriptBody(args = { "object", "property" },
78.76 + body =
78.77 + "if (property === null) return object;\n"
78.78 + + "if (object === null) return null;\n"
78.79 + + "var p = object[property]; return p ? p : null;"
78.80 + )
78.81 + private static Object getProperty(Object object, String property) {
78.82 + return null;
78.83 + }
78.84 +
78.85 + public static String createJSONP(Object[] jsonResult, Runnable whenDone) {
78.86 + int h = whenDone.hashCode();
78.87 + String name;
78.88 + for (;;) {
78.89 + name = "jsonp" + Integer.toHexString(h);
78.90 + if (defineIfUnused(name, jsonResult, whenDone)) {
78.91 + return name;
78.92 + }
78.93 + h++;
78.94 + }
78.95 + }
78.96 +
78.97 + @JavaScriptBody(args = { "name", "arr", "run" }, body =
78.98 + "if (window[name]) return false;\n "
78.99 + + "window[name] = function(data) {\n "
78.100 + + " delete window[name];\n"
78.101 + + " var el = window.document.getElementById(name);\n"
78.102 + + " el.parentNode.removeChild(el);\n"
78.103 + + " arr[0] = data;\n"
78.104 + + " run.run__V();\n"
78.105 + + "};\n"
78.106 + + "return true;\n"
78.107 + )
78.108 + private static boolean defineIfUnused(String name, Object[] arr, Runnable run) {
78.109 + return true;
78.110 + }
78.111 +
78.112 + @JavaScriptBody(args = { "s" }, body = "return eval('(' + s + ')');")
78.113 + static Object parse(String s) {
78.114 + return s;
78.115 + }
78.116 +
78.117 + @JavaScriptBody(args = { "url", "arr", "callback", "onError", "method", "data" }, body = ""
78.118 + + "var request = new XMLHttpRequest();\n"
78.119 + + "if (!method) method = 'GET';\n"
78.120 + + "request.open(method, url, true);\n"
78.121 + + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n"
78.122 + + "request.onreadystatechange = function() {\n"
78.123 + + " if (this.readyState!==4) return;\n"
78.124 + + " try {\n"
78.125 + + " arr[0] = eval('(' + this.response + ')');\n"
78.126 + + " } catch (error) {;\n"
78.127 + + " arr[0] = this.response;\n"
78.128 + + " }\n"
78.129 + + " callback.run__V();\n"
78.130 + + "};\n"
78.131 + + "request.onerror = function (e) {\n"
78.132 + + " arr[0] = e; onError.run__V();\n"
78.133 + + "}\n"
78.134 + + "if (data) request.send(data);"
78.135 + + "else request.send();"
78.136 + )
78.137 + static void loadJSON(
78.138 + String url, Object[] jsonResult, Runnable whenDone, Runnable whenErr, String method, String data
78.139 + ) {
78.140 + }
78.141 +
78.142 + @JavaScriptBody(args = { "url", "jsonp" }, body =
78.143 + "var scrpt = window.document.createElement('script');\n "
78.144 + + "scrpt.setAttribute('src', url);\n "
78.145 + + "scrpt.setAttribute('id', jsonp);\n "
78.146 + + "scrpt.setAttribute('type', 'text/javascript');\n "
78.147 + + "var body = document.getElementsByTagName('body')[0];\n "
78.148 + + "body.appendChild(scrpt);\n"
78.149 + )
78.150 + static void loadJSONP(String url, String jsonp) {
78.151 +
78.152 + }
78.153 +
78.154 + public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
78.155 + for (int i = 0; i < props.length; i++) {
78.156 + values[i] = getProperty(jsonObject, props[i]);
78.157 + }
78.158 + }
78.159 +
78.160 +}
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/Knockout.java Mon Oct 07 14:20:58 2013 +0200
79.3 @@ -0,0 +1,131 @@
79.4 +/**
79.5 + * Back 2 Browser Bytecode Translator
79.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
79.7 + *
79.8 + * This program is free software: you can redistribute it and/or modify
79.9 + * it under the terms of the GNU General Public License as published by
79.10 + * the Free Software Foundation, version 2 of the License.
79.11 + *
79.12 + * This program is distributed in the hope that it will be useful,
79.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79.15 + * GNU General Public License for more details.
79.16 + *
79.17 + * You should have received a copy of the GNU General Public License
79.18 + * along with this program. Look for COPYING file in the top folder.
79.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
79.20 + */
79.21 +package org.apidesign.bck2brwsr.ko2brwsr;
79.22 +
79.23 +import java.lang.reflect.Method;
79.24 +import java.util.List;
79.25 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
79.26 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
79.27 +
79.28 +/** Provides binding between models and bck2brwsr VM.
79.29 + *
79.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
79.31 + */
79.32 +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js")
79.33 +final class Knockout {
79.34 + /** used by tests */
79.35 + static Knockout next;
79.36 + private final Object model;
79.37 +
79.38 + Knockout(Object model) {
79.39 + this.model = model == null ? this : model;
79.40 + }
79.41 +
79.42 + public static <M> Knockout applyBindings(
79.43 + Object model, String[] propsGettersAndSetters,
79.44 + String[] methodsAndSignatures
79.45 + ) {
79.46 + applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures);
79.47 + return new Knockout(model);
79.48 + }
79.49 + public static <M> Knockout applyBindings(
79.50 + Class<M> modelClass, M model, String[] propsGettersAndSetters,
79.51 + String[] methodsAndSignatures
79.52 + ) {
79.53 + Knockout bindings = next;
79.54 + next = null;
79.55 + if (bindings == null) {
79.56 + bindings = new Knockout(null);
79.57 + }
79.58 + applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures);
79.59 + applyBindings(bindings);
79.60 + return bindings;
79.61 + }
79.62 +
79.63 + public void valueHasMutated(String prop) {
79.64 + valueHasMutated(model, prop);
79.65 + }
79.66 + @JavaScriptBody(args = { "self", "prop" }, body =
79.67 + "var p = self[prop]; if (p) p.valueHasMutated();"
79.68 + )
79.69 + public static void valueHasMutated(Object self, String prop) {
79.70 + }
79.71 +
79.72 +
79.73 + @JavaScriptBody(args = { "id", "ev" }, body = "ko.utils.triggerEvent(window.document.getElementById(id), ev.substring(2));")
79.74 + public static void triggerEvent(String id, String ev) {
79.75 + }
79.76 +
79.77 + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body =
79.78 + "var bnd = {\n"
79.79 + + " 'read': function() {\n"
79.80 + + " var v = model[getter]();\n"
79.81 + + " if (array) v = v.koArray(); else if (v !== null) v = v.valueOf();\n"
79.82 + + " return v;\n"
79.83 + + " },\n"
79.84 + + " 'owner': bindings\n"
79.85 + + "};\n"
79.86 + + "if (setter != null) {\n"
79.87 + + " bnd['write'] = function(val) {\n"
79.88 + + " var v = val === null ? null : val.valueOf();"
79.89 + + " model[setter](v);\n"
79.90 + + " };\n"
79.91 + + "}\n"
79.92 + + "bindings[prop] = ko['computed'](bnd);"
79.93 + )
79.94 + static void bind(
79.95 + Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array
79.96 + ) {
79.97 + }
79.98 +
79.99 + @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body =
79.100 + "bindings[prop] = function(data, ev) { model[sig](data, ev); };"
79.101 + )
79.102 + static void expose(
79.103 + Object bindings, Object model, String prop, String sig
79.104 + ) {
79.105 + }
79.106 +
79.107 + @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
79.108 + static void applyBindings(Object bindings) {}
79.109 +
79.110 + private static void applyImpl(
79.111 + String[] propsGettersAndSetters,
79.112 + Class<?> modelClass,
79.113 + Object bindings,
79.114 + Object model,
79.115 + String[] methodsAndSignatures
79.116 + ) throws IllegalStateException, SecurityException {
79.117 + for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
79.118 + try {
79.119 + Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
79.120 + bind(bindings, model, propsGettersAndSetters[i],
79.121 + propsGettersAndSetters[i + 1],
79.122 + propsGettersAndSetters[i + 2],
79.123 + getter.getReturnType().isPrimitive(),
79.124 + List.class.isAssignableFrom(getter.getReturnType()));
79.125 + } catch (NoSuchMethodException ex) {
79.126 + throw new IllegalStateException(ex.getMessage());
79.127 + }
79.128 + }
79.129 + for (int i = 0; i < methodsAndSignatures.length; i += 2) {
79.130 + expose(
79.131 + bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]);
79.132 + }
79.133 + }
79.134 +}
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80.2 +++ b/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/LoadWS.java Mon Oct 07 14:20:58 2013 +0200
80.3 @@ -0,0 +1,126 @@
80.4 +/**
80.5 + * Back 2 Browser Bytecode Translator
80.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
80.7 + *
80.8 + * This program is free software: you can redistribute it and/or modify
80.9 + * it under the terms of the GNU General Public License as published by
80.10 + * the Free Software Foundation, version 2 of the License.
80.11 + *
80.12 + * This program is distributed in the hope that it will be useful,
80.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
80.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80.15 + * GNU General Public License for more details.
80.16 + *
80.17 + * You should have received a copy of the GNU General Public License
80.18 + * along with this program. Look for COPYING file in the top folder.
80.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
80.20 + */
80.21 +package org.apidesign.bck2brwsr.ko2brwsr;
80.22 +
80.23 +import net.java.html.js.JavaScriptBody;
80.24 +import org.apidesign.html.json.spi.JSONCall;
80.25 +
80.26 +/** Communication with WebSockets for WebView 1.8.
80.27 + *
80.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
80.29 + */
80.30 +final class LoadWS {
80.31 + private static final boolean SUPPORTED = isWebSocket();
80.32 + private final Object ws;
80.33 + private final JSONCall call;
80.34 + LoadWS(JSONCall first, String url) {
80.35 + call = first;
80.36 + ws = initWebSocket(this, url);
80.37 + if (ws == null) {
80.38 + first.notifyError(new IllegalArgumentException("Wrong URL: " + url));
80.39 + }
80.40 + }
80.41 +
80.42 + static boolean isSupported() {
80.43 + return SUPPORTED;
80.44 + }
80.45 +
80.46 + void send(JSONCall call) {
80.47 + push(call);
80.48 + }
80.49 +
80.50 + private synchronized void push(JSONCall call) {
80.51 + send(ws, call.getMessage());
80.52 + }
80.53 +
80.54 + void onOpen(Object ev) {
80.55 + if (!call.isDoOutput()) {
80.56 + call.notifySuccess(null);
80.57 + }
80.58 + }
80.59 +
80.60 +
80.61 + @JavaScriptBody(args = { "data" }, body = "try {\n"
80.62 + + " return eval('(' + data + ')');\n"
80.63 + + " } catch (error) {;\n"
80.64 + + " return data;\n"
80.65 + + " }\n"
80.66 + )
80.67 + private static native Object toJSON(String data);
80.68 +
80.69 + void onMessage(Object ev, String data) {
80.70 + Object json = toJSON(data);
80.71 + call.notifySuccess(json);
80.72 + }
80.73 +
80.74 + void onError(Object ev) {
80.75 + call.notifyError(new Exception(ev.toString()));
80.76 + }
80.77 +
80.78 + void onClose(boolean wasClean, int code, String reason) {
80.79 + call.notifyError(null);
80.80 + }
80.81 +
80.82 + @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
80.83 + private static boolean isWebSocket() {
80.84 + return false;
80.85 + }
80.86 +
80.87 + @JavaScriptBody(args = { "back", "url" }, javacall = true, body = ""
80.88 + + "if (window.WebSocket) {\n"
80.89 + + " try {\n"
80.90 + + " var ws = new window.WebSocket(url);\n"
80.91 + + " ws.onopen = function(ev) {\n"
80.92 + + " back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onOpen(Ljava/lang/Object;)(ev);\n"
80.93 + + " };\n"
80.94 + + " ws.onmessage = function(ev) {\n"
80.95 + + " back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data);\n"
80.96 + + " };\n"
80.97 + + " ws.onerror = function(ev) {\n"
80.98 + + " back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onError(Ljava/lang/Object;)(ev);\n"
80.99 + + " };\n"
80.100 + + " ws.onclose = function(ev) {\n"
80.101 + + " back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason);\n"
80.102 + + " };\n"
80.103 + + " return ws;\n"
80.104 + + " } catch (ex) {\n"
80.105 + + " return null;\n"
80.106 + + " }\n"
80.107 + + "} else {\n"
80.108 + + " return null;\n"
80.109 + + "}\n"
80.110 + )
80.111 + private static Object initWebSocket(Object back, String url) {
80.112 + return null;
80.113 + }
80.114 +
80.115 +
80.116 + @JavaScriptBody(args = { "ws", "msg" }, body = ""
80.117 + + "ws.send(msg);"
80.118 + )
80.119 + private void send(Object ws, String msg) {
80.120 + }
80.121 +
80.122 + @JavaScriptBody(args = { "ws" }, body = "ws.close();")
80.123 + private static void close(Object ws) {
80.124 + }
80.125 +
80.126 + void close() {
80.127 + close(ws);
80.128 + }
80.129 +}
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
81.2 +++ b/ko/bck2brwsr/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Mon Oct 07 14:20:58 2013 +0200
81.3 @@ -0,0 +1,3614 @@
81.4 +/*
81.5 + * HTML via Java(tm) Language Bindings
81.6 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
81.7 + *
81.8 + * This program is free software: you can redistribute it and/or modify
81.9 + * it under the terms of the GNU General Public License as published by
81.10 + * the Free Software Foundation, version 2 of the License.
81.11 + *
81.12 + * This program is distributed in the hope that it will be useful,
81.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
81.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81.15 + * GNU General Public License for more details. apidesign.org
81.16 + * designates this particular file as subject to the
81.17 + * "Classpath" exception as provided by apidesign.org
81.18 + * in the License file that accompanied this code.
81.19 + *
81.20 + * You should have received a copy of the GNU General Public License
81.21 + * along with this program. Look for COPYING file in the top folder.
81.22 + * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
81.23 + */
81.24 +// Knockout JavaScript library v2.2.1
81.25 +// (c) Steven Sanderson - http://knockoutjs.com/
81.26 +// License: MIT (http://www.opensource.org/licenses/mit-license.php)
81.27 +
81.28 +(function(){
81.29 +var DEBUG=true;
81.30 +(function(window,document,navigator,jQuery,undefined){
81.31 +!function(factory) {
81.32 + // Support three module loading scenarios
81.33 + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
81.34 + // [1] CommonJS/Node.js
81.35 + var target = module['exports'] || exports; // module.exports is for Node.js
81.36 + factory(target);
81.37 + } else if (typeof define === 'function' && define['amd']) {
81.38 + // [2] AMD anonymous module
81.39 + define(['exports'], factory);
81.40 + } else {
81.41 + // [3] No module loader (plain <script> tag) - put directly in global namespace
81.42 + factory(window['ko'] = {});
81.43 + }
81.44 +}(function(koExports){
81.45 +// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
81.46 +// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
81.47 +var ko = typeof koExports !== 'undefined' ? koExports : {};
81.48 +// Google Closure Compiler helpers (used only to make the minified file smaller)
81.49 +ko.exportSymbol = function(koPath, object) {
81.50 + var tokens = koPath.split(".");
81.51 +
81.52 + // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
81.53 + // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
81.54 + var target = ko;
81.55 +
81.56 + for (var i = 0; i < tokens.length - 1; i++)
81.57 + target = target[tokens[i]];
81.58 + target[tokens[tokens.length - 1]] = object;
81.59 +};
81.60 +ko.exportProperty = function(owner, publicName, object) {
81.61 + owner[publicName] = object;
81.62 +};
81.63 +ko.version = "2.2.1";
81.64 +
81.65 +ko.exportSymbol('version', ko.version);
81.66 +ko.utils = new (function () {
81.67 + var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
81.68 +
81.69 + // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
81.70 + var knownEvents = {}, knownEventTypesByEventName = {};
81.71 + var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
81.72 + knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
81.73 + knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
81.74 + for (var eventType in knownEvents) {
81.75 + var knownEventsForType = knownEvents[eventType];
81.76 + if (knownEventsForType.length) {
81.77 + for (var i = 0, j = knownEventsForType.length; i < j; i++)
81.78 + knownEventTypesByEventName[knownEventsForType[i]] = eventType;
81.79 + }
81.80 + }
81.81 + var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
81.82 +
81.83 + // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
81.84 + // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
81.85 + // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
81.86 + // If there is a future need to detect specific versions of IE10+, we will amend this.
81.87 + var ieVersion = (function() {
81.88 + var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
81.89 +
81.90 + // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
81.91 + while (
81.92 + div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
81.93 + iElems[0]
81.94 + );
81.95 + return version > 4 ? version : undefined;
81.96 + }());
81.97 + var isIe6 = ieVersion === 6,
81.98 + isIe7 = ieVersion === 7;
81.99 +
81.100 + function isClickOnCheckableElement(element, eventType) {
81.101 + if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
81.102 + if (eventType.toLowerCase() != "click") return false;
81.103 + var inputType = element.type;
81.104 + return (inputType == "checkbox") || (inputType == "radio");
81.105 + }
81.106 +
81.107 + return {
81.108 + fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
81.109 +
81.110 + arrayForEach: function (array, action) {
81.111 + for (var i = 0, j = array.length; i < j; i++)
81.112 + action(array[i]);
81.113 + },
81.114 +
81.115 + arrayIndexOf: function (array, item) {
81.116 + if (typeof Array.prototype.indexOf == "function")
81.117 + return Array.prototype.indexOf.call(array, item);
81.118 + for (var i = 0, j = array.length; i < j; i++)
81.119 + if (array[i] === item)
81.120 + return i;
81.121 + return -1;
81.122 + },
81.123 +
81.124 + arrayFirst: function (array, predicate, predicateOwner) {
81.125 + for (var i = 0, j = array.length; i < j; i++)
81.126 + if (predicate.call(predicateOwner, array[i]))
81.127 + return array[i];
81.128 + return null;
81.129 + },
81.130 +
81.131 + arrayRemoveItem: function (array, itemToRemove) {
81.132 + var index = ko.utils.arrayIndexOf(array, itemToRemove);
81.133 + if (index >= 0)
81.134 + array.splice(index, 1);
81.135 + },
81.136 +
81.137 + arrayGetDistinctValues: function (array) {
81.138 + array = array || [];
81.139 + var result = [];
81.140 + for (var i = 0, j = array.length; i < j; i++) {
81.141 + if (ko.utils.arrayIndexOf(result, array[i]) < 0)
81.142 + result.push(array[i]);
81.143 + }
81.144 + return result;
81.145 + },
81.146 +
81.147 + arrayMap: function (array, mapping) {
81.148 + array = array || [];
81.149 + var result = [];
81.150 + for (var i = 0, j = array.length; i < j; i++)
81.151 + result.push(mapping(array[i]));
81.152 + return result;
81.153 + },
81.154 +
81.155 + arrayFilter: function (array, predicate) {
81.156 + array = array || [];
81.157 + var result = [];
81.158 + for (var i = 0, j = array.length; i < j; i++)
81.159 + if (predicate(array[i]))
81.160 + result.push(array[i]);
81.161 + return result;
81.162 + },
81.163 +
81.164 + arrayPushAll: function (array, valuesToPush) {
81.165 + if (valuesToPush instanceof Array)
81.166 + array.push.apply(array, valuesToPush);
81.167 + else
81.168 + for (var i = 0, j = valuesToPush.length; i < j; i++)
81.169 + array.push(valuesToPush[i]);
81.170 + return array;
81.171 + },
81.172 +
81.173 + extend: function (target, source) {
81.174 + if (source) {
81.175 + for(var prop in source) {
81.176 + if(source.hasOwnProperty(prop)) {
81.177 + target[prop] = source[prop];
81.178 + }
81.179 + }
81.180 + }
81.181 + return target;
81.182 + },
81.183 +
81.184 + emptyDomNode: function (domNode) {
81.185 + while (domNode.firstChild) {
81.186 + ko.removeNode(domNode.firstChild);
81.187 + }
81.188 + },
81.189 +
81.190 + moveCleanedNodesToContainerElement: function(nodes) {
81.191 + // Ensure it's a real array, as we're about to reparent the nodes and
81.192 + // we don't want the underlying collection to change while we're doing that.
81.193 + var nodesArray = ko.utils.makeArray(nodes);
81.194 +
81.195 + var container = document.createElement('div');
81.196 + for (var i = 0, j = nodesArray.length; i < j; i++) {
81.197 + container.appendChild(ko.cleanNode(nodesArray[i]));
81.198 + }
81.199 + return container;
81.200 + },
81.201 +
81.202 + cloneNodes: function (nodesArray, shouldCleanNodes) {
81.203 + for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
81.204 + var clonedNode = nodesArray[i].cloneNode(true);
81.205 + newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
81.206 + }
81.207 + return newNodesArray;
81.208 + },
81.209 +
81.210 + setDomNodeChildren: function (domNode, childNodes) {
81.211 + ko.utils.emptyDomNode(domNode);
81.212 + if (childNodes) {
81.213 + for (var i = 0, j = childNodes.length; i < j; i++)
81.214 + domNode.appendChild(childNodes[i]);
81.215 + }
81.216 + },
81.217 +
81.218 + replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
81.219 + var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
81.220 + if (nodesToReplaceArray.length > 0) {
81.221 + var insertionPoint = nodesToReplaceArray[0];
81.222 + var parent = insertionPoint.parentNode;
81.223 + for (var i = 0, j = newNodesArray.length; i < j; i++)
81.224 + parent.insertBefore(newNodesArray[i], insertionPoint);
81.225 + for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
81.226 + ko.removeNode(nodesToReplaceArray[i]);
81.227 + }
81.228 + }
81.229 + },
81.230 +
81.231 + setOptionNodeSelectionState: function (optionNode, isSelected) {
81.232 + // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
81.233 + if (ieVersion < 7)
81.234 + optionNode.setAttribute("selected", isSelected);
81.235 + else
81.236 + optionNode.selected = isSelected;
81.237 + },
81.238 +
81.239 + stringTrim: function (string) {
81.240 + return (string || "").replace(stringTrimRegex, "");
81.241 + },
81.242 +
81.243 + stringTokenize: function (string, delimiter) {
81.244 + var result = [];
81.245 + var tokens = (string || "").split(delimiter);
81.246 + for (var i = 0, j = tokens.length; i < j; i++) {
81.247 + var trimmed = ko.utils.stringTrim(tokens[i]);
81.248 + if (trimmed !== "")
81.249 + result.push(trimmed);
81.250 + }
81.251 + return result;
81.252 + },
81.253 +
81.254 + stringStartsWith: function (string, startsWith) {
81.255 + string = string || "";
81.256 + if (startsWith.length > string.length)
81.257 + return false;
81.258 + return string.substring(0, startsWith.length) === startsWith;
81.259 + },
81.260 +
81.261 + domNodeIsContainedBy: function (node, containedByNode) {
81.262 + if (containedByNode.compareDocumentPosition)
81.263 + return (containedByNode.compareDocumentPosition(node) & 16) == 16;
81.264 + while (node != null) {
81.265 + if (node == containedByNode)
81.266 + return true;
81.267 + node = node.parentNode;
81.268 + }
81.269 + return false;
81.270 + },
81.271 +
81.272 + domNodeIsAttachedToDocument: function (node) {
81.273 + return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
81.274 + },
81.275 +
81.276 + tagNameLower: function(element) {
81.277 + // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
81.278 + // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
81.279 + // we don't need to do the .toLowerCase() as it will always be lower case anyway.
81.280 + return element && element.tagName && element.tagName.toLowerCase();
81.281 + },
81.282 +
81.283 + registerEventHandler: function (element, eventType, handler) {
81.284 + var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
81.285 + if (!mustUseAttachEvent && typeof jQuery != "undefined") {
81.286 + if (isClickOnCheckableElement(element, eventType)) {
81.287 + // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
81.288 + // it toggles the element checked state *after* the click event handlers run, whereas native
81.289 + // click events toggle the checked state *before* the event handler.
81.290 + // Fix this by intecepting the handler and applying the correct checkedness before it runs.
81.291 + var originalHandler = handler;
81.292 + handler = function(event, eventData) {
81.293 + var jQuerySuppliedCheckedState = this.checked;
81.294 + if (eventData)
81.295 + this.checked = eventData.checkedStateBeforeEvent !== true;
81.296 + originalHandler.call(this, event);
81.297 + this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
81.298 + };
81.299 + }
81.300 + jQuery(element)['bind'](eventType, handler);
81.301 + } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
81.302 + element.addEventListener(eventType, handler, false);
81.303 + else if (typeof element.attachEvent != "undefined")
81.304 + element.attachEvent("on" + eventType, function (event) {
81.305 + handler.call(element, event);
81.306 + });
81.307 + else
81.308 + throw new Error("Browser doesn't support addEventListener or attachEvent");
81.309 + },
81.310 +
81.311 + triggerEvent: function (element, eventType) {
81.312 + if (!(element && element.nodeType))
81.313 + throw new Error("element must be a DOM node when calling triggerEvent");
81.314 +
81.315 + if (typeof jQuery != "undefined") {
81.316 + var eventData = [];
81.317 + if (isClickOnCheckableElement(element, eventType)) {
81.318 + // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
81.319 + eventData.push({ checkedStateBeforeEvent: element.checked });
81.320 + }
81.321 + jQuery(element)['trigger'](eventType, eventData);
81.322 + } else if (typeof document.createEvent == "function") {
81.323 + if (typeof element.dispatchEvent == "function") {
81.324 + var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
81.325 + var event = document.createEvent(eventCategory);
81.326 + event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
81.327 + element.dispatchEvent(event);
81.328 + }
81.329 + else
81.330 + throw new Error("The supplied element doesn't support dispatchEvent");
81.331 + } else if (typeof element.fireEvent != "undefined") {
81.332 + // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
81.333 + // so to make it consistent, we'll do it manually here
81.334 + if (isClickOnCheckableElement(element, eventType))
81.335 + element.checked = element.checked !== true;
81.336 + element.fireEvent("on" + eventType);
81.337 + }
81.338 + else
81.339 + throw new Error("Browser doesn't support triggering events");
81.340 + },
81.341 +
81.342 + unwrapObservable: function (value) {
81.343 + return ko.isObservable(value) ? value() : value;
81.344 + },
81.345 +
81.346 + peekObservable: function (value) {
81.347 + return ko.isObservable(value) ? value.peek() : value;
81.348 + },
81.349 +
81.350 + toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
81.351 + if (classNames) {
81.352 + var cssClassNameRegex = /[\w-]+/g,
81.353 + currentClassNames = node.className.match(cssClassNameRegex) || [];
81.354 + ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
81.355 + var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
81.356 + if (indexOfClass >= 0) {
81.357 + if (!shouldHaveClass)
81.358 + currentClassNames.splice(indexOfClass, 1);
81.359 + } else {
81.360 + if (shouldHaveClass)
81.361 + currentClassNames.push(className);
81.362 + }
81.363 + });
81.364 + node.className = currentClassNames.join(" ");
81.365 + }
81.366 + },
81.367 +
81.368 + setTextContent: function(element, textContent) {
81.369 + var value = ko.utils.unwrapObservable(textContent);
81.370 + if ((value === null) || (value === undefined))
81.371 + value = "";
81.372 +
81.373 + if (element.nodeType === 3) {
81.374 + element.data = value;
81.375 + } else {
81.376 + // We need there to be exactly one child: a text node.
81.377 + // If there are no children, more than one, or if it's not a text node,
81.378 + // we'll clear everything and create a single text node.
81.379 + var innerTextNode = ko.virtualElements.firstChild(element);
81.380 + if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
81.381 + ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
81.382 + } else {
81.383 + innerTextNode.data = value;
81.384 + }
81.385 +
81.386 + ko.utils.forceRefresh(element);
81.387 + }
81.388 + },
81.389 +
81.390 + setElementName: function(element, name) {
81.391 + element.name = name;
81.392 +
81.393 + // Workaround IE 6/7 issue
81.394 + // - https://github.com/SteveSanderson/knockout/issues/197
81.395 + // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
81.396 + if (ieVersion <= 7) {
81.397 + try {
81.398 + element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
81.399 + }
81.400 + catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
81.401 + }
81.402 + },
81.403 +
81.404 + forceRefresh: function(node) {
81.405 + // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
81.406 + if (ieVersion >= 9) {
81.407 + // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
81.408 + var elem = node.nodeType == 1 ? node : node.parentNode;
81.409 + if (elem.style)
81.410 + elem.style.zoom = elem.style.zoom;
81.411 + }
81.412 + },
81.413 +
81.414 + ensureSelectElementIsRenderedCorrectly: function(selectElement) {
81.415 + // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
81.416 + // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
81.417 + if (ieVersion >= 9) {
81.418 + var originalWidth = selectElement.style.width;
81.419 + selectElement.style.width = 0;
81.420 + selectElement.style.width = originalWidth;
81.421 + }
81.422 + },
81.423 +
81.424 + range: function (min, max) {
81.425 + min = ko.utils.unwrapObservable(min);
81.426 + max = ko.utils.unwrapObservable(max);
81.427 + var result = [];
81.428 + for (var i = min; i <= max; i++)
81.429 + result.push(i);
81.430 + return result;
81.431 + },
81.432 +
81.433 + makeArray: function(arrayLikeObject) {
81.434 + var result = [];
81.435 + for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
81.436 + result.push(arrayLikeObject[i]);
81.437 + };
81.438 + return result;
81.439 + },
81.440 +
81.441 + isIe6 : isIe6,
81.442 + isIe7 : isIe7,
81.443 + ieVersion : ieVersion,
81.444 +
81.445 + getFormFields: function(form, fieldName) {
81.446 + var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
81.447 + var isMatchingField = (typeof fieldName == 'string')
81.448 + ? function(field) { return field.name === fieldName }
81.449 + : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
81.450 + var matches = [];
81.451 + for (var i = fields.length - 1; i >= 0; i--) {
81.452 + if (isMatchingField(fields[i]))
81.453 + matches.push(fields[i]);
81.454 + };
81.455 + return matches;
81.456 + },
81.457 +
81.458 + parseJson: function (jsonString) {
81.459 + if (typeof jsonString == "string") {
81.460 + jsonString = ko.utils.stringTrim(jsonString);
81.461 + if (jsonString) {
81.462 + if (window.JSON && window.JSON.parse) // Use native parsing where available
81.463 + return window.JSON.parse(jsonString);
81.464 + return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
81.465 + }
81.466 + }
81.467 + return null;
81.468 + },
81.469 +
81.470 + stringifyJson: function (data, replacer, space) { // replacer and space are optional
81.471 + if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
81.472 + throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
81.473 + return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
81.474 + },
81.475 +
81.476 + postJson: function (urlOrForm, data, options) {
81.477 + options = options || {};
81.478 + var params = options['params'] || {};
81.479 + var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
81.480 + var url = urlOrForm;
81.481 +
81.482 + // If we were given a form, use its 'action' URL and pick out any requested field values
81.483 + if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
81.484 + var originalForm = urlOrForm;
81.485 + url = originalForm.action;
81.486 + for (var i = includeFields.length - 1; i >= 0; i--) {
81.487 + var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
81.488 + for (var j = fields.length - 1; j >= 0; j--)
81.489 + params[fields[j].name] = fields[j].value;
81.490 + }
81.491 + }
81.492 +
81.493 + data = ko.utils.unwrapObservable(data);
81.494 + var form = document.createElement("form");
81.495 + form.style.display = "none";
81.496 + form.action = url;
81.497 + form.method = "post";
81.498 + for (var key in data) {
81.499 + var input = document.createElement("input");
81.500 + input.name = key;
81.501 + input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
81.502 + form.appendChild(input);
81.503 + }
81.504 + for (var key in params) {
81.505 + var input = document.createElement("input");
81.506 + input.name = key;
81.507 + input.value = params[key];
81.508 + form.appendChild(input);
81.509 + }
81.510 + document.body.appendChild(form);
81.511 + options['submitter'] ? options['submitter'](form) : form.submit();
81.512 + setTimeout(function () { form.parentNode.removeChild(form); }, 0);
81.513 + }
81.514 + }
81.515 +})();
81.516 +
81.517 +ko.exportSymbol('utils', ko.utils);
81.518 +ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
81.519 +ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
81.520 +ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
81.521 +ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
81.522 +ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
81.523 +ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
81.524 +ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
81.525 +ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
81.526 +ko.exportSymbol('utils.extend', ko.utils.extend);
81.527 +ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
81.528 +ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
81.529 +ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
81.530 +ko.exportSymbol('utils.postJson', ko.utils.postJson);
81.531 +ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
81.532 +ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
81.533 +ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
81.534 +ko.exportSymbol('utils.range', ko.utils.range);
81.535 +ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
81.536 +ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
81.537 +ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
81.538 +
81.539 +if (!Function.prototype['bind']) {
81.540 + // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
81.541 + // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
81.542 + Function.prototype['bind'] = function (object) {
81.543 + var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
81.544 + return function () {
81.545 + return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
81.546 + };
81.547 + };
81.548 +}
81.549 +
81.550 +ko.utils.domData = new (function () {
81.551 + var uniqueId = 0;
81.552 + var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
81.553 + var dataStore = {};
81.554 + return {
81.555 + get: function (node, key) {
81.556 + var allDataForNode = ko.utils.domData.getAll(node, false);
81.557 + return allDataForNode === undefined ? undefined : allDataForNode[key];
81.558 + },
81.559 + set: function (node, key, value) {
81.560 + if (value === undefined) {
81.561 + // Make sure we don't actually create a new domData key if we are actually deleting a value
81.562 + if (ko.utils.domData.getAll(node, false) === undefined)
81.563 + return;
81.564 + }
81.565 + var allDataForNode = ko.utils.domData.getAll(node, true);
81.566 + allDataForNode[key] = value;
81.567 + },
81.568 + getAll: function (node, createIfNotFound) {
81.569 + var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
81.570 + var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
81.571 + if (!hasExistingDataStore) {
81.572 + if (!createIfNotFound)
81.573 + return undefined;
81.574 + dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
81.575 + dataStore[dataStoreKey] = {};
81.576 + }
81.577 + return dataStore[dataStoreKey];
81.578 + },
81.579 + clear: function (node) {
81.580 + var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
81.581 + if (dataStoreKey) {
81.582 + delete dataStore[dataStoreKey];
81.583 + node[dataStoreKeyExpandoPropertyName] = null;
81.584 + return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
81.585 + }
81.586 + return false;
81.587 + }
81.588 + }
81.589 +})();
81.590 +
81.591 +ko.exportSymbol('utils.domData', ko.utils.domData);
81.592 +ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
81.593 +
81.594 +ko.utils.domNodeDisposal = new (function () {
81.595 + var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
81.596 + var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
81.597 + var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
81.598 +
81.599 + function getDisposeCallbacksCollection(node, createIfNotFound) {
81.600 + var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
81.601 + if ((allDisposeCallbacks === undefined) && createIfNotFound) {
81.602 + allDisposeCallbacks = [];
81.603 + ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
81.604 + }
81.605 + return allDisposeCallbacks;
81.606 + }
81.607 + function destroyCallbacksCollection(node) {
81.608 + ko.utils.domData.set(node, domDataKey, undefined);
81.609 + }
81.610 +
81.611 + function cleanSingleNode(node) {
81.612 + // Run all the dispose callbacks
81.613 + var callbacks = getDisposeCallbacksCollection(node, false);
81.614 + if (callbacks) {
81.615 + callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
81.616 + for (var i = 0; i < callbacks.length; i++)
81.617 + callbacks[i](node);
81.618 + }
81.619 +
81.620 + // Also erase the DOM data
81.621 + ko.utils.domData.clear(node);
81.622 +
81.623 + // Special support for jQuery here because it's so commonly used.
81.624 + // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
81.625 + // so notify it to tear down any resources associated with the node & descendants here.
81.626 + if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
81.627 + jQuery['cleanData']([node]);
81.628 +
81.629 + // Also clear any immediate-child comment nodes, as these wouldn't have been found by
81.630 + // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
81.631 + if (cleanableNodeTypesWithDescendants[node.nodeType])
81.632 + cleanImmediateCommentTypeChildren(node);
81.633 + }
81.634 +
81.635 + function cleanImmediateCommentTypeChildren(nodeWithChildren) {
81.636 + var child, nextChild = nodeWithChildren.firstChild;
81.637 + while (child = nextChild) {
81.638 + nextChild = child.nextSibling;
81.639 + if (child.nodeType === 8)
81.640 + cleanSingleNode(child);
81.641 + }
81.642 + }
81.643 +
81.644 + return {
81.645 + addDisposeCallback : function(node, callback) {
81.646 + if (typeof callback != "function")
81.647 + throw new Error("Callback must be a function");
81.648 + getDisposeCallbacksCollection(node, true).push(callback);
81.649 + },
81.650 +
81.651 + removeDisposeCallback : function(node, callback) {
81.652 + var callbacksCollection = getDisposeCallbacksCollection(node, false);
81.653 + if (callbacksCollection) {
81.654 + ko.utils.arrayRemoveItem(callbacksCollection, callback);
81.655 + if (callbacksCollection.length == 0)
81.656 + destroyCallbacksCollection(node);
81.657 + }
81.658 + },
81.659 +
81.660 + cleanNode : function(node) {
81.661 + // First clean this node, where applicable
81.662 + if (cleanableNodeTypes[node.nodeType]) {
81.663 + cleanSingleNode(node);
81.664 +
81.665 + // ... then its descendants, where applicable
81.666 + if (cleanableNodeTypesWithDescendants[node.nodeType]) {
81.667 + // Clone the descendants list in case it changes during iteration
81.668 + var descendants = [];
81.669 + ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
81.670 + for (var i = 0, j = descendants.length; i < j; i++)
81.671 + cleanSingleNode(descendants[i]);
81.672 + }
81.673 + }
81.674 + return node;
81.675 + },
81.676 +
81.677 + removeNode : function(node) {
81.678 + ko.cleanNode(node);
81.679 + if (node.parentNode)
81.680 + node.parentNode.removeChild(node);
81.681 + }
81.682 + }
81.683 +})();
81.684 +ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
81.685 +ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
81.686 +ko.exportSymbol('cleanNode', ko.cleanNode);
81.687 +ko.exportSymbol('removeNode', ko.removeNode);
81.688 +ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
81.689 +ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
81.690 +ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
81.691 +(function () {
81.692 + var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
81.693 +
81.694 + function simpleHtmlParse(html) {
81.695 + // Based on jQuery's "clean" function, but only accounting for table-related elements.
81.696 + // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
81.697 +
81.698 + // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
81.699 + // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
81.700 + // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
81.701 + // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
81.702 +
81.703 + // Trim whitespace, otherwise indexOf won't work as expected
81.704 + var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
81.705 +
81.706 + // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
81.707 + var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
81.708 + !tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
81.709 + (!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
81.710 + /* anything else */ [0, "", ""];
81.711 +
81.712 + // Go to html and back, then peel off extra wrappers
81.713 + // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
81.714 + var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
81.715 + if (typeof window['innerShiv'] == "function") {
81.716 + div.appendChild(window['innerShiv'](markup));
81.717 + } else {
81.718 + div.innerHTML = markup;
81.719 + }
81.720 +
81.721 + // Move to the right depth
81.722 + while (wrap[0]--)
81.723 + div = div.lastChild;
81.724 +
81.725 + return ko.utils.makeArray(div.lastChild.childNodes);
81.726 + }
81.727 +
81.728 + function jQueryHtmlParse(html) {
81.729 + // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
81.730 + if (jQuery['parseHTML']) {
81.731 + return jQuery['parseHTML'](html);
81.732 + } else {
81.733 + // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
81.734 + var elems = jQuery['clean']([html]);
81.735 +
81.736 + // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
81.737 + // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
81.738 + // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
81.739 + if (elems && elems[0]) {
81.740 + // Find the top-most parent element that's a direct child of a document fragment
81.741 + var elem = elems[0];
81.742 + while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
81.743 + elem = elem.parentNode;
81.744 + // ... then detach it
81.745 + if (elem.parentNode)
81.746 + elem.parentNode.removeChild(elem);
81.747 + }
81.748 +
81.749 + return elems;
81.750 + }
81.751 + }
81.752 +
81.753 + ko.utils.parseHtmlFragment = function(html) {
81.754 + return typeof jQuery != 'undefined' ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
81.755 + : simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
81.756 + };
81.757 +
81.758 + ko.utils.setHtml = function(node, html) {
81.759 + ko.utils.emptyDomNode(node);
81.760 +
81.761 + // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
81.762 + html = ko.utils.unwrapObservable(html);
81.763 +
81.764 + if ((html !== null) && (html !== undefined)) {
81.765 + if (typeof html != 'string')
81.766 + html = html.toString();
81.767 +
81.768 + // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
81.769 + // for example <tr> elements which are not normally allowed to exist on their own.
81.770 + // If you've referenced jQuery we'll use that rather than duplicating its code.
81.771 + if (typeof jQuery != 'undefined') {
81.772 + jQuery(node)['html'](html);
81.773 + } else {
81.774 + // ... otherwise, use KO's own parsing logic.
81.775 + var parsedNodes = ko.utils.parseHtmlFragment(html);
81.776 + for (var i = 0; i < parsedNodes.length; i++)
81.777 + node.appendChild(parsedNodes[i]);
81.778 + }
81.779 + }
81.780 + };
81.781 +})();
81.782 +
81.783 +ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
81.784 +ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
81.785 +
81.786 +ko.memoization = (function () {
81.787 + var memos = {};
81.788 +
81.789 + function randomMax8HexChars() {
81.790 + return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
81.791 + }
81.792 + function generateRandomId() {
81.793 + return randomMax8HexChars() + randomMax8HexChars();
81.794 + }
81.795 + function findMemoNodes(rootNode, appendToArray) {
81.796 + if (!rootNode)
81.797 + return;
81.798 + if (rootNode.nodeType == 8) {
81.799 + var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
81.800 + if (memoId != null)
81.801 + appendToArray.push({ domNode: rootNode, memoId: memoId });
81.802 + } else if (rootNode.nodeType == 1) {
81.803 + for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
81.804 + findMemoNodes(childNodes[i], appendToArray);
81.805 + }
81.806 + }
81.807 +
81.808 + return {
81.809 + memoize: function (callback) {
81.810 + if (typeof callback != "function")
81.811 + throw new Error("You can only pass a function to ko.memoization.memoize()");
81.812 + var memoId = generateRandomId();
81.813 + memos[memoId] = callback;
81.814 + return "<!--[ko_memo:" + memoId + "]-->";
81.815 + },
81.816 +
81.817 + unmemoize: function (memoId, callbackParams) {
81.818 + var callback = memos[memoId];
81.819 + if (callback === undefined)
81.820 + throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
81.821 + try {
81.822 + callback.apply(null, callbackParams || []);
81.823 + return true;
81.824 + }
81.825 + finally { delete memos[memoId]; }
81.826 + },
81.827 +
81.828 + unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
81.829 + var memos = [];
81.830 + findMemoNodes(domNode, memos);
81.831 + for (var i = 0, j = memos.length; i < j; i++) {
81.832 + var node = memos[i].domNode;
81.833 + var combinedParams = [node];
81.834 + if (extraCallbackParamsArray)
81.835 + ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
81.836 + ko.memoization.unmemoize(memos[i].memoId, combinedParams);
81.837 + node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
81.838 + if (node.parentNode)
81.839 + node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
81.840 + }
81.841 + },
81.842 +
81.843 + parseMemoText: function (memoText) {
81.844 + var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
81.845 + return match ? match[1] : null;
81.846 + }
81.847 + };
81.848 +})();
81.849 +
81.850 +ko.exportSymbol('memoization', ko.memoization);
81.851 +ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
81.852 +ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
81.853 +ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
81.854 +ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
81.855 +ko.extenders = {
81.856 + 'throttle': function(target, timeout) {
81.857 + // Throttling means two things:
81.858 +
81.859 + // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
81.860 + // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
81.861 + target['throttleEvaluation'] = timeout;
81.862 +
81.863 + // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
81.864 + // so the target cannot change value synchronously or faster than a certain rate
81.865 + var writeTimeoutInstance = null;
81.866 + return ko.dependentObservable({
81.867 + 'read': target,
81.868 + 'write': function(value) {
81.869 + clearTimeout(writeTimeoutInstance);
81.870 + writeTimeoutInstance = setTimeout(function() {
81.871 + target(value);
81.872 + }, timeout);
81.873 + }
81.874 + });
81.875 + },
81.876 +
81.877 + 'notify': function(target, notifyWhen) {
81.878 + target["equalityComparer"] = notifyWhen == "always"
81.879 + ? function() { return false } // Treat all values as not equal
81.880 + : ko.observable["fn"]["equalityComparer"];
81.881 + return target;
81.882 + }
81.883 +};
81.884 +
81.885 +function applyExtenders(requestedExtenders) {
81.886 + var target = this;
81.887 + if (requestedExtenders) {
81.888 + for (var key in requestedExtenders) {
81.889 + var extenderHandler = ko.extenders[key];
81.890 + if (typeof extenderHandler == 'function') {
81.891 + target = extenderHandler(target, requestedExtenders[key]);
81.892 + }
81.893 + }
81.894 + }
81.895 + return target;
81.896 +}
81.897 +
81.898 +ko.exportSymbol('extenders', ko.extenders);
81.899 +
81.900 +ko.subscription = function (target, callback, disposeCallback) {
81.901 + this.target = target;
81.902 + this.callback = callback;
81.903 + this.disposeCallback = disposeCallback;
81.904 + ko.exportProperty(this, 'dispose', this.dispose);
81.905 +};
81.906 +ko.subscription.prototype.dispose = function () {
81.907 + this.isDisposed = true;
81.908 + this.disposeCallback();
81.909 +};
81.910 +
81.911 +ko.subscribable = function () {
81.912 + this._subscriptions = {};
81.913 +
81.914 + ko.utils.extend(this, ko.subscribable['fn']);
81.915 + ko.exportProperty(this, 'subscribe', this.subscribe);
81.916 + ko.exportProperty(this, 'extend', this.extend);
81.917 + ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
81.918 +}
81.919 +
81.920 +var defaultEvent = "change";
81.921 +
81.922 +ko.subscribable['fn'] = {
81.923 + subscribe: function (callback, callbackTarget, event) {
81.924 + event = event || defaultEvent;
81.925 + var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
81.926 +
81.927 + var subscription = new ko.subscription(this, boundCallback, function () {
81.928 + ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
81.929 + }.bind(this));
81.930 +
81.931 + if (!this._subscriptions[event])
81.932 + this._subscriptions[event] = [];
81.933 + this._subscriptions[event].push(subscription);
81.934 + return subscription;
81.935 + },
81.936 +
81.937 + "notifySubscribers": function (valueToNotify, event) {
81.938 + event = event || defaultEvent;
81.939 + if (this._subscriptions[event]) {
81.940 + ko.dependencyDetection.ignore(function() {
81.941 + ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
81.942 + // In case a subscription was disposed during the arrayForEach cycle, check
81.943 + // for isDisposed on each subscription before invoking its callback
81.944 + if (subscription && (subscription.isDisposed !== true))
81.945 + subscription.callback(valueToNotify);
81.946 + });
81.947 + }, this);
81.948 + }
81.949 + },
81.950 +
81.951 + getSubscriptionsCount: function () {
81.952 + var total = 0;
81.953 + for (var eventName in this._subscriptions) {
81.954 + if (this._subscriptions.hasOwnProperty(eventName))
81.955 + total += this._subscriptions[eventName].length;
81.956 + }
81.957 + return total;
81.958 + },
81.959 +
81.960 + extend: applyExtenders
81.961 +};
81.962 +
81.963 +
81.964 +ko.isSubscribable = function (instance) {
81.965 + return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
81.966 +};
81.967 +
81.968 +ko.exportSymbol('subscribable', ko.subscribable);
81.969 +ko.exportSymbol('isSubscribable', ko.isSubscribable);
81.970 +
81.971 +ko.dependencyDetection = (function () {
81.972 + var _frames = [];
81.973 +
81.974 + return {
81.975 + begin: function (callback) {
81.976 + _frames.push({ callback: callback, distinctDependencies:[] });
81.977 + },
81.978 +
81.979 + end: function () {
81.980 + _frames.pop();
81.981 + },
81.982 +
81.983 + registerDependency: function (subscribable) {
81.984 + if (!ko.isSubscribable(subscribable))
81.985 + throw new Error("Only subscribable things can act as dependencies");
81.986 + if (_frames.length > 0) {
81.987 + var topFrame = _frames[_frames.length - 1];
81.988 + if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
81.989 + return;
81.990 + topFrame.distinctDependencies.push(subscribable);
81.991 + topFrame.callback(subscribable);
81.992 + }
81.993 + },
81.994 +
81.995 + ignore: function(callback, callbackTarget, callbackArgs) {
81.996 + try {
81.997 + _frames.push(null);
81.998 + return callback.apply(callbackTarget, callbackArgs || []);
81.999 + } finally {
81.1000 + _frames.pop();
81.1001 + }
81.1002 + }
81.1003 + };
81.1004 +})();
81.1005 +var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
81.1006 +
81.1007 +ko.observable = function (initialValue) {
81.1008 + var _latestValue = initialValue;
81.1009 +
81.1010 + function observable() {
81.1011 + if (arguments.length > 0) {
81.1012 + // Write
81.1013 +
81.1014 + // Ignore writes if the value hasn't changed
81.1015 + if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
81.1016 + observable.valueWillMutate();
81.1017 + _latestValue = arguments[0];
81.1018 + if (DEBUG) observable._latestValue = _latestValue;
81.1019 + observable.valueHasMutated();
81.1020 + }
81.1021 + return this; // Permits chained assignments
81.1022 + }
81.1023 + else {
81.1024 + // Read
81.1025 + ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
81.1026 + return _latestValue;
81.1027 + }
81.1028 + }
81.1029 + if (DEBUG) observable._latestValue = _latestValue;
81.1030 + ko.subscribable.call(observable);
81.1031 + observable.peek = function() { return _latestValue };
81.1032 + observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
81.1033 + observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
81.1034 + ko.utils.extend(observable, ko.observable['fn']);
81.1035 +
81.1036 + ko.exportProperty(observable, 'peek', observable.peek);
81.1037 + ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
81.1038 + ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
81.1039 +
81.1040 + return observable;
81.1041 +}
81.1042 +
81.1043 +ko.observable['fn'] = {
81.1044 + "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
81.1045 + var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
81.1046 + return oldValueIsPrimitive ? (a === b) : false;
81.1047 + }
81.1048 +};
81.1049 +
81.1050 +var protoProperty = ko.observable.protoProperty = "__ko_proto__";
81.1051 +ko.observable['fn'][protoProperty] = ko.observable;
81.1052 +
81.1053 +ko.hasPrototype = function(instance, prototype) {
81.1054 + if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
81.1055 + if (instance[protoProperty] === prototype) return true;
81.1056 + return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
81.1057 +};
81.1058 +
81.1059 +ko.isObservable = function (instance) {
81.1060 + return ko.hasPrototype(instance, ko.observable);
81.1061 +}
81.1062 +ko.isWriteableObservable = function (instance) {
81.1063 + // Observable
81.1064 + if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
81.1065 + return true;
81.1066 + // Writeable dependent observable
81.1067 + if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
81.1068 + return true;
81.1069 + // Anything else
81.1070 + return false;
81.1071 +}
81.1072 +
81.1073 +
81.1074 +ko.exportSymbol('observable', ko.observable);
81.1075 +ko.exportSymbol('isObservable', ko.isObservable);
81.1076 +ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
81.1077 +ko.observableArray = function (initialValues) {
81.1078 + if (arguments.length == 0) {
81.1079 + // Zero-parameter constructor initializes to empty array
81.1080 + initialValues = [];
81.1081 + }
81.1082 + if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
81.1083 + throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
81.1084 +
81.1085 + var result = ko.observable(initialValues);
81.1086 + ko.utils.extend(result, ko.observableArray['fn']);
81.1087 + return result;
81.1088 +}
81.1089 +
81.1090 +ko.observableArray['fn'] = {
81.1091 + 'remove': function (valueOrPredicate) {
81.1092 + var underlyingArray = this.peek();
81.1093 + var removedValues = [];
81.1094 + var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
81.1095 + for (var i = 0; i < underlyingArray.length; i++) {
81.1096 + var value = underlyingArray[i];
81.1097 + if (predicate(value)) {
81.1098 + if (removedValues.length === 0) {
81.1099 + this.valueWillMutate();
81.1100 + }
81.1101 + removedValues.push(value);
81.1102 + underlyingArray.splice(i, 1);
81.1103 + i--;
81.1104 + }
81.1105 + }
81.1106 + if (removedValues.length) {
81.1107 + this.valueHasMutated();
81.1108 + }
81.1109 + return removedValues;
81.1110 + },
81.1111 +
81.1112 + 'removeAll': function (arrayOfValues) {
81.1113 + // If you passed zero args, we remove everything
81.1114 + if (arrayOfValues === undefined) {
81.1115 + var underlyingArray = this.peek();
81.1116 + var allValues = underlyingArray.slice(0);
81.1117 + this.valueWillMutate();
81.1118 + underlyingArray.splice(0, underlyingArray.length);
81.1119 + this.valueHasMutated();
81.1120 + return allValues;
81.1121 + }
81.1122 + // If you passed an arg, we interpret it as an array of entries to remove
81.1123 + if (!arrayOfValues)
81.1124 + return [];
81.1125 + return this['remove'](function (value) {
81.1126 + return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
81.1127 + });
81.1128 + },
81.1129 +
81.1130 + 'destroy': function (valueOrPredicate) {
81.1131 + var underlyingArray = this.peek();
81.1132 + var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
81.1133 + this.valueWillMutate();
81.1134 + for (var i = underlyingArray.length - 1; i >= 0; i--) {
81.1135 + var value = underlyingArray[i];
81.1136 + if (predicate(value))
81.1137 + underlyingArray[i]["_destroy"] = true;
81.1138 + }
81.1139 + this.valueHasMutated();
81.1140 + },
81.1141 +
81.1142 + 'destroyAll': function (arrayOfValues) {
81.1143 + // If you passed zero args, we destroy everything
81.1144 + if (arrayOfValues === undefined)
81.1145 + return this['destroy'](function() { return true });
81.1146 +
81.1147 + // If you passed an arg, we interpret it as an array of entries to destroy
81.1148 + if (!arrayOfValues)
81.1149 + return [];
81.1150 + return this['destroy'](function (value) {
81.1151 + return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
81.1152 + });
81.1153 + },
81.1154 +
81.1155 + 'indexOf': function (item) {
81.1156 + var underlyingArray = this();
81.1157 + return ko.utils.arrayIndexOf(underlyingArray, item);
81.1158 + },
81.1159 +
81.1160 + 'replace': function(oldItem, newItem) {
81.1161 + var index = this['indexOf'](oldItem);
81.1162 + if (index >= 0) {
81.1163 + this.valueWillMutate();
81.1164 + this.peek()[index] = newItem;
81.1165 + this.valueHasMutated();
81.1166 + }
81.1167 + }
81.1168 +}
81.1169 +
81.1170 +// Populate ko.observableArray.fn with read/write functions from native arrays
81.1171 +// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
81.1172 +// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
81.1173 +ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
81.1174 + ko.observableArray['fn'][methodName] = function () {
81.1175 + // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
81.1176 + // (for consistency with mutating regular observables)
81.1177 + var underlyingArray = this.peek();
81.1178 + this.valueWillMutate();
81.1179 + var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
81.1180 + this.valueHasMutated();
81.1181 + return methodCallResult;
81.1182 + };
81.1183 +});
81.1184 +
81.1185 +// Populate ko.observableArray.fn with read-only functions from native arrays
81.1186 +ko.utils.arrayForEach(["slice"], function (methodName) {
81.1187 + ko.observableArray['fn'][methodName] = function () {
81.1188 + var underlyingArray = this();
81.1189 + return underlyingArray[methodName].apply(underlyingArray, arguments);
81.1190 + };
81.1191 +});
81.1192 +
81.1193 +ko.exportSymbol('observableArray', ko.observableArray);
81.1194 +ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
81.1195 + var _latestValue,
81.1196 + _hasBeenEvaluated = false,
81.1197 + _isBeingEvaluated = false,
81.1198 + readFunction = evaluatorFunctionOrOptions;
81.1199 +
81.1200 + if (readFunction && typeof readFunction == "object") {
81.1201 + // Single-parameter syntax - everything is on this "options" param
81.1202 + options = readFunction;
81.1203 + readFunction = options["read"];
81.1204 + } else {
81.1205 + // Multi-parameter syntax - construct the options according to the params passed
81.1206 + options = options || {};
81.1207 + if (!readFunction)
81.1208 + readFunction = options["read"];
81.1209 + }
81.1210 + if (typeof readFunction != "function")
81.1211 + throw new Error("Pass a function that returns the value of the ko.computed");
81.1212 +
81.1213 + function addSubscriptionToDependency(subscribable) {
81.1214 + _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
81.1215 + }
81.1216 +
81.1217 + function disposeAllSubscriptionsToDependencies() {
81.1218 + ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
81.1219 + subscription.dispose();
81.1220 + });
81.1221 + _subscriptionsToDependencies = [];
81.1222 + }
81.1223 +
81.1224 + function evaluatePossiblyAsync() {
81.1225 + var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
81.1226 + if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
81.1227 + clearTimeout(evaluationTimeoutInstance);
81.1228 + evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
81.1229 + } else
81.1230 + evaluateImmediate();
81.1231 + }
81.1232 +
81.1233 + function evaluateImmediate() {
81.1234 + if (_isBeingEvaluated) {
81.1235 + // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
81.1236 + // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
81.1237 + // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
81.1238 + // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
81.1239 + return;
81.1240 + }
81.1241 +
81.1242 + // Don't dispose on first evaluation, because the "disposeWhen" callback might
81.1243 + // e.g., dispose when the associated DOM element isn't in the doc, and it's not
81.1244 + // going to be in the doc until *after* the first evaluation
81.1245 + if (_hasBeenEvaluated && disposeWhen()) {
81.1246 + dispose();
81.1247 + return;
81.1248 + }
81.1249 +
81.1250 + _isBeingEvaluated = true;
81.1251 + try {
81.1252 + // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
81.1253 + // Then, during evaluation, we cross off any that are in fact still being used.
81.1254 + var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
81.1255 +
81.1256 + ko.dependencyDetection.begin(function(subscribable) {
81.1257 + var inOld;
81.1258 + if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
81.1259 + disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
81.1260 + else
81.1261 + addSubscriptionToDependency(subscribable); // Brand new subscription - add it
81.1262 + });
81.1263 +
81.1264 + var newValue = readFunction.call(evaluatorFunctionTarget);
81.1265 +
81.1266 + // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
81.1267 + for (var i = disposalCandidates.length - 1; i >= 0; i--) {
81.1268 + if (disposalCandidates[i])
81.1269 + _subscriptionsToDependencies.splice(i, 1)[0].dispose();
81.1270 + }
81.1271 + _hasBeenEvaluated = true;
81.1272 +
81.1273 + dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
81.1274 + _latestValue = newValue;
81.1275 + if (DEBUG) dependentObservable._latestValue = _latestValue;
81.1276 + } finally {
81.1277 + ko.dependencyDetection.end();
81.1278 + }
81.1279 +
81.1280 + dependentObservable["notifySubscribers"](_latestValue);
81.1281 + _isBeingEvaluated = false;
81.1282 + if (!_subscriptionsToDependencies.length)
81.1283 + dispose();
81.1284 + }
81.1285 +
81.1286 + function dependentObservable() {
81.1287 + if (arguments.length > 0) {
81.1288 + if (typeof writeFunction === "function") {
81.1289 + // Writing a value
81.1290 + writeFunction.apply(evaluatorFunctionTarget, arguments);
81.1291 + } else {
81.1292 + throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
81.1293 + }
81.1294 + return this; // Permits chained assignments
81.1295 + } else {
81.1296 + // Reading the value
81.1297 + if (!_hasBeenEvaluated)
81.1298 + evaluateImmediate();
81.1299 + ko.dependencyDetection.registerDependency(dependentObservable);
81.1300 + return _latestValue;
81.1301 + }
81.1302 + }
81.1303 +
81.1304 + function peek() {
81.1305 + if (!_hasBeenEvaluated)
81.1306 + evaluateImmediate();
81.1307 + return _latestValue;
81.1308 + }
81.1309 +
81.1310 + function isActive() {
81.1311 + return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
81.1312 + }
81.1313 +
81.1314 + // By here, "options" is always non-null
81.1315 + var writeFunction = options["write"],
81.1316 + disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
81.1317 + disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
81.1318 + dispose = disposeAllSubscriptionsToDependencies,
81.1319 + _subscriptionsToDependencies = [],
81.1320 + evaluationTimeoutInstance = null;
81.1321 +
81.1322 + if (!evaluatorFunctionTarget)
81.1323 + evaluatorFunctionTarget = options["owner"];
81.1324 +
81.1325 + dependentObservable.peek = peek;
81.1326 + dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
81.1327 + dependentObservable.hasWriteFunction = typeof options["write"] === "function";
81.1328 + dependentObservable.dispose = function () { dispose(); };
81.1329 + dependentObservable.isActive = isActive;
81.1330 + dependentObservable.valueHasMutated = function() {
81.1331 + _hasBeenEvaluated = false;
81.1332 + evaluateImmediate();
81.1333 + };
81.1334 +
81.1335 + ko.subscribable.call(dependentObservable);
81.1336 + ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
81.1337 +
81.1338 + ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
81.1339 + ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
81.1340 + ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
81.1341 + ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
81.1342 +
81.1343 + // Evaluate, unless deferEvaluation is true
81.1344 + if (options['deferEvaluation'] !== true)
81.1345 + evaluateImmediate();
81.1346 +
81.1347 + // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
81.1348 + // But skip if isActive is false (there will never be any dependencies to dispose).
81.1349 + // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
81.1350 + // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
81.1351 + if (disposeWhenNodeIsRemoved && isActive()) {
81.1352 + dispose = function() {
81.1353 + ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
81.1354 + disposeAllSubscriptionsToDependencies();
81.1355 + };
81.1356 + ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
81.1357 + var existingDisposeWhenFunction = disposeWhen;
81.1358 + disposeWhen = function () {
81.1359 + return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
81.1360 + }
81.1361 + }
81.1362 +
81.1363 + return dependentObservable;
81.1364 +};
81.1365 +
81.1366 +ko.isComputed = function(instance) {
81.1367 + return ko.hasPrototype(instance, ko.dependentObservable);
81.1368 +};
81.1369 +
81.1370 +var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
81.1371 +ko.dependentObservable[protoProp] = ko.observable;
81.1372 +
81.1373 +ko.dependentObservable['fn'] = {};
81.1374 +ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
81.1375 +
81.1376 +ko.exportSymbol('dependentObservable', ko.dependentObservable);
81.1377 +ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
81.1378 +ko.exportSymbol('isComputed', ko.isComputed);
81.1379 +
81.1380 +(function() {
81.1381 + var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
81.1382 +
81.1383 + ko.toJS = function(rootObject) {
81.1384 + if (arguments.length == 0)
81.1385 + throw new Error("When calling ko.toJS, pass the object you want to convert.");
81.1386 +
81.1387 + // We just unwrap everything at every level in the object graph
81.1388 + return mapJsObjectGraph(rootObject, function(valueToMap) {
81.1389 + // Loop because an observable's value might in turn be another observable wrapper
81.1390 + for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
81.1391 + valueToMap = valueToMap();
81.1392 + return valueToMap;
81.1393 + });
81.1394 + };
81.1395 +
81.1396 + ko.toJSON = function(rootObject, replacer, space) { // replacer and space are optional
81.1397 + var plainJavaScriptObject = ko.toJS(rootObject);
81.1398 + return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
81.1399 + };
81.1400 +
81.1401 + function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
81.1402 + visitedObjects = visitedObjects || new objectLookup();
81.1403 +
81.1404 + rootObject = mapInputCallback(rootObject);
81.1405 + var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
81.1406 + if (!canHaveProperties)
81.1407 + return rootObject;
81.1408 +
81.1409 + var outputProperties = rootObject instanceof Array ? [] : {};
81.1410 + visitedObjects.save(rootObject, outputProperties);
81.1411 +
81.1412 + visitPropertiesOrArrayEntries(rootObject, function(indexer) {
81.1413 + var propertyValue = mapInputCallback(rootObject[indexer]);
81.1414 +
81.1415 + switch (typeof propertyValue) {
81.1416 + case "boolean":
81.1417 + case "number":
81.1418 + case "string":
81.1419 + case "function":
81.1420 + outputProperties[indexer] = propertyValue;
81.1421 + break;
81.1422 + case "object":
81.1423 + case "undefined":
81.1424 + var previouslyMappedValue = visitedObjects.get(propertyValue);
81.1425 + outputProperties[indexer] = (previouslyMappedValue !== undefined)
81.1426 + ? previouslyMappedValue
81.1427 + : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
81.1428 + break;
81.1429 + }
81.1430 + });
81.1431 +
81.1432 + return outputProperties;
81.1433 + }
81.1434 +
81.1435 + function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
81.1436 + if (rootObject instanceof Array) {
81.1437 + for (var i = 0; i < rootObject.length; i++)
81.1438 + visitorCallback(i);
81.1439 +
81.1440 + // For arrays, also respect toJSON property for custom mappings (fixes #278)
81.1441 + if (typeof rootObject['toJSON'] == 'function')
81.1442 + visitorCallback('toJSON');
81.1443 + } else {
81.1444 + for (var propertyName in rootObject)
81.1445 + visitorCallback(propertyName);
81.1446 + }
81.1447 + };
81.1448 +
81.1449 + function objectLookup() {
81.1450 + var keys = [];
81.1451 + var values = [];
81.1452 + this.save = function(key, value) {
81.1453 + var existingIndex = ko.utils.arrayIndexOf(keys, key);
81.1454 + if (existingIndex >= 0)
81.1455 + values[existingIndex] = value;
81.1456 + else {
81.1457 + keys.push(key);
81.1458 + values.push(value);
81.1459 + }
81.1460 + };
81.1461 + this.get = function(key) {
81.1462 + var existingIndex = ko.utils.arrayIndexOf(keys, key);
81.1463 + return (existingIndex >= 0) ? values[existingIndex] : undefined;
81.1464 + };
81.1465 + };
81.1466 +})();
81.1467 +
81.1468 +ko.exportSymbol('toJS', ko.toJS);
81.1469 +ko.exportSymbol('toJSON', ko.toJSON);
81.1470 +(function () {
81.1471 + var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
81.1472 +
81.1473 + // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
81.1474 + // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
81.1475 + // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
81.1476 + ko.selectExtensions = {
81.1477 + readValue : function(element) {
81.1478 + switch (ko.utils.tagNameLower(element)) {
81.1479 + case 'option':
81.1480 + if (element[hasDomDataExpandoProperty] === true)
81.1481 + return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
81.1482 + return ko.utils.ieVersion <= 7
81.1483 + ? (element.getAttributeNode('value').specified ? element.value : element.text)
81.1484 + : element.value;
81.1485 + case 'select':
81.1486 + return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
81.1487 + default:
81.1488 + return element.value;
81.1489 + }
81.1490 + },
81.1491 +
81.1492 + writeValue: function(element, value) {
81.1493 + switch (ko.utils.tagNameLower(element)) {
81.1494 + case 'option':
81.1495 + switch(typeof value) {
81.1496 + case "string":
81.1497 + ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
81.1498 + if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
81.1499 + delete element[hasDomDataExpandoProperty];
81.1500 + }
81.1501 + element.value = value;
81.1502 + break;
81.1503 + default:
81.1504 + // Store arbitrary object using DomData
81.1505 + ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
81.1506 + element[hasDomDataExpandoProperty] = true;
81.1507 +
81.1508 + // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
81.1509 + element.value = typeof value === "number" ? value : "";
81.1510 + break;
81.1511 + }
81.1512 + break;
81.1513 + case 'select':
81.1514 + for (var i = element.options.length - 1; i >= 0; i--) {
81.1515 + if (ko.selectExtensions.readValue(element.options[i]) == value) {
81.1516 + element.selectedIndex = i;
81.1517 + break;
81.1518 + }
81.1519 + }
81.1520 + break;
81.1521 + default:
81.1522 + if ((value === null) || (value === undefined))
81.1523 + value = "";
81.1524 + element.value = value;
81.1525 + break;
81.1526 + }
81.1527 + }
81.1528 + };
81.1529 +})();
81.1530 +
81.1531 +ko.exportSymbol('selectExtensions', ko.selectExtensions);
81.1532 +ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
81.1533 +ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
81.1534 +ko.expressionRewriting = (function () {
81.1535 + var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
81.1536 + var javaScriptReservedWords = ["true", "false"];
81.1537 +
81.1538 + // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
81.1539 + // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
81.1540 + var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
81.1541 +
81.1542 + function restoreTokens(string, tokens) {
81.1543 + var prevValue = null;
81.1544 + while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
81.1545 + prevValue = string;
81.1546 + string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
81.1547 + return tokens[tokenIndex];
81.1548 + });
81.1549 + }
81.1550 + return string;
81.1551 + }
81.1552 +
81.1553 + function getWriteableValue(expression) {
81.1554 + if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
81.1555 + return false;
81.1556 + var match = expression.match(javaScriptAssignmentTarget);
81.1557 + return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
81.1558 + }
81.1559 +
81.1560 + function ensureQuoted(key) {
81.1561 + var trimmedKey = ko.utils.stringTrim(key);
81.1562 + switch (trimmedKey.length && trimmedKey.charAt(0)) {
81.1563 + case "'":
81.1564 + case '"':
81.1565 + return key;
81.1566 + default:
81.1567 + return "'" + trimmedKey + "'";
81.1568 + }
81.1569 + }
81.1570 +
81.1571 + return {
81.1572 + bindingRewriteValidators: [],
81.1573 +
81.1574 + parseObjectLiteral: function(objectLiteralString) {
81.1575 + // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
81.1576 + // that is sufficient just to split an object literal string into a set of top-level key-value pairs
81.1577 +
81.1578 + var str = ko.utils.stringTrim(objectLiteralString);
81.1579 + if (str.length < 3)
81.1580 + return [];
81.1581 + if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
81.1582 + str = str.substring(1, str.length - 1);
81.1583 +
81.1584 + // Pull out any string literals and regex literals
81.1585 + var tokens = [];
81.1586 + var tokenStart = null, tokenEndChar;
81.1587 + for (var position = 0; position < str.length; position++) {
81.1588 + var c = str.charAt(position);
81.1589 + if (tokenStart === null) {
81.1590 + switch (c) {
81.1591 + case '"':
81.1592 + case "'":
81.1593 + case "/":
81.1594 + tokenStart = position;
81.1595 + tokenEndChar = c;
81.1596 + break;
81.1597 + }
81.1598 + } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
81.1599 + var token = str.substring(tokenStart, position + 1);
81.1600 + tokens.push(token);
81.1601 + var replacement = "@ko_token_" + (tokens.length - 1) + "@";
81.1602 + str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
81.1603 + position -= (token.length - replacement.length);
81.1604 + tokenStart = null;
81.1605 + }
81.1606 + }
81.1607 +
81.1608 + // Next pull out balanced paren, brace, and bracket blocks
81.1609 + tokenStart = null;
81.1610 + tokenEndChar = null;
81.1611 + var tokenDepth = 0, tokenStartChar = null;
81.1612 + for (var position = 0; position < str.length; position++) {
81.1613 + var c = str.charAt(position);
81.1614 + if (tokenStart === null) {
81.1615 + switch (c) {
81.1616 + case "{": tokenStart = position; tokenStartChar = c;
81.1617 + tokenEndChar = "}";
81.1618 + break;
81.1619 + case "(": tokenStart = position; tokenStartChar = c;
81.1620 + tokenEndChar = ")";
81.1621 + break;
81.1622 + case "[": tokenStart = position; tokenStartChar = c;
81.1623 + tokenEndChar = "]";
81.1624 + break;
81.1625 + }
81.1626 + }
81.1627 +
81.1628 + if (c === tokenStartChar)
81.1629 + tokenDepth++;
81.1630 + else if (c === tokenEndChar) {
81.1631 + tokenDepth--;
81.1632 + if (tokenDepth === 0) {
81.1633 + var token = str.substring(tokenStart, position + 1);
81.1634 + tokens.push(token);
81.1635 + var replacement = "@ko_token_" + (tokens.length - 1) + "@";
81.1636 + str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
81.1637 + position -= (token.length - replacement.length);
81.1638 + tokenStart = null;
81.1639 + }
81.1640 + }
81.1641 + }
81.1642 +
81.1643 + // Now we can safely split on commas to get the key/value pairs
81.1644 + var result = [];
81.1645 + var keyValuePairs = str.split(",");
81.1646 + for (var i = 0, j = keyValuePairs.length; i < j; i++) {
81.1647 + var pair = keyValuePairs[i];
81.1648 + var colonPos = pair.indexOf(":");
81.1649 + if ((colonPos > 0) && (colonPos < pair.length - 1)) {
81.1650 + var key = pair.substring(0, colonPos);
81.1651 + var value = pair.substring(colonPos + 1);
81.1652 + result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
81.1653 + } else {
81.1654 + result.push({ 'unknown': restoreTokens(pair, tokens) });
81.1655 + }
81.1656 + }
81.1657 + return result;
81.1658 + },
81.1659 +
81.1660 + preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
81.1661 + var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
81.1662 + ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
81.1663 + : objectLiteralStringOrKeyValueArray;
81.1664 + var resultStrings = [], propertyAccessorResultStrings = [];
81.1665 +
81.1666 + var keyValueEntry;
81.1667 + for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
81.1668 + if (resultStrings.length > 0)
81.1669 + resultStrings.push(",");
81.1670 +
81.1671 + if (keyValueEntry['key']) {
81.1672 + var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
81.1673 + resultStrings.push(quotedKey);
81.1674 + resultStrings.push(":");
81.1675 + resultStrings.push(val);
81.1676 +
81.1677 + if (val = getWriteableValue(ko.utils.stringTrim(val))) {
81.1678 + if (propertyAccessorResultStrings.length > 0)
81.1679 + propertyAccessorResultStrings.push(", ");
81.1680 + propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
81.1681 + }
81.1682 + } else if (keyValueEntry['unknown']) {
81.1683 + resultStrings.push(keyValueEntry['unknown']);
81.1684 + }
81.1685 + }
81.1686 +
81.1687 + var combinedResult = resultStrings.join("");
81.1688 + if (propertyAccessorResultStrings.length > 0) {
81.1689 + var allPropertyAccessors = propertyAccessorResultStrings.join("");
81.1690 + combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
81.1691 + }
81.1692 +
81.1693 + return combinedResult;
81.1694 + },
81.1695 +
81.1696 + keyValueArrayContainsKey: function(keyValueArray, key) {
81.1697 + for (var i = 0; i < keyValueArray.length; i++)
81.1698 + if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
81.1699 + return true;
81.1700 + return false;
81.1701 + },
81.1702 +
81.1703 + // Internal, private KO utility for updating model properties from within bindings
81.1704 + // property: If the property being updated is (or might be) an observable, pass it here
81.1705 + // If it turns out to be a writable observable, it will be written to directly
81.1706 + // allBindingsAccessor: All bindings in the current execution context.
81.1707 + // This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
81.1708 + // key: The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
81.1709 + // value: The value to be written
81.1710 + // checkIfDifferent: If true, and if the property being written is a writable observable, the value will only be written if
81.1711 + // it is !== existing value on that writable observable
81.1712 + writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
81.1713 + if (!property || !ko.isWriteableObservable(property)) {
81.1714 + var propWriters = allBindingsAccessor()['_ko_property_writers'];
81.1715 + if (propWriters && propWriters[key])
81.1716 + propWriters[key](value);
81.1717 + } else if (!checkIfDifferent || property.peek() !== value) {
81.1718 + property(value);
81.1719 + }
81.1720 + }
81.1721 + };
81.1722 +})();
81.1723 +
81.1724 +ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
81.1725 +ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
81.1726 +ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
81.1727 +ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
81.1728 +
81.1729 +// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
81.1730 +// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
81.1731 +ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
81.1732 +ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
81.1733 + // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
81.1734 + // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
81.1735 + // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
81.1736 + // of that virtual hierarchy
81.1737 + //
81.1738 + // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
81.1739 + // without having to scatter special cases all over the binding and templating code.
81.1740 +
81.1741 + // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
81.1742 + // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
81.1743 + // So, use node.text where available, and node.nodeValue elsewhere
81.1744 + var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
81.1745 +
81.1746 + var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
81.1747 + var endCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
81.1748 + var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
81.1749 +
81.1750 + function isStartComment(node) {
81.1751 + return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
81.1752 + }
81.1753 +
81.1754 + function isEndComment(node) {
81.1755 + return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
81.1756 + }
81.1757 +
81.1758 + function getVirtualChildren(startComment, allowUnbalanced) {
81.1759 + var currentNode = startComment;
81.1760 + var depth = 1;
81.1761 + var children = [];
81.1762 + while (currentNode = currentNode.nextSibling) {
81.1763 + if (isEndComment(currentNode)) {
81.1764 + depth--;
81.1765 + if (depth === 0)
81.1766 + return children;
81.1767 + }
81.1768 +
81.1769 + children.push(currentNode);
81.1770 +
81.1771 + if (isStartComment(currentNode))
81.1772 + depth++;
81.1773 + }
81.1774 + if (!allowUnbalanced)
81.1775 + throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
81.1776 + return null;
81.1777 + }
81.1778 +
81.1779 + function getMatchingEndComment(startComment, allowUnbalanced) {
81.1780 + var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
81.1781 + if (allVirtualChildren) {
81.1782 + if (allVirtualChildren.length > 0)
81.1783 + return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
81.1784 + return startComment.nextSibling;
81.1785 + } else
81.1786 + return null; // Must have no matching end comment, and allowUnbalanced is true
81.1787 + }
81.1788 +
81.1789 + function getUnbalancedChildTags(node) {
81.1790 + // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
81.1791 + // from <div>OK</div><!-- /ko --><!-- /ko -->, returns: <!-- /ko --><!-- /ko -->
81.1792 + var childNode = node.firstChild, captureRemaining = null;
81.1793 + if (childNode) {
81.1794 + do {
81.1795 + if (captureRemaining) // We already hit an unbalanced node and are now just scooping up all subsequent nodes
81.1796 + captureRemaining.push(childNode);
81.1797 + else if (isStartComment(childNode)) {
81.1798 + var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
81.1799 + if (matchingEndComment) // It's a balanced tag, so skip immediately to the end of this virtual set
81.1800 + childNode = matchingEndComment;
81.1801 + else
81.1802 + captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
81.1803 + } else if (isEndComment(childNode)) {
81.1804 + captureRemaining = [childNode]; // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
81.1805 + }
81.1806 + } while (childNode = childNode.nextSibling);
81.1807 + }
81.1808 + return captureRemaining;
81.1809 + }
81.1810 +
81.1811 + ko.virtualElements = {
81.1812 + allowedBindings: {},
81.1813 +
81.1814 + childNodes: function(node) {
81.1815 + return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
81.1816 + },
81.1817 +
81.1818 + emptyNode: function(node) {
81.1819 + if (!isStartComment(node))
81.1820 + ko.utils.emptyDomNode(node);
81.1821 + else {
81.1822 + var virtualChildren = ko.virtualElements.childNodes(node);
81.1823 + for (var i = 0, j = virtualChildren.length; i < j; i++)
81.1824 + ko.removeNode(virtualChildren[i]);
81.1825 + }
81.1826 + },
81.1827 +
81.1828 + setDomNodeChildren: function(node, childNodes) {
81.1829 + if (!isStartComment(node))
81.1830 + ko.utils.setDomNodeChildren(node, childNodes);
81.1831 + else {
81.1832 + ko.virtualElements.emptyNode(node);
81.1833 + var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
81.1834 + for (var i = 0, j = childNodes.length; i < j; i++)
81.1835 + endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
81.1836 + }
81.1837 + },
81.1838 +
81.1839 + prepend: function(containerNode, nodeToPrepend) {
81.1840 + if (!isStartComment(containerNode)) {
81.1841 + if (containerNode.firstChild)
81.1842 + containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
81.1843 + else
81.1844 + containerNode.appendChild(nodeToPrepend);
81.1845 + } else {
81.1846 + // Start comments must always have a parent and at least one following sibling (the end comment)
81.1847 + containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
81.1848 + }
81.1849 + },
81.1850 +
81.1851 + insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
81.1852 + if (!insertAfterNode) {
81.1853 + ko.virtualElements.prepend(containerNode, nodeToInsert);
81.1854 + } else if (!isStartComment(containerNode)) {
81.1855 + // Insert after insertion point
81.1856 + if (insertAfterNode.nextSibling)
81.1857 + containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
81.1858 + else
81.1859 + containerNode.appendChild(nodeToInsert);
81.1860 + } else {
81.1861 + // Children of start comments must always have a parent and at least one following sibling (the end comment)
81.1862 + containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
81.1863 + }
81.1864 + },
81.1865 +
81.1866 + firstChild: function(node) {
81.1867 + if (!isStartComment(node))
81.1868 + return node.firstChild;
81.1869 + if (!node.nextSibling || isEndComment(node.nextSibling))
81.1870 + return null;
81.1871 + return node.nextSibling;
81.1872 + },
81.1873 +
81.1874 + nextSibling: function(node) {
81.1875 + if (isStartComment(node))
81.1876 + node = getMatchingEndComment(node);
81.1877 + if (node.nextSibling && isEndComment(node.nextSibling))
81.1878 + return null;
81.1879 + return node.nextSibling;
81.1880 + },
81.1881 +
81.1882 + virtualNodeBindingValue: function(node) {
81.1883 + var regexMatch = isStartComment(node);
81.1884 + return regexMatch ? regexMatch[1] : null;
81.1885 + },
81.1886 +
81.1887 + normaliseVirtualElementDomStructure: function(elementVerified) {
81.1888 + // Workaround for https://github.com/SteveSanderson/knockout/issues/155
81.1889 + // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
81.1890 + // that are direct descendants of <ul> into the preceding <li>)
81.1891 + if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
81.1892 + return;
81.1893 +
81.1894 + // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
81.1895 + // must be intended to appear *after* that child, so move them there.
81.1896 + var childNode = elementVerified.firstChild;
81.1897 + if (childNode) {
81.1898 + do {
81.1899 + if (childNode.nodeType === 1) {
81.1900 + var unbalancedTags = getUnbalancedChildTags(childNode);
81.1901 + if (unbalancedTags) {
81.1902 + // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
81.1903 + var nodeToInsertBefore = childNode.nextSibling;
81.1904 + for (var i = 0; i < unbalancedTags.length; i++) {
81.1905 + if (nodeToInsertBefore)
81.1906 + elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
81.1907 + else
81.1908 + elementVerified.appendChild(unbalancedTags[i]);
81.1909 + }
81.1910 + }
81.1911 + }
81.1912 + } while (childNode = childNode.nextSibling);
81.1913 + }
81.1914 + }
81.1915 + };
81.1916 +})();
81.1917 +ko.exportSymbol('virtualElements', ko.virtualElements);
81.1918 +ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
81.1919 +ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
81.1920 +//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild); // firstChild is not minified
81.1921 +ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
81.1922 +//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling); // nextSibling is not minified
81.1923 +ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
81.1924 +ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
81.1925 +(function() {
81.1926 + var defaultBindingAttributeName = "data-bind";
81.1927 +
81.1928 + ko.bindingProvider = function() {
81.1929 + this.bindingCache = {};
81.1930 + };
81.1931 +
81.1932 + ko.utils.extend(ko.bindingProvider.prototype, {
81.1933 + 'nodeHasBindings': function(node) {
81.1934 + switch (node.nodeType) {
81.1935 + case 1: return node.getAttribute(defaultBindingAttributeName) != null; // Element
81.1936 + case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
81.1937 + default: return false;
81.1938 + }
81.1939 + },
81.1940 +
81.1941 + 'getBindings': function(node, bindingContext) {
81.1942 + var bindingsString = this['getBindingsString'](node, bindingContext);
81.1943 + return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
81.1944 + },
81.1945 +
81.1946 + // The following function is only used internally by this default provider.
81.1947 + // It's not part of the interface definition for a general binding provider.
81.1948 + 'getBindingsString': function(node, bindingContext) {
81.1949 + switch (node.nodeType) {
81.1950 + case 1: return node.getAttribute(defaultBindingAttributeName); // Element
81.1951 + case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
81.1952 + default: return null;
81.1953 + }
81.1954 + },
81.1955 +
81.1956 + // The following function is only used internally by this default provider.
81.1957 + // It's not part of the interface definition for a general binding provider.
81.1958 + 'parseBindingsString': function(bindingsString, bindingContext, node) {
81.1959 + try {
81.1960 + var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
81.1961 + return bindingFunction(bindingContext, node);
81.1962 + } catch (ex) {
81.1963 + throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
81.1964 + }
81.1965 + }
81.1966 + });
81.1967 +
81.1968 + ko.bindingProvider['instance'] = new ko.bindingProvider();
81.1969 +
81.1970 + function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
81.1971 + var cacheKey = bindingsString;
81.1972 + return cache[cacheKey]
81.1973 + || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
81.1974 + }
81.1975 +
81.1976 + function createBindingsStringEvaluator(bindingsString) {
81.1977 + // Build the source for a function that evaluates "expression"
81.1978 + // For each scope variable, add an extra level of "with" nesting
81.1979 + // Example result: with(sc1) { with(sc0) { return (expression) } }
81.1980 + var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
81.1981 + functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
81.1982 + return new Function("$context", "$element", functionBody);
81.1983 + }
81.1984 +})();
81.1985 +
81.1986 +ko.exportSymbol('bindingProvider', ko.bindingProvider);
81.1987 +(function () {
81.1988 + ko.bindingHandlers = {};
81.1989 +
81.1990 + ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
81.1991 + if (parentBindingContext) {
81.1992 + ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
81.1993 + this['$parentContext'] = parentBindingContext;
81.1994 + this['$parent'] = parentBindingContext['$data'];
81.1995 + this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
81.1996 + this['$parents'].unshift(this['$parent']);
81.1997 + } else {
81.1998 + this['$parents'] = [];
81.1999 + this['$root'] = dataItem;
81.2000 + // Export 'ko' in the binding context so it will be available in bindings and templates
81.2001 + // even if 'ko' isn't exported as a global, such as when using an AMD loader.
81.2002 + // See https://github.com/SteveSanderson/knockout/issues/490
81.2003 + this['ko'] = ko;
81.2004 + }
81.2005 + this['$data'] = dataItem;
81.2006 + if (dataItemAlias)
81.2007 + this[dataItemAlias] = dataItem;
81.2008 + }
81.2009 + ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
81.2010 + return new ko.bindingContext(dataItem, this, dataItemAlias);
81.2011 + };
81.2012 + ko.bindingContext.prototype['extend'] = function(properties) {
81.2013 + var clone = ko.utils.extend(new ko.bindingContext(), this);
81.2014 + return ko.utils.extend(clone, properties);
81.2015 + };
81.2016 +
81.2017 + function validateThatBindingIsAllowedForVirtualElements(bindingName) {
81.2018 + var validator = ko.virtualElements.allowedBindings[bindingName];
81.2019 + if (!validator)
81.2020 + throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
81.2021 + }
81.2022 +
81.2023 + function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
81.2024 + var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
81.2025 + while (currentChild = nextInQueue) {
81.2026 + // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
81.2027 + nextInQueue = ko.virtualElements.nextSibling(currentChild);
81.2028 + applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
81.2029 + }
81.2030 + }
81.2031 +
81.2032 + function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
81.2033 + var shouldBindDescendants = true;
81.2034 +
81.2035 + // Perf optimisation: Apply bindings only if...
81.2036 + // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
81.2037 + // Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
81.2038 + // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
81.2039 + var isElement = (nodeVerified.nodeType === 1);
81.2040 + if (isElement) // Workaround IE <= 8 HTML parsing weirdness
81.2041 + ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
81.2042 +
81.2043 + var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
81.2044 + || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
81.2045 + if (shouldApplyBindings)
81.2046 + shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
81.2047 +
81.2048 + if (shouldBindDescendants) {
81.2049 + // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
81.2050 + // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
81.2051 + // hence bindingContextsMayDifferFromDomParentElement is false
81.2052 + // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
81.2053 + // skip over any number of intermediate virtual elements, any of which might define a custom binding context,
81.2054 + // hence bindingContextsMayDifferFromDomParentElement is true
81.2055 + applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
81.2056 + }
81.2057 + }
81.2058 +
81.2059 + function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
81.2060 + // Need to be sure that inits are only run once, and updates never run until all the inits have been run
81.2061 + var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
81.2062 +
81.2063 + // Each time the dependentObservable is evaluated (after data changes),
81.2064 + // the binding attribute is reparsed so that it can pick out the correct
81.2065 + // model properties in the context of the changed data.
81.2066 + // DOM event callbacks need to be able to access this changed data,
81.2067 + // so we need a single parsedBindings variable (shared by all callbacks
81.2068 + // associated with this node's bindings) that all the closures can access.
81.2069 + var parsedBindings;
81.2070 + function makeValueAccessor(bindingKey) {
81.2071 + return function () { return parsedBindings[bindingKey] }
81.2072 + }
81.2073 + function parsedBindingsAccessor() {
81.2074 + return parsedBindings;
81.2075 + }
81.2076 +
81.2077 + var bindingHandlerThatControlsDescendantBindings;
81.2078 + ko.dependentObservable(
81.2079 + function () {
81.2080 + // Ensure we have a nonnull binding context to work with
81.2081 + var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
81.2082 + ? viewModelOrBindingContext
81.2083 + : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
81.2084 + var viewModel = bindingContextInstance['$data'];
81.2085 +
81.2086 + // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
81.2087 + // we can easily recover it just by scanning up the node's ancestors in the DOM
81.2088 + // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
81.2089 + if (bindingContextMayDifferFromDomParentElement)
81.2090 + ko.storedBindingContextForNode(node, bindingContextInstance);
81.2091 +
81.2092 + // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
81.2093 + var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
81.2094 + parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
81.2095 +
81.2096 + if (parsedBindings) {
81.2097 + // First run all the inits, so bindings can register for notification on changes
81.2098 + if (initPhase === 0) {
81.2099 + initPhase = 1;
81.2100 + for (var bindingKey in parsedBindings) {
81.2101 + var binding = ko.bindingHandlers[bindingKey];
81.2102 + if (binding && node.nodeType === 8)
81.2103 + validateThatBindingIsAllowedForVirtualElements(bindingKey);
81.2104 +
81.2105 + if (binding && typeof binding["init"] == "function") {
81.2106 + var handlerInitFn = binding["init"];
81.2107 + var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
81.2108 +
81.2109 + // If this binding handler claims to control descendant bindings, make a note of this
81.2110 + if (initResult && initResult['controlsDescendantBindings']) {
81.2111 + if (bindingHandlerThatControlsDescendantBindings !== undefined)
81.2112 + throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
81.2113 + bindingHandlerThatControlsDescendantBindings = bindingKey;
81.2114 + }
81.2115 + }
81.2116 + }
81.2117 + initPhase = 2;
81.2118 + }
81.2119 +
81.2120 + // ... then run all the updates, which might trigger changes even on the first evaluation
81.2121 + if (initPhase === 2) {
81.2122 + for (var bindingKey in parsedBindings) {
81.2123 + var binding = ko.bindingHandlers[bindingKey];
81.2124 + if (binding && typeof binding["update"] == "function") {
81.2125 + var handlerUpdateFn = binding["update"];
81.2126 + handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
81.2127 + }
81.2128 + }
81.2129 + }
81.2130 + }
81.2131 + },
81.2132 + null,
81.2133 + { disposeWhenNodeIsRemoved : node }
81.2134 + );
81.2135 +
81.2136 + return {
81.2137 + shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
81.2138 + };
81.2139 + };
81.2140 +
81.2141 + var storedBindingContextDomDataKey = "__ko_bindingContext__";
81.2142 + ko.storedBindingContextForNode = function (node, bindingContext) {
81.2143 + if (arguments.length == 2)
81.2144 + ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
81.2145 + else
81.2146 + return ko.utils.domData.get(node, storedBindingContextDomDataKey);
81.2147 + }
81.2148 +
81.2149 + ko.applyBindingsToNode = function (node, bindings, viewModel) {
81.2150 + if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
81.2151 + ko.virtualElements.normaliseVirtualElementDomStructure(node);
81.2152 + return applyBindingsToNodeInternal(node, bindings, viewModel, true);
81.2153 + };
81.2154 +
81.2155 + ko.applyBindingsToDescendants = function(viewModel, rootNode) {
81.2156 + if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
81.2157 + applyBindingsToDescendantsInternal(viewModel, rootNode, true);
81.2158 + };
81.2159 +
81.2160 + ko.applyBindings = function (viewModel, rootNode) {
81.2161 + if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
81.2162 + throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
81.2163 + rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
81.2164 +
81.2165 + applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
81.2166 + };
81.2167 +
81.2168 + // Retrieving binding context from arbitrary nodes
81.2169 + ko.contextFor = function(node) {
81.2170 + // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
81.2171 + switch (node.nodeType) {
81.2172 + case 1:
81.2173 + case 8:
81.2174 + var context = ko.storedBindingContextForNode(node);
81.2175 + if (context) return context;
81.2176 + if (node.parentNode) return ko.contextFor(node.parentNode);
81.2177 + break;
81.2178 + }
81.2179 + return undefined;
81.2180 + };
81.2181 + ko.dataFor = function(node) {
81.2182 + var context = ko.contextFor(node);
81.2183 + return context ? context['$data'] : undefined;
81.2184 + };
81.2185 +
81.2186 + ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
81.2187 + ko.exportSymbol('applyBindings', ko.applyBindings);
81.2188 + ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
81.2189 + ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
81.2190 + ko.exportSymbol('contextFor', ko.contextFor);
81.2191 + ko.exportSymbol('dataFor', ko.dataFor);
81.2192 +})();
81.2193 +var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
81.2194 +ko.bindingHandlers['attr'] = {
81.2195 + 'update': function(element, valueAccessor, allBindingsAccessor) {
81.2196 + var value = ko.utils.unwrapObservable(valueAccessor()) || {};
81.2197 + for (var attrName in value) {
81.2198 + if (typeof attrName == "string") {
81.2199 + var attrValue = ko.utils.unwrapObservable(value[attrName]);
81.2200 +
81.2201 + // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
81.2202 + // when someProp is a "no value"-like value (strictly null, false, or undefined)
81.2203 + // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
81.2204 + var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
81.2205 + if (toRemove)
81.2206 + element.removeAttribute(attrName);
81.2207 +
81.2208 + // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
81.2209 + // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
81.2210 + // but instead of figuring out the mode, we'll just set the attribute through the Javascript
81.2211 + // property for IE <= 8.
81.2212 + if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
81.2213 + attrName = attrHtmlToJavascriptMap[attrName];
81.2214 + if (toRemove)
81.2215 + element.removeAttribute(attrName);
81.2216 + else
81.2217 + element[attrName] = attrValue;
81.2218 + } else if (!toRemove) {
81.2219 + try {
81.2220 + element.setAttribute(attrName, attrValue.toString());
81.2221 + } catch (err) {
81.2222 + // ignore for now
81.2223 + if (console) {
81.2224 + console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
81.2225 + }
81.2226 + }
81.2227 + }
81.2228 +
81.2229 + // Treat "name" specially - although you can think of it as an attribute, it also needs
81.2230 + // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
81.2231 + // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
81.2232 + // entirely, and there's no strong reason to allow for such casing in HTML.
81.2233 + if (attrName === "name") {
81.2234 + ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
81.2235 + }
81.2236 + }
81.2237 + }
81.2238 + }
81.2239 +};
81.2240 +ko.bindingHandlers['checked'] = {
81.2241 + 'init': function (element, valueAccessor, allBindingsAccessor) {
81.2242 + var updateHandler = function() {
81.2243 + var valueToWrite;
81.2244 + if (element.type == "checkbox") {
81.2245 + valueToWrite = element.checked;
81.2246 + } else if ((element.type == "radio") && (element.checked)) {
81.2247 + valueToWrite = element.value;
81.2248 + } else {
81.2249 + return; // "checked" binding only responds to checkboxes and selected radio buttons
81.2250 + }
81.2251 +
81.2252 + var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
81.2253 + if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
81.2254 + // For checkboxes bound to an array, we add/remove the checkbox value to that array
81.2255 + // This works for both observable and non-observable arrays
81.2256 + var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
81.2257 + if (element.checked && (existingEntryIndex < 0))
81.2258 + modelValue.push(element.value);
81.2259 + else if ((!element.checked) && (existingEntryIndex >= 0))
81.2260 + modelValue.splice(existingEntryIndex, 1);
81.2261 + } else {
81.2262 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
81.2263 + }
81.2264 + };
81.2265 + ko.utils.registerEventHandler(element, "click", updateHandler);
81.2266 +
81.2267 + // IE 6 won't allow radio buttons to be selected unless they have a name
81.2268 + if ((element.type == "radio") && !element.name)
81.2269 + ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
81.2270 + },
81.2271 + 'update': function (element, valueAccessor) {
81.2272 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2273 +
81.2274 + if (element.type == "checkbox") {
81.2275 + if (value instanceof Array) {
81.2276 + // When bound to an array, the checkbox being checked represents its value being present in that array
81.2277 + element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
81.2278 + } else {
81.2279 + // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
81.2280 + element.checked = value;
81.2281 + }
81.2282 + } else if (element.type == "radio") {
81.2283 + element.checked = (element.value == value);
81.2284 + }
81.2285 + }
81.2286 +};
81.2287 +var classesWrittenByBindingKey = '__ko__cssValue';
81.2288 +ko.bindingHandlers['css'] = {
81.2289 + 'update': function (element, valueAccessor) {
81.2290 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2291 + if (typeof value == "object") {
81.2292 + for (var className in value) {
81.2293 + var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
81.2294 + ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
81.2295 + }
81.2296 + } else {
81.2297 + value = String(value || ''); // Make sure we don't try to store or set a non-string value
81.2298 + ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
81.2299 + element[classesWrittenByBindingKey] = value;
81.2300 + ko.utils.toggleDomNodeCssClass(element, value, true);
81.2301 + }
81.2302 + }
81.2303 +};
81.2304 +ko.bindingHandlers['enable'] = {
81.2305 + 'update': function (element, valueAccessor) {
81.2306 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2307 + if (value && element.disabled)
81.2308 + element.removeAttribute("disabled");
81.2309 + else if ((!value) && (!element.disabled))
81.2310 + element.disabled = true;
81.2311 + }
81.2312 +};
81.2313 +
81.2314 +ko.bindingHandlers['disable'] = {
81.2315 + 'update': function (element, valueAccessor) {
81.2316 + ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
81.2317 + }
81.2318 +};
81.2319 +// For certain common events (currently just 'click'), allow a simplified data-binding syntax
81.2320 +// e.g. click:handler instead of the usual full-length event:{click:handler}
81.2321 +function makeEventHandlerShortcut(eventName) {
81.2322 + ko.bindingHandlers[eventName] = {
81.2323 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
81.2324 + var newValueAccessor = function () {
81.2325 + var result = {};
81.2326 + result[eventName] = valueAccessor();
81.2327 + return result;
81.2328 + };
81.2329 + return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
81.2330 + }
81.2331 + }
81.2332 +}
81.2333 +
81.2334 +ko.bindingHandlers['event'] = {
81.2335 + 'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
81.2336 + var eventsToHandle = valueAccessor() || {};
81.2337 + for(var eventNameOutsideClosure in eventsToHandle) {
81.2338 + (function() {
81.2339 + var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
81.2340 + if (typeof eventName == "string") {
81.2341 + ko.utils.registerEventHandler(element, eventName, function (event) {
81.2342 + var handlerReturnValue;
81.2343 + var handlerFunction = valueAccessor()[eventName];
81.2344 + if (!handlerFunction)
81.2345 + return;
81.2346 + var allBindings = allBindingsAccessor();
81.2347 +
81.2348 + try {
81.2349 + // Take all the event args, and prefix with the viewmodel
81.2350 + var argsForHandler = ko.utils.makeArray(arguments);
81.2351 + argsForHandler.unshift(viewModel);
81.2352 + handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
81.2353 + } finally {
81.2354 + if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
81.2355 + if (event.preventDefault)
81.2356 + event.preventDefault();
81.2357 + else
81.2358 + event.returnValue = false;
81.2359 + }
81.2360 + }
81.2361 +
81.2362 + var bubble = allBindings[eventName + 'Bubble'] !== false;
81.2363 + if (!bubble) {
81.2364 + event.cancelBubble = true;
81.2365 + if (event.stopPropagation)
81.2366 + event.stopPropagation();
81.2367 + }
81.2368 + });
81.2369 + }
81.2370 + })();
81.2371 + }
81.2372 + }
81.2373 +};
81.2374 +// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
81.2375 +// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
81.2376 +ko.bindingHandlers['foreach'] = {
81.2377 + makeTemplateValueAccessor: function(valueAccessor) {
81.2378 + return function() {
81.2379 + var modelValue = valueAccessor(),
81.2380 + unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
81.2381 +
81.2382 + // If unwrappedValue is the array, pass in the wrapped value on its own
81.2383 + // The value will be unwrapped and tracked within the template binding
81.2384 + // (See https://github.com/SteveSanderson/knockout/issues/523)
81.2385 + if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
81.2386 + return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
81.2387 +
81.2388 + // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
81.2389 + ko.utils.unwrapObservable(modelValue);
81.2390 + return {
81.2391 + 'foreach': unwrappedValue['data'],
81.2392 + 'as': unwrappedValue['as'],
81.2393 + 'includeDestroyed': unwrappedValue['includeDestroyed'],
81.2394 + 'afterAdd': unwrappedValue['afterAdd'],
81.2395 + 'beforeRemove': unwrappedValue['beforeRemove'],
81.2396 + 'afterRender': unwrappedValue['afterRender'],
81.2397 + 'beforeMove': unwrappedValue['beforeMove'],
81.2398 + 'afterMove': unwrappedValue['afterMove'],
81.2399 + 'templateEngine': ko.nativeTemplateEngine.instance
81.2400 + };
81.2401 + };
81.2402 + },
81.2403 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
81.2404 + return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
81.2405 + },
81.2406 + 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
81.2407 + return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
81.2408 + }
81.2409 +};
81.2410 +ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
81.2411 +ko.virtualElements.allowedBindings['foreach'] = true;
81.2412 +var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
81.2413 +ko.bindingHandlers['hasfocus'] = {
81.2414 + 'init': function(element, valueAccessor, allBindingsAccessor) {
81.2415 + var handleElementFocusChange = function(isFocused) {
81.2416 + // Where possible, ignore which event was raised and determine focus state using activeElement,
81.2417 + // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
81.2418 + // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
81.2419 + // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
81.2420 + // from calling 'blur()' on the element when it loses focus.
81.2421 + // Discussion at https://github.com/SteveSanderson/knockout/pull/352
81.2422 + element[hasfocusUpdatingProperty] = true;
81.2423 + var ownerDoc = element.ownerDocument;
81.2424 + if ("activeElement" in ownerDoc) {
81.2425 + isFocused = (ownerDoc.activeElement === element);
81.2426 + }
81.2427 + var modelValue = valueAccessor();
81.2428 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
81.2429 + element[hasfocusUpdatingProperty] = false;
81.2430 + };
81.2431 + var handleElementFocusIn = handleElementFocusChange.bind(null, true);
81.2432 + var handleElementFocusOut = handleElementFocusChange.bind(null, false);
81.2433 +
81.2434 + ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
81.2435 + ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
81.2436 + ko.utils.registerEventHandler(element, "blur", handleElementFocusOut);
81.2437 + ko.utils.registerEventHandler(element, "focusout", handleElementFocusOut); // For IE
81.2438 + },
81.2439 + 'update': function(element, valueAccessor) {
81.2440 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2441 + if (!element[hasfocusUpdatingProperty]) {
81.2442 + value ? element.focus() : element.blur();
81.2443 + ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
81.2444 + }
81.2445 + }
81.2446 +};
81.2447 +ko.bindingHandlers['html'] = {
81.2448 + 'init': function() {
81.2449 + // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
81.2450 + return { 'controlsDescendantBindings': true };
81.2451 + },
81.2452 + 'update': function (element, valueAccessor) {
81.2453 + // setHtml will unwrap the value if needed
81.2454 + ko.utils.setHtml(element, valueAccessor());
81.2455 + }
81.2456 +};
81.2457 +var withIfDomDataKey = '__ko_withIfBindingData';
81.2458 +// Makes a binding like with or if
81.2459 +function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
81.2460 + ko.bindingHandlers[bindingKey] = {
81.2461 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
81.2462 + ko.utils.domData.set(element, withIfDomDataKey, {});
81.2463 + return { 'controlsDescendantBindings': true };
81.2464 + },
81.2465 + 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
81.2466 + var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
81.2467 + dataValue = ko.utils.unwrapObservable(valueAccessor()),
81.2468 + shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
81.2469 + isFirstRender = !withIfData.savedNodes,
81.2470 + needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
81.2471 +
81.2472 + if (needsRefresh) {
81.2473 + if (isFirstRender) {
81.2474 + withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
81.2475 + }
81.2476 +
81.2477 + if (shouldDisplay) {
81.2478 + if (!isFirstRender) {
81.2479 + ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
81.2480 + }
81.2481 + ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
81.2482 + } else {
81.2483 + ko.virtualElements.emptyNode(element);
81.2484 + }
81.2485 +
81.2486 + withIfData.didDisplayOnLastUpdate = shouldDisplay;
81.2487 + }
81.2488 + }
81.2489 + };
81.2490 + ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
81.2491 + ko.virtualElements.allowedBindings[bindingKey] = true;
81.2492 +}
81.2493 +
81.2494 +// Construct the actual binding handlers
81.2495 +makeWithIfBinding('if');
81.2496 +makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
81.2497 +makeWithIfBinding('with', true /* isWith */, false /* isNot */,
81.2498 + function(bindingContext, dataValue) {
81.2499 + return bindingContext['createChildContext'](dataValue);
81.2500 + }
81.2501 +);
81.2502 +function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
81.2503 + if (preferModelValue) {
81.2504 + if (modelValue !== ko.selectExtensions.readValue(element))
81.2505 + ko.selectExtensions.writeValue(element, modelValue);
81.2506 + }
81.2507 +
81.2508 + // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
81.2509 + // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
81.2510 + // change the model value to match the dropdown.
81.2511 + if (modelValue !== ko.selectExtensions.readValue(element))
81.2512 + ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
81.2513 +};
81.2514 +
81.2515 +ko.bindingHandlers['options'] = {
81.2516 + 'update': function (element, valueAccessor, allBindingsAccessor) {
81.2517 + if (ko.utils.tagNameLower(element) !== "select")
81.2518 + throw new Error("options binding applies only to SELECT elements");
81.2519 +
81.2520 + var selectWasPreviouslyEmpty = element.length == 0;
81.2521 + var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
81.2522 + return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
81.2523 + }), function (node) {
81.2524 + return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
81.2525 + });
81.2526 + var previousScrollTop = element.scrollTop;
81.2527 +
81.2528 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2529 + var selectedValue = element.value;
81.2530 +
81.2531 + // Remove all existing <option>s.
81.2532 + // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
81.2533 + while (element.length > 0) {
81.2534 + ko.cleanNode(element.options[0]);
81.2535 + element.remove(0);
81.2536 + }
81.2537 +
81.2538 + if (value) {
81.2539 + var allBindings = allBindingsAccessor(),
81.2540 + includeDestroyed = allBindings['optionsIncludeDestroyed'];
81.2541 +
81.2542 + if (typeof value.length != "number")
81.2543 + value = [value];
81.2544 + if (allBindings['optionsCaption']) {
81.2545 + var option = document.createElement("option");
81.2546 + ko.utils.setHtml(option, allBindings['optionsCaption']);
81.2547 + ko.selectExtensions.writeValue(option, undefined);
81.2548 + element.appendChild(option);
81.2549 + }
81.2550 +
81.2551 + for (var i = 0, j = value.length; i < j; i++) {
81.2552 + // Skip destroyed items
81.2553 + var arrayEntry = value[i];
81.2554 + if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
81.2555 + continue;
81.2556 +
81.2557 + var option = document.createElement("option");
81.2558 +
81.2559 + function applyToObject(object, predicate, defaultValue) {
81.2560 + var predicateType = typeof predicate;
81.2561 + if (predicateType == "function") // Given a function; run it against the data value
81.2562 + return predicate(object);
81.2563 + else if (predicateType == "string") // Given a string; treat it as a property name on the data value
81.2564 + return object[predicate];
81.2565 + else // Given no optionsText arg; use the data value itself
81.2566 + return defaultValue;
81.2567 + }
81.2568 +
81.2569 + // Apply a value to the option element
81.2570 + var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
81.2571 + ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
81.2572 +
81.2573 + // Apply some text to the option element
81.2574 + var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
81.2575 + ko.utils.setTextContent(option, optionText);
81.2576 +
81.2577 + element.appendChild(option);
81.2578 + }
81.2579 +
81.2580 + // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
81.2581 + // That's why we first added them without selection. Now it's time to set the selection.
81.2582 + var newOptions = element.getElementsByTagName("option");
81.2583 + var countSelectionsRetained = 0;
81.2584 + for (var i = 0, j = newOptions.length; i < j; i++) {
81.2585 + if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
81.2586 + ko.utils.setOptionNodeSelectionState(newOptions[i], true);
81.2587 + countSelectionsRetained++;
81.2588 + }
81.2589 + }
81.2590 +
81.2591 + element.scrollTop = previousScrollTop;
81.2592 +
81.2593 + if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
81.2594 + // Ensure consistency between model value and selected option.
81.2595 + // If the dropdown is being populated for the first time here (or was otherwise previously empty),
81.2596 + // the dropdown selection state is meaningless, so we preserve the model value.
81.2597 + ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
81.2598 + }
81.2599 +
81.2600 + // Workaround for IE9 bug
81.2601 + ko.utils.ensureSelectElementIsRenderedCorrectly(element);
81.2602 + }
81.2603 + }
81.2604 +};
81.2605 +ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
81.2606 +ko.bindingHandlers['selectedOptions'] = {
81.2607 + 'init': function (element, valueAccessor, allBindingsAccessor) {
81.2608 + ko.utils.registerEventHandler(element, "change", function () {
81.2609 + var value = valueAccessor(), valueToWrite = [];
81.2610 + ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
81.2611 + if (node.selected)
81.2612 + valueToWrite.push(ko.selectExtensions.readValue(node));
81.2613 + });
81.2614 + ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
81.2615 + });
81.2616 + },
81.2617 + 'update': function (element, valueAccessor) {
81.2618 + if (ko.utils.tagNameLower(element) != "select")
81.2619 + throw new Error("values binding applies only to SELECT elements");
81.2620 +
81.2621 + var newValue = ko.utils.unwrapObservable(valueAccessor());
81.2622 + if (newValue && typeof newValue.length == "number") {
81.2623 + ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
81.2624 + var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
81.2625 + ko.utils.setOptionNodeSelectionState(node, isSelected);
81.2626 + });
81.2627 + }
81.2628 + }
81.2629 +};
81.2630 +ko.bindingHandlers['style'] = {
81.2631 + 'update': function (element, valueAccessor) {
81.2632 + var value = ko.utils.unwrapObservable(valueAccessor() || {});
81.2633 + for (var styleName in value) {
81.2634 + if (typeof styleName == "string") {
81.2635 + var styleValue = ko.utils.unwrapObservable(value[styleName]);
81.2636 + element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
81.2637 + }
81.2638 + }
81.2639 + }
81.2640 +};
81.2641 +ko.bindingHandlers['submit'] = {
81.2642 + 'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
81.2643 + if (typeof valueAccessor() != "function")
81.2644 + throw new Error("The value for a submit binding must be a function");
81.2645 + ko.utils.registerEventHandler(element, "submit", function (event) {
81.2646 + var handlerReturnValue;
81.2647 + var value = valueAccessor();
81.2648 + try { handlerReturnValue = value.call(viewModel, element); }
81.2649 + finally {
81.2650 + if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
81.2651 + if (event.preventDefault)
81.2652 + event.preventDefault();
81.2653 + else
81.2654 + event.returnValue = false;
81.2655 + }
81.2656 + }
81.2657 + });
81.2658 + }
81.2659 +};
81.2660 +ko.bindingHandlers['text'] = {
81.2661 + 'update': function (element, valueAccessor) {
81.2662 + ko.utils.setTextContent(element, valueAccessor());
81.2663 + }
81.2664 +};
81.2665 +ko.virtualElements.allowedBindings['text'] = true;
81.2666 +ko.bindingHandlers['uniqueName'] = {
81.2667 + 'init': function (element, valueAccessor) {
81.2668 + if (valueAccessor()) {
81.2669 + var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
81.2670 + ko.utils.setElementName(element, name);
81.2671 + }
81.2672 + }
81.2673 +};
81.2674 +ko.bindingHandlers['uniqueName'].currentIndex = 0;
81.2675 +ko.bindingHandlers['value'] = {
81.2676 + 'init': function (element, valueAccessor, allBindingsAccessor) {
81.2677 + // Always catch "change" event; possibly other events too if asked
81.2678 + var eventsToCatch = ["change"];
81.2679 + var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
81.2680 + var propertyChangedFired = false;
81.2681 + if (requestedEventsToCatch) {
81.2682 + if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
81.2683 + requestedEventsToCatch = [requestedEventsToCatch];
81.2684 + ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
81.2685 + eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
81.2686 + }
81.2687 +
81.2688 + var valueUpdateHandler = function() {
81.2689 + propertyChangedFired = false;
81.2690 + var modelValue = valueAccessor();
81.2691 + var elementValue = ko.selectExtensions.readValue(element);
81.2692 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
81.2693 + }
81.2694 +
81.2695 + // Workaround for https://github.com/SteveSanderson/knockout/issues/122
81.2696 + // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
81.2697 + var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
81.2698 + && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
81.2699 + if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
81.2700 + ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
81.2701 + ko.utils.registerEventHandler(element, "blur", function() {
81.2702 + if (propertyChangedFired) {
81.2703 + valueUpdateHandler();
81.2704 + }
81.2705 + });
81.2706 + }
81.2707 +
81.2708 + ko.utils.arrayForEach(eventsToCatch, function(eventName) {
81.2709 + // The syntax "after<eventname>" means "run the handler asynchronously after the event"
81.2710 + // This is useful, for example, to catch "keydown" events after the browser has updated the control
81.2711 + // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
81.2712 + var handler = valueUpdateHandler;
81.2713 + if (ko.utils.stringStartsWith(eventName, "after")) {
81.2714 + handler = function() { setTimeout(valueUpdateHandler, 0) };
81.2715 + eventName = eventName.substring("after".length);
81.2716 + }
81.2717 + ko.utils.registerEventHandler(element, eventName, handler);
81.2718 + });
81.2719 + },
81.2720 + 'update': function (element, valueAccessor) {
81.2721 + var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
81.2722 + var newValue = ko.utils.unwrapObservable(valueAccessor());
81.2723 + var elementValue = ko.selectExtensions.readValue(element);
81.2724 + var valueHasChanged = (newValue != elementValue);
81.2725 +
81.2726 + // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
81.2727 + // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
81.2728 + if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
81.2729 + valueHasChanged = true;
81.2730 +
81.2731 + if (valueHasChanged) {
81.2732 + var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
81.2733 + applyValueAction();
81.2734 +
81.2735 + // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
81.2736 + // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
81.2737 + // to apply the value as well.
81.2738 + var alsoApplyAsynchronously = valueIsSelectOption;
81.2739 + if (alsoApplyAsynchronously)
81.2740 + setTimeout(applyValueAction, 0);
81.2741 + }
81.2742 +
81.2743 + // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
81.2744 + // because you're not allowed to have a model value that disagrees with a visible UI selection.
81.2745 + if (valueIsSelectOption && (element.length > 0))
81.2746 + ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
81.2747 + }
81.2748 +};
81.2749 +ko.bindingHandlers['visible'] = {
81.2750 + 'update': function (element, valueAccessor) {
81.2751 + var value = ko.utils.unwrapObservable(valueAccessor());
81.2752 + var isCurrentlyVisible = !(element.style.display == "none");
81.2753 + if (value && !isCurrentlyVisible)
81.2754 + element.style.display = "";
81.2755 + else if ((!value) && isCurrentlyVisible)
81.2756 + element.style.display = "none";
81.2757 + }
81.2758 +};
81.2759 +// 'click' is just a shorthand for the usual full-length event:{click:handler}
81.2760 +makeEventHandlerShortcut('click');
81.2761 +// If you want to make a custom template engine,
81.2762 +//
81.2763 +// [1] Inherit from this class (like ko.nativeTemplateEngine does)
81.2764 +// [2] Override 'renderTemplateSource', supplying a function with this signature:
81.2765 +//
81.2766 +// function (templateSource, bindingContext, options) {
81.2767 +// // - templateSource.text() is the text of the template you should render
81.2768 +// // - bindingContext.$data is the data you should pass into the template
81.2769 +// // - you might also want to make bindingContext.$parent, bindingContext.$parents,
81.2770 +// // and bindingContext.$root available in the template too
81.2771 +// // - options gives you access to any other properties set on "data-bind: { template: options }"
81.2772 +// //
81.2773 +// // Return value: an array of DOM nodes
81.2774 +// }
81.2775 +//
81.2776 +// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
81.2777 +//
81.2778 +// function (script) {
81.2779 +// // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
81.2780 +// // For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
81.2781 +// }
81.2782 +//
81.2783 +// This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
81.2784 +// If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
81.2785 +// and then you don't need to override 'createJavaScriptEvaluatorBlock'.
81.2786 +
81.2787 +ko.templateEngine = function () { };
81.2788 +
81.2789 +ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
81.2790 + throw new Error("Override renderTemplateSource");
81.2791 +};
81.2792 +
81.2793 +ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
81.2794 + throw new Error("Override createJavaScriptEvaluatorBlock");
81.2795 +};
81.2796 +
81.2797 +ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
81.2798 + // Named template
81.2799 + if (typeof template == "string") {
81.2800 + templateDocument = templateDocument || document;
81.2801 + var elem = templateDocument.getElementById(template);
81.2802 + if (!elem)
81.2803 + throw new Error("Cannot find template with ID " + template);
81.2804 + return new ko.templateSources.domElement(elem);
81.2805 + } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
81.2806 + // Anonymous template
81.2807 + return new ko.templateSources.anonymousTemplate(template);
81.2808 + } else
81.2809 + throw new Error("Unknown template type: " + template);
81.2810 +};
81.2811 +
81.2812 +ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
81.2813 + var templateSource = this['makeTemplateSource'](template, templateDocument);
81.2814 + return this['renderTemplateSource'](templateSource, bindingContext, options);
81.2815 +};
81.2816 +
81.2817 +ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
81.2818 + // Skip rewriting if requested
81.2819 + if (this['allowTemplateRewriting'] === false)
81.2820 + return true;
81.2821 + return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
81.2822 +};
81.2823 +
81.2824 +ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
81.2825 + var templateSource = this['makeTemplateSource'](template, templateDocument);
81.2826 + var rewritten = rewriterCallback(templateSource['text']());
81.2827 + templateSource['text'](rewritten);
81.2828 + templateSource['data']("isRewritten", true);
81.2829 +};
81.2830 +
81.2831 +ko.exportSymbol('templateEngine', ko.templateEngine);
81.2832 +
81.2833 +ko.templateRewriting = (function () {
81.2834 + var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
81.2835 + var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
81.2836 +
81.2837 + function validateDataBindValuesForRewriting(keyValueArray) {
81.2838 + var allValidators = ko.expressionRewriting.bindingRewriteValidators;
81.2839 + for (var i = 0; i < keyValueArray.length; i++) {
81.2840 + var key = keyValueArray[i]['key'];
81.2841 + if (allValidators.hasOwnProperty(key)) {
81.2842 + var validator = allValidators[key];
81.2843 +
81.2844 + if (typeof validator === "function") {
81.2845 + var possibleErrorMessage = validator(keyValueArray[i]['value']);
81.2846 + if (possibleErrorMessage)
81.2847 + throw new Error(possibleErrorMessage);
81.2848 + } else if (!validator) {
81.2849 + throw new Error("This template engine does not support the '" + key + "' binding within its templates");
81.2850 + }
81.2851 + }
81.2852 + }
81.2853 + }
81.2854 +
81.2855 + function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
81.2856 + var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
81.2857 + validateDataBindValuesForRewriting(dataBindKeyValueArray);
81.2858 + var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
81.2859 +
81.2860 + // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
81.2861 + // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
81.2862 + // extra indirection.
81.2863 + var applyBindingsToNextSiblingScript =
81.2864 + "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
81.2865 + return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
81.2866 + }
81.2867 +
81.2868 + return {
81.2869 + ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
81.2870 + if (!templateEngine['isTemplateRewritten'](template, templateDocument))
81.2871 + templateEngine['rewriteTemplate'](template, function (htmlString) {
81.2872 + return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
81.2873 + }, templateDocument);
81.2874 + },
81.2875 +
81.2876 + memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
81.2877 + return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
81.2878 + return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
81.2879 + }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
81.2880 + return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
81.2881 + });
81.2882 + },
81.2883 +
81.2884 + applyMemoizedBindingsToNextSibling: function (bindings) {
81.2885 + return ko.memoization.memoize(function (domNode, bindingContext) {
81.2886 + if (domNode.nextSibling)
81.2887 + ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
81.2888 + });
81.2889 + }
81.2890 + }
81.2891 +})();
81.2892 +
81.2893 +
81.2894 +// Exported only because it has to be referenced by string lookup from within rewritten template
81.2895 +ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
81.2896 +(function() {
81.2897 + // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
81.2898 + // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
81.2899 + //
81.2900 + // Two are provided by default:
81.2901 + // 1. ko.templateSources.domElement - reads/writes the text content of an arbitrary DOM element
81.2902 + // 2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
81.2903 + // without reading/writing the actual element text content, since it will be overwritten
81.2904 + // with the rendered template output.
81.2905 + // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
81.2906 + // Template sources need to have the following functions:
81.2907 + // text() - returns the template text from your storage location
81.2908 + // text(value) - writes the supplied template text to your storage location
81.2909 + // data(key) - reads values stored using data(key, value) - see below
81.2910 + // data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
81.2911 + //
81.2912 + // Optionally, template sources can also have the following functions:
81.2913 + // nodes() - returns a DOM element containing the nodes of this template, where available
81.2914 + // nodes(value) - writes the given DOM element to your storage location
81.2915 + // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
81.2916 + // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
81.2917 + //
81.2918 + // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
81.2919 + // using and overriding "makeTemplateSource" to return an instance of your custom template source.
81.2920 +
81.2921 + ko.templateSources = {};
81.2922 +
81.2923 + // ---- ko.templateSources.domElement -----
81.2924 +
81.2925 + ko.templateSources.domElement = function(element) {
81.2926 + this.domElement = element;
81.2927 + }
81.2928 +
81.2929 + ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
81.2930 + var tagNameLower = ko.utils.tagNameLower(this.domElement),
81.2931 + elemContentsProperty = tagNameLower === "script" ? "text"
81.2932 + : tagNameLower === "textarea" ? "value"
81.2933 + : "innerHTML";
81.2934 +
81.2935 + if (arguments.length == 0) {
81.2936 + return this.domElement[elemContentsProperty];
81.2937 + } else {
81.2938 + var valueToWrite = arguments[0];
81.2939 + if (elemContentsProperty === "innerHTML")
81.2940 + ko.utils.setHtml(this.domElement, valueToWrite);
81.2941 + else
81.2942 + this.domElement[elemContentsProperty] = valueToWrite;
81.2943 + }
81.2944 + };
81.2945 +
81.2946 + ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
81.2947 + if (arguments.length === 1) {
81.2948 + return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
81.2949 + } else {
81.2950 + ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
81.2951 + }
81.2952 + };
81.2953 +
81.2954 + // ---- ko.templateSources.anonymousTemplate -----
81.2955 + // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
81.2956 + // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
81.2957 + // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
81.2958 +
81.2959 + var anonymousTemplatesDomDataKey = "__ko_anon_template__";
81.2960 + ko.templateSources.anonymousTemplate = function(element) {
81.2961 + this.domElement = element;
81.2962 + }
81.2963 + ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
81.2964 + ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
81.2965 + if (arguments.length == 0) {
81.2966 + var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
81.2967 + if (templateData.textData === undefined && templateData.containerData)
81.2968 + templateData.textData = templateData.containerData.innerHTML;
81.2969 + return templateData.textData;
81.2970 + } else {
81.2971 + var valueToWrite = arguments[0];
81.2972 + ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
81.2973 + }
81.2974 + };
81.2975 + ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
81.2976 + if (arguments.length == 0) {
81.2977 + var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
81.2978 + return templateData.containerData;
81.2979 + } else {
81.2980 + var valueToWrite = arguments[0];
81.2981 + ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
81.2982 + }
81.2983 + };
81.2984 +
81.2985 + ko.exportSymbol('templateSources', ko.templateSources);
81.2986 + ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
81.2987 + ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
81.2988 +})();
81.2989 +(function () {
81.2990 + var _templateEngine;
81.2991 + ko.setTemplateEngine = function (templateEngine) {
81.2992 + if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
81.2993 + throw new Error("templateEngine must inherit from ko.templateEngine");
81.2994 + _templateEngine = templateEngine;
81.2995 + }
81.2996 +
81.2997 + function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
81.2998 + var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
81.2999 + while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
81.3000 + nextInQueue = ko.virtualElements.nextSibling(node);
81.3001 + if (node.nodeType === 1 || node.nodeType === 8)
81.3002 + action(node);
81.3003 + }
81.3004 + }
81.3005 +
81.3006 + function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
81.3007 + // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
81.3008 + // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
81.3009 + // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
81.3010 + // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
81.3011 + // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
81.3012 +
81.3013 + if (continuousNodeArray.length) {
81.3014 + var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
81.3015 +
81.3016 + // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
81.3017 + // whereas a regular applyBindings won't introduce new memoized nodes
81.3018 + invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
81.3019 + ko.applyBindings(bindingContext, node);
81.3020 + });
81.3021 + invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
81.3022 + ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
81.3023 + });
81.3024 + }
81.3025 + }
81.3026 +
81.3027 + function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
81.3028 + return nodeOrNodeArray.nodeType ? nodeOrNodeArray
81.3029 + : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
81.3030 + : null;
81.3031 + }
81.3032 +
81.3033 + function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
81.3034 + options = options || {};
81.3035 + var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
81.3036 + var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
81.3037 + var templateEngineToUse = (options['templateEngine'] || _templateEngine);
81.3038 + ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
81.3039 + var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
81.3040 +
81.3041 + // Loosely check result is an array of DOM nodes
81.3042 + if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
81.3043 + throw new Error("Template engine must return an array of DOM nodes");
81.3044 +
81.3045 + var haveAddedNodesToParent = false;
81.3046 + switch (renderMode) {
81.3047 + case "replaceChildren":
81.3048 + ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
81.3049 + haveAddedNodesToParent = true;
81.3050 + break;
81.3051 + case "replaceNode":
81.3052 + ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
81.3053 + haveAddedNodesToParent = true;
81.3054 + break;
81.3055 + case "ignoreTargetNode": break;
81.3056 + default:
81.3057 + throw new Error("Unknown renderMode: " + renderMode);
81.3058 + }
81.3059 +
81.3060 + if (haveAddedNodesToParent) {
81.3061 + activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
81.3062 + if (options['afterRender'])
81.3063 + ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
81.3064 + }
81.3065 +
81.3066 + return renderedNodesArray;
81.3067 + }
81.3068 +
81.3069 + ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
81.3070 + options = options || {};
81.3071 + if ((options['templateEngine'] || _templateEngine) == undefined)
81.3072 + throw new Error("Set a template engine before calling renderTemplate");
81.3073 + renderMode = renderMode || "replaceChildren";
81.3074 +
81.3075 + if (targetNodeOrNodeArray) {
81.3076 + var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
81.3077 +
81.3078 + var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
81.3079 + var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
81.3080 +
81.3081 + return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
81.3082 + function () {
81.3083 + // Ensure we've got a proper binding context to work with
81.3084 + var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
81.3085 + ? dataOrBindingContext
81.3086 + : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
81.3087 +
81.3088 + // Support selecting template as a function of the data being rendered
81.3089 + var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
81.3090 +
81.3091 + var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
81.3092 + if (renderMode == "replaceNode") {
81.3093 + targetNodeOrNodeArray = renderedNodesArray;
81.3094 + firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
81.3095 + }
81.3096 + },
81.3097 + null,
81.3098 + { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
81.3099 + );
81.3100 + } else {
81.3101 + // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
81.3102 + return ko.memoization.memoize(function (domNode) {
81.3103 + ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
81.3104 + });
81.3105 + }
81.3106 + };
81.3107 +
81.3108 + ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
81.3109 + // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
81.3110 + // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
81.3111 + var arrayItemContext;
81.3112 +
81.3113 + // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
81.3114 + var executeTemplateForArrayItem = function (arrayValue, index) {
81.3115 + // Support selecting template as a function of the data being rendered
81.3116 + arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
81.3117 + arrayItemContext['$index'] = index;
81.3118 + var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
81.3119 + return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
81.3120 + }
81.3121 +
81.3122 + // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
81.3123 + var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
81.3124 + activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
81.3125 + if (options['afterRender'])
81.3126 + options['afterRender'](addedNodesArray, arrayValue);
81.3127 + };
81.3128 +
81.3129 + return ko.dependentObservable(function () {
81.3130 + var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
81.3131 + if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
81.3132 + unwrappedArray = [unwrappedArray];
81.3133 +
81.3134 + // Filter out any entries marked as destroyed
81.3135 + var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
81.3136 + return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
81.3137 + });
81.3138 +
81.3139 + // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
81.3140 + // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
81.3141 + ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
81.3142 +
81.3143 + }, null, { disposeWhenNodeIsRemoved: targetNode });
81.3144 + };
81.3145 +
81.3146 + var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
81.3147 + function disposeOldComputedAndStoreNewOne(element, newComputed) {
81.3148 + var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
81.3149 + if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
81.3150 + oldComputed.dispose();
81.3151 + ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
81.3152 + }
81.3153 +
81.3154 + ko.bindingHandlers['template'] = {
81.3155 + 'init': function(element, valueAccessor) {
81.3156 + // Support anonymous templates
81.3157 + var bindingValue = ko.utils.unwrapObservable(valueAccessor());
81.3158 + if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
81.3159 + // It's an anonymous template - store the element contents, then clear the element
81.3160 + var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
81.3161 + container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
81.3162 + new ko.templateSources.anonymousTemplate(element)['nodes'](container);
81.3163 + }
81.3164 + return { 'controlsDescendantBindings': true };
81.3165 + },
81.3166 + 'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
81.3167 + var templateName = ko.utils.unwrapObservable(valueAccessor()),
81.3168 + options = {},
81.3169 + shouldDisplay = true,
81.3170 + dataValue,
81.3171 + templateComputed = null;
81.3172 +
81.3173 + if (typeof templateName != "string") {
81.3174 + options = templateName;
81.3175 + templateName = options['name'];
81.3176 +
81.3177 + // Support "if"/"ifnot" conditions
81.3178 + if ('if' in options)
81.3179 + shouldDisplay = ko.utils.unwrapObservable(options['if']);
81.3180 + if (shouldDisplay && 'ifnot' in options)
81.3181 + shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
81.3182 +
81.3183 + dataValue = ko.utils.unwrapObservable(options['data']);
81.3184 + }
81.3185 +
81.3186 + if ('foreach' in options) {
81.3187 + // Render once for each data point (treating data set as empty if shouldDisplay==false)
81.3188 + var dataArray = (shouldDisplay && options['foreach']) || [];
81.3189 + templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
81.3190 + } else if (!shouldDisplay) {
81.3191 + ko.virtualElements.emptyNode(element);
81.3192 + } else {
81.3193 + // Render once for this single data point (or use the viewModel if no data was provided)
81.3194 + var innerBindingContext = ('data' in options) ?
81.3195 + bindingContext['createChildContext'](dataValue, options['as']) : // Given an explitit 'data' value, we create a child binding context for it
81.3196 + bindingContext; // Given no explicit 'data' value, we retain the same binding context
81.3197 + templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
81.3198 + }
81.3199 +
81.3200 + // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
81.3201 + disposeOldComputedAndStoreNewOne(element, templateComputed);
81.3202 + }
81.3203 + };
81.3204 +
81.3205 + // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
81.3206 + ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
81.3207 + var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
81.3208 +
81.3209 + if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
81.3210 + return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
81.3211 +
81.3212 + if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
81.3213 + return null; // Named templates can be rewritten, so return "no error"
81.3214 + return "This template engine does not support anonymous templates nested within its templates";
81.3215 + };
81.3216 +
81.3217 + ko.virtualElements.allowedBindings['template'] = true;
81.3218 +})();
81.3219 +
81.3220 +ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
81.3221 +ko.exportSymbol('renderTemplate', ko.renderTemplate);
81.3222 +
81.3223 +ko.utils.compareArrays = (function () {
81.3224 + var statusNotInOld = 'added', statusNotInNew = 'deleted';
81.3225 +
81.3226 + // Simple calculation based on Levenshtein distance.
81.3227 + function compareArrays(oldArray, newArray, dontLimitMoves) {
81.3228 + oldArray = oldArray || [];
81.3229 + newArray = newArray || [];
81.3230 +
81.3231 + if (oldArray.length <= newArray.length)
81.3232 + return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
81.3233 + else
81.3234 + return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
81.3235 + }
81.3236 +
81.3237 + function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
81.3238 + var myMin = Math.min,
81.3239 + myMax = Math.max,
81.3240 + editDistanceMatrix = [],
81.3241 + smlIndex, smlIndexMax = smlArray.length,
81.3242 + bigIndex, bigIndexMax = bigArray.length,
81.3243 + compareRange = (bigIndexMax - smlIndexMax) || 1,
81.3244 + maxDistance = smlIndexMax + bigIndexMax + 1,
81.3245 + thisRow, lastRow,
81.3246 + bigIndexMaxForRow, bigIndexMinForRow;
81.3247 +
81.3248 + for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
81.3249 + lastRow = thisRow;
81.3250 + editDistanceMatrix.push(thisRow = []);
81.3251 + bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
81.3252 + bigIndexMinForRow = myMax(0, smlIndex - 1);
81.3253 + for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
81.3254 + if (!bigIndex)
81.3255 + thisRow[bigIndex] = smlIndex + 1;
81.3256 + else if (!smlIndex) // Top row - transform empty array into new array via additions
81.3257 + thisRow[bigIndex] = bigIndex + 1;
81.3258 + else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
81.3259 + thisRow[bigIndex] = lastRow[bigIndex - 1]; // copy value (no edit)
81.3260 + else {
81.3261 + var northDistance = lastRow[bigIndex] || maxDistance; // not in big (deletion)
81.3262 + var westDistance = thisRow[bigIndex - 1] || maxDistance; // not in small (addition)
81.3263 + thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
81.3264 + }
81.3265 + }
81.3266 + }
81.3267 +
81.3268 + var editScript = [], meMinusOne, notInSml = [], notInBig = [];
81.3269 + for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
81.3270 + meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
81.3271 + if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
81.3272 + notInSml.push(editScript[editScript.length] = { // added
81.3273 + 'status': statusNotInSml,
81.3274 + 'value': bigArray[--bigIndex],
81.3275 + 'index': bigIndex });
81.3276 + } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
81.3277 + notInBig.push(editScript[editScript.length] = { // deleted
81.3278 + 'status': statusNotInBig,
81.3279 + 'value': smlArray[--smlIndex],
81.3280 + 'index': smlIndex });
81.3281 + } else {
81.3282 + editScript.push({
81.3283 + 'status': "retained",
81.3284 + 'value': bigArray[--bigIndex] });
81.3285 + --smlIndex;
81.3286 + }
81.3287 + }
81.3288 +
81.3289 + if (notInSml.length && notInBig.length) {
81.3290 + // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
81.3291 + // smlIndexMax keeps the time complexity of this algorithm linear.
81.3292 + var limitFailedCompares = smlIndexMax * 10, failedCompares,
81.3293 + a, d, notInSmlItem, notInBigItem;
81.3294 + // Go through the items that have been added and deleted and try to find matches between them.
81.3295 + for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
81.3296 + for (d = 0; notInBigItem = notInBig[d]; d++) {
81.3297 + if (notInSmlItem['value'] === notInBigItem['value']) {
81.3298 + notInSmlItem['moved'] = notInBigItem['index'];
81.3299 + notInBigItem['moved'] = notInSmlItem['index'];
81.3300 + notInBig.splice(d,1); // This item is marked as moved; so remove it from notInBig list
81.3301 + failedCompares = d = 0; // Reset failed compares count because we're checking for consecutive failures
81.3302 + break;
81.3303 + }
81.3304 + }
81.3305 + failedCompares += d;
81.3306 + }
81.3307 + }
81.3308 + return editScript.reverse();
81.3309 + }
81.3310 +
81.3311 + return compareArrays;
81.3312 +})();
81.3313 +
81.3314 +ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
81.3315 +
81.3316 +(function () {
81.3317 + // Objective:
81.3318 + // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
81.3319 + // map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
81.3320 + // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
81.3321 + // so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
81.3322 + // previously mapped - retain those nodes, and just insert/delete other ones
81.3323 +
81.3324 + // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
81.3325 + // You can use this, for example, to activate bindings on those nodes.
81.3326 +
81.3327 + function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
81.3328 + // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
81.3329 + // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
81.3330 + // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
81.3331 + // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
81.3332 + // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
81.3333 + //
81.3334 + // Rules:
81.3335 + // [A] Any leading nodes that aren't in the document any more should be ignored
81.3336 + // These most likely correspond to memoization nodes that were already removed during binding
81.3337 + // See https://github.com/SteveSanderson/knockout/pull/440
81.3338 + // [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
81.3339 + // have already been removed, and include any nodes that have been inserted among the previous collection
81.3340 +
81.3341 + // Rule [A]
81.3342 + while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
81.3343 + contiguousNodeArray.splice(0, 1);
81.3344 +
81.3345 + // Rule [B]
81.3346 + if (contiguousNodeArray.length > 1) {
81.3347 + // Build up the actual new contiguous node set
81.3348 + var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
81.3349 + while (current !== last) {
81.3350 + current = current.nextSibling;
81.3351 + if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
81.3352 + return;
81.3353 + newContiguousSet.push(current);
81.3354 + }
81.3355 +
81.3356 + // ... then mutate the input array to match this.
81.3357 + // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
81.3358 + Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
81.3359 + }
81.3360 + return contiguousNodeArray;
81.3361 + }
81.3362 +
81.3363 + function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
81.3364 + // Map this array value inside a dependentObservable so we re-map when any dependency changes
81.3365 + var mappedNodes = [];
81.3366 + var dependentObservable = ko.dependentObservable(function() {
81.3367 + var newMappedNodes = mapping(valueToMap, index) || [];
81.3368 +
81.3369 + // On subsequent evaluations, just replace the previously-inserted DOM nodes
81.3370 + if (mappedNodes.length > 0) {
81.3371 + ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
81.3372 + if (callbackAfterAddingNodes)
81.3373 + ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
81.3374 + }
81.3375 +
81.3376 + // Replace the contents of the mappedNodes array, thereby updating the record
81.3377 + // of which nodes would be deleted if valueToMap was itself later removed
81.3378 + mappedNodes.splice(0, mappedNodes.length);
81.3379 + ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
81.3380 + }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
81.3381 + return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
81.3382 + }
81.3383 +
81.3384 + var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
81.3385 +
81.3386 + ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
81.3387 + // Compare the provided array against the previous one
81.3388 + array = array || [];
81.3389 + options = options || {};
81.3390 + var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
81.3391 + var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
81.3392 + var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
81.3393 + var editScript = ko.utils.compareArrays(lastArray, array);
81.3394 +
81.3395 + // Build the new mapping result
81.3396 + var newMappingResult = [];
81.3397 + var lastMappingResultIndex = 0;
81.3398 + var newMappingResultIndex = 0;
81.3399 +
81.3400 + var nodesToDelete = [];
81.3401 + var itemsToProcess = [];
81.3402 + var itemsForBeforeRemoveCallbacks = [];
81.3403 + var itemsForMoveCallbacks = [];
81.3404 + var itemsForAfterAddCallbacks = [];
81.3405 + var mapData;
81.3406 +
81.3407 + function itemMovedOrRetained(editScriptIndex, oldPosition) {
81.3408 + mapData = lastMappingResult[oldPosition];
81.3409 + if (newMappingResultIndex !== oldPosition)
81.3410 + itemsForMoveCallbacks[editScriptIndex] = mapData;
81.3411 + // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
81.3412 + mapData.indexObservable(newMappingResultIndex++);
81.3413 + fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
81.3414 + newMappingResult.push(mapData);
81.3415 + itemsToProcess.push(mapData);
81.3416 + }
81.3417 +
81.3418 + function callCallback(callback, items) {
81.3419 + if (callback) {
81.3420 + for (var i = 0, n = items.length; i < n; i++) {
81.3421 + if (items[i]) {
81.3422 + ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
81.3423 + callback(node, i, items[i].arrayEntry);
81.3424 + });
81.3425 + }
81.3426 + }
81.3427 + }
81.3428 + }
81.3429 +
81.3430 + for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
81.3431 + movedIndex = editScriptItem['moved'];
81.3432 + switch (editScriptItem['status']) {
81.3433 + case "deleted":
81.3434 + if (movedIndex === undefined) {
81.3435 + mapData = lastMappingResult[lastMappingResultIndex];
81.3436 +
81.3437 + // Stop tracking changes to the mapping for these nodes
81.3438 + if (mapData.dependentObservable)
81.3439 + mapData.dependentObservable.dispose();
81.3440 +
81.3441 + // Queue these nodes for later removal
81.3442 + nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
81.3443 + if (options['beforeRemove']) {
81.3444 + itemsForBeforeRemoveCallbacks[i] = mapData;
81.3445 + itemsToProcess.push(mapData);
81.3446 + }
81.3447 + }
81.3448 + lastMappingResultIndex++;
81.3449 + break;
81.3450 +
81.3451 + case "retained":
81.3452 + itemMovedOrRetained(i, lastMappingResultIndex++);
81.3453 + break;
81.3454 +
81.3455 + case "added":
81.3456 + if (movedIndex !== undefined) {
81.3457 + itemMovedOrRetained(i, movedIndex);
81.3458 + } else {
81.3459 + mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
81.3460 + newMappingResult.push(mapData);
81.3461 + itemsToProcess.push(mapData);
81.3462 + if (!isFirstExecution)
81.3463 + itemsForAfterAddCallbacks[i] = mapData;
81.3464 + }
81.3465 + break;
81.3466 + }
81.3467 + }
81.3468 +
81.3469 + // Call beforeMove first before any changes have been made to the DOM
81.3470 + callCallback(options['beforeMove'], itemsForMoveCallbacks);
81.3471 +
81.3472 + // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
81.3473 + ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
81.3474 +
81.3475 + // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
81.3476 + for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
81.3477 + // Get nodes for newly added items
81.3478 + if (!mapData.mappedNodes)
81.3479 + ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
81.3480 +
81.3481 + // Put nodes in the right place if they aren't there already
81.3482 + for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
81.3483 + if (node !== nextNode)
81.3484 + ko.virtualElements.insertAfter(domNode, node, lastNode);
81.3485 + }
81.3486 +
81.3487 + // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
81.3488 + if (!mapData.initialized && callbackAfterAddingNodes) {
81.3489 + callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
81.3490 + mapData.initialized = true;
81.3491 + }
81.3492 + }
81.3493 +
81.3494 + // If there's a beforeRemove callback, call it after reordering.
81.3495 + // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
81.3496 + // some sort of animation, which is why we first reorder the nodes that will be removed. If the
81.3497 + // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
81.3498 + // Perhaps we'll make that change in the future if this scenario becomes more common.
81.3499 + callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
81.3500 +
81.3501 + // Finally call afterMove and afterAdd callbacks
81.3502 + callCallback(options['afterMove'], itemsForMoveCallbacks);
81.3503 + callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
81.3504 +
81.3505 + // Store a copy of the array items we just considered so we can difference it next time
81.3506 + ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
81.3507 + }
81.3508 +})();
81.3509 +
81.3510 +ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
81.3511 +ko.nativeTemplateEngine = function () {
81.3512 + this['allowTemplateRewriting'] = false;
81.3513 +}
81.3514 +
81.3515 +ko.nativeTemplateEngine.prototype = new ko.templateEngine();
81.3516 +ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
81.3517 + var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
81.3518 + templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
81.3519 + templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
81.3520 +
81.3521 + if (templateNodes) {
81.3522 + return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
81.3523 + } else {
81.3524 + var templateText = templateSource['text']();
81.3525 + return ko.utils.parseHtmlFragment(templateText);
81.3526 + }
81.3527 +};
81.3528 +
81.3529 +ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
81.3530 +ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
81.3531 +
81.3532 +ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
81.3533 +(function() {
81.3534 + ko.jqueryTmplTemplateEngine = function () {
81.3535 + // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
81.3536 + // doesn't expose a version number, so we have to infer it.
81.3537 + // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
81.3538 + // which KO internally refers to as version "2", so older versions are no longer detected.
81.3539 + var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
81.3540 + if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
81.3541 + return 0;
81.3542 + // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
81.3543 + try {
81.3544 + if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
81.3545 + // Since 1.0.0pre, custom tags should append markup to an array called "__"
81.3546 + return 2; // Final version of jquery.tmpl
81.3547 + }
81.3548 + } catch(ex) { /* Apparently not the version we were looking for */ }
81.3549 +
81.3550 + return 1; // Any older version that we don't support
81.3551 + })();
81.3552 +
81.3553 + function ensureHasReferencedJQueryTemplates() {
81.3554 + if (jQueryTmplVersion < 2)
81.3555 + throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
81.3556 + }
81.3557 +
81.3558 + function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
81.3559 + return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
81.3560 + }
81.3561 +
81.3562 + this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
81.3563 + options = options || {};
81.3564 + ensureHasReferencedJQueryTemplates();
81.3565 +
81.3566 + // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
81.3567 + var precompiled = templateSource['data']('precompiled');
81.3568 + if (!precompiled) {
81.3569 + var templateText = templateSource['text']() || "";
81.3570 + // Wrap in "with($whatever.koBindingContext) { ... }"
81.3571 + templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
81.3572 +
81.3573 + precompiled = jQuery['template'](null, templateText);
81.3574 + templateSource['data']('precompiled', precompiled);
81.3575 + }
81.3576 +
81.3577 + var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
81.3578 + var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
81.3579 +
81.3580 + var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
81.3581 + resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
81.3582 +
81.3583 + jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
81.3584 + return resultNodes;
81.3585 + };
81.3586 +
81.3587 + this['createJavaScriptEvaluatorBlock'] = function(script) {
81.3588 + return "{{ko_code ((function() { return " + script + " })()) }}";
81.3589 + };
81.3590 +
81.3591 + this['addTemplate'] = function(templateName, templateMarkup) {
81.3592 + document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
81.3593 + };
81.3594 +
81.3595 + if (jQueryTmplVersion > 0) {
81.3596 + jQuery['tmpl']['tag']['ko_code'] = {
81.3597 + open: "__.push($1 || '');"
81.3598 + };
81.3599 + jQuery['tmpl']['tag']['ko_with'] = {
81.3600 + open: "with($1) {",
81.3601 + close: "} "
81.3602 + };
81.3603 + }
81.3604 + };
81.3605 +
81.3606 + ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
81.3607 +
81.3608 + // Use this one by default *only if jquery.tmpl is referenced*
81.3609 + var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
81.3610 + if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
81.3611 + ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
81.3612 +
81.3613 + ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
81.3614 +})();
81.3615 +});
81.3616 +})(window,document,navigator,window["jQuery"]);
81.3617 +})();
81.3618 \ No newline at end of file
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrKnockoutTest.java Mon Oct 07 14:20:58 2013 +0200
82.3 @@ -0,0 +1,120 @@
82.4 +/**
82.5 + * Back 2 Browser Bytecode Translator
82.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
82.7 + *
82.8 + * This program is free software: you can redistribute it and/or modify
82.9 + * it under the terms of the GNU General Public License as published by
82.10 + * the Free Software Foundation, version 2 of the License.
82.11 + *
82.12 + * This program is distributed in the hope that it will be useful,
82.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
82.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82.15 + * GNU General Public License for more details.
82.16 + *
82.17 + * You should have received a copy of the GNU General Public License
82.18 + * along with this program. Look for COPYING file in the top folder.
82.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
82.20 + */
82.21 +package org.apidesign.bck2brwsr.ko2brwsr;
82.22 +
82.23 +import java.io.IOException;
82.24 +import java.net.URI;
82.25 +import java.net.URISyntaxException;
82.26 +import java.net.URL;
82.27 +import java.util.Map;
82.28 +import net.java.html.BrwsrCtx;
82.29 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
82.30 +import org.apidesign.bck2brwsr.vmtest.VMTest;
82.31 +import org.apidesign.html.context.spi.Contexts;
82.32 +import org.apidesign.html.json.spi.Technology;
82.33 +import org.apidesign.html.json.spi.Transfer;
82.34 +import org.apidesign.html.json.spi.WSTransfer;
82.35 +import org.apidesign.html.json.tck.KOTest;
82.36 +import org.apidesign.html.json.tck.KnockoutTCK;
82.37 +import org.openide.util.lookup.ServiceProvider;
82.38 +import org.testng.annotations.Factory;
82.39 +
82.40 +/**
82.41 + *
82.42 + * @author Jaroslav Tulach <jtulach@netbeans.org>
82.43 + */
82.44 +@ServiceProvider(service = KnockoutTCK.class)
82.45 +public final class Bck2BrwsrKnockoutTest extends KnockoutTCK {
82.46 + @Factory public static Object[] create() {
82.47 + return VMTest.newTests().
82.48 + withClasses(testClasses()).
82.49 + withLaunchers("bck2brwsr").
82.50 + withTestAnnotation(KOTest.class).
82.51 + build();
82.52 + }
82.53 +
82.54 + @Override
82.55 + public BrwsrCtx createContext() {
82.56 + return Contexts.newBuilder().
82.57 + register(Transfer.class, BrwsrCtxImpl.DEFAULT, 9).
82.58 + register(WSTransfer.class, BrwsrCtxImpl.DEFAULT, 9).
82.59 + register(Technology.class, BrwsrCtxImpl.DEFAULT, 9).build();
82.60 + }
82.61 +
82.62 +
82.63 +
82.64 + @Override
82.65 + public Object createJSON(Map<String, Object> values) {
82.66 + Object json = createJSON();
82.67 +
82.68 + for (Map.Entry<String, Object> entry : values.entrySet()) {
82.69 + putValue(json, entry.getKey(), entry.getValue());
82.70 + }
82.71 + return json;
82.72 + }
82.73 +
82.74 + @JavaScriptBody(args = {}, body = "return new Object();")
82.75 + private static native Object createJSON();
82.76 +
82.77 + @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
82.78 + private static native void putValue(Object json, String key, Object value);
82.79 +
82.80 + @Override
82.81 + public Object executeScript(String script, Object[] arguments) {
82.82 + return execScript(script, arguments);
82.83 + }
82.84 +
82.85 + @JavaScriptBody(args = { "s", "args" }, body =
82.86 + "var f = new Function(s); return f.apply(null, args);"
82.87 + )
82.88 + private static native Object execScript(String s, Object[] arguments);
82.89 +
82.90 + @JavaScriptBody(args = { }, body =
82.91 + "var h;"
82.92 + + "if (!!window && !!window.location && !!window.location.href)\n"
82.93 + + " h = window.location.href;\n"
82.94 + + "else "
82.95 + + " h = null;"
82.96 + + "return h;\n"
82.97 + )
82.98 + private static native String findBaseURL();
82.99 +
82.100 + @Override
82.101 + public URI prepareURL(String content, String mimeType, String[] parameters) {
82.102 + try {
82.103 + final URL baseURL = new URL(findBaseURL());
82.104 + StringBuilder sb = new StringBuilder();
82.105 + sb.append("/dynamic?mimeType=").append(mimeType);
82.106 + for (int i = 0; i < parameters.length; i++) {
82.107 + sb.append("¶m" + i).append("=").append(parameters[i]);
82.108 + }
82.109 + String mangle = content.replace("\n", "%0a")
82.110 + .replace("\"", "\\\"").replace(" ", "%20");
82.111 + sb.append("&content=").append(mangle);
82.112 +
82.113 + URL query = new URL(baseURL, sb.toString());
82.114 + String uri = (String) query.getContent(new Class[] { String.class });
82.115 + URI connectTo = new URI(uri.trim());
82.116 + return connectTo;
82.117 + } catch (IOException ex) {
82.118 + throw new IllegalStateException(ex);
82.119 + } catch (URISyntaxException ex) {
82.120 + throw new IllegalStateException(ex);
82.121 + }
82.122 + }
82.123 +}
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83.2 +++ b/ko/fx/pom.xml Mon Oct 07 14:20:58 2013 +0200
83.3 @@ -0,0 +1,119 @@
83.4 +<?xml version="1.0"?>
83.5 +<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/xsd/maven-4.0.0.xsd">
83.6 + <modelVersion>4.0.0</modelVersion>
83.7 + <parent>
83.8 + <groupId>org.apidesign.bck2brwsr</groupId>
83.9 + <artifactId>ko</artifactId>
83.10 + <version>0.9-SNAPSHOT</version>
83.11 + </parent>
83.12 + <groupId>org.apidesign.bck2brwsr</groupId>
83.13 + <artifactId>ko-fx</artifactId>
83.14 + <version>0.9-SNAPSHOT</version>
83.15 + <name>Knockout.fx in Brwsr</name>
83.16 + <url>http://maven.apache.org</url>
83.17 + <properties>
83.18 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
83.19 + </properties>
83.20 + <build>
83.21 + <plugins>
83.22 + <plugin>
83.23 + <groupId>org.apache.maven.plugins</groupId>
83.24 + <artifactId>maven-javadoc-plugin</artifactId>
83.25 + <configuration>
83.26 + <skip>false</skip>
83.27 + </configuration>
83.28 + </plugin>
83.29 + </plugins>
83.30 + </build>
83.31 + <dependencies>
83.32 + <dependency>
83.33 + <groupId>com.oracle</groupId>
83.34 + <artifactId>javafx</artifactId>
83.35 + <version>2.2</version>
83.36 + <scope>system</scope>
83.37 + <systemPath>${jfxrt.jar}</systemPath>
83.38 + </dependency>
83.39 + <dependency>
83.40 + <groupId>org.json</groupId>
83.41 + <artifactId>json</artifactId>
83.42 + <version>20090211</version>
83.43 + <type>jar</type>
83.44 + </dependency>
83.45 + <dependency>
83.46 + <groupId>org.apidesign.html</groupId>
83.47 + <artifactId>net.java.html.json</artifactId>
83.48 + <version>${net.java.html.version}</version>
83.49 + </dependency>
83.50 + <dependency>
83.51 + <groupId>org.testng</groupId>
83.52 + <artifactId>testng</artifactId>
83.53 + <scope>test</scope>
83.54 + </dependency>
83.55 + <dependency>
83.56 + <groupId>org.apidesign.html</groupId>
83.57 + <artifactId>net.java.html.json.tck</artifactId>
83.58 + <version>${net.java.html.version}</version>
83.59 + <scope>test</scope>
83.60 + </dependency>
83.61 + <dependency>
83.62 + <groupId>org.netbeans.api</groupId>
83.63 + <artifactId>org-openide-util</artifactId>
83.64 + <scope>provided</scope>
83.65 + </dependency>
83.66 + <dependency>
83.67 + <groupId>org.apidesign.bck2brwsr</groupId>
83.68 + <artifactId>launcher.fx</artifactId>
83.69 + <version>${project.version}</version>
83.70 + <scope>test</scope>
83.71 + </dependency>
83.72 + <dependency>
83.73 + <groupId>org.apidesign.html</groupId>
83.74 + <artifactId>net.java.html.boot</artifactId>
83.75 + <version>${net.java.html.version}</version>
83.76 + <type>jar</type>
83.77 + </dependency>
83.78 + <dependency>
83.79 + <groupId>org.apidesign.html</groupId>
83.80 + <artifactId>ko-fx</artifactId>
83.81 + <version>${net.java.html.version}</version>
83.82 + <type>jar</type>
83.83 + </dependency>
83.84 + <dependency>
83.85 + <groupId>org.apidesign.bck2brwsr</groupId>
83.86 + <artifactId>vmtest</artifactId>
83.87 + <version>${project.version}</version>
83.88 + <scope>test</scope>
83.89 + <type>jar</type>
83.90 + </dependency>
83.91 + <dependency>
83.92 + <groupId>org.apidesign.html</groupId>
83.93 + <artifactId>ko-ws-tyrus</artifactId>
83.94 + <version>${net.java.html.version}</version>
83.95 + <scope>test</scope>
83.96 + </dependency>
83.97 + </dependencies>
83.98 + <profiles>
83.99 + <profile>
83.100 + <id>jdk8</id>
83.101 + <activation>
83.102 + <file>
83.103 + <exists>${java.home}/lib/ext/jfxrt.jar</exists>
83.104 + </file>
83.105 + </activation>
83.106 + <properties>
83.107 + <jfxrt.jar>${java.home}/lib/ext/jfxrt.jar</jfxrt.jar>
83.108 + </properties>
83.109 + </profile>
83.110 + <profile>
83.111 + <id>jdk7</id>
83.112 + <activation>
83.113 + <file>
83.114 + <exists>${java.home}/lib/jfxrt.jar</exists>
83.115 + </file>
83.116 + </activation>
83.117 + <properties>
83.118 + <jfxrt.jar>${java.home}/lib/jfxrt.jar</jfxrt.jar>
83.119 + </properties>
83.120 + </profile>
83.121 + </profiles>
83.122 +</project>
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
84.2 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java Mon Oct 07 14:20:58 2013 +0200
84.3 @@ -0,0 +1,133 @@
84.4 +/**
84.5 + * Back 2 Browser Bytecode Translator
84.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
84.7 + *
84.8 + * This program is free software: you can redistribute it and/or modify
84.9 + * it under the terms of the GNU General Public License as published by
84.10 + * the Free Software Foundation, version 2 of the License.
84.11 + *
84.12 + * This program is distributed in the hope that it will be useful,
84.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
84.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84.15 + * GNU General Public License for more details.
84.16 + *
84.17 + * You should have received a copy of the GNU General Public License
84.18 + * along with this program. Look for COPYING file in the top folder.
84.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
84.20 + */
84.21 +package org.apidesign.bck2brwsr.kofx;
84.22 +
84.23 +import java.io.BufferedReader;
84.24 +import java.io.IOException;
84.25 +import java.io.InputStreamReader;
84.26 +import java.net.URI;
84.27 +import java.net.URISyntaxException;
84.28 +import java.net.URL;
84.29 +import java.net.URLConnection;
84.30 +import java.util.Map;
84.31 +import net.java.html.BrwsrCtx;
84.32 +import net.java.html.js.JavaScriptBody;
84.33 +import org.apidesign.bck2brwsr.vmtest.VMTest;
84.34 +import org.apidesign.html.boot.impl.FnUtils;
84.35 +import org.apidesign.html.context.spi.Contexts;
84.36 +import org.apidesign.html.json.spi.Technology;
84.37 +import org.apidesign.html.json.spi.Transfer;
84.38 +import org.apidesign.html.json.spi.WSTransfer;
84.39 +import org.apidesign.html.json.tck.KOTest;
84.40 +import org.apidesign.html.json.tck.KnockoutTCK;
84.41 +import org.apidesign.html.kofx.FXContext;
84.42 +import org.apidesign.html.wstyrus.TyrusContext;
84.43 +import org.json.JSONException;
84.44 +import org.json.JSONObject;
84.45 +import org.openide.util.lookup.ServiceProvider;
84.46 +import org.testng.annotations.Factory;
84.47 +
84.48 +/**
84.49 + *
84.50 + * @author Jaroslav Tulach <jtulach@netbeans.org>
84.51 + */
84.52 +@ServiceProvider(service = KnockoutTCK.class)
84.53 +public final class KnockoutFXTest extends KnockoutTCK {
84.54 + public KnockoutFXTest() {
84.55 + }
84.56 +
84.57 + @Factory public static Object[] compatibilityTests() {
84.58 + return VMTest.newTests().
84.59 + withClasses(testClasses()).
84.60 + withTestAnnotation(KOTest.class).
84.61 + withLaunchers("fxbrwsr").build();
84.62 + }
84.63 +
84.64 + @Override
84.65 + public BrwsrCtx createContext() {
84.66 + FXContext fx = new FXContext(FnUtils.currentPresenter());
84.67 + TyrusContext tc = new TyrusContext();
84.68 + Contexts.Builder b = Contexts.newBuilder().
84.69 + register(Technology.class, fx, 10).
84.70 + register(Transfer.class, fx, 10);
84.71 + try {
84.72 + Class.forName("java.util.function.Function");
84.73 + // prefer WebView's WebSockets on JDK8
84.74 + b.register(WSTransfer.class, fx, 10);
84.75 + } catch (ClassNotFoundException ex) {
84.76 + // ok, JDK7 needs tyrus
84.77 + b.register(WSTransfer.class, tc, 20);
84.78 + }
84.79 + return b.build();
84.80 + }
84.81 +
84.82 + @Override
84.83 + public Object createJSON(Map<String, Object> values) {
84.84 + JSONObject json = new JSONObject();
84.85 + for (Map.Entry<String, Object> entry : values.entrySet()) {
84.86 + try {
84.87 + json.put(entry.getKey(), entry.getValue());
84.88 + } catch (JSONException ex) {
84.89 + throw new IllegalStateException(ex);
84.90 + }
84.91 + }
84.92 + return json;
84.93 + }
84.94 +
84.95 + @Override
84.96 + @JavaScriptBody(args = { "s", "args" }, body = ""
84.97 + + "var f = new Function(s); "
84.98 + + "return f.apply(null, args);"
84.99 + )
84.100 + public native Object executeScript(String script, Object[] arguments);
84.101 +
84.102 + @JavaScriptBody(args = { }, body =
84.103 + "var h;"
84.104 + + "if (!!window && !!window.location && !!window.location.href)\n"
84.105 + + " h = window.location.href;\n"
84.106 + + "else "
84.107 + + " h = null;"
84.108 + + "return h;\n"
84.109 + )
84.110 + private static native String findBaseURL();
84.111 +
84.112 + @Override
84.113 + public URI prepareURL(String content, String mimeType, String[] parameters) {
84.114 + try {
84.115 + final URL baseURL = new URL(findBaseURL());
84.116 + StringBuilder sb = new StringBuilder();
84.117 + sb.append("/dynamic?mimeType=").append(mimeType);
84.118 + for (int i = 0; i < parameters.length; i++) {
84.119 + sb.append("¶m" + i).append("=").append(parameters[i]);
84.120 + }
84.121 + String mangle = content.replace("\n", "%0a")
84.122 + .replace("\"", "\\\"").replace(" ", "%20");
84.123 + sb.append("&content=").append(mangle);
84.124 +
84.125 + URL query = new URL(baseURL, sb.toString());
84.126 + URLConnection c = query.openConnection();
84.127 + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
84.128 + URI connectTo = new URI(br.readLine());
84.129 + return connectTo;
84.130 + } catch (IOException ex) {
84.131 + throw new IllegalStateException(ex);
84.132 + } catch (URISyntaxException ex) {
84.133 + throw new IllegalStateException(ex);
84.134 + }
84.135 + }
84.136 +}
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
85.2 +++ b/ko/pom.xml Mon Oct 07 14:20:58 2013 +0200
85.3 @@ -0,0 +1,20 @@
85.4 +<?xml version="1.0" encoding="UTF-8"?>
85.5 +<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/xsd/maven-4.0.0.xsd">
85.6 + <modelVersion>4.0.0</modelVersion>
85.7 + <groupId>org.apidesign.bck2brwsr</groupId>
85.8 + <artifactId>ko</artifactId>
85.9 + <version>0.9-SNAPSHOT</version>
85.10 + <packaging>pom</packaging>
85.11 + <name>Bck2Brwsr Knockout Support</name>
85.12 + <parent>
85.13 + <groupId>org.apidesign</groupId>
85.14 + <artifactId>bck2brwsr</artifactId>
85.15 + <version>0.9-SNAPSHOT</version>
85.16 + </parent>
85.17 + <modules>
85.18 + <module>archetype</module>
85.19 + <module>archetype-test</module>
85.20 + <module>bck2brwsr</module>
85.21 + <module>fx</module>
85.22 + </modules>
85.23 +</project>
86.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
86.2 +++ b/launcher/api/pom.xml Mon Oct 07 14:20:58 2013 +0200
86.3 @@ -0,0 +1,31 @@
86.4 +<?xml version="1.0"?>
86.5 +<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/xsd/maven-4.0.0.xsd">
86.6 + <modelVersion>4.0.0</modelVersion>
86.7 + <parent>
86.8 + <groupId>org.apidesign.bck2brwsr</groupId>
86.9 + <artifactId>launcher-pom</artifactId>
86.10 + <version>0.9-SNAPSHOT</version>
86.11 + </parent>
86.12 + <groupId>org.apidesign.bck2brwsr</groupId>
86.13 + <artifactId>launcher</artifactId>
86.14 + <version>0.9-SNAPSHOT</version>
86.15 + <name>Launcher API</name>
86.16 + <url>http://maven.apache.org</url>
86.17 + <properties>
86.18 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
86.19 + </properties>
86.20 + <build>
86.21 + <plugins>
86.22 + <plugin>
86.23 + <groupId>org.apache.maven.plugins</groupId>
86.24 + <artifactId>maven-javadoc-plugin</artifactId>
86.25 + <configuration>
86.26 + <subpackages>org.apidesign.bck2brwsr.launcher</subpackages>
86.27 + <skip>false</skip>
86.28 + </configuration>
86.29 + </plugin>
86.30 + </plugins>
86.31 + </build>
86.32 + <dependencies>
86.33 + </dependencies>
86.34 +</project>
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Mon Oct 07 14:20:58 2013 +0200
87.3 @@ -0,0 +1,115 @@
87.4 +/**
87.5 + * Back 2 Browser Bytecode Translator
87.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
87.7 + *
87.8 + * This program is free software: you can redistribute it and/or modify
87.9 + * it under the terms of the GNU General Public License as published by
87.10 + * the Free Software Foundation, version 2 of the License.
87.11 + *
87.12 + * This program is distributed in the hope that it will be useful,
87.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
87.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
87.15 + * GNU General Public License for more details.
87.16 + *
87.17 + * You should have received a copy of the GNU General Public License
87.18 + * along with this program. Look for COPYING file in the top folder.
87.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
87.20 + */
87.21 +package org.apidesign.bck2brwsr.launcher;
87.22 +
87.23 +import java.io.IOException;
87.24 +import java.io.InputStream;
87.25 +import java.net.URI;
87.26 +import java.util.ArrayList;
87.27 +import java.util.List;
87.28 +import java.util.concurrent.CountDownLatch;
87.29 +import java.util.concurrent.TimeUnit;
87.30 +
87.31 +/** Represents individual method invocation, its context and its result.
87.32 + *
87.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
87.34 + */
87.35 +public final class InvocationContext {
87.36 + final CountDownLatch wait = new CountDownLatch(1);
87.37 + final Class<?> clazz;
87.38 + final String methodName;
87.39 + private final Launcher launcher;
87.40 + private String result;
87.41 + private Throwable exception;
87.42 + String html;
87.43 + final List<Resource> resources = new ArrayList<>();
87.44 +
87.45 + InvocationContext(Launcher launcher, Class<?> clazz, String methodName) {
87.46 + this.launcher = launcher;
87.47 + this.clazz = clazz;
87.48 + this.methodName = methodName;
87.49 + }
87.50 +
87.51 + /** An HTML fragment to be available for the execution. Useful primarily when
87.52 + * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}.
87.53 + * @param html the html fragment
87.54 + */
87.55 + public void setHtmlFragment(String html) {
87.56 + this.html = html;
87.57 + }
87.58 +
87.59 + /** HTTP resource to be available during execution. An invocation may
87.60 + * perform an HTTP query and obtain a resource relative to the page.
87.61 + */
87.62 + public void addHttpResource(String relativePath, String mimeType, String[] parameters, InputStream content) {
87.63 + if (relativePath == null || mimeType == null || content == null || parameters == null) {
87.64 + throw new NullPointerException();
87.65 + }
87.66 + resources.add(new Resource(content, mimeType, relativePath, parameters));
87.67 + }
87.68 +
87.69 + /** Invokes the associated method.
87.70 + * @return the textual result of the invocation
87.71 + */
87.72 + public String invoke() throws IOException {
87.73 + launcher.runMethod(this);
87.74 + return toString();
87.75 + }
87.76 +
87.77 + /** Obtains textual result of the invocation.
87.78 + * @return text representing the exception or result value
87.79 + */
87.80 + @Override
87.81 + public String toString() {
87.82 + if (exception != null) {
87.83 + return exception.toString();
87.84 + }
87.85 + return result;
87.86 + }
87.87 +
87.88 + /**
87.89 + * @param timeOut
87.90 + * @throws InterruptedException
87.91 + */
87.92 + void await(long timeOut) throws InterruptedException {
87.93 + wait.await(timeOut, TimeUnit.MILLISECONDS);
87.94 + }
87.95 +
87.96 + void result(String r, Throwable e) {
87.97 + this.result = r;
87.98 + this.exception = e;
87.99 + wait.countDown();
87.100 + }
87.101 +
87.102 + static final class Resource {
87.103 + final InputStream httpContent;
87.104 + final String httpType;
87.105 + final String httpPath;
87.106 + final String[] parameters;
87.107 +
87.108 + Resource(InputStream httpContent, String httpType, String httpPath,
87.109 + String[] parameters
87.110 + ) {
87.111 + httpContent.mark(Integer.MAX_VALUE);
87.112 + this.httpContent = httpContent;
87.113 + this.httpType = httpType;
87.114 + this.httpPath = httpPath;
87.115 + this.parameters = parameters;
87.116 + }
87.117 + }
87.118 +}
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
88.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Mon Oct 07 14:20:58 2013 +0200
88.3 @@ -0,0 +1,186 @@
88.4 +/**
88.5 + * Back 2 Browser Bytecode Translator
88.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
88.7 + *
88.8 + * This program is free software: you can redistribute it and/or modify
88.9 + * it under the terms of the GNU General Public License as published by
88.10 + * the Free Software Foundation, version 2 of the License.
88.11 + *
88.12 + * This program is distributed in the hope that it will be useful,
88.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
88.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88.15 + * GNU General Public License for more details.
88.16 + *
88.17 + * You should have received a copy of the GNU General Public License
88.18 + * along with this program. Look for COPYING file in the top folder.
88.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
88.20 + */
88.21 +package org.apidesign.bck2brwsr.launcher;
88.22 +
88.23 +import java.io.Closeable;
88.24 +import java.io.File;
88.25 +import java.io.IOException;
88.26 +import java.lang.reflect.Constructor;
88.27 +
88.28 +/** An abstraction for executing tests in a Bck2Brwsr virtual machine.
88.29 + * Either in {@link Launcher#createJavaScript JavaScript engine},
88.30 + * or in {@link Launcher#createBrowser external browser}.
88.31 + * <p>
88.32 + * There also are methods to {@link #showDir(java.io.File, java.lang.String) display pages}
88.33 + * in an external browser served by internal HTTP server.
88.34 + *
88.35 + * @author Jaroslav Tulach <jtulach@netbeans.org>
88.36 + */
88.37 +public abstract class Launcher {
88.38 +
88.39 + Launcher() {
88.40 + }
88.41 +
88.42 + /** Initializes the launcher. This may mean starting a web browser or
88.43 + * initializing execution engine.
88.44 + * @throws IOException if something goes wrong
88.45 + */
88.46 + public abstract void initialize() throws IOException;
88.47 +
88.48 + /** Shuts down the launcher.
88.49 + * @throws IOException if something goes wrong
88.50 + */
88.51 + public abstract void shutdown() throws IOException;
88.52 +
88.53 +
88.54 + /** Builds an invocation context. The context can later be customized
88.55 + * and {@link InvocationContext#invoke() invoked}.
88.56 + *
88.57 + * @param clazz the class to execute method from
88.58 + * @param method the method to execute
88.59 + * @return the context pointing to the selected method
88.60 + */
88.61 + public InvocationContext createInvocation(Class<?> clazz, String method) {
88.62 + return new InvocationContext(this, clazz, method);
88.63 + }
88.64 +
88.65 +
88.66 + /** Creates launcher that uses internal JavaScript engine (Rhino).
88.67 + * @return the launcher
88.68 + */
88.69 + public static Launcher createJavaScript() {
88.70 + try {
88.71 + Class<?> c = loadClass("org.apidesign.bck2brwsr.launcher.JSLauncher");
88.72 + return (Launcher) c.newInstance();
88.73 + } catch (Exception ex) {
88.74 + throw new IllegalStateException("Please include org.apidesign.bck2brwsr:launcher.html dependency!", ex);
88.75 + }
88.76 + }
88.77 +
88.78 + /** Creates launcher that is using external browser.
88.79 + *
88.80 + * @param cmd <code>null</code> to use <code>java.awt.Desktop</code> to show the launcher
88.81 + * or a string to execute in an external process (with a parameter to the URL)
88.82 + * @return launcher executing in external browser.
88.83 + */
88.84 + public static Launcher createBrowser(String cmd) {
88.85 + String msg = "Trying to create browser '" + cmd + "'";
88.86 + try {
88.87 + Class<?> c;
88.88 + if ("fxbrwsr".equals(cmd)) { // NOI18N
88.89 + msg = "Please include org.apidesign.bck2brwsr:launcher.fx dependency!";
88.90 + c = loadClass("org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher"); // NOI18N
88.91 + } else {
88.92 + msg = "Please include org.apidesign.bck2brwsr:launcher.html dependency!";
88.93 + c = loadClass("org.apidesign.bck2brwsr.launcher.Bck2BrwsrLauncher"); // NOI18N
88.94 + if ("bck2brwsr".equals(cmd)) { // NOI18N
88.95 + // use default executable
88.96 + cmd = null;
88.97 + }
88.98 + }
88.99 + Constructor<?> cnstr = c.getConstructor(String.class);
88.100 + return (Launcher) cnstr.newInstance(cmd);
88.101 + } catch (Exception ex) {
88.102 + throw new IllegalStateException(msg, ex);
88.103 + }
88.104 + }
88.105 +
88.106 + /** Starts an HTTP server which provides access to classes and resources
88.107 + * available in the <code>classes</code> URL and shows a start page
88.108 + * available as {@link ClassLoader#getResource(java.lang.String)} from the
88.109 + * provide classloader. Opens a browser with URL showing the start page.
88.110 + *
88.111 + * @param classes classloader offering access to classes and resources
88.112 + * @param startpage page to show in the browser
88.113 + * @return interface that allows one to stop the server
88.114 + * @throws IOException if something goes wrong
88.115 + */
88.116 + public static Closeable showURL(ClassLoader classes, String startpage) throws IOException {
88.117 + return showURL(null, classes, startpage);
88.118 + }
88.119 + /** Starts an HTTP server which provides access to classes and resources
88.120 + * available in the <code>classes</code> URL and shows a start page
88.121 + * available as {@link ClassLoader#getResource(java.lang.String)} from the
88.122 + * provide classloader. Opens a browser with URL showing the start page.
88.123 + *
88.124 + * @param brwsr name of browser to use or <code>null</code>
88.125 + * @param classes classloader offering access to classes and resources
88.126 + * @param startpage page to show in the browser
88.127 + * @return interface that allows one to stop the server
88.128 + * @throws IOException if something goes wrong
88.129 + * @since 0.7
88.130 + */
88.131 + public static Closeable showURL(String brwsr, ClassLoader classes, String startpage) throws IOException {
88.132 + Launcher l = createBrowser(brwsr);
88.133 + l.addClassLoader(classes);
88.134 + l.showURL(startpage);
88.135 + return (Closeable) l;
88.136 + }
88.137 + /** Starts an HTTP server which provides access to certain directory.
88.138 + * The <code>startpage</code> should be relative location inside the root
88.139 + * directory. Opens a browser with URL showing the start page.
88.140 + *
88.141 + * @param brwsr type of the browser to use
88.142 + * @param directory the root directory on disk
88.143 + * @param classes additional classloader with access to classes or <code>null</code>
88.144 + * @param startpage relative path from the root to the page
88.145 + * @return instance of server that can be closed
88.146 + * @exception IOException if something goes wrong.
88.147 + * @since 0.8
88.148 + */
88.149 + public static Closeable showDir(String brwsr, File directory, ClassLoader classes, String startpage) throws IOException {
88.150 + Launcher l = createBrowser(brwsr);
88.151 + if (classes != null) {
88.152 + l.addClassLoader(classes);
88.153 + }
88.154 + l.showDirectory(directory, startpage, classes != null);
88.155 + return (Closeable) l;
88.156 + }
88.157 +
88.158 + /** Starts an HTTP server which provides access to certain directory.
88.159 + * The <code>startpage</code> should be relative location inside the root
88.160 + * directory. Opens a browser with URL showing the start page.
88.161 + *
88.162 + * @param directory the root directory on disk
88.163 + * @param startpage relative path from the root to the page
88.164 + * @return instance of server that can be closed
88.165 + * @exception IOException if something goes wrong.
88.166 + */
88.167 + public static Closeable showDir(File directory, String startpage) throws IOException {
88.168 + return showDir(null, directory, null, startpage);
88.169 + }
88.170 +
88.171 + abstract InvocationContext runMethod(InvocationContext c) throws IOException;
88.172 +
88.173 +
88.174 + private static Class<?> loadClass(String cn) throws ClassNotFoundException {
88.175 + return Launcher.class.getClassLoader().loadClass(cn);
88.176 + }
88.177 +
88.178 + void showDirectory(File directory, String startpage, boolean addClasses) throws IOException {
88.179 + throw new UnsupportedOperationException();
88.180 + }
88.181 +
88.182 + void showURL(String startpage) throws IOException {
88.183 + throw new UnsupportedOperationException();
88.184 + }
88.185 +
88.186 + void addClassLoader(ClassLoader classes) {
88.187 + throw new UnsupportedOperationException();
88.188 + }
88.189 +}
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
89.2 +++ b/launcher/fx/pom.xml Mon Oct 07 14:20:58 2013 +0200
89.3 @@ -0,0 +1,99 @@
89.4 +<?xml version="1.0"?>
89.5 +<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/xsd/maven-4.0.0.xsd">
89.6 + <modelVersion>4.0.0</modelVersion>
89.7 + <parent>
89.8 + <groupId>org.apidesign.bck2brwsr</groupId>
89.9 + <artifactId>launcher-pom</artifactId>
89.10 + <version>0.9-SNAPSHOT</version>
89.11 + </parent>
89.12 + <groupId>org.apidesign.bck2brwsr</groupId>
89.13 + <artifactId>launcher.fx</artifactId>
89.14 + <version>0.9-SNAPSHOT</version>
89.15 + <name>FXBrwsr Launcher</name>
89.16 + <url>http://maven.apache.org</url>
89.17 + <build>
89.18 + <plugins>
89.19 + <plugin>
89.20 + <groupId>org.apache.maven.plugins</groupId>
89.21 + <artifactId>maven-compiler-plugin</artifactId>
89.22 + <version>2.3.2</version>
89.23 + <configuration>
89.24 + <source>1.6</source>
89.25 + <target>1.6</target>
89.26 + </configuration>
89.27 + </plugin>
89.28 + <plugin>
89.29 + <groupId>org.apache.maven.plugins</groupId>
89.30 + <artifactId>maven-javadoc-plugin</artifactId>
89.31 + <configuration>
89.32 + <subpackages>org.apidesign.bck2brwsr.launcher.fx</subpackages>
89.33 + <skip>false</skip>
89.34 + </configuration>
89.35 + </plugin>
89.36 + </plugins>
89.37 + </build>
89.38 + <properties>
89.39 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
89.40 + </properties>
89.41 + <dependencies>
89.42 + <dependency>
89.43 + <groupId>${project.groupId}</groupId>
89.44 + <artifactId>launcher</artifactId>
89.45 + <version>${project.version}</version>
89.46 + </dependency>
89.47 + <dependency>
89.48 + <groupId>org.glassfish.grizzly</groupId>
89.49 + <artifactId>grizzly-http-server</artifactId>
89.50 + <version>${grizzly.version}</version>
89.51 + </dependency>
89.52 + <dependency>
89.53 + <groupId>com.oracle</groupId>
89.54 + <artifactId>javafx</artifactId>
89.55 + <version>2.2</version>
89.56 + <scope>system</scope>
89.57 + <systemPath>${jfxrt.jar}</systemPath>
89.58 + </dependency>
89.59 + <dependency>
89.60 + <groupId>org.testng</groupId>
89.61 + <artifactId>testng</artifactId>
89.62 + <scope>test</scope>
89.63 + </dependency>
89.64 + <dependency>
89.65 + <groupId>org.netbeans.modules</groupId>
89.66 + <artifactId>org-netbeans-bootstrap</artifactId>
89.67 + <version>RELEASE73</version>
89.68 + </dependency>
89.69 + <dependency>
89.70 + <groupId>${project.groupId}</groupId>
89.71 + <artifactId>core</artifactId>
89.72 + <version>${project.version}</version>
89.73 + <scope>compile</scope>
89.74 + </dependency>
89.75 + <dependency>
89.76 + <groupId>org.ow2.asm</groupId>
89.77 + <artifactId>asm</artifactId>
89.78 + <version>4.1</version>
89.79 + </dependency>
89.80 + <dependency>
89.81 + <groupId>org.apidesign.html</groupId>
89.82 + <artifactId>net.java.html.boot</artifactId>
89.83 + <version>${net.java.html.version}</version>
89.84 + </dependency>
89.85 + <dependency>
89.86 + <groupId>org.glassfish.grizzly</groupId>
89.87 + <artifactId>grizzly-websockets-server</artifactId>
89.88 + <version>${grizzly.version}</version>
89.89 + <type>jar</type>
89.90 + </dependency>
89.91 + <dependency>
89.92 + <groupId>org.glassfish.grizzly</groupId>
89.93 + <artifactId>grizzly-http-servlet</artifactId>
89.94 + <version>${grizzly.version}</version>
89.95 + </dependency>
89.96 + <dependency>
89.97 + <groupId>javax.servlet</groupId>
89.98 + <artifactId>javax.servlet-api</artifactId>
89.99 + <version>3.1.0</version>
89.100 + </dependency>
89.101 + </dependencies>
89.102 +</project>
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
90.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Mon Oct 07 14:20:58 2013 +0200
90.3 @@ -0,0 +1,751 @@
90.4 +/**
90.5 + * Back 2 Browser Bytecode Translator
90.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
90.7 + *
90.8 + * This program is free software: you can redistribute it and/or modify
90.9 + * it under the terms of the GNU General Public License as published by
90.10 + * the Free Software Foundation, version 2 of the License.
90.11 + *
90.12 + * This program is distributed in the hope that it will be useful,
90.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
90.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90.15 + * GNU General Public License for more details.
90.16 + *
90.17 + * You should have received a copy of the GNU General Public License
90.18 + * along with this program. Look for COPYING file in the top folder.
90.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
90.20 + */
90.21 +package org.apidesign.bck2brwsr.launcher;
90.22 +
90.23 +import java.io.ByteArrayInputStream;
90.24 +import java.io.ByteArrayOutputStream;
90.25 +import java.io.Closeable;
90.26 +import java.io.File;
90.27 +import java.io.IOException;
90.28 +import java.io.InputStream;
90.29 +import java.io.InterruptedIOException;
90.30 +import java.io.OutputStream;
90.31 +import java.io.Reader;
90.32 +import java.io.UnsupportedEncodingException;
90.33 +import java.io.Writer;
90.34 +import java.net.URI;
90.35 +import java.net.URISyntaxException;
90.36 +import java.net.URL;
90.37 +import java.util.ArrayList;
90.38 +import java.util.Arrays;
90.39 +import java.util.Enumeration;
90.40 +import java.util.LinkedHashSet;
90.41 +import java.util.List;
90.42 +import java.util.Set;
90.43 +import java.util.concurrent.BlockingQueue;
90.44 +import java.util.concurrent.Callable;
90.45 +import java.util.concurrent.CountDownLatch;
90.46 +import java.util.concurrent.LinkedBlockingQueue;
90.47 +import java.util.concurrent.TimeUnit;
90.48 +import java.util.logging.Level;
90.49 +import java.util.logging.Logger;
90.50 +import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource;
90.51 +import org.glassfish.grizzly.PortRange;
90.52 +import org.glassfish.grizzly.http.server.HttpHandler;
90.53 +import org.glassfish.grizzly.http.server.HttpServer;
90.54 +import org.glassfish.grizzly.http.server.NetworkListener;
90.55 +import org.glassfish.grizzly.http.server.Request;
90.56 +import org.glassfish.grizzly.http.server.Response;
90.57 +import org.glassfish.grizzly.http.server.ServerConfiguration;
90.58 +import org.glassfish.grizzly.http.server.StaticHttpHandler;
90.59 +import org.glassfish.grizzly.http.util.HttpStatus;
90.60 +import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
90.61 +import org.glassfish.grizzly.websockets.WebSocket;
90.62 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
90.63 +import org.glassfish.grizzly.websockets.WebSocketApplication;
90.64 +import org.glassfish.grizzly.websockets.WebSocketEngine;
90.65 +import org.openide.util.Exceptions;
90.66 +
90.67 +/**
90.68 + * Lightweight server to launch Bck2Brwsr applications and tests.
90.69 + * Supports execution in native browser as well as Java's internal
90.70 + * execution engine.
90.71 + */
90.72 +abstract class BaseHTTPLauncher extends Launcher implements Closeable, Callable<HttpServer> {
90.73 + static final Logger LOG = Logger.getLogger(BaseHTTPLauncher.class.getName());
90.74 + private static final InvocationContext END = new InvocationContext(null, null, null);
90.75 + private final Set<ClassLoader> loaders = new LinkedHashSet<ClassLoader>();
90.76 + private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<InvocationContext>();
90.77 + private long timeOut;
90.78 + private final Res resources = new Res();
90.79 + private final String cmd;
90.80 + private Object[] brwsr;
90.81 + private HttpServer server;
90.82 + private CountDownLatch wait;
90.83 +
90.84 + public BaseHTTPLauncher(String cmd) {
90.85 + this.cmd = cmd;
90.86 + addClassLoader(BaseHTTPLauncher.class.getClassLoader());
90.87 + setTimeout(180000);
90.88 + }
90.89 +
90.90 + @Override
90.91 + InvocationContext runMethod(InvocationContext c) throws IOException {
90.92 + loaders.add(c.clazz.getClassLoader());
90.93 + methods.add(c);
90.94 + try {
90.95 + c.await(timeOut);
90.96 + } catch (InterruptedException ex) {
90.97 + throw new IOException(ex);
90.98 + }
90.99 + return c;
90.100 + }
90.101 +
90.102 + public void setTimeout(long ms) {
90.103 + timeOut = ms;
90.104 + }
90.105 +
90.106 + public void addClassLoader(ClassLoader url) {
90.107 + this.loaders.add(url);
90.108 + }
90.109 +
90.110 + ClassLoader[] loaders() {
90.111 + return loaders.toArray(new ClassLoader[loaders.size()]);
90.112 + }
90.113 +
90.114 + public void showURL(String startpage) throws IOException {
90.115 + if (!startpage.startsWith("/")) {
90.116 + startpage = "/" + startpage;
90.117 + }
90.118 + HttpServer s = initServer(".", true, "");
90.119 + int last = startpage.lastIndexOf('/');
90.120 + String prefix = startpage.substring(0, last);
90.121 + String simpleName = startpage.substring(last);
90.122 + s.getServerConfiguration().addHttpHandler(new SubTree(resources, prefix), "/");
90.123 + server = s;
90.124 + try {
90.125 + launchServerAndBrwsr(s, simpleName);
90.126 + } catch (Exception ex) {
90.127 + throw new IOException(ex);
90.128 + }
90.129 + }
90.130 +
90.131 + void showDirectory(File dir, String startpage, boolean addClasses) throws IOException {
90.132 + if (!startpage.startsWith("/")) {
90.133 + startpage = "/" + startpage;
90.134 + }
90.135 + String prefix = "";
90.136 + int last = startpage.lastIndexOf('/');
90.137 + if (last >= 0) {
90.138 + prefix = startpage.substring(0, last);
90.139 + }
90.140 + HttpServer s = initServer(dir.getPath(), addClasses, prefix);
90.141 + try {
90.142 + launchServerAndBrwsr(s, startpage);
90.143 + } catch (Exception ex) {
90.144 + throw new IOException(ex);
90.145 + }
90.146 + }
90.147 +
90.148 + @Override
90.149 + public void initialize() throws IOException {
90.150 + try {
90.151 + executeInBrowser();
90.152 + } catch (InterruptedException ex) {
90.153 + final InterruptedIOException iio = new InterruptedIOException(ex.getMessage());
90.154 + iio.initCause(ex);
90.155 + throw iio;
90.156 + } catch (Exception ex) {
90.157 + if (ex instanceof IOException) {
90.158 + throw (IOException)ex;
90.159 + }
90.160 + if (ex instanceof RuntimeException) {
90.161 + throw (RuntimeException)ex;
90.162 + }
90.163 + throw new IOException(ex);
90.164 + }
90.165 + }
90.166 +
90.167 + private HttpServer initServer(String path, boolean addClasses, String vmPrefix) throws IOException {
90.168 + HttpServer s = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
90.169 + /*
90.170 + ThreadPoolConfig fewThreads = ThreadPoolConfig.defaultConfig().copy().
90.171 + setPoolName("Fx/Bck2 Brwsr").
90.172 + setCorePoolSize(3).
90.173 + setMaxPoolSize(5);
90.174 + ThreadPoolConfig oneKernel = ThreadPoolConfig.defaultConfig().copy().
90.175 + setPoolName("Kernel Fx/Bck2").
90.176 + setCorePoolSize(3).
90.177 + setMaxPoolSize(3);
90.178 + for (NetworkListener nl : s.getListeners()) {
90.179 + nl.getTransport().setWorkerThreadPoolConfig(fewThreads);
90.180 + nl.getTransport().setKernelThreadPoolConfig(oneKernel);
90.181 + }
90.182 + */
90.183 + final ServerConfiguration conf = s.getServerConfiguration();
90.184 + VMAndPages vm = new VMAndPages();
90.185 + conf.addHttpHandler(vm, "/");
90.186 + if (vmPrefix != null) {
90.187 + vm.registerVM(vmPrefix + "/bck2brwsr.js");
90.188 + }
90.189 + if (path != null) {
90.190 + vm.addDocRoot(path);
90.191 + }
90.192 + if (addClasses) {
90.193 + conf.addHttpHandler(new Classes(resources), "/classes/");
90.194 + }
90.195 + final WebSocketAddOn addon = new WebSocketAddOn();
90.196 + for (NetworkListener listener : s.getListeners()) {
90.197 + listener.registerAddOn(addon);
90.198 + }
90.199 + return s;
90.200 + }
90.201 +
90.202 + private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
90.203 + wait = new CountDownLatch(1);
90.204 + server = initServer(".", true, "");
90.205 + final ServerConfiguration conf = server.getServerConfiguration();
90.206 +
90.207 + class DynamicResourceHandler extends HttpHandler {
90.208 + private final InvocationContext ic;
90.209 + private int resourcesCount;
90.210 + DynamicResourceHandler delegate;
90.211 + public DynamicResourceHandler(InvocationContext ic) {
90.212 + this.ic = ic;
90.213 + for (Resource r : ic.resources) {
90.214 + conf.addHttpHandler(this, r.httpPath);
90.215 + }
90.216 + }
90.217 +
90.218 + public void close(DynamicResourceHandler del) {
90.219 + conf.removeHttpHandler(this);
90.220 + delegate = del;
90.221 + }
90.222 +
90.223 + @Override
90.224 + public void service(Request request, Response response) throws Exception {
90.225 + if (delegate != null) {
90.226 + delegate.service(request, response);
90.227 + return;
90.228 + }
90.229 +
90.230 + if ("/dynamic".equals(request.getRequestURI())) {
90.231 + boolean webSocket = false;
90.232 + String mimeType = request.getParameter("mimeType");
90.233 + List<String> params = new ArrayList<String>();
90.234 + for (int i = 0; ; i++) {
90.235 + String p = request.getParameter("param" + i);
90.236 + if (p == null) {
90.237 + break;
90.238 + }
90.239 + params.add(p);
90.240 + if ("protocol:ws".equals(p)) {
90.241 + webSocket = true;
90.242 + continue;
90.243 + } }
90.244 + final String cnt = request.getParameter("content");
90.245 + String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
90.246 + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
90.247 + URI url;
90.248 + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
90.249 + if (webSocket) {
90.250 + url = registerWebSocket(res);
90.251 + } else {
90.252 + url = registerResource(res);
90.253 + }
90.254 + response.getWriter().write(url.toString());
90.255 + response.getWriter().write("\n");
90.256 + return;
90.257 + }
90.258 +
90.259 + for (Resource r : ic.resources) {
90.260 + if (r.httpPath.equals(request.getRequestURI())) {
90.261 + LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI());
90.262 + response.setContentType(r.httpType);
90.263 + r.httpContent.reset();
90.264 + String[] params = null;
90.265 + if (r.parameters.length != 0) {
90.266 + params = new String[r.parameters.length];
90.267 + for (int i = 0; i < r.parameters.length; i++) {
90.268 + params[i] = request.getParameter(r.parameters[i]);
90.269 + if (params[i] == null) {
90.270 + if ("http.method".equals(r.parameters[i])) {
90.271 + params[i] = request.getMethod().toString();
90.272 + } else if ("http.requestBody".equals(r.parameters[i])) {
90.273 + Reader rdr = request.getReader();
90.274 + StringBuilder sb = new StringBuilder();
90.275 + for (;;) {
90.276 + int ch = rdr.read();
90.277 + if (ch == -1) {
90.278 + break;
90.279 + }
90.280 + sb.append((char)ch);
90.281 + }
90.282 + params[i] = sb.toString();
90.283 + }
90.284 + }
90.285 + if (params[i] == null) {
90.286 + params[i] = "null";
90.287 + }
90.288 + }
90.289 + }
90.290 +
90.291 + copyStream(r.httpContent, response.getOutputStream(), null, params);
90.292 + }
90.293 + }
90.294 + }
90.295 +
90.296 + private URI registerWebSocket(Resource r) {
90.297 + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
90.298 + return pageURL("ws", server, r.httpPath);
90.299 + }
90.300 +
90.301 + private URI registerResource(Resource r) {
90.302 + if (!ic.resources.contains(r)) {
90.303 + ic.resources.add(r);
90.304 + conf.addHttpHandler(this, r.httpPath);
90.305 + }
90.306 + return pageURL("http", server, r.httpPath);
90.307 + }
90.308 + }
90.309 +
90.310 + conf.addHttpHandler(new Page(resources, harnessResource()), "/execute");
90.311 +
90.312 + conf.addHttpHandler(new HttpHandler() {
90.313 + int cnt;
90.314 + List<InvocationContext> cases = new ArrayList<InvocationContext>();
90.315 + DynamicResourceHandler prev;
90.316 + @Override
90.317 + public void service(Request request, Response response) throws Exception {
90.318 + String id = request.getParameter("request");
90.319 + String value = request.getParameter("result");
90.320 + if (value != null && value.indexOf((char)0xC5) != -1) {
90.321 + value = toUTF8(value);
90.322 + }
90.323 +
90.324 +
90.325 + InvocationContext mi = null;
90.326 + int caseNmbr = -1;
90.327 +
90.328 + if (id != null && value != null) {
90.329 + LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value});
90.330 + value = decodeURL(value);
90.331 + int indx = Integer.parseInt(id);
90.332 + cases.get(indx).result(value, null);
90.333 + if (++indx < cases.size()) {
90.334 + mi = cases.get(indx);
90.335 + LOG.log(Level.INFO, "Re-executing case {0}", indx);
90.336 + caseNmbr = indx;
90.337 + }
90.338 + } else {
90.339 + if (!cases.isEmpty()) {
90.340 + LOG.info("Re-executing test cases");
90.341 + mi = cases.get(0);
90.342 + caseNmbr = 0;
90.343 + }
90.344 + }
90.345 +
90.346 + if (mi == null) {
90.347 + mi = methods.take();
90.348 + caseNmbr = cnt++;
90.349 + }
90.350 + if (mi == END) {
90.351 + response.getWriter().write("");
90.352 + wait.countDown();
90.353 + cnt = 0;
90.354 + LOG.log(Level.INFO, "End of data reached. Exiting.");
90.355 + return;
90.356 + }
90.357 + final DynamicResourceHandler newRH = new DynamicResourceHandler(mi);
90.358 + if (prev != null) {
90.359 + prev.close(newRH);
90.360 + }
90.361 + prev = newRH;
90.362 + conf.addHttpHandler(prev, "/dynamic");
90.363 +
90.364 + cases.add(mi);
90.365 + final String cn = mi.clazz.getName();
90.366 + final String mn = mi.methodName;
90.367 + LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn});
90.368 + response.getWriter().write("{"
90.369 + + "className: '" + cn + "', "
90.370 + + "methodName: '" + mn + "', "
90.371 + + "request: " + caseNmbr
90.372 + );
90.373 + if (mi.html != null) {
90.374 + response.getWriter().write(", html: '");
90.375 + response.getWriter().write(encodeJSON(mi.html));
90.376 + response.getWriter().write("'");
90.377 + }
90.378 + response.getWriter().write("}");
90.379 + }
90.380 + }, "/data");
90.381 +
90.382 + this.brwsr = launchServerAndBrwsr(server, "/execute");
90.383 + }
90.384 +
90.385 + private static String encodeJSON(String in) {
90.386 + StringBuilder sb = new StringBuilder();
90.387 + for (int i = 0; i < in.length(); i++) {
90.388 + char ch = in.charAt(i);
90.389 + if (ch < 32 || ch == '\'' || ch == '"') {
90.390 + sb.append("\\u");
90.391 + String hs = "0000" + Integer.toHexString(ch);
90.392 + hs = hs.substring(hs.length() - 4);
90.393 + sb.append(hs);
90.394 + } else {
90.395 + sb.append(ch);
90.396 + }
90.397 + }
90.398 + return sb.toString();
90.399 + }
90.400 +
90.401 + @Override
90.402 + public void shutdown() throws IOException {
90.403 + methods.offer(END);
90.404 + for (;;) {
90.405 + int prev = methods.size();
90.406 + try {
90.407 + if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) {
90.408 + break;
90.409 + }
90.410 + } catch (InterruptedException ex) {
90.411 + throw new IOException(ex);
90.412 + }
90.413 + if (prev == methods.size()) {
90.414 + LOG.log(
90.415 + Level.WARNING,
90.416 + "Timeout and no test has been executed meanwhile (at {0}). Giving up.",
90.417 + methods.size()
90.418 + );
90.419 + break;
90.420 + }
90.421 + LOG.log(Level.INFO,
90.422 + "Timeout, but tests got from {0} to {1}. Trying again.",
90.423 + new Object[]{prev, methods.size()}
90.424 + );
90.425 + }
90.426 + stopServerAndBrwsr(server, brwsr);
90.427 + }
90.428 +
90.429 + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
90.430 + for (;;) {
90.431 + int ch = is.read();
90.432 + if (ch == -1) {
90.433 + break;
90.434 + }
90.435 + if (ch == '$' && params.length > 0) {
90.436 + int cnt = is.read() - '0';
90.437 + if (baseURL != null && cnt == 'U' - '0') {
90.438 + os.write(baseURL.getBytes("UTF-8"));
90.439 + } else {
90.440 + if (cnt >= 0 && cnt < params.length) {
90.441 + os.write(params[cnt].getBytes("UTF-8"));
90.442 + } else {
90.443 + os.write('$');
90.444 + os.write(cnt + '0');
90.445 + }
90.446 + }
90.447 + } else {
90.448 + os.write(ch);
90.449 + }
90.450 + }
90.451 + }
90.452 +
90.453 + private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
90.454 + server.start();
90.455 + URI uri = pageURL("http", server, page);
90.456 + return showBrwsr(uri);
90.457 + }
90.458 + private static String toUTF8(String value) throws UnsupportedEncodingException {
90.459 + byte[] arr = new byte[value.length()];
90.460 + for (int i = 0; i < arr.length; i++) {
90.461 + arr[i] = (byte)value.charAt(i);
90.462 + }
90.463 + return new String(arr, "UTF-8");
90.464 + }
90.465 +
90.466 + private static String decodeURL(String s) {
90.467 + for (;;) {
90.468 + int pos = s.indexOf('%');
90.469 + if (pos == -1) {
90.470 + return s;
90.471 + }
90.472 + int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16);
90.473 + s = s.substring(0, pos) + (char)i + s.substring(pos + 2);
90.474 + }
90.475 + }
90.476 +
90.477 + private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException {
90.478 + if (brwsr == null) {
90.479 + return;
90.480 + }
90.481 + Process process = (Process)brwsr[0];
90.482 +
90.483 + server.stop();
90.484 + InputStream stdout = process.getInputStream();
90.485 + InputStream stderr = process.getErrorStream();
90.486 + drain("StdOut", stdout);
90.487 + drain("StdErr", stderr);
90.488 + process.destroy();
90.489 + int res;
90.490 + try {
90.491 + res = process.waitFor();
90.492 + } catch (InterruptedException ex) {
90.493 + throw new IOException(ex);
90.494 + }
90.495 + LOG.log(Level.INFO, "Exit code: {0}", res);
90.496 +
90.497 + deleteTree((File)brwsr[1]);
90.498 + }
90.499 +
90.500 + private static void drain(String name, InputStream is) throws IOException {
90.501 + int av = is.available();
90.502 + if (av > 0) {
90.503 + StringBuilder sb = new StringBuilder();
90.504 + sb.append("v== ").append(name).append(" ==v\n");
90.505 + while (av-- > 0) {
90.506 + sb.append((char)is.read());
90.507 + }
90.508 + sb.append("\n^== ").append(name).append(" ==^");
90.509 + LOG.log(Level.INFO, sb.toString());
90.510 + }
90.511 + }
90.512 +
90.513 + private void deleteTree(File file) {
90.514 + if (file == null) {
90.515 + return;
90.516 + }
90.517 + File[] arr = file.listFiles();
90.518 + if (arr != null) {
90.519 + for (File s : arr) {
90.520 + deleteTree(s);
90.521 + }
90.522 + }
90.523 + file.delete();
90.524 + }
90.525 +
90.526 + @Override
90.527 + public HttpServer call() throws Exception {
90.528 + return server;
90.529 + }
90.530 +
90.531 + @Override
90.532 + public void close() throws IOException {
90.533 + shutdown();
90.534 + }
90.535 +
90.536 + protected Object[] showBrwsr(URI uri) throws IOException {
90.537 + LOG.log(Level.INFO, "Showing {0}", uri);
90.538 + if (cmd == null) {
90.539 + try {
90.540 + LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
90.541 + System.getProperty("java.vm.name"),
90.542 + System.getProperty("java.vm.vendor"),
90.543 + System.getProperty("java.vm.version"),
90.544 + });
90.545 + java.awt.Desktop.getDesktop().browse(uri);
90.546 + LOG.log(Level.INFO, "Desktop.browse successfully finished");
90.547 + return null;
90.548 + } catch (UnsupportedOperationException ex) {
90.549 + LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
90.550 + LOG.log(Level.FINE, null, ex);
90.551 + }
90.552 + }
90.553 + {
90.554 + String cmdName = cmd == null ? "xdg-open" : cmd;
90.555 + String[] cmdArr = {
90.556 + cmdName, uri.toString()
90.557 + };
90.558 + LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
90.559 + final Process process = Runtime.getRuntime().exec(cmdArr);
90.560 + return new Object[] { process, null };
90.561 + }
90.562 + }
90.563 +
90.564 + abstract void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException;
90.565 + abstract String harnessResource();
90.566 +
90.567 + private static URI pageURL(String protocol, HttpServer server, final String page) {
90.568 + NetworkListener listener = server.getListeners().iterator().next();
90.569 + int port = listener.getPort();
90.570 + try {
90.571 + return new URI(protocol + "://localhost:" + port + page);
90.572 + } catch (URISyntaxException ex) {
90.573 + throw new IllegalStateException(ex);
90.574 + }
90.575 + }
90.576 +
90.577 + class Res {
90.578 + public InputStream get(String resource) throws IOException {
90.579 + URL u = null;
90.580 + for (ClassLoader l : loaders) {
90.581 + Enumeration<URL> en = l.getResources(resource);
90.582 + while (en.hasMoreElements()) {
90.583 + u = en.nextElement();
90.584 + if (u.toExternalForm().matches("^.*emul.*rt\\.jar.*$")) {
90.585 + return u.openStream();
90.586 + }
90.587 + }
90.588 + }
90.589 + if (u != null) {
90.590 + if (u.toExternalForm().contains("rt.jar")) {
90.591 + LOG.log(Level.WARNING, "Fallback to bootclasspath for {0}", u);
90.592 + }
90.593 + return u.openStream();
90.594 + }
90.595 + throw new IOException("Can't find " + resource);
90.596 + }
90.597 + }
90.598 +
90.599 + private static class Page extends HttpHandler {
90.600 + final String resource;
90.601 + private final String[] args;
90.602 + private final Res res;
90.603 +
90.604 + public Page(Res res, String resource, String... args) {
90.605 + this.res = res;
90.606 + this.resource = resource;
90.607 + this.args = args.length == 0 ? new String[] { "$0" } : args;
90.608 + }
90.609 +
90.610 + @Override
90.611 + public void service(Request request, Response response) throws Exception {
90.612 + String r = computePage(request);
90.613 + if (r.startsWith("/")) {
90.614 + r = r.substring(1);
90.615 + }
90.616 + String[] replace = {};
90.617 + if (r.endsWith(".html")) {
90.618 + response.setContentType("text/html");
90.619 + LOG.info("Content type text/html");
90.620 + replace = args;
90.621 + }
90.622 + if (r.endsWith(".xhtml")) {
90.623 + response.setContentType("application/xhtml+xml");
90.624 + LOG.info("Content type application/xhtml+xml");
90.625 + replace = args;
90.626 + }
90.627 + OutputStream os = response.getOutputStream();
90.628 + try {
90.629 + InputStream is = res.get(r);
90.630 + copyStream(is, os, request.getRequestURL().toString(), replace);
90.631 + } catch (IOException ex) {
90.632 + response.setDetailMessage(ex.getLocalizedMessage());
90.633 + response.setError();
90.634 + response.setStatus(404);
90.635 + }
90.636 + }
90.637 +
90.638 + protected String computePage(Request request) {
90.639 + String r = resource;
90.640 + if (r == null) {
90.641 + r = request.getHttpHandlerPath();
90.642 + }
90.643 + return r;
90.644 + }
90.645 + }
90.646 +
90.647 + private static class SubTree extends Page {
90.648 +
90.649 + public SubTree(Res res, String resource, String... args) {
90.650 + super(res, resource, args);
90.651 + }
90.652 +
90.653 + @Override
90.654 + protected String computePage(Request request) {
90.655 + return resource + request.getHttpHandlerPath();
90.656 + }
90.657 +
90.658 +
90.659 + }
90.660 +
90.661 + private class VMAndPages extends StaticHttpHandler {
90.662 + private String vmResource;
90.663 +
90.664 + public VMAndPages() {
90.665 + super((String[]) null);
90.666 + }
90.667 +
90.668 + @Override
90.669 + public void service(Request request, Response response) throws Exception {
90.670 + if (request.getRequestURI().equals(vmResource)) {
90.671 + response.setCharacterEncoding("UTF-8");
90.672 + response.setContentType("text/javascript");
90.673 + StringBuilder sb = new StringBuilder();
90.674 + generateBck2BrwsrJS(sb, BaseHTTPLauncher.this.resources);
90.675 + response.getWriter().write(sb.toString());
90.676 + } else {
90.677 + super.service(request, response);
90.678 + }
90.679 + }
90.680 +
90.681 + private void registerVM(String vmResource) {
90.682 + this.vmResource = vmResource;
90.683 + }
90.684 + }
90.685 +
90.686 + private static class Classes extends HttpHandler {
90.687 + private final Res loader;
90.688 +
90.689 + public Classes(Res loader) {
90.690 + this.loader = loader;
90.691 + }
90.692 +
90.693 + @Override
90.694 + public void service(Request request, Response response) throws Exception {
90.695 + String res = request.getHttpHandlerPath();
90.696 + if (res.startsWith("/")) {
90.697 + res = res.substring(1);
90.698 + }
90.699 + InputStream is = null;
90.700 + try {
90.701 + is = loader.get(res);
90.702 + response.setContentType("text/javascript");
90.703 + Writer w = response.getWriter();
90.704 + w.append("[");
90.705 + for (int i = 0;; i++) {
90.706 + int b = is.read();
90.707 + if (b == -1) {
90.708 + break;
90.709 + }
90.710 + if (i > 0) {
90.711 + w.append(", ");
90.712 + }
90.713 + if (i % 20 == 0) {
90.714 + w.write("\n");
90.715 + }
90.716 + if (b > 127) {
90.717 + b = b - 256;
90.718 + }
90.719 + w.append(Integer.toString(b));
90.720 + }
90.721 + w.append("\n]");
90.722 + } catch (IOException ex) {
90.723 + response.setStatus(HttpStatus.NOT_FOUND_404);
90.724 + response.setError();
90.725 + response.setDetailMessage(ex.getMessage());
90.726 + } finally {
90.727 + if (is != null) {
90.728 + is.close();
90.729 + }
90.730 + }
90.731 + }
90.732 + }
90.733 + private static class WS extends WebSocketApplication {
90.734 +
90.735 + private final Resource r;
90.736 +
90.737 + private WS(Resource r) {
90.738 + this.r = r;
90.739 + }
90.740 +
90.741 + @Override
90.742 + public void onMessage(WebSocket socket, String text) {
90.743 + try {
90.744 + r.httpContent.reset();
90.745 + ByteArrayOutputStream out = new ByteArrayOutputStream();
90.746 + copyStream(r.httpContent, out, null, text);
90.747 + String s = new String(out.toByteArray(), "UTF-8");
90.748 + socket.send(s);
90.749 + } catch (IOException ex) {
90.750 + Exceptions.printStackTrace(ex);
90.751 + }
90.752 + }
90.753 +
90.754 + }}
91.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
91.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java Mon Oct 07 14:20:58 2013 +0200
91.3 @@ -0,0 +1,186 @@
91.4 +/**
91.5 + * Back 2 Browser Bytecode Translator
91.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
91.7 + *
91.8 + * This program is free software: you can redistribute it and/or modify
91.9 + * it under the terms of the GNU General Public License as published by
91.10 + * the Free Software Foundation, version 2 of the License.
91.11 + *
91.12 + * This program is distributed in the hope that it will be useful,
91.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
91.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
91.15 + * GNU General Public License for more details.
91.16 + *
91.17 + * You should have received a copy of the GNU General Public License
91.18 + * along with this program. Look for COPYING file in the top folder.
91.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
91.20 + */
91.21 +package org.apidesign.bck2brwsr.launcher;
91.22 +
91.23 +import java.io.File;
91.24 +import org.apidesign.bck2brwsr.launcher.fximpl.FXBrwsr;
91.25 +import java.io.IOException;
91.26 +import java.io.InputStream;
91.27 +import java.lang.reflect.Method;
91.28 +import java.net.JarURLConnection;
91.29 +import java.net.URI;
91.30 +import java.net.URISyntaxException;
91.31 +import java.net.URL;
91.32 +import java.net.URLClassLoader;
91.33 +import java.util.ArrayList;
91.34 +import java.util.Enumeration;
91.35 +import java.util.List;
91.36 +
91.37 +import java.util.concurrent.Executors;
91.38 +import java.util.jar.Manifest;
91.39 +import java.util.logging.Level;
91.40 +import java.util.logging.Logger;
91.41 +import javafx.application.Platform;
91.42 +import org.apidesign.bck2brwsr.launcher.fximpl.JVMBridge;
91.43 +import org.openide.util.Exceptions;
91.44 +
91.45 +/**
91.46 + *
91.47 + * @author Jaroslav Tulach <jtulach@netbeans.org>
91.48 + */
91.49 +final class FXBrwsrLauncher extends BaseHTTPLauncher {
91.50 + private static final Logger LOG = Logger.getLogger(FXBrwsrLauncher.class.getName());
91.51 + static {
91.52 + try {
91.53 + Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
91.54 + m.setAccessible(true);
91.55 + URL l = new URL("file://" + System.getProperty("java.home") + "/lib/jfxrt.jar");
91.56 + LOG.log(Level.INFO, "url : {0}", l);
91.57 + m.invoke(ClassLoader.getSystemClassLoader(), l);
91.58 + } catch (Exception ex) {
91.59 + throw new LinkageError("Can't add jfxrt.jar on the classpath", ex);
91.60 + }
91.61 + }
91.62 +
91.63 + public FXBrwsrLauncher(String ignore) {
91.64 + super(null);
91.65 + }
91.66 +
91.67 + @Override
91.68 + protected Object[] showBrwsr(final URI url) throws IOException {
91.69 + try {
91.70 + LOG.log(Level.INFO, "showBrwsr for {0}", url);
91.71 + JVMBridge.registerClassLoaders(loaders());
91.72 + LOG.info("About to launch WebView");
91.73 + Executors.newSingleThreadExecutor().submit(new Runnable() {
91.74 + @Override
91.75 + public void run() {
91.76 + LOG.log(Level.INFO, "In FX thread. Launching!");
91.77 + try {
91.78 + List<String> params = new ArrayList<String>();
91.79 + params.add(url.toString());
91.80 + if (isDebugged()) {
91.81 + params.add("--toolbar=true");
91.82 + params.add("--firebug=true");
91.83 + String ud = System.getProperty("netbeans.user");
91.84 + if (ud != null) {
91.85 + params.add("--userdir=" + ud);
91.86 + }
91.87 + }
91.88 + FXBrwsr.launch(FXBrwsr.class, params.toArray(new String[params.size()]));
91.89 + LOG.log(Level.INFO, "Launcher is back. Closing");
91.90 + close();
91.91 + System.exit(0);
91.92 + } catch (Throwable ex) {
91.93 + LOG.log(Level.WARNING, "Error launching Web View", ex);
91.94 + }
91.95 + }
91.96 + });
91.97 + } catch (Throwable ex) {
91.98 + LOG.log(Level.WARNING, "Can't open WebView", ex);
91.99 + }
91.100 + return null;
91.101 + }
91.102 +
91.103 + @Override
91.104 + void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException {
91.105 + sb.append("(function() {\n"
91.106 + + " var impl = this.bck2brwsr;\n"
91.107 + + " this.bck2brwsr = function() { return impl; };\n");
91.108 + sb.append("})(window);\n");
91.109 + JVMBridge.onBck2BrwsrLoad();
91.110 + }
91.111 +
91.112 + @Override
91.113 + public void close() throws IOException {
91.114 + super.close();
91.115 + Platform.exit();
91.116 + }
91.117 +
91.118 + String harnessResource() {
91.119 + return "org/apidesign/bck2brwsr/launcher/fximpl/harness.xhtml";
91.120 + }
91.121 +
91.122 + public static void main(String... args) throws IOException {
91.123 + String startPage = null;
91.124 +
91.125 + final ClassLoader cl = FXBrwsrLauncher.class.getClassLoader();
91.126 + URL[] manifestURL = { null };
91.127 + startPage = findStartPage(cl, startPage, manifestURL);
91.128 + if (startPage == null) {
91.129 + throw new NullPointerException("Can't find StartPage tag in manifests!");
91.130 + }
91.131 +
91.132 + File dir = new File(".");
91.133 + if (manifestURL[0].getProtocol().equals("jar")) {
91.134 + try {
91.135 + dir = new File(
91.136 + ((JarURLConnection)manifestURL[0].openConnection()).getJarFileURL().toURI()
91.137 + ).getParentFile();
91.138 + } catch (URISyntaxException ex) {
91.139 + LOG.log(Level.WARNING, "Can't find root directory", ex);
91.140 + }
91.141 + }
91.142 +
91.143 + Launcher.showDir("fxbrwsr", dir, cl, startPage);
91.144 + }
91.145 +
91.146 + private static String findStartPage(
91.147 + final ClassLoader cl, String startPage, URL[] startURL
91.148 + ) throws IOException {
91.149 + Enumeration<URL> en = cl.getResources("META-INF/MANIFEST.MF");
91.150 + while (en.hasMoreElements()) {
91.151 + URL url = en.nextElement();
91.152 + Manifest mf;
91.153 + InputStream is = null;
91.154 + try {
91.155 + is = url.openStream();
91.156 + mf = new Manifest(is);
91.157 + } finally {
91.158 + if (is != null) is.close();
91.159 + }
91.160 + String sp = mf.getMainAttributes().getValue("StartPage");
91.161 + if (sp != null) {
91.162 + startPage = sp;
91.163 + if (startURL != null) {
91.164 + startURL[0] = url;
91.165 + }
91.166 + break;
91.167 + }
91.168 + }
91.169 + return startPage;
91.170 + }
91.171 +
91.172 + private static boolean isDebugged() {
91.173 + try {
91.174 + return isDebuggedImpl();
91.175 + } catch (LinkageError e) {
91.176 + return false;
91.177 + }
91.178 + }
91.179 +
91.180 + private static boolean isDebuggedImpl() {
91.181 + java.lang.management.RuntimeMXBean runtime;
91.182 + runtime = java.lang.management.ManagementFactory.getRuntimeMXBean();
91.183 + List<String> args = runtime.getInputArguments();
91.184 + if (args.contains("-Xdebug")) { // NOI18N
91.185 + return true;
91.186 + }
91.187 + return false;
91.188 + }
91.189 +}
92.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
92.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fx/LauncherFX.java Mon Oct 07 14:20:58 2013 +0200
92.3 @@ -0,0 +1,32 @@
92.4 +/**
92.5 + * Back 2 Browser Bytecode Translator
92.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
92.7 + *
92.8 + * This program is free software: you can redistribute it and/or modify
92.9 + * it under the terms of the GNU General Public License as published by
92.10 + * the Free Software Foundation, version 2 of the License.
92.11 + *
92.12 + * This program is distributed in the hope that it will be useful,
92.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
92.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
92.15 + * GNU General Public License for more details.
92.16 + *
92.17 + * You should have received a copy of the GNU General Public License
92.18 + * along with this program. Look for COPYING file in the top folder.
92.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
92.20 + */
92.21 +package org.apidesign.bck2brwsr.launcher.fx;
92.22 +
92.23 +import org.apidesign.bck2brwsr.launcher.Launcher;
92.24 +
92.25 +/** This is a launcher for the <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a>
92.26 + * project that is using <b>JavaFX</b>'s WebView to display the browser inside
92.27 + * real Java virtual machine. Use {@link Launcher} methods to access this
92.28 + * functionality via public, supported methods.
92.29 + *
92.30 + * @author Jaroslav Tulach
92.31 + */
92.32 +public final class LauncherFX {
92.33 + private LauncherFX() {
92.34 + }
92.35 +}
93.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
93.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java Mon Oct 07 14:20:58 2013 +0200
93.3 @@ -0,0 +1,379 @@
93.4 +/**
93.5 + * Back 2 Browser Bytecode Translator
93.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
93.7 + *
93.8 + * This program is free software: you can redistribute it and/or modify
93.9 + * it under the terms of the GNU General Public License as published by
93.10 + * the Free Software Foundation, version 2 of the License.
93.11 + *
93.12 + * This program is distributed in the hope that it will be useful,
93.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
93.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93.15 + * GNU General Public License for more details.
93.16 + *
93.17 + * You should have received a copy of the GNU General Public License
93.18 + * along with this program. Look for COPYING file in the top folder.
93.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
93.20 + */
93.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
93.22 +
93.23 +import java.util.ArrayList;
93.24 +import java.util.List;
93.25 +import javafx.beans.InvalidationListener;
93.26 +import javafx.beans.Observable;
93.27 +import javafx.beans.value.ChangeListener;
93.28 +import javafx.beans.value.ObservableValue;
93.29 +import javafx.collections.FXCollections;
93.30 +import javafx.scene.control.ComboBox;
93.31 +import javafx.scene.control.ScrollPane;
93.32 +import javafx.scene.control.Separator;
93.33 +import javafx.scene.control.Toggle;
93.34 +import javafx.scene.control.ToggleButton;
93.35 +import javafx.scene.control.ToggleGroup;
93.36 +import javafx.scene.control.ToolBar;
93.37 +import javafx.scene.control.Tooltip;
93.38 +import javafx.scene.image.Image;
93.39 +import javafx.scene.image.ImageView;
93.40 +import javafx.scene.layout.Pane;
93.41 +import javafx.scene.web.WebEngine;
93.42 +import javafx.scene.web.WebView;
93.43 +
93.44 +final class BrowserToolbar extends ToolBar {
93.45 + private final ArrayList<ResizeBtn> resizeButtons;
93.46 + private final WebView webView;
93.47 + private final Pane container;
93.48 + private final ToggleGroup resizeGroup = new ToggleGroup();
93.49 + private final ComboBox<String> comboZoom = new ComboBox<String>();
93.50 +
93.51 + BrowserToolbar(WebView webView, Pane container, boolean useFirebug) {
93.52 + this.webView = webView;
93.53 + this.container = container;
93.54 +
93.55 + List<ResizeOption> options = ResizeOption.loadAll();
93.56 + options.add( 0, ResizeOption.SIZE_TO_FIT );
93.57 + resizeButtons = new ArrayList<ResizeBtn>( options.size() );
93.58 +
93.59 + for( ResizeOption ro : options ) {
93.60 + ResizeBtn button = new ResizeBtn(ro);
93.61 + resizeButtons.add( button );
93.62 + resizeGroup.getToggles().add( button );
93.63 + getItems().add( button );
93.64 + }
93.65 + resizeButtons.get( 0 ).setSelected( true );
93.66 + resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
93.67 +
93.68 + @Override
93.69 + public void invalidated( Observable o ) {
93.70 + resize();
93.71 + }
93.72 + });
93.73 +
93.74 + getItems().add( new Separator() );
93.75 +
93.76 + getItems().add( comboZoom );
93.77 + ArrayList<String> zoomModel = new ArrayList<String>( 6 );
93.78 + zoomModel.add( "200%" ); //NOI18N
93.79 + zoomModel.add( "150%" ); //NOI18N
93.80 + zoomModel.add( "100%" ); //NOI18N
93.81 + zoomModel.add( "75%" ); //NOI18N
93.82 + zoomModel.add( "50%" ); //NOI18N
93.83 + comboZoom.setItems( FXCollections.observableList( zoomModel ) );
93.84 + comboZoom.setEditable( true );
93.85 + comboZoom.setValue( "100%" ); //NOI18N
93.86 + comboZoom.valueProperty().addListener( new ChangeListener<String>() {
93.87 +
93.88 + @Override
93.89 + public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
93.90 + String newZoom = zoom( t1 );
93.91 + comboZoom.setValue( newZoom );
93.92 + }
93.93 + });
93.94 +
93.95 + if (useFirebug) {
93.96 + getItems().add(new Separator());
93.97 +
93.98 + final ToggleButton firebug = new ToggleButton(null, new ImageView(
93.99 + new Image(BrowserToolbar.class.getResourceAsStream("firebug.png"))
93.100 + ));
93.101 + firebug.setTooltip(new Tooltip("Show/Hide firebug"));
93.102 + firebug.selectedProperty().addListener(new InvalidationListener() {
93.103 + @Override
93.104 + public void invalidated(Observable o) {
93.105 + toggleFireBug(firebug.isSelected());
93.106 + }
93.107 + });
93.108 + getItems().add(firebug);
93.109 + }
93.110 + }
93.111 +
93.112 + private String zoom( String zoomFactor ) {
93.113 + if( zoomFactor.trim().isEmpty() )
93.114 + return null;
93.115 +
93.116 + try {
93.117 + zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
93.118 + zoomFactor = zoomFactor.trim();
93.119 + double zoom = Double.parseDouble( zoomFactor );
93.120 + zoom = Math.abs( zoom )/100;
93.121 + if( zoom <= 0.0 )
93.122 + return null;
93.123 + webView.impl_setScale( zoom );
93.124 + return (int)(100*zoom) + "%"; //NOI18N
93.125 + } catch( NumberFormatException nfe ) {
93.126 + //ignore
93.127 + }
93.128 + return null;
93.129 + }
93.130 +
93.131 + private void resize() {
93.132 + Toggle selection = resizeGroup.getSelectedToggle();
93.133 + if( selection instanceof ResizeBtn ) {
93.134 + ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
93.135 + if( ro == ResizeOption.SIZE_TO_FIT ) {
93.136 + _autofit();
93.137 + } else {
93.138 + _resize( ro.getWidth(), ro.getHeight() );
93.139 + }
93.140 + }
93.141 +
93.142 + }
93.143 +
93.144 + private void _resize( final double width, final double height ) {
93.145 + ScrollPane scroll;
93.146 + if( !(container.getChildren().get( 0) instanceof ScrollPane) ) {
93.147 + scroll = new ScrollPane();
93.148 + scroll.setContent( webView );
93.149 + container.getChildren().clear();
93.150 + container.getChildren().add( scroll );
93.151 + } else {
93.152 + scroll = ( ScrollPane ) container.getChildren().get( 0 );
93.153 + }
93.154 + scroll.setPrefViewportWidth( width );
93.155 + scroll.setPrefViewportHeight(height );
93.156 + webView.setMaxWidth( width );
93.157 + webView.setMaxHeight( height );
93.158 + webView.setMinWidth( width );
93.159 + webView.setMinHeight( height );
93.160 + }
93.161 +
93.162 + private void _autofit() {
93.163 + if( container.getChildren().get( 0) instanceof ScrollPane ) {
93.164 + container.getChildren().clear();
93.165 + container.getChildren().add( webView );
93.166 + }
93.167 + webView.setMaxWidth( Integer.MAX_VALUE );
93.168 + webView.setMaxHeight( Integer.MAX_VALUE );
93.169 + webView.setMinWidth( -1 );
93.170 + webView.setMinHeight( -1 );
93.171 + webView.autosize();
93.172 + }
93.173 +
93.174 + final void toggleFireBug(boolean enable) {
93.175 + WebEngine eng = webView.getEngine();
93.176 + Object installed = eng.executeScript("window.Firebug");
93.177 + if ("undefined".equals(installed)) {
93.178 + StringBuilder sb = new StringBuilder();
93.179 + sb.append("var scr = window.document.createElement('script');\n");
93.180 + sb.append("scr.type = 'text/javascript';\n");
93.181 + sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n");
93.182 + sb.append("scr.text = '{ startOpened: true }';\n");
93.183 + sb.append("var head = window.document.getElementsByTagName('head')[0];");
93.184 + sb.append("head.appendChild(scr);\n");
93.185 + sb.append("var html = window.document.getElementsByTagName('html')[0];");
93.186 + sb.append("html.debug = true;\n");
93.187 + eng.executeScript(sb.toString());
93.188 + } else {
93.189 + if (enable) {
93.190 + eng.executeScript("Firebug.chrome.open()");
93.191 + } else {
93.192 + eng.executeScript("Firebug.chrome.close()");
93.193 + }
93.194 + }
93.195 + }
93.196 +
93.197 + /**
93.198 + * Button to resize the browser window.
93.199 + * Taken from NetBeans. Kept GPLwithCPEx license.
93.200 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
93.201 + *
93.202 + * @author S. Aubrecht
93.203 + */
93.204 + static final class ResizeBtn extends ToggleButton {
93.205 +
93.206 + private final ResizeOption resizeOption;
93.207 +
93.208 + ResizeBtn(ResizeOption resizeOption) {
93.209 + super(null, new ImageView(toImage(resizeOption)));
93.210 + this.resizeOption = resizeOption;
93.211 + setTooltip(new Tooltip(resizeOption.getToolTip()));
93.212 + }
93.213 +
93.214 + ResizeOption getResizeOption() {
93.215 + return resizeOption;
93.216 + }
93.217 +
93.218 + static Image toImage(ResizeOption ro) {
93.219 + if (ro == ResizeOption.SIZE_TO_FIT) {
93.220 + return ResizeOption.Type.CUSTOM.getImage();
93.221 + }
93.222 + return ro.getType().getImage();
93.223 + }
93.224 + }
93.225 +
93.226 + /**
93.227 + * Immutable value class describing a single button to resize web browser window.
93.228 + * Taken from NetBeans. Kept GPLwithCPEx license.
93.229 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
93.230 + *
93.231 + * @author S. Aubrecht
93.232 + */
93.233 + static final class ResizeOption {
93.234 +
93.235 + private final Type type;
93.236 + private final String displayName;
93.237 + private final int width;
93.238 + private final int height;
93.239 + private final boolean isDefault;
93.240 +
93.241 + enum Type {
93.242 + DESKTOP("desktop.png"),
93.243 + TABLET_PORTRAIT("tabletPortrait.png"),
93.244 + TABLET_LANDSCAPE("tabletLandscape.png"),
93.245 + SMARTPHONE_PORTRAIT("handheldPortrait.png"),
93.246 + SMARTPHONE_LANDSCAPE("handheldLandscape.png"),
93.247 + WIDESCREEN("widescreen.png"),
93.248 + NETBOOK("netbook.png"),
93.249 + CUSTOM("sizeToFit.png");
93.250 +
93.251 +
93.252 + private final String resource;
93.253 +
93.254 + private Type(String r) {
93.255 + resource = r;
93.256 + }
93.257 +
93.258 + public Image getImage() {
93.259 + return new Image(Type.class.getResourceAsStream(resource));
93.260 + }
93.261 + }
93.262 +
93.263 + private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
93.264 + super();
93.265 + this.type = type;
93.266 + this.displayName = displayName;
93.267 + this.width = width;
93.268 + this.height = height;
93.269 + this.isDefault = isDefault;
93.270 + }
93.271 +
93.272 + static List<ResizeOption> loadAll() {
93.273 + List<ResizeOption> res = new ArrayList<ResizeOption>(10);
93.274 + res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
93.275 + res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
93.276 + res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
93.277 + res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
93.278 + res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
93.279 + res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
93.280 + res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
93.281 + return res;
93.282 + }
93.283 +
93.284 + /**
93.285 + * Creates a new instance.
93.286 + * @param type
93.287 + * @param displayName Display name to show in tooltip, cannot be empty.
93.288 + * @param width Screen width
93.289 + * @param height Screen height
93.290 + * @param showInToolbar True to show in web developer toolbar.
93.291 + * @param isDefault True if this is a predefined option that cannot be removed.
93.292 + * @return New instance.
93.293 + */
93.294 + public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
93.295 + if (width <= 0 || height <= 0) {
93.296 + throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
93.297 + }
93.298 + return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
93.299 + }
93.300 + /**
93.301 + * An extra option to size the browser content to fit its window.
93.302 + */
93.303 + public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
93.304 +
93.305 + public String getDisplayName() {
93.306 + return displayName;
93.307 + }
93.308 +
93.309 + public Type getType() {
93.310 + return type;
93.311 + }
93.312 +
93.313 + public int getWidth() {
93.314 + return width;
93.315 + }
93.316 +
93.317 + public int getHeight() {
93.318 + return height;
93.319 + }
93.320 +
93.321 + public boolean isDefault() {
93.322 + return isDefault;
93.323 + }
93.324 +
93.325 + @Override
93.326 + public String toString() {
93.327 + return displayName;
93.328 + }
93.329 +
93.330 + public String getToolTip() {
93.331 + if (width < 0 || height < 0) {
93.332 + return displayName;
93.333 + }
93.334 + StringBuilder sb = new StringBuilder();
93.335 + sb.append(width);
93.336 + sb.append(" x "); //NOI18N
93.337 + sb.append(height);
93.338 + sb.append(" ("); //NOI18N
93.339 + sb.append(displayName);
93.340 + sb.append(')'); //NOI18N
93.341 + return sb.toString();
93.342 + }
93.343 +
93.344 + @Override
93.345 + public boolean equals(Object obj) {
93.346 + if (obj == null) {
93.347 + return false;
93.348 + }
93.349 + if (getClass() != obj.getClass()) {
93.350 + return false;
93.351 + }
93.352 + final ResizeOption other = (ResizeOption) obj;
93.353 + if (this.type != other.type) {
93.354 + return false;
93.355 + }
93.356 + if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
93.357 + return false;
93.358 + }
93.359 + if (this.width != other.width) {
93.360 + return false;
93.361 + }
93.362 + if (this.height != other.height) {
93.363 + return false;
93.364 + }
93.365 + if (this.isDefault != other.isDefault) {
93.366 + return false;
93.367 + }
93.368 + return true;
93.369 + }
93.370 +
93.371 + @Override
93.372 + public int hashCode() {
93.373 + int hash = 7;
93.374 + hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
93.375 + hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
93.376 + hash = 11 * hash + this.width;
93.377 + hash = 11 * hash + this.height;
93.378 + hash = 11 * hash + (this.isDefault ? 1 : 0);
93.379 + return hash;
93.380 + }
93.381 + }
93.382 +}
94.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java Mon Oct 07 14:20:58 2013 +0200
94.3 @@ -0,0 +1,362 @@
94.4 +/**
94.5 + * Back 2 Browser Bytecode Translator
94.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
94.7 + *
94.8 + * This program is free software: you can redistribute it and/or modify
94.9 + * it under the terms of the GNU General Public License as published by
94.10 + * the Free Software Foundation, version 2 of the License.
94.11 + *
94.12 + * This program is distributed in the hope that it will be useful,
94.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
94.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94.15 + * GNU General Public License for more details.
94.16 + *
94.17 + * You should have received a copy of the GNU General Public License
94.18 + * along with this program. Look for COPYING file in the top folder.
94.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
94.20 + */
94.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
94.22 +
94.23 +import java.io.IOException;
94.24 +import java.io.InputStream;
94.25 +import java.io.UnsupportedEncodingException;
94.26 +import java.lang.reflect.InvocationTargetException;
94.27 +import java.lang.reflect.Method;
94.28 +import java.lang.reflect.Modifier;
94.29 +import java.net.URL;
94.30 +import java.util.Enumeration;
94.31 +import netscape.javascript.JSObject;
94.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
94.33 +
94.34 +/**
94.35 + *
94.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
94.37 + */
94.38 +public final class Console {
94.39 + public Console() {
94.40 + }
94.41 +
94.42 + @JavaScriptBody(args = { "elem", "attr" }, body = "return elem[attr].toString();")
94.43 + private static native Object getAttr(Object elem, String attr);
94.44 +
94.45 + @JavaScriptBody(args = { "id", "attr", "value" }, body = "window.document.getElementById(id)[attr] = value;")
94.46 + private static native void setAttr(String id, String attr, Object value);
94.47 +
94.48 + @JavaScriptBody(args = { "elem", "attr", "value" }, body = "elem[attr] = value;")
94.49 + private static native void setAttr(Object id, String attr, Object value);
94.50 +
94.51 + private static void closeWindow() {}
94.52 +
94.53 + private static Object textArea;
94.54 + private static Object statusArea;
94.55 +
94.56 + private static void log(String newText) {
94.57 + if (textArea == null) {
94.58 + return;
94.59 + }
94.60 + String attr = "value";
94.61 + setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText);
94.62 + setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight"));
94.63 + }
94.64 +
94.65 + private static void beginTest(Case c) {
94.66 + Object[] arr = new Object[2];
94.67 + beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
94.68 + textArea = arr[0];
94.69 + statusArea = arr[1];
94.70 + }
94.71 +
94.72 + private static void finishTest(Case c, Object res) {
94.73 + if ("null".equals(res)) {
94.74 + setAttr(statusArea, "innerHTML", "Success");
94.75 + } else {
94.76 + setAttr(statusArea, "innerHTML", "Result " + res);
94.77 + }
94.78 + statusArea = null;
94.79 + textArea = null;
94.80 + }
94.81 +
94.82 + @JavaScriptBody(args = { "test", "c", "arr" }, body =
94.83 + "var ul = window.document.getElementById('bck2brwsr.result');\n"
94.84 + + "var li = window.document.createElement('li');\n"
94.85 + + "var span = window.document.createElement('span');"
94.86 + + "span.innerHTML = test + ' - ';\n"
94.87 + + "var details = window.document.createElement('a');\n"
94.88 + + "details.innerHTML = 'Details';\n"
94.89 + + "details.href = '#';\n"
94.90 + + "var p = window.document.createElement('p');\n"
94.91 + + "var status = window.document.createElement('a');\n"
94.92 + + "status.innerHTML = 'running';"
94.93 + + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n"
94.94 + + "status.onclick = function() { c.again(arr); }\n"
94.95 + + "var pre = window.document.createElement('textarea');\n"
94.96 + + "pre.cols = 100;"
94.97 + + "pre.rows = 10;"
94.98 + + "li.appendChild(span);\n"
94.99 + + "li.appendChild(status);\n"
94.100 + + "var span = window.document.createElement('span');"
94.101 + + "span.innerHTML = ' ';\n"
94.102 + + "li.appendChild(span);\n"
94.103 + + "li.appendChild(details);\n"
94.104 + + "p.appendChild(pre);\n"
94.105 + + "ul.appendChild(li);\n"
94.106 + + "arr[0] = pre;\n"
94.107 + + "arr[1] = status;\n"
94.108 + )
94.109 + private static native void beginTest(String test, Case c, Object[] arr);
94.110 +
94.111 + @JavaScriptBody(args = { "url", "callback", "arr" }, body =
94.112 + "var request = new XMLHttpRequest();\n"
94.113 + + "request.open('GET', url, true);\n"
94.114 + + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
94.115 + + "request.onreadystatechange = function() {\n"
94.116 + + " if (this.readyState!==4) return;\n"
94.117 + + " try {\n"
94.118 + + " arr[0] = this.responseText;\n"
94.119 + + " callback.run();\n"
94.120 + + " } catch (e) { alert(e); }\n"
94.121 + + "};\n"
94.122 + + "request.send();\n"
94.123 + )
94.124 + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
94.125 +
94.126 + public static void runHarness(String url) throws IOException {
94.127 + new Console().harness(url);
94.128 + }
94.129 +
94.130 + public void harness(String url) throws IOException {
94.131 + log("Connecting to " + url);
94.132 + Request r = new Request(url);
94.133 + }
94.134 +
94.135 + private static class Request implements Runnable {
94.136 + private final String[] arr = { null };
94.137 + private final String url;
94.138 + private Case c;
94.139 + private int retries;
94.140 +
94.141 + private Request(String url) throws IOException {
94.142 + this.url = url;
94.143 + loadText(url, new Run(this), arr);
94.144 + }
94.145 + private Request(String url, String u) throws IOException {
94.146 + this.url = url;
94.147 + loadText(u, new Run(this), arr);
94.148 + }
94.149 +
94.150 + @Override
94.151 + public void run() {
94.152 + Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
94.153 + try {
94.154 + if (c == null) {
94.155 + String data = arr[0];
94.156 +
94.157 + if (data == null) {
94.158 + log("Some error exiting");
94.159 + closeWindow();
94.160 + return;
94.161 + }
94.162 +
94.163 + if (data.isEmpty()) {
94.164 + log("No data, exiting");
94.165 + closeWindow();
94.166 + return;
94.167 + }
94.168 +
94.169 + c = Case.parseData(data);
94.170 + beginTest(c);
94.171 + log("Got \"" + data + "\"");
94.172 + } else {
94.173 + log("Processing \"" + arr[0] + "\" for " + retries + " time");
94.174 + }
94.175 + Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest();
94.176 + finishTest(c, result);
94.177 +
94.178 + String u = url + "?request=" + c.getRequestId() + "&result=" + result;
94.179 + new Request(url, u);
94.180 + } catch (Exception ex) {
94.181 + if (ex instanceof InterruptedException) {
94.182 + log("Re-scheduling in 100ms");
94.183 + schedule(new Run(this), 100);
94.184 + return;
94.185 + }
94.186 + log(ex.getClass().getName() + ":" + ex.getMessage());
94.187 + }
94.188 + }
94.189 + }
94.190 +
94.191 + private static String encodeURL(String r) throws UnsupportedEncodingException {
94.192 + final String SPECIAL = "%$&+,/:;=?@";
94.193 + StringBuilder sb = new StringBuilder();
94.194 + byte[] utf8 = r.getBytes("UTF-8");
94.195 + for (int i = 0; i < utf8.length; i++) {
94.196 + int ch = utf8[i] & 0xff;
94.197 + if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) {
94.198 + final String numbers = "0" + Integer.toHexString(ch);
94.199 + sb.append("%").append(numbers.substring(numbers.length() - 2));
94.200 + } else {
94.201 + if (ch == 32) {
94.202 + sb.append("+");
94.203 + } else {
94.204 + sb.append((char)ch);
94.205 + }
94.206 + }
94.207 + }
94.208 + return sb.toString();
94.209 + }
94.210 +
94.211 + static String invoke(String clazz, String method) throws
94.212 + ClassNotFoundException, InvocationTargetException, IllegalAccessException,
94.213 + InstantiationException, InterruptedException {
94.214 + final Object r = new Case(null).invokeMethod(clazz, method);
94.215 + return r == null ? "null" : r.toString().toString();
94.216 + }
94.217 +
94.218 + /** Helper method that inspects the classpath and loads given resource
94.219 + * (usually a class file). Used while running tests in Rhino.
94.220 + *
94.221 + * @param name resource name to find
94.222 + * @return the array of bytes in the given resource
94.223 + * @throws IOException I/O in case something goes wrong
94.224 + */
94.225 + public static byte[] read(String name) throws IOException {
94.226 + URL u = null;
94.227 + Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
94.228 + while (en.hasMoreElements()) {
94.229 + u = en.nextElement();
94.230 + }
94.231 + if (u == null) {
94.232 + throw new IOException("Can't find " + name);
94.233 + }
94.234 + InputStream is = null;
94.235 + try {
94.236 + is = u.openStream();
94.237 + byte[] arr;
94.238 + arr = new byte[is.available()];
94.239 + int offset = 0;
94.240 + while (offset < arr.length) {
94.241 + int len = is.read(arr, offset, arr.length - offset);
94.242 + if (len == -1) {
94.243 + throw new IOException("Can't read " + name);
94.244 + }
94.245 + offset += len;
94.246 + }
94.247 + return arr;
94.248 + } finally {
94.249 + if (is != null) is.close();
94.250 + }
94.251 + }
94.252 +
94.253 + private static void turnAssetionStatusOn() {
94.254 + }
94.255 +
94.256 + @JavaScriptBody(args = { "r", "time" }, body = "return window.setTimeout(function() { r.run(); }, time);")
94.257 + private static native Object schedule(Runnable r, int time);
94.258 +
94.259 + private static final class Case {
94.260 + private final Object data;
94.261 + private Object inst;
94.262 +
94.263 + private Case(Object data) {
94.264 + this.data = data;
94.265 + }
94.266 +
94.267 + public static Case parseData(String s) {
94.268 + return new Case(toJSON(s));
94.269 + }
94.270 +
94.271 + public String getMethodName() {
94.272 + return (String) value("methodName", data);
94.273 + }
94.274 +
94.275 + public String getClassName() {
94.276 + return (String) value("className", data);
94.277 + }
94.278 +
94.279 + public int getRequestId() {
94.280 + Object v = value("request", data);
94.281 + if (v instanceof Number) {
94.282 + return ((Number)v).intValue();
94.283 + }
94.284 + return Integer.parseInt(v.toString());
94.285 + }
94.286 +
94.287 + public String getHtmlFragment() {
94.288 + return (String) value("html", data);
94.289 + }
94.290 +
94.291 + void again(Object[] arr) {
94.292 + try {
94.293 + textArea = arr[0];
94.294 + statusArea = arr[1];
94.295 + setAttr(textArea, "value", "");
94.296 + runTest();
94.297 + } catch (Exception ex) {
94.298 + log(ex.getClass().getName() + ":" + ex.getMessage());
94.299 + }
94.300 + }
94.301 +
94.302 + private Object runTest() throws IllegalAccessException,
94.303 + IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException,
94.304 + InvocationTargetException, InstantiationException, InterruptedException {
94.305 + if (this.getHtmlFragment() != null) {
94.306 + setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment());
94.307 + }
94.308 + log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId());
94.309 + Object result = invokeMethod(this.getClassName(), this.getMethodName());
94.310 + setAttr("bck2brwsr.fragment", "innerHTML", "");
94.311 + log("Result: " + result);
94.312 + result = encodeURL("" + result);
94.313 + log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result);
94.314 + return result;
94.315 + }
94.316 +
94.317 + private Object invokeMethod(String clazz, String method)
94.318 + throws ClassNotFoundException, InvocationTargetException,
94.319 + InterruptedException, IllegalAccessException, IllegalArgumentException,
94.320 + InstantiationException {
94.321 + Method found = null;
94.322 + Class<?> c = Class.forName(clazz);
94.323 + for (Method m : c.getMethods()) {
94.324 + if (m.getName().equals(method)) {
94.325 + found = m;
94.326 + }
94.327 + }
94.328 + Object res;
94.329 + if (found != null) {
94.330 + try {
94.331 + if ((found.getModifiers() & Modifier.STATIC) != 0) {
94.332 + res = found.invoke(null);
94.333 + } else {
94.334 + if (inst == null) {
94.335 + inst = c.newInstance();
94.336 + }
94.337 + res = found.invoke(inst);
94.338 + }
94.339 + } catch (Throwable ex) {
94.340 + if (ex instanceof InvocationTargetException) {
94.341 + ex = ((InvocationTargetException) ex).getTargetException();
94.342 + }
94.343 + if (ex instanceof InterruptedException) {
94.344 + throw (InterruptedException)ex;
94.345 + }
94.346 + res = ex.getClass().getName() + ":" + ex.getMessage();
94.347 + }
94.348 + } else {
94.349 + res = "Can't find method " + method + " in " + clazz;
94.350 + }
94.351 + return res;
94.352 + }
94.353 +
94.354 + @JavaScriptBody(args = { "s" }, body = "return eval('(' + s + ')');")
94.355 + private static native Object toJSON(String s);
94.356 +
94.357 + private static Object value(String p, Object d) {
94.358 + return ((JSObject)d).getMember(p);
94.359 + }
94.360 + }
94.361 +
94.362 + static {
94.363 + turnAssetionStatusOn();
94.364 + }
94.365 +}
95.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java Mon Oct 07 14:20:58 2013 +0200
95.3 @@ -0,0 +1,177 @@
95.4 +/**
95.5 + * Back 2 Browser Bytecode Translator
95.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
95.7 + *
95.8 + * This program is free software: you can redistribute it and/or modify
95.9 + * it under the terms of the GNU General Public License as published by
95.10 + * the Free Software Foundation, version 2 of the License.
95.11 + *
95.12 + * This program is distributed in the hope that it will be useful,
95.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
95.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95.15 + * GNU General Public License for more details.
95.16 + *
95.17 + * You should have received a copy of the GNU General Public License
95.18 + * along with this program. Look for COPYING file in the top folder.
95.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
95.20 + */
95.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
95.22 +
95.23 +import java.util.List;
95.24 +import java.util.TooManyListenersException;
95.25 +import java.util.logging.Level;
95.26 +import java.util.logging.Logger;
95.27 +import javafx.application.Application;
95.28 +import javafx.application.Platform;
95.29 +import javafx.beans.value.ChangeListener;
95.30 +import javafx.beans.value.ObservableValue;
95.31 +import javafx.event.ActionEvent;
95.32 +import javafx.event.EventHandler;
95.33 +import javafx.geometry.Insets;
95.34 +import javafx.geometry.Pos;
95.35 +import javafx.scene.Scene;
95.36 +import javafx.scene.control.Button;
95.37 +import javafx.scene.control.ToolBar;
95.38 +import javafx.scene.layout.BorderPane;
95.39 +import javafx.scene.layout.HBox;
95.40 +import javafx.scene.layout.VBox;
95.41 +import javafx.scene.text.Text;
95.42 +import javafx.scene.web.WebEngine;
95.43 +import javafx.scene.web.WebEvent;
95.44 +import javafx.scene.web.WebView;
95.45 +import javafx.stage.Modality;
95.46 +import javafx.stage.Stage;
95.47 +import netscape.javascript.JSObject;
95.48 +
95.49 +/**
95.50 + * Demonstrates a WebView object accessing a web page.
95.51 + *
95.52 + * @see javafx.scene.web.WebView
95.53 + * @see javafx.scene.web.WebEngine
95.54 + */
95.55 +public class FXBrwsr extends Application {
95.56 + private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
95.57 +
95.58 + @Override
95.59 + public void start(Stage primaryStage) throws Exception {
95.60 + WebView view = new WebView();
95.61 + WebController wc = new WebController(view, getParameters().getUnnamed());
95.62 +
95.63 + FXInspect.initialize(view.getEngine());
95.64 +
95.65 + final VBox vbox = new VBox();
95.66 + vbox.setAlignment( Pos.CENTER );
95.67 + vbox.setStyle( "-fx-background-color: #808080;");
95.68 +
95.69 +
95.70 + HBox hbox = new HBox();
95.71 + hbox.setStyle( "-fx-background-color: #808080;");
95.72 + hbox.setAlignment(Pos.CENTER);
95.73 + hbox.getChildren().add(vbox);
95.74 + vbox.getChildren().add(view);
95.75 +
95.76 + BorderPane root = new BorderPane();
95.77 + final boolean showToolbar = "true".equals(this.getParameters().getNamed().get("toolbar")); // NOI18N
95.78 + final boolean useFirebug = "true".equals(this.getParameters().getNamed().get("firebug")); // NOI18N
95.79 + if (showToolbar) {
95.80 + final ToolBar toolbar = new BrowserToolbar(view, vbox, useFirebug);
95.81 + root.setTop( toolbar );
95.82 + }
95.83 + root.setCenter(hbox);
95.84 +
95.85 + Scene scene = new Scene(root, 800, 600);
95.86 +
95.87 + primaryStage.setTitle( "Device Emulator" );
95.88 + primaryStage.setScene( scene );
95.89 + primaryStage.show();
95.90 + }
95.91 +
95.92 + /**
95.93 + * Create a resizable WebView pane
95.94 + */
95.95 + private static class WebController {
95.96 + private final JVMBridge bridge;
95.97 +
95.98 + public WebController(WebView view, List<String> params) {
95.99 + this.bridge = new JVMBridge(view.getEngine());
95.100 + LOG.log(Level.INFO, "Initializing WebView with {0}", params);
95.101 + final WebEngine eng = view.getEngine();
95.102 + try {
95.103 + JVMBridge.addBck2BrwsrLoad(new InitBck2Brwsr(eng));
95.104 + } catch (TooManyListenersException ex) {
95.105 + LOG.log(Level.SEVERE, null, ex);
95.106 + }
95.107 +
95.108 + if (params.size() > 0) {
95.109 + LOG.log(Level.INFO, "loading page {0}", params.get(0));
95.110 + eng.load(params.get(0));
95.111 + LOG.fine("back from load");
95.112 + }
95.113 + eng.setOnAlert(new EventHandler<WebEvent<String>>() {
95.114 + @Override
95.115 + public void handle(WebEvent<String> t) {
95.116 + final Stage dialogStage = new Stage();
95.117 + dialogStage.initModality(Modality.WINDOW_MODAL);
95.118 + dialogStage.setTitle("Warning");
95.119 + final Button button = new Button("Close");
95.120 + final Text text = new Text(t.getData());
95.121 +
95.122 + VBox box = new VBox();
95.123 + box.setAlignment(Pos.CENTER);
95.124 + box.setSpacing(10);
95.125 + box.setPadding(new Insets(10));
95.126 + box.getChildren().addAll(text, button);
95.127 +
95.128 + dialogStage.setScene(new Scene(box));
95.129 +
95.130 + button.setCancelButton(true);
95.131 + button.setOnAction(new EventHandler<ActionEvent>() {
95.132 + @Override
95.133 + public void handle(ActionEvent t) {
95.134 + dialogStage.close();
95.135 + }
95.136 + });
95.137 +
95.138 + dialogStage.centerOnScreen();
95.139 + dialogStage.showAndWait();
95.140 + }
95.141 + });
95.142 + }
95.143 +
95.144 + boolean initBck2Brwsr(WebEngine webEngine) {
95.145 + JSObject jsobj = (JSObject) webEngine.executeScript("window");
95.146 + LOG.log(Level.FINE, "window: {0}", jsobj);
95.147 + Object prev = jsobj.getMember("bck2brwsr");
95.148 + if ("undefined".equals(prev)) {
95.149 + jsobj.setMember("bck2brwsr", bridge);
95.150 + return true;
95.151 + }
95.152 + return false;
95.153 + }
95.154 +
95.155 + private class InitBck2Brwsr implements ChangeListener<Void>, Runnable {
95.156 + private final WebEngine eng;
95.157 +
95.158 + public InitBck2Brwsr(WebEngine eng) {
95.159 + this.eng = eng;
95.160 + }
95.161 +
95.162 + @Override
95.163 + public synchronized void changed(ObservableValue<? extends Void> ov, Void t, Void t1) {
95.164 + Platform.runLater(this);
95.165 + try {
95.166 + wait();
95.167 + } catch (InterruptedException ex) {
95.168 + LOG.log(Level.SEVERE, null, ex);
95.169 + }
95.170 + }
95.171 +
95.172 + @Override
95.173 + public synchronized void run() {
95.174 + initBck2Brwsr(eng);
95.175 + notifyAll();
95.176 + }
95.177 + }
95.178 + }
95.179 +
95.180 +}
96.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
96.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXInspect.java Mon Oct 07 14:20:58 2013 +0200
96.3 @@ -0,0 +1,112 @@
96.4 +/**
96.5 + * Back 2 Browser Bytecode Translator
96.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
96.7 + *
96.8 + * This program is free software: you can redistribute it and/or modify
96.9 + * it under the terms of the GNU General Public License as published by
96.10 + * the Free Software Foundation, version 2 of the License.
96.11 + *
96.12 + * This program is distributed in the hope that it will be useful,
96.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
96.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96.15 + * GNU General Public License for more details.
96.16 + *
96.17 + * You should have received a copy of the GNU General Public License
96.18 + * along with this program. Look for COPYING file in the top folder.
96.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
96.20 + */
96.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
96.22 +
96.23 +import com.sun.javafx.scene.web.Debugger;
96.24 +import java.io.IOException;
96.25 +import java.io.ObjectInputStream;
96.26 +import java.io.ObjectOutputStream;
96.27 +import java.net.InetAddress;
96.28 +import java.net.Socket;
96.29 +import java.nio.charset.StandardCharsets;
96.30 +import java.util.logging.Level;
96.31 +import java.util.logging.Logger;
96.32 +import javafx.application.Platform;
96.33 +import javafx.scene.web.WebEngine;
96.34 +import javafx.util.Callback;
96.35 +import org.openide.util.Exceptions;
96.36 +
96.37 +/**
96.38 + *
96.39 + * @author Jaroslav Tulach <jtulach@netbeans.org>
96.40 + */
96.41 +final class FXInspect implements Runnable {
96.42 + private static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
96.43 +
96.44 +
96.45 + private final WebEngine engine;
96.46 + private final ObjectInputStream input;
96.47 +
96.48 + private FXInspect(WebEngine engine, int port) throws IOException {
96.49 + this.engine = engine;
96.50 +
96.51 + Socket socket = new Socket(InetAddress.getByName(null), port);
96.52 + ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
96.53 + this.input = new ObjectInputStream(socket.getInputStream());
96.54 + initializeDebugger(output);
96.55 + }
96.56 +
96.57 + static boolean initialize(WebEngine engine) {
96.58 + final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
96.59 + if (inspectPort != -1) {
96.60 + try {
96.61 + FXInspect inspector = new FXInspect(engine, inspectPort);
96.62 + Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
96.63 + t.start();
96.64 + return true;
96.65 + } catch (IOException ex) {
96.66 + LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
96.67 + }
96.68 + }
96.69 + return false;
96.70 + }
96.71 +
96.72 + private void initializeDebugger(final ObjectOutputStream output) {
96.73 + Platform.runLater(new Runnable() {
96.74 + @Override
96.75 + public void run() {
96.76 + Debugger debugger = engine.impl_getDebugger();
96.77 + debugger.setEnabled(true);
96.78 + debugger.setMessageCallback(new Callback<String,Void>() {
96.79 + @Override
96.80 + public Void call(String message) {
96.81 + try {
96.82 + byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
96.83 + output.writeInt(bytes.length);
96.84 + output.write(bytes);
96.85 + output.flush();
96.86 + } catch (IOException ioex) {
96.87 + ioex.printStackTrace();
96.88 + }
96.89 + return null;
96.90 + }
96.91 + });
96.92 + }
96.93 + });
96.94 + }
96.95 +
96.96 + @Override
96.97 + public void run() {
96.98 + try {
96.99 + while (true) {
96.100 + int length = input.readInt();
96.101 + byte[] bytes = new byte[length];
96.102 + input.readFully(bytes);
96.103 + final String message = new String(bytes, StandardCharsets.UTF_8);
96.104 + Platform.runLater(new Runnable() {
96.105 + @Override
96.106 + public void run() {
96.107 + engine.impl_getDebugger().sendMessage(message);
96.108 + }
96.109 + });
96.110 + }
96.111 + } catch (IOException ioex) {
96.112 + ioex.printStackTrace();
96.113 + }
96.114 + }
96.115 +}
97.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
97.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Mon Oct 07 14:20:58 2013 +0200
97.3 @@ -0,0 +1,152 @@
97.4 +/**
97.5 + * Back 2 Browser Bytecode Translator
97.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
97.7 + *
97.8 + * This program is free software: you can redistribute it and/or modify
97.9 + * it under the terms of the GNU General Public License as published by
97.10 + * the Free Software Foundation, version 2 of the License.
97.11 + *
97.12 + * This program is distributed in the hope that it will be useful,
97.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
97.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
97.15 + * GNU General Public License for more details.
97.16 + *
97.17 + * You should have received a copy of the GNU General Public License
97.18 + * along with this program. Look for COPYING file in the top folder.
97.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
97.20 + */
97.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
97.22 +
97.23 +import java.io.BufferedReader;
97.24 +import java.io.Reader;
97.25 +import org.apidesign.html.boot.spi.Fn;
97.26 +import java.net.URL;
97.27 +import java.util.ArrayList;
97.28 +import java.util.Arrays;
97.29 +import java.util.Collection;
97.30 +import java.util.List;
97.31 +import java.util.TooManyListenersException;
97.32 +import javafx.beans.value.ChangeListener;
97.33 +import javafx.scene.web.WebEngine;
97.34 +import netscape.javascript.JSObject;
97.35 +import org.apidesign.html.boot.impl.FindResources;
97.36 +import org.apidesign.html.boot.impl.FnUtils;
97.37 +
97.38 +/**
97.39 + *
97.40 + * @author Jaroslav Tulach <jtulach@netbeans.org>
97.41 + */
97.42 +public final class JVMBridge {
97.43 + private final WebEngine engine;
97.44 + private final ClassLoader cl;
97.45 + private final WebPresenter presenter;
97.46 +
97.47 + private static ClassLoader[] ldrs;
97.48 + private static ChangeListener<Void> onBck2BrwsrLoad;
97.49 +
97.50 + JVMBridge(WebEngine eng) {
97.51 + this.engine = eng;
97.52 + final ClassLoader p = JVMBridge.class.getClassLoader().getParent();
97.53 + this.presenter = new WebPresenter();
97.54 + this.cl = FnUtils.newLoader(presenter, presenter, p);
97.55 + }
97.56 +
97.57 + public static void registerClassLoaders(ClassLoader[] loaders) {
97.58 + ldrs = loaders.clone();
97.59 + }
97.60 +
97.61 + public static void addBck2BrwsrLoad(ChangeListener<Void> l) throws TooManyListenersException {
97.62 + if (onBck2BrwsrLoad != null) {
97.63 + throw new TooManyListenersException();
97.64 + }
97.65 + onBck2BrwsrLoad = l;
97.66 + }
97.67 +
97.68 + public static void onBck2BrwsrLoad() {
97.69 + ChangeListener<Void> l = onBck2BrwsrLoad;
97.70 + if (l != null) {
97.71 + l.changed(null, null, null);
97.72 + }
97.73 + }
97.74 +
97.75 + public Class<?> loadClass(String name) throws ClassNotFoundException {
97.76 + FnUtils.currentPresenter(presenter);
97.77 + return Class.forName(name, true, cl);
97.78 + }
97.79 +
97.80 + private final class WebPresenter implements FindResources, Fn.Presenter {
97.81 + @Override
97.82 + public void findResources(String name, Collection<? super URL> results, boolean oneIsEnough) {
97.83 + if (ldrs != null) for (ClassLoader l : ldrs) {
97.84 + URL u = l.getResource(name);
97.85 + if (u != null) {
97.86 + results.add(u);
97.87 + }
97.88 + }
97.89 + }
97.90 +
97.91 + @Override
97.92 + public Fn defineFn(String code, String... names) {
97.93 + StringBuilder sb = new StringBuilder();
97.94 + sb.append("(function() {");
97.95 + sb.append(" return function(");
97.96 + String sep = "";
97.97 + for (String n : names) {
97.98 + sb.append(sep).append(n);
97.99 + sep = ",";
97.100 + }
97.101 + sb.append(") {\n");
97.102 + sb.append(code);
97.103 + sb.append("};");
97.104 + sb.append("})()");
97.105 +
97.106 + JSObject x = (JSObject) engine.executeScript(sb.toString());
97.107 + return new JSFn(this, x);
97.108 + }
97.109 +
97.110 + @Override
97.111 + public void displayPage(URL page, Runnable onPageLoad) {
97.112 + throw new UnsupportedOperationException("Not supported yet.");
97.113 + }
97.114 +
97.115 + @Override
97.116 + public void loadScript(Reader code) throws Exception {
97.117 + BufferedReader r = new BufferedReader(code);
97.118 + StringBuilder sb = new StringBuilder();
97.119 + for (;;) {
97.120 + String l = r.readLine();
97.121 + if (l == null) {
97.122 + break;
97.123 + }
97.124 + sb.append(l).append('\n');
97.125 + }
97.126 + engine.executeScript(sb.toString());
97.127 + }
97.128 + }
97.129 +
97.130 + private static final class JSFn extends Fn {
97.131 + private final JSObject fn;
97.132 +
97.133 + private JSFn(WebPresenter cl, JSObject fn) {
97.134 + super(cl);
97.135 + this.fn = fn;
97.136 + }
97.137 +
97.138 + @Override
97.139 + public Object invoke(Object thiz, Object... args) throws Exception {
97.140 + try {
97.141 + List<Object> all = new ArrayList<Object>(args.length + 1);
97.142 + all.add(thiz == null ? fn : thiz);
97.143 + all.addAll(Arrays.asList(args));
97.144 + Object ret = fn.call("call", all.toArray()); // NOI18N
97.145 + return ret == fn ? null : ret;
97.146 + } catch (Error t) {
97.147 + t.printStackTrace();
97.148 + throw t;
97.149 + } catch (Exception t) {
97.150 + t.printStackTrace();
97.151 + throw t;
97.152 + }
97.153 + }
97.154 + }
97.155 +}
98.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
98.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java Mon Oct 07 14:20:58 2013 +0200
98.3 @@ -0,0 +1,35 @@
98.4 +/**
98.5 + * Back 2 Browser Bytecode Translator
98.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
98.7 + *
98.8 + * This program is free software: you can redistribute it and/or modify
98.9 + * it under the terms of the GNU General Public License as published by
98.10 + * the Free Software Foundation, version 2 of the License.
98.11 + *
98.12 + * This program is distributed in the hope that it will be useful,
98.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
98.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98.15 + * GNU General Public License for more details.
98.16 + *
98.17 + * You should have received a copy of the GNU General Public License
98.18 + * along with this program. Look for COPYING file in the top folder.
98.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
98.20 + */
98.21 +
98.22 +package org.apidesign.bck2brwsr.launcher.fximpl;
98.23 +
98.24 +/**
98.25 + *
98.26 + * @author Jaroslav Tulach <jtulach@netbeans.org>
98.27 + */
98.28 +public final class Run implements Runnable {
98.29 + private final Runnable r;
98.30 + Run(Runnable r) {
98.31 + this.r = r;
98.32 + }
98.33 +
98.34 + @Override
98.35 + public void run() {
98.36 + r.run();
98.37 + }
98.38 +}
99.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/desktop.png has changed
100.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/firebug.png has changed
101.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/handheldLandscape.png has changed
102.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/handheldPortrait.png has changed
103.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103.2 +++ b/launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/harness.xhtml Mon Oct 07 14:20:58 2013 +0200
103.3 @@ -0,0 +1,52 @@
103.4 +<?xml version="1.0" encoding="UTF-8"?>
103.5 +<!--
103.6 +
103.7 + Back 2 Browser Bytecode Translator
103.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
103.9 +
103.10 + This program is free software: you can redistribute it and/or modify
103.11 + it under the terms of the GNU General Public License as published by
103.12 + the Free Software Foundation, version 2 of the License.
103.13 +
103.14 + This program is distributed in the hope that it will be useful,
103.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
103.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
103.17 + GNU General Public License for more details.
103.18 +
103.19 + You should have received a copy of the GNU General Public License
103.20 + along with this program. Look for COPYING file in the top folder.
103.21 + If not, see http://opensource.org/licenses/GPL-2.0.
103.22 +
103.23 +-->
103.24 +<!DOCTYPE html>
103.25 +<html xmlns="http://www.w3.org/1999/xhtml">
103.26 + <head>
103.27 + <title>Bck2Brwsr Harness</title>
103.28 + </head>
103.29 + <body>
103.30 + <script src="/bck2brwsr.js"></script>
103.31 + <script>
103.32 + var vm = bck2brwsr();
103.33 + </script>
103.34 +
103.35 + <h1>Bck2Brwsr Execution Harness</h1>
103.36 +
103.37 + <ul id="bck2brwsr.result" style="width: 100%;" >
103.38 + </ul>
103.39 +
103.40 + <div id="bck2brwsr.fragment"/>
103.41 +
103.42 + <script type="text/javascript">
103.43 + try {
103.44 + (function() {
103.45 + var cls = vm.loadClass('org.apidesign.bck2brwsr.launcher.fximpl.Console');
103.46 + // fxbrwsr mangling
103.47 + var inst = cls.newInstance();
103.48 + inst.harness('$U/../data');
103.49 + })();
103.50 + } catch (err) {
103.51 + alert('Error executing harness: ' + err);
103.52 + }
103.53 + </script>
103.54 + </body>
103.55 +</html>
104.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/netbook.png has changed
105.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/selectionMode.png has changed
106.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/sizeToFit.png has changed
107.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/tabletLandscape.png has changed
108.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/tabletPortrait.png has changed
109.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/widescreen.png has changed
110.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
110.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java Mon Oct 07 14:20:58 2013 +0200
110.3 @@ -0,0 +1,182 @@
110.4 +/**
110.5 + * Back 2 Browser Bytecode Translator
110.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
110.7 + *
110.8 + * This program is free software: you can redistribute it and/or modify
110.9 + * it under the terms of the GNU General Public License as published by
110.10 + * the Free Software Foundation, version 2 of the License.
110.11 + *
110.12 + * This program is distributed in the hope that it will be useful,
110.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
110.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110.15 + * GNU General Public License for more details.
110.16 + *
110.17 + * You should have received a copy of the GNU General Public License
110.18 + * along with this program. Look for COPYING file in the top folder.
110.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
110.20 + */
110.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
110.22 +
110.23 +import java.io.Reader;
110.24 +import java.lang.reflect.InvocationTargetException;
110.25 +import java.lang.reflect.Method;
110.26 +import java.net.URL;
110.27 +import java.net.URLClassLoader;
110.28 +import java.util.ArrayList;
110.29 +import java.util.Arrays;
110.30 +import java.util.Collection;
110.31 +import java.util.List;
110.32 +import javax.script.Invocable;
110.33 +import javax.script.ScriptEngine;
110.34 +import javax.script.ScriptEngineManager;
110.35 +import javax.script.ScriptException;
110.36 +import org.apidesign.html.boot.spi.Fn;
110.37 +import org.apidesign.html.boot.impl.FindResources;
110.38 +import org.apidesign.html.boot.impl.FnUtils;
110.39 +import static org.testng.Assert.*;
110.40 +import org.testng.annotations.BeforeClass;
110.41 +import org.testng.annotations.BeforeMethod;
110.42 +import org.testng.annotations.Test;
110.43 +
110.44 +/**
110.45 + *
110.46 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
110.47 + */
110.48 +public class JsClassLoaderTest {
110.49 + private static ClassLoader loader;
110.50 + private static Class<?> methodClass;
110.51 + private static Fn.Presenter presenter;
110.52 +
110.53 + public JsClassLoaderTest() {
110.54 + }
110.55 +
110.56 + @BeforeClass
110.57 + public static void setUpClass() throws Exception {
110.58 + ScriptEngineManager sem = new ScriptEngineManager();
110.59 + final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
110.60 +
110.61 + final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
110.62 + ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
110.63 + final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
110.64 + class Fr implements FindResources, Fn.Presenter {
110.65 + @Override
110.66 + public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
110.67 + URL u = ul.getResource(path);
110.68 + if (u != null) {
110.69 + results.add(u);
110.70 + }
110.71 + }
110.72 +
110.73 + @Override
110.74 + public Fn defineFn(String code, String... names) {
110.75 + StringBuilder sb = new StringBuilder();
110.76 + sb.append("(function() {");
110.77 + sb.append("return function(");
110.78 + String sep = "";
110.79 + for (String n : names) {
110.80 + sb.append(sep);
110.81 + sb.append(n);
110.82 + sep = ", ";
110.83 + }
110.84 + sb.append(") {");
110.85 + sb.append(code);
110.86 + sb.append("};");
110.87 + sb.append("})()");
110.88 + try {
110.89 + final Object val = eng.eval(sb.toString());
110.90 + return new Fn(this) {
110.91 + @Override
110.92 + public Object invoke(Object thiz, Object... args) throws Exception {
110.93 + List<Object> all = new ArrayList<Object>(args.length + 1);
110.94 + all.add(thiz == null ? val : thiz);
110.95 + all.addAll(Arrays.asList(args));
110.96 + Invocable inv = (Invocable)eng;
110.97 + Object ret = inv.invokeMethod(val, "call", all.toArray());
110.98 + return ret == val ? null : ret;
110.99 + }
110.100 + };
110.101 + } catch (ScriptException ex) {
110.102 + throw new LinkageError("Can't parse: " + sb, ex);
110.103 + }
110.104 + }
110.105 +
110.106 + @Override
110.107 + public void displayPage(URL page, Runnable onPageLoad) {
110.108 + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
110.109 + }
110.110 +
110.111 + @Override
110.112 + public void loadScript(Reader code) throws Exception {
110.113 + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
110.114 + }
110.115 + }
110.116 +
110.117 + Fr fr = new Fr();
110.118 + presenter = fr;
110.119 + loader = FnUtils.newLoader(fr, fr, parent);
110.120 + methodClass = loader.loadClass(JsMethods.class.getName());
110.121 + }
110.122 +
110.123 + @BeforeMethod public void registerPresenter() {
110.124 + FnUtils.currentPresenter(presenter);
110.125 + }
110.126 +
110.127 + @Test public void noParamMethod() throws Throwable {
110.128 + Method plus = methodClass.getMethod("fortyTwo");
110.129 + try {
110.130 + final Object val = plus.invoke(null);
110.131 + assertTrue(val instanceof Number, "A number returned " + val);
110.132 + assertEquals(((Number)val).intValue(), 42);
110.133 + } catch (InvocationTargetException ex) {
110.134 + throw ex.getTargetException();
110.135 + }
110.136 + }
110.137 +
110.138 + @Test public void testExecuteScript() throws Throwable {
110.139 + Method plus = methodClass.getMethod("plus", int.class, int.class);
110.140 + try {
110.141 + assertEquals(plus.invoke(null, 10, 20), 30);
110.142 + } catch (InvocationTargetException ex) {
110.143 + throw ex.getTargetException();
110.144 + }
110.145 + }
110.146 +
110.147 + @Test public void overloadedMethod() throws Throwable {
110.148 + Method plus = methodClass.getMethod("plus", int.class);
110.149 + try {
110.150 + assertEquals(plus.invoke(null, 10), 10);
110.151 + } catch (InvocationTargetException ex) {
110.152 + throw ex.getTargetException();
110.153 + }
110.154 + }
110.155 +
110.156 + @Test public void instanceMethod() throws Throwable {
110.157 + Method plus = methodClass.getMethod("plusInst", int.class);
110.158 + Object inst = methodClass.newInstance();
110.159 + try {
110.160 + assertEquals(plus.invoke(inst, 10), 10);
110.161 + } catch (InvocationTargetException ex) {
110.162 + throw ex.getTargetException();
110.163 + }
110.164 + }
110.165 +
110.166 + @Test public void staticThis() throws Throwable {
110.167 + Method st = methodClass.getMethod("staticThis");
110.168 + try {
110.169 + assertNull(st.invoke(null));
110.170 + } catch (InvocationTargetException ex) {
110.171 + throw ex.getTargetException();
110.172 + }
110.173 + }
110.174 +
110.175 + @Test public void getThis() throws Throwable {
110.176 + Object th = methodClass.newInstance();
110.177 + Method st = methodClass.getMethod("getThis");
110.178 + try {
110.179 + assertEquals(st.invoke(th), th);
110.180 + } catch (InvocationTargetException ex) {
110.181 + throw ex.getTargetException();
110.182 + }
110.183 + }
110.184 +
110.185 +}
110.186 \ No newline at end of file
111.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
111.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsMethods.java Mon Oct 07 14:20:58 2013 +0200
111.3 @@ -0,0 +1,45 @@
111.4 +/**
111.5 + * Back 2 Browser Bytecode Translator
111.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
111.7 + *
111.8 + * This program is free software: you can redistribute it and/or modify
111.9 + * it under the terms of the GNU General Public License as published by
111.10 + * the Free Software Foundation, version 2 of the License.
111.11 + *
111.12 + * This program is distributed in the hope that it will be useful,
111.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
111.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111.15 + * GNU General Public License for more details.
111.16 + *
111.17 + * You should have received a copy of the GNU General Public License
111.18 + * along with this program. Look for COPYING file in the top folder.
111.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
111.20 + */
111.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
111.22 +
111.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
111.24 +
111.25 +/**
111.26 + *
111.27 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
111.28 + */
111.29 +public class JsMethods {
111.30 + @JavaScriptBody(args = {}, body = "return 42;")
111.31 + public static Object fortyTwo() {
111.32 + return -42;
111.33 + }
111.34 +
111.35 + @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
111.36 + public static native int plus(int x, int y);
111.37 +
111.38 + @JavaScriptBody(args = {"x"}, body = "return x;")
111.39 + public static native int plus(int x);
111.40 +
111.41 + @JavaScriptBody(args = {}, body = "return this;")
111.42 + public static native Object staticThis();
111.43 +
111.44 + @JavaScriptBody(args = {}, body = "return this;")
111.45 + public native Object getThis();
111.46 + @JavaScriptBody(args = {"x"}, body = "return x;")
111.47 + public native int plusInst(int x);
111.48 +}
112.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
112.2 +++ b/launcher/http/pom.xml Mon Oct 07 14:20:58 2013 +0200
112.3 @@ -0,0 +1,60 @@
112.4 +<?xml version="1.0"?>
112.5 +<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/xsd/maven-4.0.0.xsd">
112.6 + <modelVersion>4.0.0</modelVersion>
112.7 + <parent>
112.8 + <groupId>org.apidesign.bck2brwsr</groupId>
112.9 + <artifactId>launcher-pom</artifactId>
112.10 + <version>0.9-SNAPSHOT</version>
112.11 + </parent>
112.12 + <groupId>org.apidesign.bck2brwsr</groupId>
112.13 + <artifactId>launcher.http</artifactId>
112.14 + <version>0.9-SNAPSHOT</version>
112.15 + <name>Bck2Brwsr Launcher</name>
112.16 + <url>http://maven.apache.org</url>
112.17 + <build>
112.18 + <plugins>
112.19 + <plugin>
112.20 + <groupId>org.apache.maven.plugins</groupId>
112.21 + <artifactId>maven-compiler-plugin</artifactId>
112.22 + <version>2.3.2</version>
112.23 + <configuration>
112.24 + <source>1.7</source>
112.25 + <target>1.7</target>
112.26 + </configuration>
112.27 + </plugin>
112.28 + <plugin>
112.29 + <groupId>org.apache.maven.plugins</groupId>
112.30 + <artifactId>maven-javadoc-plugin</artifactId>
112.31 + <configuration>
112.32 + <subpackages>org.apidesign.bck2brwsr.launcher.b2b</subpackages>
112.33 + <skip>false</skip>
112.34 + </configuration>
112.35 + </plugin>
112.36 + </plugins>
112.37 + </build>
112.38 + <properties>
112.39 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
112.40 + </properties>
112.41 + <dependencies>
112.42 + <dependency>
112.43 + <groupId>${project.groupId}</groupId>
112.44 + <artifactId>launcher</artifactId>
112.45 + <version>${project.version}</version>
112.46 + </dependency>
112.47 + <dependency>
112.48 + <groupId>${project.groupId}</groupId>
112.49 + <artifactId>launcher.fx</artifactId>
112.50 + <version>${project.version}</version>
112.51 + </dependency>
112.52 + <dependency>
112.53 + <groupId>org.glassfish.grizzly</groupId>
112.54 + <artifactId>grizzly-http-server</artifactId>
112.55 + <version>${grizzly.version}</version>
112.56 + </dependency>
112.57 + <dependency>
112.58 + <groupId>${project.groupId}</groupId>
112.59 + <artifactId>vm4brwsr</artifactId>
112.60 + <version>${project.version}</version>
112.61 + </dependency>
112.62 + </dependencies>
112.63 +</project>
113.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
113.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Mon Oct 07 14:20:58 2013 +0200
113.3 @@ -0,0 +1,70 @@
113.4 +/**
113.5 + * Back 2 Browser Bytecode Translator
113.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
113.7 + *
113.8 + * This program is free software: you can redistribute it and/or modify
113.9 + * it under the terms of the GNU General Public License as published by
113.10 + * the Free Software Foundation, version 2 of the License.
113.11 + *
113.12 + * This program is distributed in the hope that it will be useful,
113.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
113.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
113.15 + * GNU General Public License for more details.
113.16 + *
113.17 + * You should have received a copy of the GNU General Public License
113.18 + * along with this program. Look for COPYING file in the top folder.
113.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
113.20 + */
113.21 +package org.apidesign.bck2brwsr.launcher;
113.22 +
113.23 +import java.io.IOException;
113.24 +import java.io.InputStream;
113.25 +import org.apidesign.vm4brwsr.Bck2Brwsr;
113.26 +
113.27 +/**
113.28 + * Lightweight server to launch Bck2Brwsr applications and tests.
113.29 + * Supports execution in native browser as well as Java's internal
113.30 + * execution engine.
113.31 + */
113.32 +final class Bck2BrwsrLauncher extends BaseHTTPLauncher {
113.33 +
113.34 + public Bck2BrwsrLauncher(String cmd) {
113.35 + super(cmd);
113.36 + }
113.37 +
113.38 + @Override
113.39 + String harnessResource() {
113.40 + return "org/apidesign/bck2brwsr/launcher/harness.xhtml";
113.41 + }
113.42 +
113.43 + @Override
113.44 + void generateBck2BrwsrJS(StringBuilder sb, final Res loader) throws IOException {
113.45 + class R implements Bck2Brwsr.Resources {
113.46 + @Override
113.47 + public InputStream get(String resource) throws IOException {
113.48 + return loader.get(resource);
113.49 + }
113.50 + }
113.51 +
113.52 + Bck2Brwsr.generate(sb, new R());
113.53 + sb.append(
113.54 + "(function WrapperVM(global) {"
113.55 + + " function ldCls(res) {\n"
113.56 + + " var request = new XMLHttpRequest();\n"
113.57 + + " request.open('GET', '/classes/' + res, false);\n"
113.58 + + " request.send();\n"
113.59 + + " if (request.status !== 200) return null;\n"
113.60 + + " var arr = eval('(' + request.responseText + ')');\n"
113.61 + + " return arr;\n"
113.62 + + " }\n"
113.63 + + " var prevvm = global.bck2brwsr;\n"
113.64 + + " global.bck2brwsr = function() {\n"
113.65 + + " var args = Array.prototype.slice.apply(arguments);\n"
113.66 + + " args.unshift(ldCls);\n"
113.67 + + " return prevvm.apply(null, args);\n"
113.68 + + " };\n"
113.69 + + "})(this);\n"
113.70 + );
113.71 + }
113.72 +
113.73 +}
114.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Mon Oct 07 14:20:58 2013 +0200
114.3 @@ -0,0 +1,135 @@
114.4 +/**
114.5 + * Back 2 Browser Bytecode Translator
114.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
114.7 + *
114.8 + * This program is free software: you can redistribute it and/or modify
114.9 + * it under the terms of the GNU General Public License as published by
114.10 + * the Free Software Foundation, version 2 of the License.
114.11 + *
114.12 + * This program is distributed in the hope that it will be useful,
114.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
114.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
114.15 + * GNU General Public License for more details.
114.16 + *
114.17 + * You should have received a copy of the GNU General Public License
114.18 + * along with this program. Look for COPYING file in the top folder.
114.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
114.20 + */
114.21 +package org.apidesign.bck2brwsr.launcher;
114.22 +
114.23 +import org.apidesign.bck2brwsr.launcher.impl.Console;
114.24 +import java.io.IOException;
114.25 +import java.io.InputStream;
114.26 +import java.net.URL;
114.27 +import java.util.Enumeration;
114.28 +import java.util.LinkedHashSet;
114.29 +import java.util.Set;
114.30 +import java.util.logging.Level;
114.31 +import java.util.logging.Logger;
114.32 +import javax.script.Invocable;
114.33 +import javax.script.ScriptEngine;
114.34 +import javax.script.ScriptEngineManager;
114.35 +import javax.script.ScriptException;
114.36 +import org.apidesign.vm4brwsr.Bck2Brwsr;
114.37 +
114.38 +/**
114.39 + * Tests execution in Java's internal scripting engine.
114.40 + */
114.41 +final class JSLauncher extends Launcher {
114.42 + private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName());
114.43 + private Set<ClassLoader> loaders = new LinkedHashSet<>();
114.44 + private final Res resources = new Res();
114.45 + private Invocable code;
114.46 + private StringBuilder codeSeq;
114.47 + private Object console;
114.48 +
114.49 + JSLauncher() {
114.50 + addClassLoader(Bck2Brwsr.class.getClassLoader());
114.51 + }
114.52 +
114.53 + @Override InvocationContext runMethod(InvocationContext mi) {
114.54 + loaders.add(mi.clazz.getClassLoader());
114.55 + try {
114.56 + long time = System.currentTimeMillis();
114.57 + LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName});
114.58 + String res = code.invokeMethod(
114.59 + console,
114.60 + "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
114.61 + mi.clazz.getName(), mi.methodName).toString();
114.62 + time = System.currentTimeMillis() - time;
114.63 + LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time});
114.64 + mi.result(res, null);
114.65 + } catch (ScriptException | NoSuchMethodException ex) {
114.66 + mi.result(null, ex);
114.67 + }
114.68 + return mi;
114.69 + }
114.70 +
114.71 + public void addClassLoader(ClassLoader url) {
114.72 + this.loaders.add(url);
114.73 + }
114.74 +
114.75 + @Override
114.76 + public void initialize() throws IOException {
114.77 + try {
114.78 + initRhino();
114.79 + } catch (Exception ex) {
114.80 + if (ex instanceof IOException) {
114.81 + throw (IOException)ex;
114.82 + }
114.83 + if (ex instanceof RuntimeException) {
114.84 + throw (RuntimeException)ex;
114.85 + }
114.86 + throw new IOException(ex);
114.87 + }
114.88 + }
114.89 +
114.90 + private void initRhino() throws IOException, ScriptException, NoSuchMethodException {
114.91 + StringBuilder sb = new StringBuilder();
114.92 + Bck2Brwsr.generate(sb, new Res());
114.93 +
114.94 + ScriptEngineManager sem = new ScriptEngineManager();
114.95 + ScriptEngine mach = sem.getEngineByExtension("js");
114.96 +
114.97 + sb.append(
114.98 + "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);"
114.99 + + "\nfunction initVM() { return vm; };"
114.100 + + "\n");
114.101 +
114.102 + Object res = mach.eval(sb.toString());
114.103 + if (!(mach instanceof Invocable)) {
114.104 + throw new IOException("It is invocable object: " + res);
114.105 + }
114.106 + code = (Invocable) mach;
114.107 + codeSeq = sb;
114.108 +
114.109 + Object vm = code.invokeFunction("initVM");
114.110 + console = code.invokeMethod(vm, "loadClass", Console.class.getName());
114.111 + }
114.112 +
114.113 + @Override
114.114 + public void shutdown() throws IOException {
114.115 + }
114.116 +
114.117 + @Override
114.118 + public String toString() {
114.119 + return codeSeq.toString();
114.120 + }
114.121 +
114.122 + private class Res implements Bck2Brwsr.Resources {
114.123 + @Override
114.124 + public InputStream get(String resource) throws IOException {
114.125 + for (ClassLoader l : loaders) {
114.126 + URL u = null;
114.127 + Enumeration<URL> en = l.getResources(resource);
114.128 + while (en.hasMoreElements()) {
114.129 + u = en.nextElement();
114.130 + }
114.131 + if (u != null) {
114.132 + return u.openStream();
114.133 + }
114.134 + }
114.135 + throw new IOException("Can't find " + resource);
114.136 + }
114.137 + }
114.138 +}
115.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
115.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/b2b/LauncherBck2Brwsr.java Mon Oct 07 14:20:58 2013 +0200
115.3 @@ -0,0 +1,33 @@
115.4 +/**
115.5 + * Back 2 Browser Bytecode Translator
115.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
115.7 + *
115.8 + * This program is free software: you can redistribute it and/or modify
115.9 + * it under the terms of the GNU General Public License as published by
115.10 + * the Free Software Foundation, version 2 of the License.
115.11 + *
115.12 + * This program is distributed in the hope that it will be useful,
115.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
115.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
115.15 + * GNU General Public License for more details.
115.16 + *
115.17 + * You should have received a copy of the GNU General Public License
115.18 + * along with this program. Look for COPYING file in the top folder.
115.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
115.20 + */
115.21 +package org.apidesign.bck2brwsr.launcher.b2b;
115.22 +
115.23 +import java.awt.Desktop;
115.24 +import org.apidesign.bck2brwsr.launcher.Launcher;
115.25 +
115.26 +/** This is a launcher for the <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a>
115.27 + * project that is using {@link Desktop} (or {@link Process}) to display the
115.28 + * external browser in separate process. Use {@link Launcher} methods to access this
115.29 + * functionality via public, supported methods.
115.30 + *
115.31 + * @author Jaroslav Tulach
115.32 + */
115.33 +public final class LauncherBck2Brwsr {
115.34 + private LauncherBck2Brwsr() {
115.35 + }
115.36 +}
116.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
116.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Mon Oct 07 14:20:58 2013 +0200
116.3 @@ -0,0 +1,356 @@
116.4 +/**
116.5 + * Back 2 Browser Bytecode Translator
116.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
116.7 + *
116.8 + * This program is free software: you can redistribute it and/or modify
116.9 + * it under the terms of the GNU General Public License as published by
116.10 + * the Free Software Foundation, version 2 of the License.
116.11 + *
116.12 + * This program is distributed in the hope that it will be useful,
116.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
116.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
116.15 + * GNU General Public License for more details.
116.16 + *
116.17 + * You should have received a copy of the GNU General Public License
116.18 + * along with this program. Look for COPYING file in the top folder.
116.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
116.20 + */
116.21 +package org.apidesign.bck2brwsr.launcher.impl;
116.22 +
116.23 +import java.io.IOException;
116.24 +import java.io.InputStream;
116.25 +import java.io.UnsupportedEncodingException;
116.26 +import java.lang.reflect.InvocationTargetException;
116.27 +import java.lang.reflect.Method;
116.28 +import java.lang.reflect.Modifier;
116.29 +import java.net.URL;
116.30 +import java.util.Enumeration;
116.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
116.32 +
116.33 +/**
116.34 + *
116.35 + * @author Jaroslav Tulach <jtulach@netbeans.org>
116.36 + */
116.37 +public class Console {
116.38 + private Console() {
116.39 + }
116.40 + static {
116.41 + turnAssetionStatusOn();
116.42 + }
116.43 +
116.44 + @JavaScriptBody(args = {"id", "attr"}, body =
116.45 + "return window.document.getElementById(id)[attr].toString();")
116.46 + private static native Object getAttr(String id, String attr);
116.47 + @JavaScriptBody(args = {"elem", "attr"}, body =
116.48 + "return elem[attr].toString();")
116.49 + private static native Object getAttr(Object elem, String attr);
116.50 +
116.51 + @JavaScriptBody(args = {"id", "attr", "value"}, body =
116.52 + "window.document.getElementById(id)[attr] = value;")
116.53 + private static native void setAttr(String id, String attr, Object value);
116.54 + @JavaScriptBody(args = {"elem", "attr", "value"}, body =
116.55 + "elem[attr] = value;")
116.56 + private static native void setAttr(Object id, String attr, Object value);
116.57 +
116.58 + @JavaScriptBody(args = {}, body = "return; window.close();")
116.59 + private static native void closeWindow();
116.60 +
116.61 + private static Object textArea;
116.62 + private static Object statusArea;
116.63 +
116.64 + private static void log(String newText) {
116.65 + if (textArea == null) {
116.66 + return;
116.67 + }
116.68 + String attr = "value";
116.69 + setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText);
116.70 + setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight"));
116.71 + }
116.72 +
116.73 + private static void beginTest(Case c) {
116.74 + Object[] arr = new Object[2];
116.75 + beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
116.76 + textArea = arr[0];
116.77 + statusArea = arr[1];
116.78 + }
116.79 +
116.80 + private static void finishTest(Case c, Object res) {
116.81 + if ("null".equals(res)) {
116.82 + setAttr(statusArea, "innerHTML", "Success");
116.83 + } else {
116.84 + setAttr(statusArea, "innerHTML", "Result " + res);
116.85 + }
116.86 + statusArea = null;
116.87 + textArea = null;
116.88 + }
116.89 +
116.90 + @JavaScriptBody(args = { "test", "c", "arr" }, body =
116.91 + "var ul = window.document.getElementById('bck2brwsr.result');\n"
116.92 + + "var li = window.document.createElement('li');\n"
116.93 + + "var span = window.document.createElement('span');"
116.94 + + "span.innerHTML = test + ' - ';\n"
116.95 + + "var details = window.document.createElement('a');\n"
116.96 + + "details.innerHTML = 'Details';\n"
116.97 + + "details.href = '#';\n"
116.98 + + "var p = window.document.createElement('p');\n"
116.99 + + "var status = window.document.createElement('a');\n"
116.100 + + "status.innerHTML = 'running';"
116.101 + + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n"
116.102 + + "status.onclick = function() { c.again__V_3Ljava_lang_Object_2(arr); }\n"
116.103 + + "var pre = window.document.createElement('textarea');\n"
116.104 + + "pre.cols = 100;"
116.105 + + "pre.rows = 10;"
116.106 + + "li.appendChild(span);\n"
116.107 + + "li.appendChild(status);\n"
116.108 + + "var span = window.document.createElement('span');"
116.109 + + "span.innerHTML = ' ';\n"
116.110 + + "li.appendChild(span);\n"
116.111 + + "li.appendChild(details);\n"
116.112 + + "p.appendChild(pre);\n"
116.113 + + "ul.appendChild(li);\n"
116.114 + + "arr[0] = pre;\n"
116.115 + + "arr[1] = status;\n"
116.116 + )
116.117 + private static native void beginTest(String test, Case c, Object[] arr);
116.118 +
116.119 + @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
116.120 + + "var request = new XMLHttpRequest();\n"
116.121 + + "request.open('GET', url, true);\n"
116.122 + + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
116.123 + + "request.onreadystatechange = function() {\n"
116.124 + + " if (this.readyState!==4) return;\n"
116.125 + + " arr[0] = this.responseText;\n"
116.126 + + " callback.run__V();\n"
116.127 + + "};"
116.128 + + "request.send();"
116.129 + )
116.130 + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
116.131 +
116.132 + public static void harness(String url) throws IOException {
116.133 + log("Connecting to " + url);
116.134 + Request r = new Request(url);
116.135 + }
116.136 +
116.137 + private static class Request implements Runnable {
116.138 + private final String[] arr = { null };
116.139 + private final String url;
116.140 + private Case c;
116.141 + private int retries;
116.142 +
116.143 + private Request(String url) throws IOException {
116.144 + this.url = url;
116.145 + loadText(url, this, arr);
116.146 + }
116.147 + private Request(String url, String u) throws IOException {
116.148 + this.url = url;
116.149 + loadText(u, this, arr);
116.150 + }
116.151 +
116.152 + @Override
116.153 + public void run() {
116.154 + try {
116.155 + if (c == null) {
116.156 + String data = arr[0];
116.157 +
116.158 + if (data == null) {
116.159 + log("Some error exiting");
116.160 + closeWindow();
116.161 + return;
116.162 + }
116.163 +
116.164 + if (data.isEmpty()) {
116.165 + log("No data, exiting");
116.166 + closeWindow();
116.167 + return;
116.168 + }
116.169 +
116.170 + c = Case.parseData(data);
116.171 + beginTest(c);
116.172 + log("Got \"" + data + "\"");
116.173 + } else {
116.174 + log("Processing \"" + arr[0] + "\" for " + retries + " time");
116.175 + }
116.176 + Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest();
116.177 + finishTest(c, result);
116.178 +
116.179 + String u = url + "?request=" + c.getRequestId() + "&result=" + result;
116.180 + new Request(url, u);
116.181 + } catch (Exception ex) {
116.182 + if (ex instanceof InterruptedException) {
116.183 + log("Re-scheduling in 100ms");
116.184 + schedule(this, 100);
116.185 + return;
116.186 + }
116.187 + log(ex.getClass().getName() + ":" + ex.getMessage());
116.188 + }
116.189 + }
116.190 + }
116.191 +
116.192 + private static String encodeURL(String r) throws UnsupportedEncodingException {
116.193 + final String SPECIAL = "%$&+,/:;=?@";
116.194 + StringBuilder sb = new StringBuilder();
116.195 + byte[] utf8 = r.getBytes("UTF-8");
116.196 + for (int i = 0; i < utf8.length; i++) {
116.197 + int ch = utf8[i] & 0xff;
116.198 + if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) {
116.199 + final String numbers = "0" + Integer.toHexString(ch);
116.200 + sb.append("%").append(numbers.substring(numbers.length() - 2));
116.201 + } else {
116.202 + if (ch == 32) {
116.203 + sb.append("+");
116.204 + } else {
116.205 + sb.append((char)ch);
116.206 + }
116.207 + }
116.208 + }
116.209 + return sb.toString();
116.210 + }
116.211 +
116.212 + static String invoke(String clazz, String method) throws
116.213 + ClassNotFoundException, InvocationTargetException, IllegalAccessException,
116.214 + InstantiationException, InterruptedException {
116.215 + final Object r = new Case(null).invokeMethod(clazz, method);
116.216 + return r == null ? "null" : r.toString().toString();
116.217 + }
116.218 +
116.219 + /** Helper method that inspects the classpath and loads given resource
116.220 + * (usually a class file). Used while running tests in Rhino.
116.221 + *
116.222 + * @param name resource name to find
116.223 + * @return the array of bytes in the given resource
116.224 + * @throws IOException I/O in case something goes wrong
116.225 + */
116.226 + public static byte[] read(String name) throws IOException {
116.227 + URL u = null;
116.228 + Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
116.229 + while (en.hasMoreElements()) {
116.230 + u = en.nextElement();
116.231 + }
116.232 + if (u == null) {
116.233 + throw new IOException("Can't find " + name);
116.234 + }
116.235 + try (InputStream is = u.openStream()) {
116.236 + byte[] arr;
116.237 + arr = new byte[is.available()];
116.238 + int offset = 0;
116.239 + while (offset < arr.length) {
116.240 + int len = is.read(arr, offset, arr.length - offset);
116.241 + if (len == -1) {
116.242 + throw new IOException("Can't read " + name);
116.243 + }
116.244 + offset += len;
116.245 + }
116.246 + return arr;
116.247 + }
116.248 + }
116.249 +
116.250 + @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
116.251 + private static void turnAssetionStatusOn() {
116.252 + }
116.253 +
116.254 + @JavaScriptBody(args = {"r", "time"}, body =
116.255 + "return window.setTimeout(function() { r.run__V(); }, time);")
116.256 + private static native Object schedule(Runnable r, int time);
116.257 +
116.258 + private static final class Case {
116.259 + private final Object data;
116.260 + private Object inst;
116.261 +
116.262 + private Case(Object data) {
116.263 + this.data = data;
116.264 + }
116.265 +
116.266 + public static Case parseData(String s) {
116.267 + return new Case(toJSON(s));
116.268 + }
116.269 +
116.270 + public String getMethodName() {
116.271 + return value("methodName", data);
116.272 + }
116.273 +
116.274 + public String getClassName() {
116.275 + return value("className", data);
116.276 + }
116.277 +
116.278 + public String getRequestId() {
116.279 + return value("request", data);
116.280 + }
116.281 +
116.282 + public String getHtmlFragment() {
116.283 + return value("html", data);
116.284 + }
116.285 +
116.286 + void again(Object[] arr) {
116.287 + try {
116.288 + textArea = arr[0];
116.289 + statusArea = arr[1];
116.290 + setAttr(textArea, "value", "");
116.291 + runTest();
116.292 + } catch (Exception ex) {
116.293 + log(ex.getClass().getName() + ":" + ex.getMessage());
116.294 + }
116.295 + }
116.296 +
116.297 + private Object runTest() throws IllegalAccessException,
116.298 + IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException,
116.299 + InvocationTargetException, InstantiationException, InterruptedException {
116.300 + if (this.getHtmlFragment() != null) {
116.301 + setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment());
116.302 + }
116.303 + log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId());
116.304 + Object result = invokeMethod(this.getClassName(), this.getMethodName());
116.305 + setAttr("bck2brwsr.fragment", "innerHTML", "");
116.306 + log("Result: " + result);
116.307 + result = encodeURL("" + result);
116.308 + log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result);
116.309 + return result;
116.310 + }
116.311 +
116.312 + private Object invokeMethod(String clazz, String method)
116.313 + throws ClassNotFoundException, InvocationTargetException,
116.314 + InterruptedException, IllegalAccessException, IllegalArgumentException,
116.315 + InstantiationException {
116.316 + Method found = null;
116.317 + Class<?> c = Class.forName(clazz);
116.318 + for (Method m : c.getMethods()) {
116.319 + if (m.getName().equals(method)) {
116.320 + found = m;
116.321 + }
116.322 + }
116.323 + Object res;
116.324 + if (found != null) {
116.325 + try {
116.326 + if ((found.getModifiers() & Modifier.STATIC) != 0) {
116.327 + res = found.invoke(null);
116.328 + } else {
116.329 + if (inst == null) {
116.330 + inst = c.newInstance();
116.331 + }
116.332 + res = found.invoke(inst);
116.333 + }
116.334 + } catch (Throwable ex) {
116.335 + if (ex instanceof InvocationTargetException) {
116.336 + ex = ((InvocationTargetException) ex).getTargetException();
116.337 + }
116.338 + if (ex instanceof InterruptedException) {
116.339 + throw (InterruptedException)ex;
116.340 + }
116.341 + res = ex.getClass().getName() + ":" + ex.getMessage();
116.342 + }
116.343 + } else {
116.344 + res = "Can't find method " + method + " in " + clazz;
116.345 + }
116.346 + return res;
116.347 + }
116.348 +
116.349 + @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
116.350 + private static native Object toJSON(String s);
116.351 +
116.352 + @JavaScriptBody(args = {"p", "d"}, body =
116.353 + "var v = d[p];\n"
116.354 + + "if (typeof v === 'undefined') return null;\n"
116.355 + + "return v.toString();"
116.356 + )
116.357 + private static native String value(String p, Object d);
116.358 + }
116.359 +}
117.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
117.2 +++ b/launcher/http/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Mon Oct 07 14:20:58 2013 +0200
117.3 @@ -0,0 +1,43 @@
117.4 +<?xml version="1.0" encoding="UTF-8"?>
117.5 +<!--
117.6 +
117.7 + Back 2 Browser Bytecode Translator
117.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
117.9 +
117.10 + This program is free software: you can redistribute it and/or modify
117.11 + it under the terms of the GNU General Public License as published by
117.12 + the Free Software Foundation, version 2 of the License.
117.13 +
117.14 + This program is distributed in the hope that it will be useful,
117.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
117.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117.17 + GNU General Public License for more details.
117.18 +
117.19 + You should have received a copy of the GNU General Public License
117.20 + along with this program. Look for COPYING file in the top folder.
117.21 + If not, see http://opensource.org/licenses/GPL-2.0.
117.22 +
117.23 +-->
117.24 +<!DOCTYPE html>
117.25 +<html xmlns="http://www.w3.org/1999/xhtml">
117.26 + <head>
117.27 + <title>Bck2Brwsr Harness</title>
117.28 + </head>
117.29 + <body>
117.30 + <script src="/bck2brwsr.js"></script>
117.31 + <script>
117.32 + var vm = bck2brwsr();
117.33 + </script>
117.34 +
117.35 + <h1>Bck2Brwsr Execution Harness</h1>
117.36 +
117.37 + <ul id="bck2brwsr.result" style="width: 100%;" >
117.38 + </ul>
117.39 +
117.40 + <div id="bck2brwsr.fragment"/>
117.41 +
117.42 + <script type="text/javascript">
117.43 + vm.loadClass('org.apidesign.bck2brwsr.launcher.impl.Console').harness__VLjava_lang_String_2('$U/../data');
117.44 + </script>
117.45 + </body>
117.46 +</html>
118.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
118.2 +++ b/launcher/pom.xml Mon Oct 07 14:20:58 2013 +0200
118.3 @@ -0,0 +1,22 @@
118.4 +<?xml version="1.0" encoding="UTF-8"?>
118.5 +<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/xsd/maven-4.0.0.xsd">
118.6 + <modelVersion>4.0.0</modelVersion>
118.7 + <parent>
118.8 + <artifactId>bck2brwsr</artifactId>
118.9 + <groupId>org.apidesign</groupId>
118.10 + <version>0.9-SNAPSHOT</version>
118.11 + </parent>
118.12 + <groupId>org.apidesign.bck2brwsr</groupId>
118.13 + <artifactId>launcher-pom</artifactId>
118.14 + <version>0.9-SNAPSHOT</version>
118.15 + <packaging>pom</packaging>
118.16 + <name>Launchers</name>
118.17 + <properties>
118.18 + <grizzly.version>2.3.3</grizzly.version>
118.19 + </properties>
118.20 + <modules>
118.21 + <module>api</module>
118.22 + <module>http</module>
118.23 + <module>fx</module>
118.24 + </modules>
118.25 +</project>
118.26 \ No newline at end of file
119.1 --- a/pom.xml Wed Feb 27 17:50:47 2013 +0100
119.2 +++ b/pom.xml Mon Oct 07 14:20:58 2013 +0200
119.3 @@ -3,7 +3,7 @@
119.4 <modelVersion>4.0.0</modelVersion>
119.5 <groupId>org.apidesign</groupId>
119.6 <artifactId>bck2brwsr</artifactId>
119.7 - <version>0.3-SNAPSHOT</version>
119.8 + <version>0.9-SNAPSHOT</version>
119.9 <packaging>pom</packaging>
119.10 <name>Back 2 Browser</name>
119.11 <parent>
119.12 @@ -11,11 +11,19 @@
119.13 <artifactId>jvnet-parent</artifactId>
119.14 <version>3</version>
119.15 </parent>
119.16 + <properties>
119.17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
119.18 + <netbeans.version>RELEASE73</netbeans.version>
119.19 + <license>COPYING</license>
119.20 + <net.java.html.version>0.6</net.java.html.version>
119.21 + </properties>
119.22 <modules>
119.23 <module>dew</module>
119.24 <module>javaquery</module>
119.25 <module>benchmarks</module>
119.26 <module>ide</module>
119.27 + <module>ko</module>
119.28 + <module>launcher</module>
119.29 <module>rt</module>
119.30 </modules>
119.31 <licenses>
119.32 @@ -33,6 +41,7 @@
119.33 <connection>scm:hg:http://source.apidesign.org/hg/bck2brwsr</connection>
119.34 <developerConnection>scm:hg:https://source.apidesign.org/hg/bck2brwsr</developerConnection>
119.35 <url>http://source.apidesign.org/hg/bck2brwsr</url>
119.36 + <tag>HEAD</tag>
119.37 </scm>
119.38 <repositories>
119.39 <repository>
119.40 @@ -78,14 +87,26 @@
119.41 <exclude>*</exclude>
119.42 <exclude>.*/**</exclude>
119.43 <exclude>rt/emul/*/src/main/**</exclude>
119.44 - <exclude>rt/javap/**</exclude>
119.45 - <exclude>rt/mojo/src/main/resources/archetype-resources/**</exclude>
119.46 - <exclude>rt/vmtest/src/test/resources/**</exclude>
119.47 + <exclude>rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java</exclude>
119.48 + <exclude>rt/archetype/src/main/resources/archetype-resources/**</exclude>
119.49 + <exclude>rt/emul/compact/src/test/resources/**</exclude>
119.50 <exclude>dew/src/main/resources/org/apidesign/bck2brwsr/dew/**</exclude>
119.51 <exclude>javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js</exclude>
119.52 + <exclude>ko/archetype/src/main/resources/archetype-resources/**</exclude>
119.53 + <exclude>ko/*/src/main/resources/org/apidesign/*/*/knockout-2.2.1.js</exclude>
119.54 </excludes>
119.55 </configuration>
119.56 </plugin>
119.57 + <plugin>
119.58 + <artifactId>maven-release-plugin</artifactId>
119.59 + <version>2.4</version>
119.60 + <configuration>
119.61 + <mavenExecutorId>forked-path</mavenExecutorId>
119.62 + <useReleaseProfile>false</useReleaseProfile>
119.63 + <arguments>-Pjvnet-release -Pgpg</arguments>
119.64 + <tag>release-${releaseVersion}</tag>
119.65 + </configuration>
119.66 + </plugin>
119.67 </plugins>
119.68 <pluginManagement>
119.69 <plugins>
119.70 @@ -94,6 +115,23 @@
119.71 <artifactId>maven-surefire-plugin</artifactId>
119.72 <version>2.13</version>
119.73 </plugin>
119.74 + <plugin>
119.75 + <groupId>org.apache.maven.plugins</groupId>
119.76 + <artifactId>maven-javadoc-plugin</artifactId>
119.77 + <version>2.9</version>
119.78 + <configuration>
119.79 + <skip>true</skip>
119.80 + </configuration>
119.81 + </plugin>
119.82 + <plugin>
119.83 + <groupId>org.apache.maven.plugins</groupId>
119.84 + <artifactId>maven-compiler-plugin</artifactId>
119.85 + <version>2.3.2</version>
119.86 + <configuration>
119.87 + <source>1.7</source>
119.88 + <target>1.7</target>
119.89 + </configuration>
119.90 + </plugin>
119.91 </plugins>
119.92 </pluginManagement>
119.93 </build>
119.94 @@ -114,19 +152,137 @@
119.95 <dependency>
119.96 <groupId>org.netbeans.api</groupId>
119.97 <artifactId>org-netbeans-modules-classfile</artifactId>
119.98 - <version>RELEASE72</version>
119.99 + <version>${netbeans.version}</version>
119.100 <type>jar</type>
119.101 </dependency>
119.102 <dependency>
119.103 <groupId>org.netbeans.api</groupId>
119.104 <artifactId>org-openide-util-lookup</artifactId>
119.105 - <version>RELEASE72</version>
119.106 + <version>${netbeans.version}</version>
119.107 <scope>compile</scope>
119.108 <type>jar</type>
119.109 </dependency>
119.110 + <dependency>
119.111 + <groupId>org.netbeans.api</groupId>
119.112 + <artifactId>org-netbeans-api-annotations-common</artifactId>
119.113 + <version>${netbeans.version}</version>
119.114 + </dependency>
119.115 + <dependency>
119.116 + <groupId>org.netbeans.api</groupId>
119.117 + <artifactId>org-netbeans-modules-java-source</artifactId>
119.118 + <version>${netbeans.version}</version>
119.119 + </dependency>
119.120 + <dependency>
119.121 + <groupId>org.netbeans.api</groupId>
119.122 + <artifactId>org-netbeans-libs-javacapi</artifactId>
119.123 + <version>${netbeans.version}</version>
119.124 + </dependency>
119.125 + <dependency>
119.126 + <groupId>org.netbeans.api</groupId>
119.127 + <artifactId>org-netbeans-spi-java-hints</artifactId>
119.128 + <version>${netbeans.version}</version>
119.129 + </dependency>
119.130 + <dependency>
119.131 + <groupId>org.netbeans.api</groupId>
119.132 + <artifactId>org-netbeans-modules-parsing-api</artifactId>
119.133 + <version>${netbeans.version}</version>
119.134 + </dependency>
119.135 + <dependency>
119.136 + <groupId>org.netbeans.api</groupId>
119.137 + <artifactId>org-netbeans-spi-editor-hints</artifactId>
119.138 + <version>${netbeans.version}</version>
119.139 + </dependency>
119.140 + <dependency>
119.141 + <groupId>org.netbeans.api</groupId>
119.142 + <artifactId>org-openide-util</artifactId>
119.143 + <version>${netbeans.version}</version>
119.144 + </dependency>
119.145 + <dependency>
119.146 + <groupId>org.netbeans.api</groupId>
119.147 + <artifactId>org-netbeans-modules-java-lexer</artifactId>
119.148 + <version>${netbeans.version}</version>
119.149 + </dependency>
119.150 + <dependency>
119.151 + <groupId>org.netbeans.api</groupId>
119.152 + <artifactId>org-netbeans-modules-lexer</artifactId>
119.153 + <version>${netbeans.version}</version>
119.154 + </dependency>
119.155 + <dependency>
119.156 + <groupId>org.netbeans.api</groupId>
119.157 + <artifactId>org-netbeans-modules-java-hints-test</artifactId>
119.158 + <version>${netbeans.version}</version>
119.159 + </dependency>
119.160 + <dependency>
119.161 + <groupId>org.netbeans.api</groupId>
119.162 + <artifactId>org-netbeans-libs-junit4</artifactId>
119.163 + <version>${netbeans.version}</version>
119.164 + </dependency>
119.165 + <dependency>
119.166 + <groupId>org.netbeans.modules</groupId>
119.167 + <artifactId>org-netbeans-lib-nbjavac</artifactId>
119.168 + <version>${netbeans.version}</version>
119.169 + </dependency>
119.170 + <dependency>
119.171 + <groupId>org.netbeans.modules</groupId>
119.172 + <artifactId>org-netbeans-modules-web-browser-api</artifactId>
119.173 + <version>${netbeans.version}</version>
119.174 + <exclusions>
119.175 + <exclusion>
119.176 + <artifactId>org-netbeans-core</artifactId>
119.177 + <groupId>org.netbeans.modules</groupId>
119.178 + </exclusion>
119.179 + <exclusion>
119.180 + <artifactId>org-netbeans-core-multiview</artifactId>
119.181 + <groupId>org.netbeans.api</groupId>
119.182 + </exclusion>
119.183 + <exclusion>
119.184 + <artifactId>org-netbeans-libs-lucene</artifactId>
119.185 + <groupId>org.netbeans.api</groupId>
119.186 + </exclusion>
119.187 + <exclusion>
119.188 + <artifactId>org-netbeans-modules-diff</artifactId>
119.189 + <groupId>org.netbeans.api</groupId>
119.190 + </exclusion>
119.191 + <exclusion>
119.192 + <artifactId>org-netbeans-modules-editor-fold</artifactId>
119.193 + <groupId>org.netbeans.api</groupId>
119.194 + </exclusion>
119.195 + <exclusion>
119.196 + <artifactId>org-netbeans-modules-editor-guards</artifactId>
119.197 + <groupId>org.netbeans.api</groupId>
119.198 + </exclusion>
119.199 + </exclusions>
119.200 + </dependency>
119.201 + <dependency>
119.202 + <artifactId>org-netbeans-modules-projectapi</artifactId>
119.203 + <groupId>org.netbeans.api</groupId>
119.204 + <type>jar</type>
119.205 + <version>${netbeans.version}</version>
119.206 + </dependency>
119.207 </dependencies>
119.208 </dependencyManagement>
119.209 - <properties>
119.210 - <license>COPYING</license>
119.211 - </properties>
119.212 -</project>
119.213 \ No newline at end of file
119.214 + <profiles>
119.215 + <profile>
119.216 + <id>jdk8</id>
119.217 + <activation>
119.218 + <file>
119.219 + <exists>${java.home}/lib/ext/jfxrt.jar</exists>
119.220 + </file>
119.221 + </activation>
119.222 + <properties>
119.223 + <jfxrt.jar>${java.home}/lib/ext/jfxrt.jar</jfxrt.jar>
119.224 + </properties>
119.225 + </profile>
119.226 + <profile>
119.227 + <id>jdk7</id>
119.228 + <activation>
119.229 + <file>
119.230 + <exists>${java.home}/lib/jfxrt.jar</exists>
119.231 + </file>
119.232 + </activation>
119.233 + <properties>
119.234 + <jfxrt.jar>${java.home}/lib/jfxrt.jar</jfxrt.jar>
119.235 + </properties>
119.236 + </profile>
119.237 + </profiles>
119.238 +</project>
120.1 --- a/rt/core/pom.xml Wed Feb 27 17:50:47 2013 +0100
120.2 +++ b/rt/core/pom.xml Mon Oct 07 14:20:58 2013 +0200
120.3 @@ -1,15 +1,14 @@
120.4 <?xml version="1.0"?>
120.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
120.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
120.7 +<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/xsd/maven-4.0.0.xsd">
120.8 <modelVersion>4.0.0</modelVersion>
120.9 <parent>
120.10 <groupId>org.apidesign.bck2brwsr</groupId>
120.11 <artifactId>rt</artifactId>
120.12 - <version>0.3-SNAPSHOT</version>
120.13 + <version>0.9-SNAPSHOT</version>
120.14 </parent>
120.15 <groupId>org.apidesign.bck2brwsr</groupId>
120.16 <artifactId>core</artifactId>
120.17 - <version>0.3-SNAPSHOT</version>
120.18 + <version>0.9-SNAPSHOT</version>
120.19 <name>Bck2Brwsr Native Annotations</name>
120.20 <url>http://maven.apache.org</url>
120.21 <build>
120.22 @@ -23,6 +22,14 @@
120.23 <target>1.7</target>
120.24 </configuration>
120.25 </plugin>
120.26 + <plugin>
120.27 + <groupId>org.apache.maven.plugins</groupId>
120.28 + <artifactId>maven-javadoc-plugin</artifactId>
120.29 + <configuration>
120.30 + <excludePackageNames>org.apidesign.bck2brwsr.core.impl</excludePackageNames>
120.31 + <skip>false</skip>
120.32 + </configuration>
120.33 + </plugin>
120.34 </plugins>
120.35 </build>
120.36 <properties>
121.1 --- a/rt/core/src/main/java/org/apidesign/bck2brwsr/core/ExtraJavaScript.java Wed Feb 27 17:50:47 2013 +0100
121.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/ExtraJavaScript.java Mon Oct 07 14:20:58 2013 +0200
121.3 @@ -22,14 +22,16 @@
121.4 import java.lang.annotation.RetentionPolicy;
121.5 import java.lang.annotation.Target;
121.6
121.7 -/**
121.8 +/** A way to include pre-made JavaScript scripts and libraries.
121.9 + * The {@link #resource()} is loaded into the JavaScript VM and its object
121.10 + * can be referenced from the class annotated by this annotation.
121.11 *
121.12 * @author Jaroslav Tulach <jtulach@netbeans.org>
121.13 */
121.14 @Retention(RetentionPolicy.CLASS)
121.15 @Target(ElementType.TYPE)
121.16 public @interface ExtraJavaScript {
121.17 - /** location of a script to load */
121.18 + /** fully qualified location of a script to load. Start the path with slash. */
121.19 String resource();
121.20 /** should the class file still be processed or not? */
121.21 boolean processByteCode() default true;
122.1 --- a/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptBody.java Wed Feb 27 17:50:47 2013 +0100
122.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptBody.java Mon Oct 07 14:20:58 2013 +0200
122.3 @@ -22,22 +22,17 @@
122.4 import java.lang.annotation.RetentionPolicy;
122.5 import java.lang.annotation.Target;
122.6
122.7 -/** Put this method on a method in case it should have a special
122.8 - * body in the <em>JavaScript</em>.
122.9 +/** Put this annotation on a method to provide its special implementation
122.10 + * in JavaScript. This is a way to define <em>native</em> methods that
122.11 + * interact with the surrounding environment.
122.12 *
122.13 * @author Jaroslav Tulach <jtulach@netbeans.org>
122.14 */
122.15 @Retention(RetentionPolicy.CLASS)
122.16 @Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
122.17 public @interface JavaScriptBody {
122.18 - /** Names of parameters for the method.
122.19 - *
122.20 - * <!--
122.21 - * If not specified
122.22 - * it will be <code>arg0, arg1, arg2</code>. In case of
122.23 - * instance methods, the <code>arg0</code> is reference
122.24 - * to <code>this</code>.
122.25 - * -->
122.26 + /** Names of parameters for the method generated method that can
122.27 + * be referenced from {@link #body()}.
122.28 *
122.29 * @return array of the names of parameters for the method
122.30 * in JavaScript
122.31 @@ -46,6 +41,12 @@
122.32
122.33 /** The actual body of the method in JavaScript. This string will be
122.34 * put into generated header (ends with '{') and footer (ends with '}').
122.35 + * The body can reference provided arguments. In case of non-static
122.36 + * instance method it may reference <code>this</code>. It can also
122.37 + * call methods and access fields - if
122.38 + * <a href="http://wiki.apidesign.org/wiki/Bck2BrwsrMangling">proper mangling</a>
122.39 + * is used. Methods that return some value should end with <code>return</code>
122.40 + * statement.
122.41 */
122.42 public String body();
122.43 }
123.1 --- a/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptOnly.java Wed Feb 27 17:50:47 2013 +0100
123.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptOnly.java Mon Oct 07 14:20:58 2013 +0200
123.3 @@ -22,16 +22,17 @@
123.4 import java.lang.annotation.RetentionPolicy;
123.5 import java.lang.annotation.Target;
123.6
123.7 -/** Don't include given field or method in generated JavaScript. Rather
123.8 - * generate completely independent JavaScript code.
123.9 +/** Don't include given method in the generated JavaScript at all. Rather
123.10 + * generate completely independent JavaScript code consisting of
123.11 + * <code>"{@link #name()}" = "{@link #value()}"</code>.
123.12 *
123.13 * @author Jaroslav Tulach <jtulach@netbeans.org>
123.14 */
123.15 @Retention(RetentionPolicy.CLASS)
123.16 -@Target({ ElementType.METHOD, ElementType.FIELD })
123.17 +@Target({ ElementType.METHOD })
123.18 public @interface JavaScriptOnly {
123.19 /** name of the variable to assign given value to */
123.20 String name() default "";
123.21 - /** value to assign to given field */
123.22 + /** value to assign to the {@link #name()} variable */
123.23 String value() default "";
123.24 }
124.1 --- a/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptPrototype.java Wed Feb 27 17:50:47 2013 +0100
124.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/JavaScriptPrototype.java Mon Oct 07 14:20:58 2013 +0200
124.3 @@ -22,7 +22,14 @@
124.4 import java.lang.annotation.RetentionPolicy;
124.5 import java.lang.annotation.Target;
124.6
124.7 -/** Controls how JavaScript inheritance should be handled.
124.8 +/** Influence the inheritance of your class when converted to JavaScript.
124.9 + * Sometimes one does not want
124.10 + * to mimic the Java hierarchy, but modify it a bit. For example it makes
124.11 + * sense to treat every (JavaScript) string literal as {@link String}.
124.12 + * One can do it by making {@link String} subclass JavaScript <code>String</code>
124.13 + * and use <code>String.prototype</code> as a container for all {@link String}
124.14 + * methods.
124.15 + *
124.16 * @author Jaroslav Tulach <jtulach@netbeans.org>
124.17 */
124.18 @Retention(RetentionPolicy.CLASS)
125.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125.2 +++ b/rt/emul/brwsrtest/pom.xml Mon Oct 07 14:20:58 2013 +0200
125.3 @@ -0,0 +1,52 @@
125.4 +<?xml version="1.0"?>
125.5 +<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/xsd/maven-4.0.0.xsd">
125.6 + <modelVersion>4.0.0</modelVersion>
125.7 + <parent>
125.8 + <groupId>org.apidesign.bck2brwsr</groupId>
125.9 + <artifactId>emul.pom</artifactId>
125.10 + <version>0.9-SNAPSHOT</version>
125.11 + </parent>
125.12 + <groupId>org.apidesign.bck2brwsr</groupId>
125.13 + <artifactId>brwsrtest</artifactId>
125.14 + <version>0.9-SNAPSHOT</version>
125.15 + <name>Tests Inside Real Browser</name>
125.16 + <url>http://maven.apache.org</url>
125.17 + <properties>
125.18 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
125.19 + </properties>
125.20 + <build>
125.21 + <plugins>
125.22 + <plugin>
125.23 + <groupId>org.apache.maven.plugins</groupId>
125.24 + <artifactId>maven-deploy-plugin</artifactId>
125.25 + <version>2.7</version>
125.26 + <configuration>
125.27 + <skip>true</skip>
125.28 + </configuration>
125.29 + </plugin>
125.30 + <plugin>
125.31 + <groupId>org.apache.maven.plugins</groupId>
125.32 + <artifactId>maven-surefire-plugin</artifactId>
125.33 + <configuration>
125.34 + <systemPropertyVariables>
125.35 + <vmtest.js>brwsr</vmtest.js>
125.36 + </systemPropertyVariables>
125.37 + </configuration>
125.38 + </plugin>
125.39 + </plugins>
125.40 + </build>
125.41 + <dependencies>
125.42 + <dependency>
125.43 + <groupId>${project.groupId}</groupId>
125.44 + <artifactId>vmtest</artifactId>
125.45 + <version>${project.version}</version>
125.46 + <scope>test</scope>
125.47 + </dependency>
125.48 + <dependency>
125.49 + <groupId>${project.groupId}</groupId>
125.50 + <artifactId>launcher.http</artifactId>
125.51 + <version>${project.version}</version>
125.52 + <scope>provided</scope>
125.53 + </dependency>
125.54 + </dependencies>
125.55 +</project>
126.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126.2 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/BooleanTest.java Mon Oct 07 14:20:58 2013 +0200
126.3 @@ -0,0 +1,49 @@
126.4 +/**
126.5 + * Back 2 Browser Bytecode Translator
126.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
126.7 + *
126.8 + * This program is free software: you can redistribute it and/or modify
126.9 + * it under the terms of the GNU General Public License as published by
126.10 + * the Free Software Foundation, version 2 of the License.
126.11 + *
126.12 + * This program is distributed in the hope that it will be useful,
126.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
126.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
126.15 + * GNU General Public License for more details.
126.16 + *
126.17 + * You should have received a copy of the GNU General Public License
126.18 + * along with this program. Look for COPYING file in the top folder.
126.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
126.20 + */
126.21 +package org.apidesign.bck2brwsr.brwsrtest;
126.22 +
126.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
126.24 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
126.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
126.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
126.27 +import org.testng.annotations.Factory;
126.28 +
126.29 +/**
126.30 + *
126.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
126.32 + */
126.33 +public class BooleanTest {
126.34 + @JavaScriptBody(args = { "tr" }, body = "return tr ? true : false;")
126.35 + private static native Object trueFalse(boolean tr);
126.36 +
126.37 + @BrwsrTest public void isTrueInstanceOfBoolean() {
126.38 + Object t = trueFalse(true);
126.39 + assert t instanceof Boolean : "Should be boolean: " + t;
126.40 + assert ((boolean)t) : "and is true";
126.41 + }
126.42 +
126.43 + @BrwsrTest public void isFalseInstanceOfBoolean() {
126.44 + Object t = trueFalse(false);
126.45 + assert t instanceof Boolean : "Should be boolean: " + t;
126.46 + assert !((boolean)t) : "and is false: " + t;
126.47 + }
126.48 +
126.49 + @Factory public static Object[] create() {
126.50 + return VMTest.create(BooleanTest.class);
126.51 + }
126.52 +}
127.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127.2 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/DoubleBitsTest.java Mon Oct 07 14:20:58 2013 +0200
127.3 @@ -0,0 +1,42 @@
127.4 +/**
127.5 + * Back 2 Browser Bytecode Translator
127.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
127.7 + *
127.8 + * This program is free software: you can redistribute it and/or modify
127.9 + * it under the terms of the GNU General Public License as published by
127.10 + * the Free Software Foundation, version 2 of the License.
127.11 + *
127.12 + * This program is distributed in the hope that it will be useful,
127.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
127.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
127.15 + * GNU General Public License for more details.
127.16 + *
127.17 + * You should have received a copy of the GNU General Public License
127.18 + * along with this program. Look for COPYING file in the top folder.
127.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
127.20 + */
127.21 +package org.apidesign.bck2brwsr.brwsrtest;
127.22 +
127.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
127.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
127.25 +import org.testng.annotations.Factory;
127.26 +
127.27 +/**
127.28 + *
127.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
127.30 + */
127.31 +public class DoubleBitsTest {
127.32 +
127.33 + @Compare public String doubleToBits() {
127.34 + long val = Double.doubleToLongBits(333.456);
127.35 + return Long.toString(val);
127.36 + }
127.37 +
127.38 + @Compare public int floatToBits() {
127.39 + return Float.floatToIntBits(333.456f);
127.40 + }
127.41 +
127.42 + @Factory public static Object[] create() {
127.43 + return VMTest.create(DoubleBitsTest.class);
127.44 + }
127.45 +}
128.1 --- a/rt/emul/compact/pom.xml Wed Feb 27 17:50:47 2013 +0100
128.2 +++ b/rt/emul/compact/pom.xml Mon Oct 07 14:20:58 2013 +0200
128.3 @@ -1,15 +1,14 @@
128.4 <?xml version="1.0"?>
128.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
128.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
128.7 +<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/xsd/maven-4.0.0.xsd">
128.8 <modelVersion>4.0.0</modelVersion>
128.9 <parent>
128.10 <groupId>org.apidesign.bck2brwsr</groupId>
128.11 <artifactId>emul.pom</artifactId>
128.12 - <version>0.3-SNAPSHOT</version>
128.13 + <version>0.9-SNAPSHOT</version>
128.14 </parent>
128.15 <groupId>org.apidesign.bck2brwsr</groupId>
128.16 <artifactId>emul</artifactId>
128.17 - <version>0.3-SNAPSHOT</version>
128.18 + <version>0.9-SNAPSHOT</version>
128.19 <name>Bck2Brwsr API Profile</name>
128.20 <url>http://maven.apache.org</url>
128.21 <properties>
128.22 @@ -29,6 +28,18 @@
128.23 <scope>test</scope>
128.24 </dependency>
128.25 <dependency>
128.26 + <groupId>${project.groupId}</groupId>
128.27 + <artifactId>launcher.http</artifactId>
128.28 + <version>${project.version}</version>
128.29 + <scope>test</scope>
128.30 + <exclusions>
128.31 + <exclusion>
128.32 + <groupId>com.oracle</groupId>
128.33 + <artifactId>javafx</artifactId>
128.34 + </exclusion>
128.35 + </exclusions>
128.36 + </dependency>
128.37 + <dependency>
128.38 <groupId>org.netbeans.api</groupId>
128.39 <artifactId>org-openide-util-lookup</artifactId>
128.40 <scope>test</scope>
128.41 @@ -48,6 +59,15 @@
128.42 <target>1.7</target>
128.43 </configuration>
128.44 </plugin>
128.45 + <plugin>
128.46 + <groupId>org.apache.maven.plugins</groupId>
128.47 + <artifactId>maven-javadoc-plugin</artifactId>
128.48 + <configuration>
128.49 + <excludePackageNames>org.apidesign.bck2brwsr.emul.*</excludePackageNames>
128.50 + <skip>false</skip>
128.51 + <includeDependencySources>true</includeDependencySources>
128.52 + </configuration>
128.53 + </plugin>
128.54 <plugin>
128.55 <artifactId>maven-assembly-plugin</artifactId>
128.56 <version>2.4</version>
129.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
129.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedWriter.java Mon Oct 07 14:20:58 2013 +0200
129.3 @@ -0,0 +1,271 @@
129.4 +/*
129.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
129.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
129.7 + *
129.8 + * This code is free software; you can redistribute it and/or modify it
129.9 + * under the terms of the GNU General Public License version 2 only, as
129.10 + * published by the Free Software Foundation. Oracle designates this
129.11 + * particular file as subject to the "Classpath" exception as provided
129.12 + * by Oracle in the LICENSE file that accompanied this code.
129.13 + *
129.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
129.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
129.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
129.17 + * version 2 for more details (a copy is included in the LICENSE file that
129.18 + * accompanied this code).
129.19 + *
129.20 + * You should have received a copy of the GNU General Public License version
129.21 + * 2 along with this work; if not, write to the Free Software Foundation,
129.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
129.23 + *
129.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
129.25 + * or visit www.oracle.com if you need additional information or have any
129.26 + * questions.
129.27 + */
129.28 +
129.29 +package java.io;
129.30 +
129.31 +
129.32 +/**
129.33 + * Writes text to a character-output stream, buffering characters so as to
129.34 + * provide for the efficient writing of single characters, arrays, and strings.
129.35 + *
129.36 + * <p> The buffer size may be specified, or the default size may be accepted.
129.37 + * The default is large enough for most purposes.
129.38 + *
129.39 + * <p> A newLine() method is provided, which uses the platform's own notion of
129.40 + * line separator as defined by the system property <tt>line.separator</tt>.
129.41 + * Not all platforms use the newline character ('\n') to terminate lines.
129.42 + * Calling this method to terminate each output line is therefore preferred to
129.43 + * writing a newline character directly.
129.44 + *
129.45 + * <p> In general, a Writer sends its output immediately to the underlying
129.46 + * character or byte stream. Unless prompt output is required, it is advisable
129.47 + * to wrap a BufferedWriter around any Writer whose write() operations may be
129.48 + * costly, such as FileWriters and OutputStreamWriters. For example,
129.49 + *
129.50 + * <pre>
129.51 + * PrintWriter out
129.52 + * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
129.53 + * </pre>
129.54 + *
129.55 + * will buffer the PrintWriter's output to the file. Without buffering, each
129.56 + * invocation of a print() method would cause characters to be converted into
129.57 + * bytes that would then be written immediately to the file, which can be very
129.58 + * inefficient.
129.59 + *
129.60 + * @see PrintWriter
129.61 + * @see FileWriter
129.62 + * @see OutputStreamWriter
129.63 + * @see java.nio.file.Files#newBufferedWriter
129.64 + *
129.65 + * @author Mark Reinhold
129.66 + * @since JDK1.1
129.67 + */
129.68 +
129.69 +public class BufferedWriter extends Writer {
129.70 +
129.71 + private Writer out;
129.72 +
129.73 + private char cb[];
129.74 + private int nChars, nextChar;
129.75 +
129.76 + private static int defaultCharBufferSize = 8192;
129.77 +
129.78 + /**
129.79 + * Line separator string. This is the value of the line.separator
129.80 + * property at the moment that the stream was created.
129.81 + */
129.82 + private String lineSeparator;
129.83 +
129.84 + /**
129.85 + * Creates a buffered character-output stream that uses a default-sized
129.86 + * output buffer.
129.87 + *
129.88 + * @param out A Writer
129.89 + */
129.90 + public BufferedWriter(Writer out) {
129.91 + this(out, defaultCharBufferSize);
129.92 + }
129.93 +
129.94 + /**
129.95 + * Creates a new buffered character-output stream that uses an output
129.96 + * buffer of the given size.
129.97 + *
129.98 + * @param out A Writer
129.99 + * @param sz Output-buffer size, a positive integer
129.100 + *
129.101 + * @exception IllegalArgumentException If sz is <= 0
129.102 + */
129.103 + public BufferedWriter(Writer out, int sz) {
129.104 + super(out);
129.105 + if (sz <= 0)
129.106 + throw new IllegalArgumentException("Buffer size <= 0");
129.107 + this.out = out;
129.108 + cb = new char[sz];
129.109 + nChars = sz;
129.110 + nextChar = 0;
129.111 +
129.112 + lineSeparator = "\n";
129.113 + }
129.114 +
129.115 + /** Checks to make sure that the stream has not been closed */
129.116 + private void ensureOpen() throws IOException {
129.117 + if (out == null)
129.118 + throw new IOException("Stream closed");
129.119 + }
129.120 +
129.121 + /**
129.122 + * Flushes the output buffer to the underlying character stream, without
129.123 + * flushing the stream itself. This method is non-private only so that it
129.124 + * may be invoked by PrintStream.
129.125 + */
129.126 + void flushBuffer() throws IOException {
129.127 + synchronized (lock) {
129.128 + ensureOpen();
129.129 + if (nextChar == 0)
129.130 + return;
129.131 + out.write(cb, 0, nextChar);
129.132 + nextChar = 0;
129.133 + }
129.134 + }
129.135 +
129.136 + /**
129.137 + * Writes a single character.
129.138 + *
129.139 + * @exception IOException If an I/O error occurs
129.140 + */
129.141 + public void write(int c) throws IOException {
129.142 + synchronized (lock) {
129.143 + ensureOpen();
129.144 + if (nextChar >= nChars)
129.145 + flushBuffer();
129.146 + cb[nextChar++] = (char) c;
129.147 + }
129.148 + }
129.149 +
129.150 + /**
129.151 + * Our own little min method, to avoid loading java.lang.Math if we've run
129.152 + * out of file descriptors and we're trying to print a stack trace.
129.153 + */
129.154 + private int min(int a, int b) {
129.155 + if (a < b) return a;
129.156 + return b;
129.157 + }
129.158 +
129.159 + /**
129.160 + * Writes a portion of an array of characters.
129.161 + *
129.162 + * <p> Ordinarily this method stores characters from the given array into
129.163 + * this stream's buffer, flushing the buffer to the underlying stream as
129.164 + * needed. If the requested length is at least as large as the buffer,
129.165 + * however, then this method will flush the buffer and write the characters
129.166 + * directly to the underlying stream. Thus redundant
129.167 + * <code>BufferedWriter</code>s will not copy data unnecessarily.
129.168 + *
129.169 + * @param cbuf A character array
129.170 + * @param off Offset from which to start reading characters
129.171 + * @param len Number of characters to write
129.172 + *
129.173 + * @exception IOException If an I/O error occurs
129.174 + */
129.175 + public void write(char cbuf[], int off, int len) throws IOException {
129.176 + synchronized (lock) {
129.177 + ensureOpen();
129.178 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
129.179 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
129.180 + throw new IndexOutOfBoundsException();
129.181 + } else if (len == 0) {
129.182 + return;
129.183 + }
129.184 +
129.185 + if (len >= nChars) {
129.186 + /* If the request length exceeds the size of the output buffer,
129.187 + flush the buffer and then write the data directly. In this
129.188 + way buffered streams will cascade harmlessly. */
129.189 + flushBuffer();
129.190 + out.write(cbuf, off, len);
129.191 + return;
129.192 + }
129.193 +
129.194 + int b = off, t = off + len;
129.195 + while (b < t) {
129.196 + int d = min(nChars - nextChar, t - b);
129.197 + System.arraycopy(cbuf, b, cb, nextChar, d);
129.198 + b += d;
129.199 + nextChar += d;
129.200 + if (nextChar >= nChars)
129.201 + flushBuffer();
129.202 + }
129.203 + }
129.204 + }
129.205 +
129.206 + /**
129.207 + * Writes a portion of a String.
129.208 + *
129.209 + * <p> If the value of the <tt>len</tt> parameter is negative then no
129.210 + * characters are written. This is contrary to the specification of this
129.211 + * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
129.212 + * superclass}, which requires that an {@link IndexOutOfBoundsException} be
129.213 + * thrown.
129.214 + *
129.215 + * @param s String to be written
129.216 + * @param off Offset from which to start reading characters
129.217 + * @param len Number of characters to be written
129.218 + *
129.219 + * @exception IOException If an I/O error occurs
129.220 + */
129.221 + public void write(String s, int off, int len) throws IOException {
129.222 + synchronized (lock) {
129.223 + ensureOpen();
129.224 +
129.225 + int b = off, t = off + len;
129.226 + while (b < t) {
129.227 + int d = min(nChars - nextChar, t - b);
129.228 + s.getChars(b, b + d, cb, nextChar);
129.229 + b += d;
129.230 + nextChar += d;
129.231 + if (nextChar >= nChars)
129.232 + flushBuffer();
129.233 + }
129.234 + }
129.235 + }
129.236 +
129.237 + /**
129.238 + * Writes a line separator. The line separator string is defined by the
129.239 + * system property <tt>line.separator</tt>, and is not necessarily a single
129.240 + * newline ('\n') character.
129.241 + *
129.242 + * @exception IOException If an I/O error occurs
129.243 + */
129.244 + public void newLine() throws IOException {
129.245 + write(lineSeparator);
129.246 + }
129.247 +
129.248 + /**
129.249 + * Flushes the stream.
129.250 + *
129.251 + * @exception IOException If an I/O error occurs
129.252 + */
129.253 + public void flush() throws IOException {
129.254 + synchronized (lock) {
129.255 + flushBuffer();
129.256 + out.flush();
129.257 + }
129.258 + }
129.259 +
129.260 + public void close() throws IOException {
129.261 + synchronized (lock) {
129.262 + if (out == null) {
129.263 + return;
129.264 + }
129.265 + try {
129.266 + flushBuffer();
129.267 + } finally {
129.268 + out.close();
129.269 + out = null;
129.270 + cb = null;
129.271 + }
129.272 + }
129.273 + }
129.274 +}
130.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
130.2 +++ b/rt/emul/compact/src/main/java/java/io/File.java Mon Oct 07 14:20:58 2013 +0200
130.3 @@ -0,0 +1,1927 @@
130.4 +/*
130.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
130.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
130.7 + *
130.8 + * This code is free software; you can redistribute it and/or modify it
130.9 + * under the terms of the GNU General Public License version 2 only, as
130.10 + * published by the Free Software Foundation. Oracle designates this
130.11 + * particular file as subject to the "Classpath" exception as provided
130.12 + * by Oracle in the LICENSE file that accompanied this code.
130.13 + *
130.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
130.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
130.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
130.17 + * version 2 for more details (a copy is included in the LICENSE file that
130.18 + * accompanied this code).
130.19 + *
130.20 + * You should have received a copy of the GNU General Public License version
130.21 + * 2 along with this work; if not, write to the Free Software Foundation,
130.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
130.23 + *
130.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
130.25 + * or visit www.oracle.com if you need additional information or have any
130.26 + * questions.
130.27 + */
130.28 +
130.29 +package java.io;
130.30 +
130.31 +import java.net.URI;
130.32 +import java.net.URL;
130.33 +import java.net.MalformedURLException;
130.34 +import java.net.URISyntaxException;
130.35 +
130.36 +/**
130.37 + * An abstract representation of file and directory pathnames.
130.38 + *
130.39 + * <p> User interfaces and operating systems use system-dependent <em>pathname
130.40 + * strings</em> to name files and directories. This class presents an
130.41 + * abstract, system-independent view of hierarchical pathnames. An
130.42 + * <em>abstract pathname</em> has two components:
130.43 + *
130.44 + * <ol>
130.45 + * <li> An optional system-dependent <em>prefix</em> string,
130.46 + * such as a disk-drive specifier, <code>"/"</code> for the UNIX root
130.47 + * directory, or <code>"\\\\"</code> for a Microsoft Windows UNC pathname, and
130.48 + * <li> A sequence of zero or more string <em>names</em>.
130.49 + * </ol>
130.50 + *
130.51 + * The first name in an abstract pathname may be a directory name or, in the
130.52 + * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name
130.53 + * in an abstract pathname denotes a directory; the last name may denote
130.54 + * either a directory or a file. The <em>empty</em> abstract pathname has no
130.55 + * prefix and an empty name sequence.
130.56 + *
130.57 + * <p> The conversion of a pathname string to or from an abstract pathname is
130.58 + * inherently system-dependent. When an abstract pathname is converted into a
130.59 + * pathname string, each name is separated from the next by a single copy of
130.60 + * the default <em>separator character</em>. The default name-separator
130.61 + * character is defined by the system property <code>file.separator</code>, and
130.62 + * is made available in the public static fields <code>{@link
130.63 + * #separator}</code> and <code>{@link #separatorChar}</code> of this class.
130.64 + * When a pathname string is converted into an abstract pathname, the names
130.65 + * within it may be separated by the default name-separator character or by any
130.66 + * other name-separator character that is supported by the underlying system.
130.67 + *
130.68 + * <p> A pathname, whether abstract or in string form, may be either
130.69 + * <em>absolute</em> or <em>relative</em>. An absolute pathname is complete in
130.70 + * that no other information is required in order to locate the file that it
130.71 + * denotes. A relative pathname, in contrast, must be interpreted in terms of
130.72 + * information taken from some other pathname. By default the classes in the
130.73 + * <code>java.io</code> package always resolve relative pathnames against the
130.74 + * current user directory. This directory is named by the system property
130.75 + * <code>user.dir</code>, and is typically the directory in which the Java
130.76 + * virtual machine was invoked.
130.77 + *
130.78 + * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking
130.79 + * the {@link #getParent} method of this class and consists of the pathname's
130.80 + * prefix and each name in the pathname's name sequence except for the last.
130.81 + * Each directory's absolute pathname is an ancestor of any <tt>File</tt>
130.82 + * object with an absolute abstract pathname which begins with the directory's
130.83 + * absolute pathname. For example, the directory denoted by the abstract
130.84 + * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the
130.85 + * pathname <tt>"/usr/local/bin"</tt>.
130.86 + *
130.87 + * <p> The prefix concept is used to handle root directories on UNIX platforms,
130.88 + * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms,
130.89 + * as follows:
130.90 + *
130.91 + * <ul>
130.92 + *
130.93 + * <li> For UNIX platforms, the prefix of an absolute pathname is always
130.94 + * <code>"/"</code>. Relative pathnames have no prefix. The abstract pathname
130.95 + * denoting the root directory has the prefix <code>"/"</code> and an empty
130.96 + * name sequence.
130.97 + *
130.98 + * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive
130.99 + * specifier consists of the drive letter followed by <code>":"</code> and
130.100 + * possibly followed by <code>"\\"</code> if the pathname is absolute. The
130.101 + * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share
130.102 + * name are the first two names in the name sequence. A relative pathname that
130.103 + * does not specify a drive has no prefix.
130.104 + *
130.105 + * </ul>
130.106 + *
130.107 + * <p> Instances of this class may or may not denote an actual file-system
130.108 + * object such as a file or a directory. If it does denote such an object
130.109 + * then that object resides in a <i>partition</i>. A partition is an
130.110 + * operating system-specific portion of storage for a file system. A single
130.111 + * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may
130.112 + * contain multiple partitions. The object, if any, will reside on the
130.113 + * partition <a name="partName">named</a> by some ancestor of the absolute
130.114 + * form of this pathname.
130.115 + *
130.116 + * <p> A file system may implement restrictions to certain operations on the
130.117 + * actual file-system object, such as reading, writing, and executing. These
130.118 + * restrictions are collectively known as <i>access permissions</i>. The file
130.119 + * system may have multiple sets of access permissions on a single object.
130.120 + * For example, one set may apply to the object's <i>owner</i>, and another
130.121 + * may apply to all other users. The access permissions on an object may
130.122 + * cause some methods in this class to fail.
130.123 + *
130.124 + * <p> Instances of the <code>File</code> class are immutable; that is, once
130.125 + * created, the abstract pathname represented by a <code>File</code> object
130.126 + * will never change.
130.127 + *
130.128 + * <h4>Interoperability with {@code java.nio.file} package</h4>
130.129 + *
130.130 + * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
130.131 + * package defines interfaces and classes for the Java virtual machine to access
130.132 + * files, file attributes, and file systems. This API may be used to overcome
130.133 + * many of the limitations of the {@code java.io.File} class.
130.134 + * The {@link #toPath toPath} method may be used to obtain a {@link
130.135 + * Path} that uses the abstract path represented by a {@code File} object to
130.136 + * locate a file. The resulting {@code Path} may be used with the {@link
130.137 + * java.nio.file.Files} class to provide more efficient and extensive access to
130.138 + * additional file operations, file attributes, and I/O exceptions to help
130.139 + * diagnose errors when an operation on a file fails.
130.140 + *
130.141 + * @author unascribed
130.142 + * @since JDK1.0
130.143 + */
130.144 +
130.145 +public class File
130.146 + implements Serializable, Comparable<File>
130.147 +{
130.148 +
130.149 + /**
130.150 + * The FileSystem object representing the platform's local file system.
130.151 + */
130.152 + static private FileSystem fs = new FileSystem();
130.153 + private static class FileSystem {
130.154 +
130.155 + private char getSeparator() {
130.156 + return '/';
130.157 + }
130.158 +
130.159 + private String resolve(String path, String child) {
130.160 + return path + '/' + child;
130.161 + }
130.162 +
130.163 + private String normalize(String pathname) {
130.164 + return pathname;
130.165 + }
130.166 +
130.167 + private int prefixLength(String path) {
130.168 + return 0;
130.169 + }
130.170 +
130.171 + private String getDefaultParent() {
130.172 + return "/";
130.173 + }
130.174 +
130.175 + private String fromURIPath(String p) {
130.176 + return p;
130.177 + }
130.178 +
130.179 + private boolean isAbsolute(File aThis) {
130.180 + return aThis.getPath().startsWith("/");
130.181 + }
130.182 +
130.183 + private int compare(File one, File two) {
130.184 + return one.getPath().compareTo(two.getPath());
130.185 + }
130.186 +
130.187 + private int hashCode(File aThis) {
130.188 + return aThis.getPath().hashCode();
130.189 + }
130.190 +
130.191 + private char getPathSeparator() {
130.192 + return ':';
130.193 + }
130.194 +
130.195 + }
130.196 +
130.197 + /**
130.198 + * This abstract pathname's normalized pathname string. A normalized
130.199 + * pathname string uses the default name-separator character and does not
130.200 + * contain any duplicate or redundant separators.
130.201 + *
130.202 + * @serial
130.203 + */
130.204 + private String path;
130.205 +
130.206 + /**
130.207 + * The length of this abstract pathname's prefix, or zero if it has no
130.208 + * prefix.
130.209 + */
130.210 + private transient int prefixLength;
130.211 +
130.212 + /**
130.213 + * Returns the length of this abstract pathname's prefix.
130.214 + * For use by FileSystem classes.
130.215 + */
130.216 + int getPrefixLength() {
130.217 + return prefixLength;
130.218 + }
130.219 +
130.220 + /**
130.221 + * The system-dependent default name-separator character. This field is
130.222 + * initialized to contain the first character of the value of the system
130.223 + * property <code>file.separator</code>. On UNIX systems the value of this
130.224 + * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
130.225 + *
130.226 + * @see java.lang.System#getProperty(java.lang.String)
130.227 + */
130.228 + public static final char separatorChar = fs.getSeparator();
130.229 +
130.230 + /**
130.231 + * The system-dependent default name-separator character, represented as a
130.232 + * string for convenience. This string contains a single character, namely
130.233 + * <code>{@link #separatorChar}</code>.
130.234 + */
130.235 + public static final String separator = "" + separatorChar;
130.236 +
130.237 + /**
130.238 + * The system-dependent path-separator character. This field is
130.239 + * initialized to contain the first character of the value of the system
130.240 + * property <code>path.separator</code>. This character is used to
130.241 + * separate filenames in a sequence of files given as a <em>path list</em>.
130.242 + * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it
130.243 + * is <code>';'</code>.
130.244 + *
130.245 + * @see java.lang.System#getProperty(java.lang.String)
130.246 + */
130.247 + public static final char pathSeparatorChar = fs.getPathSeparator();
130.248 +
130.249 + /**
130.250 + * The system-dependent path-separator character, represented as a string
130.251 + * for convenience. This string contains a single character, namely
130.252 + * <code>{@link #pathSeparatorChar}</code>.
130.253 + */
130.254 + public static final String pathSeparator = "" + pathSeparatorChar;
130.255 +
130.256 +
130.257 + /* -- Constructors -- */
130.258 +
130.259 + /**
130.260 + * Internal constructor for already-normalized pathname strings.
130.261 + */
130.262 + private File(String pathname, int prefixLength) {
130.263 + this.path = pathname;
130.264 + this.prefixLength = prefixLength;
130.265 + }
130.266 +
130.267 + /**
130.268 + * Internal constructor for already-normalized pathname strings.
130.269 + * The parameter order is used to disambiguate this method from the
130.270 + * public(File, String) constructor.
130.271 + */
130.272 + private File(String child, File parent) {
130.273 + assert parent.path != null;
130.274 + assert (!parent.path.equals(""));
130.275 + this.path = fs.resolve(parent.path, child);
130.276 + this.prefixLength = parent.prefixLength;
130.277 + }
130.278 +
130.279 + /**
130.280 + * Creates a new <code>File</code> instance by converting the given
130.281 + * pathname string into an abstract pathname. If the given string is
130.282 + * the empty string, then the result is the empty abstract pathname.
130.283 + *
130.284 + * @param pathname A pathname string
130.285 + * @throws NullPointerException
130.286 + * If the <code>pathname</code> argument is <code>null</code>
130.287 + */
130.288 + public File(String pathname) {
130.289 + if (pathname == null) {
130.290 + throw new NullPointerException();
130.291 + }
130.292 + this.path = fs.normalize(pathname);
130.293 + this.prefixLength = fs.prefixLength(this.path);
130.294 + }
130.295 +
130.296 + /* Note: The two-argument File constructors do not interpret an empty
130.297 + parent abstract pathname as the current user directory. An empty parent
130.298 + instead causes the child to be resolved against the system-dependent
130.299 + directory defined by the FileSystem.getDefaultParent method. On Unix
130.300 + this default is "/", while on Microsoft Windows it is "\\". This is required for
130.301 + compatibility with the original behavior of this class. */
130.302 +
130.303 + /**
130.304 + * Creates a new <code>File</code> instance from a parent pathname string
130.305 + * and a child pathname string.
130.306 + *
130.307 + * <p> If <code>parent</code> is <code>null</code> then the new
130.308 + * <code>File</code> instance is created as if by invoking the
130.309 + * single-argument <code>File</code> constructor on the given
130.310 + * <code>child</code> pathname string.
130.311 + *
130.312 + * <p> Otherwise the <code>parent</code> pathname string is taken to denote
130.313 + * a directory, and the <code>child</code> pathname string is taken to
130.314 + * denote either a directory or a file. If the <code>child</code> pathname
130.315 + * string is absolute then it is converted into a relative pathname in a
130.316 + * system-dependent way. If <code>parent</code> is the empty string then
130.317 + * the new <code>File</code> instance is created by converting
130.318 + * <code>child</code> into an abstract pathname and resolving the result
130.319 + * against a system-dependent default directory. Otherwise each pathname
130.320 + * string is converted into an abstract pathname and the child abstract
130.321 + * pathname is resolved against the parent.
130.322 + *
130.323 + * @param parent The parent pathname string
130.324 + * @param child The child pathname string
130.325 + * @throws NullPointerException
130.326 + * If <code>child</code> is <code>null</code>
130.327 + */
130.328 + public File(String parent, String child) {
130.329 + if (child == null) {
130.330 + throw new NullPointerException();
130.331 + }
130.332 + if (parent != null) {
130.333 + if (parent.equals("")) {
130.334 + this.path = fs.resolve(fs.getDefaultParent(),
130.335 + fs.normalize(child));
130.336 + } else {
130.337 + this.path = fs.resolve(fs.normalize(parent),
130.338 + fs.normalize(child));
130.339 + }
130.340 + } else {
130.341 + this.path = fs.normalize(child);
130.342 + }
130.343 + this.prefixLength = fs.prefixLength(this.path);
130.344 + }
130.345 +
130.346 + /**
130.347 + * Creates a new <code>File</code> instance from a parent abstract
130.348 + * pathname and a child pathname string.
130.349 + *
130.350 + * <p> If <code>parent</code> is <code>null</code> then the new
130.351 + * <code>File</code> instance is created as if by invoking the
130.352 + * single-argument <code>File</code> constructor on the given
130.353 + * <code>child</code> pathname string.
130.354 + *
130.355 + * <p> Otherwise the <code>parent</code> abstract pathname is taken to
130.356 + * denote a directory, and the <code>child</code> pathname string is taken
130.357 + * to denote either a directory or a file. If the <code>child</code>
130.358 + * pathname string is absolute then it is converted into a relative
130.359 + * pathname in a system-dependent way. If <code>parent</code> is the empty
130.360 + * abstract pathname then the new <code>File</code> instance is created by
130.361 + * converting <code>child</code> into an abstract pathname and resolving
130.362 + * the result against a system-dependent default directory. Otherwise each
130.363 + * pathname string is converted into an abstract pathname and the child
130.364 + * abstract pathname is resolved against the parent.
130.365 + *
130.366 + * @param parent The parent abstract pathname
130.367 + * @param child The child pathname string
130.368 + * @throws NullPointerException
130.369 + * If <code>child</code> is <code>null</code>
130.370 + */
130.371 + public File(File parent, String child) {
130.372 + if (child == null) {
130.373 + throw new NullPointerException();
130.374 + }
130.375 + if (parent != null) {
130.376 + if (parent.path.equals("")) {
130.377 + this.path = fs.resolve(fs.getDefaultParent(),
130.378 + fs.normalize(child));
130.379 + } else {
130.380 + this.path = fs.resolve(parent.path,
130.381 + fs.normalize(child));
130.382 + }
130.383 + } else {
130.384 + this.path = fs.normalize(child);
130.385 + }
130.386 + this.prefixLength = fs.prefixLength(this.path);
130.387 + }
130.388 +
130.389 + /**
130.390 + * Creates a new <tt>File</tt> instance by converting the given
130.391 + * <tt>file:</tt> URI into an abstract pathname.
130.392 + *
130.393 + * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence
130.394 + * the transformation performed by this constructor is also
130.395 + * system-dependent.
130.396 + *
130.397 + * <p> For a given abstract pathname <i>f</i> it is guaranteed that
130.398 + *
130.399 + * <blockquote><tt>
130.400 + * new File(</tt><i> f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
130.401 + * </tt></blockquote>
130.402 + *
130.403 + * so long as the original abstract pathname, the URI, and the new abstract
130.404 + * pathname are all created in (possibly different invocations of) the same
130.405 + * Java virtual machine. This relationship typically does not hold,
130.406 + * however, when a <tt>file:</tt> URI that is created in a virtual machine
130.407 + * on one operating system is converted into an abstract pathname in a
130.408 + * virtual machine on a different operating system.
130.409 + *
130.410 + * @param uri
130.411 + * An absolute, hierarchical URI with a scheme equal to
130.412 + * <tt>"file"</tt>, a non-empty path component, and undefined
130.413 + * authority, query, and fragment components
130.414 + *
130.415 + * @throws NullPointerException
130.416 + * If <tt>uri</tt> is <tt>null</tt>
130.417 + *
130.418 + * @throws IllegalArgumentException
130.419 + * If the preconditions on the parameter do not hold
130.420 + *
130.421 + * @see #toURI()
130.422 + * @see java.net.URI
130.423 + * @since 1.4
130.424 + */
130.425 + public File(URI uri) {
130.426 +
130.427 + // Check our many preconditions
130.428 + if (!uri.isAbsolute())
130.429 + throw new IllegalArgumentException("URI is not absolute");
130.430 + if (uri.isOpaque())
130.431 + throw new IllegalArgumentException("URI is not hierarchical");
130.432 + String scheme = uri.getScheme();
130.433 + if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
130.434 + throw new IllegalArgumentException("URI scheme is not \"file\"");
130.435 + if (uri.getAuthority() != null)
130.436 + throw new IllegalArgumentException("URI has an authority component");
130.437 + if (uri.getFragment() != null)
130.438 + throw new IllegalArgumentException("URI has a fragment component");
130.439 + if (uri.getQuery() != null)
130.440 + throw new IllegalArgumentException("URI has a query component");
130.441 + String p = uri.getPath();
130.442 + if (p.equals(""))
130.443 + throw new IllegalArgumentException("URI path component is empty");
130.444 +
130.445 + // Okay, now initialize
130.446 + p = fs.fromURIPath(p);
130.447 + if (File.separatorChar != '/')
130.448 + p = p.replace('/', File.separatorChar);
130.449 + this.path = fs.normalize(p);
130.450 + this.prefixLength = fs.prefixLength(this.path);
130.451 + }
130.452 +
130.453 +
130.454 + /* -- Path-component accessors -- */
130.455 +
130.456 + /**
130.457 + * Returns the name of the file or directory denoted by this abstract
130.458 + * pathname. This is just the last name in the pathname's name
130.459 + * sequence. If the pathname's name sequence is empty, then the empty
130.460 + * string is returned.
130.461 + *
130.462 + * @return The name of the file or directory denoted by this abstract
130.463 + * pathname, or the empty string if this pathname's name sequence
130.464 + * is empty
130.465 + */
130.466 + public String getName() {
130.467 + int index = path.lastIndexOf(separatorChar);
130.468 + if (index < prefixLength) return path.substring(prefixLength);
130.469 + return path.substring(index + 1);
130.470 + }
130.471 +
130.472 + /**
130.473 + * Returns the pathname string of this abstract pathname's parent, or
130.474 + * <code>null</code> if this pathname does not name a parent directory.
130.475 + *
130.476 + * <p> The <em>parent</em> of an abstract pathname consists of the
130.477 + * pathname's prefix, if any, and each name in the pathname's name
130.478 + * sequence except for the last. If the name sequence is empty then
130.479 + * the pathname does not name a parent directory.
130.480 + *
130.481 + * @return The pathname string of the parent directory named by this
130.482 + * abstract pathname, or <code>null</code> if this pathname
130.483 + * does not name a parent
130.484 + */
130.485 + public String getParent() {
130.486 + int index = path.lastIndexOf(separatorChar);
130.487 + if (index < prefixLength) {
130.488 + if ((prefixLength > 0) && (path.length() > prefixLength))
130.489 + return path.substring(0, prefixLength);
130.490 + return null;
130.491 + }
130.492 + return path.substring(0, index);
130.493 + }
130.494 +
130.495 + /**
130.496 + * Returns the abstract pathname of this abstract pathname's parent,
130.497 + * or <code>null</code> if this pathname does not name a parent
130.498 + * directory.
130.499 + *
130.500 + * <p> The <em>parent</em> of an abstract pathname consists of the
130.501 + * pathname's prefix, if any, and each name in the pathname's name
130.502 + * sequence except for the last. If the name sequence is empty then
130.503 + * the pathname does not name a parent directory.
130.504 + *
130.505 + * @return The abstract pathname of the parent directory named by this
130.506 + * abstract pathname, or <code>null</code> if this pathname
130.507 + * does not name a parent
130.508 + *
130.509 + * @since 1.2
130.510 + */
130.511 + public File getParentFile() {
130.512 + String p = this.getParent();
130.513 + if (p == null) return null;
130.514 + return new File(p, this.prefixLength);
130.515 + }
130.516 +
130.517 + /**
130.518 + * Converts this abstract pathname into a pathname string. The resulting
130.519 + * string uses the {@link #separator default name-separator character} to
130.520 + * separate the names in the name sequence.
130.521 + *
130.522 + * @return The string form of this abstract pathname
130.523 + */
130.524 + public String getPath() {
130.525 + return path;
130.526 + }
130.527 +
130.528 +
130.529 + /* -- Path operations -- */
130.530 +
130.531 + /**
130.532 + * Tests whether this abstract pathname is absolute. The definition of
130.533 + * absolute pathname is system dependent. On UNIX systems, a pathname is
130.534 + * absolute if its prefix is <code>"/"</code>. On Microsoft Windows systems, a
130.535 + * pathname is absolute if its prefix is a drive specifier followed by
130.536 + * <code>"\\"</code>, or if its prefix is <code>"\\\\"</code>.
130.537 + *
130.538 + * @return <code>true</code> if this abstract pathname is absolute,
130.539 + * <code>false</code> otherwise
130.540 + */
130.541 + public boolean isAbsolute() {
130.542 + return fs.isAbsolute(this);
130.543 + }
130.544 +
130.545 + /**
130.546 + * Returns the absolute pathname string of this abstract pathname.
130.547 + *
130.548 + * <p> If this abstract pathname is already absolute, then the pathname
130.549 + * string is simply returned as if by the <code>{@link #getPath}</code>
130.550 + * method. If this abstract pathname is the empty abstract pathname then
130.551 + * the pathname string of the current user directory, which is named by the
130.552 + * system property <code>user.dir</code>, is returned. Otherwise this
130.553 + * pathname is resolved in a system-dependent way. On UNIX systems, a
130.554 + * relative pathname is made absolute by resolving it against the current
130.555 + * user directory. On Microsoft Windows systems, a relative pathname is made absolute
130.556 + * by resolving it against the current directory of the drive named by the
130.557 + * pathname, if any; if not, it is resolved against the current user
130.558 + * directory.
130.559 + *
130.560 + * @return The absolute pathname string denoting the same file or
130.561 + * directory as this abstract pathname
130.562 + *
130.563 + * @throws SecurityException
130.564 + * If a required system property value cannot be accessed.
130.565 + *
130.566 + * @see java.io.File#isAbsolute()
130.567 + */
130.568 + public String getAbsolutePath() {
130.569 + throw new SecurityException();
130.570 + }
130.571 +
130.572 + /**
130.573 + * Returns the absolute form of this abstract pathname. Equivalent to
130.574 + * <code>new File(this.{@link #getAbsolutePath})</code>.
130.575 + *
130.576 + * @return The absolute abstract pathname denoting the same file or
130.577 + * directory as this abstract pathname
130.578 + *
130.579 + * @throws SecurityException
130.580 + * If a required system property value cannot be accessed.
130.581 + *
130.582 + * @since 1.2
130.583 + */
130.584 + public File getAbsoluteFile() {
130.585 + String absPath = getAbsolutePath();
130.586 + return new File(absPath, fs.prefixLength(absPath));
130.587 + }
130.588 +
130.589 + /**
130.590 + * Returns the canonical pathname string of this abstract pathname.
130.591 + *
130.592 + * <p> A canonical pathname is both absolute and unique. The precise
130.593 + * definition of canonical form is system-dependent. This method first
130.594 + * converts this pathname to absolute form if necessary, as if by invoking the
130.595 + * {@link #getAbsolutePath} method, and then maps it to its unique form in a
130.596 + * system-dependent way. This typically involves removing redundant names
130.597 + * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving
130.598 + * symbolic links (on UNIX platforms), and converting drive letters to a
130.599 + * standard case (on Microsoft Windows platforms).
130.600 + *
130.601 + * <p> Every pathname that denotes an existing file or directory has a
130.602 + * unique canonical form. Every pathname that denotes a nonexistent file
130.603 + * or directory also has a unique canonical form. The canonical form of
130.604 + * the pathname of a nonexistent file or directory may be different from
130.605 + * the canonical form of the same pathname after the file or directory is
130.606 + * created. Similarly, the canonical form of the pathname of an existing
130.607 + * file or directory may be different from the canonical form of the same
130.608 + * pathname after the file or directory is deleted.
130.609 + *
130.610 + * @return The canonical pathname string denoting the same file or
130.611 + * directory as this abstract pathname
130.612 + *
130.613 + * @throws IOException
130.614 + * If an I/O error occurs, which is possible because the
130.615 + * construction of the canonical pathname may require
130.616 + * filesystem queries
130.617 + *
130.618 + * @throws SecurityException
130.619 + * If a required system property value cannot be accessed, or
130.620 + * if a security manager exists and its <code>{@link
130.621 + * java.lang.SecurityManager#checkRead}</code> method denies
130.622 + * read access to the file
130.623 + *
130.624 + * @since JDK1.1
130.625 + * @see Path#toRealPath
130.626 + */
130.627 + public String getCanonicalPath() throws IOException {
130.628 + throw new SecurityException();
130.629 + }
130.630 +
130.631 + /**
130.632 + * Returns the canonical form of this abstract pathname. Equivalent to
130.633 + * <code>new File(this.{@link #getCanonicalPath})</code>.
130.634 + *
130.635 + * @return The canonical pathname string denoting the same file or
130.636 + * directory as this abstract pathname
130.637 + *
130.638 + * @throws IOException
130.639 + * If an I/O error occurs, which is possible because the
130.640 + * construction of the canonical pathname may require
130.641 + * filesystem queries
130.642 + *
130.643 + * @throws SecurityException
130.644 + * If a required system property value cannot be accessed, or
130.645 + * if a security manager exists and its <code>{@link
130.646 + * java.lang.SecurityManager#checkRead}</code> method denies
130.647 + * read access to the file
130.648 + *
130.649 + * @since 1.2
130.650 + * @see Path#toRealPath
130.651 + */
130.652 + public File getCanonicalFile() throws IOException {
130.653 + String canonPath = getCanonicalPath();
130.654 + return new File(canonPath, fs.prefixLength(canonPath));
130.655 + }
130.656 +
130.657 + private static String slashify(String path, boolean isDirectory) {
130.658 + String p = path;
130.659 + if (File.separatorChar != '/')
130.660 + p = p.replace(File.separatorChar, '/');
130.661 + if (!p.startsWith("/"))
130.662 + p = "/" + p;
130.663 + if (!p.endsWith("/") && isDirectory)
130.664 + p = p + "/";
130.665 + return p;
130.666 + }
130.667 +
130.668 + /**
130.669 + * Converts this abstract pathname into a <code>file:</code> URL. The
130.670 + * exact form of the URL is system-dependent. If it can be determined that
130.671 + * the file denoted by this abstract pathname is a directory, then the
130.672 + * resulting URL will end with a slash.
130.673 + *
130.674 + * @return A URL object representing the equivalent file URL
130.675 + *
130.676 + * @throws MalformedURLException
130.677 + * If the path cannot be parsed as a URL
130.678 + *
130.679 + * @see #toURI()
130.680 + * @see java.net.URI
130.681 + * @see java.net.URI#toURL()
130.682 + * @see java.net.URL
130.683 + * @since 1.2
130.684 + *
130.685 + * @deprecated This method does not automatically escape characters that
130.686 + * are illegal in URLs. It is recommended that new code convert an
130.687 + * abstract pathname into a URL by first converting it into a URI, via the
130.688 + * {@link #toURI() toURI} method, and then converting the URI into a URL
130.689 + * via the {@link java.net.URI#toURL() URI.toURL} method.
130.690 + */
130.691 + @Deprecated
130.692 + public URL toURL() throws MalformedURLException {
130.693 + return new URL("file", "", slashify(getAbsolutePath(), isDirectory()));
130.694 + }
130.695 +
130.696 + /**
130.697 + * Constructs a <tt>file:</tt> URI that represents this abstract pathname.
130.698 + *
130.699 + * <p> The exact form of the URI is system-dependent. If it can be
130.700 + * determined that the file denoted by this abstract pathname is a
130.701 + * directory, then the resulting URI will end with a slash.
130.702 + *
130.703 + * <p> For a given abstract pathname <i>f</i>, it is guaranteed that
130.704 + *
130.705 + * <blockquote><tt>
130.706 + * new {@link #File(java.net.URI) File}(</tt><i> f</i><tt>.toURI()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
130.707 + * </tt></blockquote>
130.708 + *
130.709 + * so long as the original abstract pathname, the URI, and the new abstract
130.710 + * pathname are all created in (possibly different invocations of) the same
130.711 + * Java virtual machine. Due to the system-dependent nature of abstract
130.712 + * pathnames, however, this relationship typically does not hold when a
130.713 + * <tt>file:</tt> URI that is created in a virtual machine on one operating
130.714 + * system is converted into an abstract pathname in a virtual machine on a
130.715 + * different operating system.
130.716 + *
130.717 + * <p> Note that when this abstract pathname represents a UNC pathname then
130.718 + * all components of the UNC (including the server name component) are encoded
130.719 + * in the {@code URI} path. The authority component is undefined, meaning
130.720 + * that it is represented as {@code null}. The {@link Path} class defines the
130.721 + * {@link Path#toUri toUri} method to encode the server name in the authority
130.722 + * component of the resulting {@code URI}. The {@link #toPath toPath} method
130.723 + * may be used to obtain a {@code Path} representing this abstract pathname.
130.724 + *
130.725 + * @return An absolute, hierarchical URI with a scheme equal to
130.726 + * <tt>"file"</tt>, a path representing this abstract pathname,
130.727 + * and undefined authority, query, and fragment components
130.728 + * @throws SecurityException If a required system property value cannot
130.729 + * be accessed.
130.730 + *
130.731 + * @see #File(java.net.URI)
130.732 + * @see java.net.URI
130.733 + * @see java.net.URI#toURL()
130.734 + * @since 1.4
130.735 + */
130.736 + public URI toURI() {
130.737 + try {
130.738 + File f = getAbsoluteFile();
130.739 + String sp = slashify(f.getPath(), f.isDirectory());
130.740 + if (sp.startsWith("//"))
130.741 + sp = "//" + sp;
130.742 + return new URI("file", null, sp, null);
130.743 + } catch (URISyntaxException x) {
130.744 + throw new Error(x); // Can't happen
130.745 + }
130.746 + }
130.747 +
130.748 +
130.749 + /* -- Attribute accessors -- */
130.750 +
130.751 + /**
130.752 + * Tests whether the application can read the file denoted by this
130.753 + * abstract pathname.
130.754 + *
130.755 + * @return <code>true</code> if and only if the file specified by this
130.756 + * abstract pathname exists <em>and</em> can be read by the
130.757 + * application; <code>false</code> otherwise
130.758 + *
130.759 + * @throws SecurityException
130.760 + * If a security manager exists and its <code>{@link
130.761 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.762 + * method denies read access to the file
130.763 + */
130.764 + public boolean canRead() {
130.765 + throw new SecurityException();
130.766 + }
130.767 +
130.768 + /**
130.769 + * Tests whether the application can modify the file denoted by this
130.770 + * abstract pathname.
130.771 + *
130.772 + * @return <code>true</code> if and only if the file system actually
130.773 + * contains a file denoted by this abstract pathname <em>and</em>
130.774 + * the application is allowed to write to the file;
130.775 + * <code>false</code> otherwise.
130.776 + *
130.777 + * @throws SecurityException
130.778 + * If a security manager exists and its <code>{@link
130.779 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.780 + * method denies write access to the file
130.781 + */
130.782 + public boolean canWrite() {
130.783 + throw new SecurityException();
130.784 + }
130.785 +
130.786 + /**
130.787 + * Tests whether the file or directory denoted by this abstract pathname
130.788 + * exists.
130.789 + *
130.790 + * @return <code>true</code> if and only if the file or directory denoted
130.791 + * by this abstract pathname exists; <code>false</code> otherwise
130.792 + *
130.793 + * @throws SecurityException
130.794 + * If a security manager exists and its <code>{@link
130.795 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.796 + * method denies read access to the file or directory
130.797 + */
130.798 + public boolean exists() {
130.799 + throw new SecurityException();
130.800 + }
130.801 +
130.802 + /**
130.803 + * Tests whether the file denoted by this abstract pathname is a
130.804 + * directory.
130.805 + *
130.806 + * <p> Where it is required to distinguish an I/O exception from the case
130.807 + * that the file is not a directory, or where several attributes of the
130.808 + * same file are required at the same time, then the {@link
130.809 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
130.810 + * Files.readAttributes} method may be used.
130.811 + *
130.812 + * @return <code>true</code> if and only if the file denoted by this
130.813 + * abstract pathname exists <em>and</em> is a directory;
130.814 + * <code>false</code> otherwise
130.815 + *
130.816 + * @throws SecurityException
130.817 + * If a security manager exists and its <code>{@link
130.818 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.819 + * method denies read access to the file
130.820 + */
130.821 + public boolean isDirectory() {
130.822 + throw new SecurityException();
130.823 + }
130.824 +
130.825 + /**
130.826 + * Tests whether the file denoted by this abstract pathname is a normal
130.827 + * file. A file is <em>normal</em> if it is not a directory and, in
130.828 + * addition, satisfies other system-dependent criteria. Any non-directory
130.829 + * file created by a Java application is guaranteed to be a normal file.
130.830 + *
130.831 + * <p> Where it is required to distinguish an I/O exception from the case
130.832 + * that the file is not a normal file, or where several attributes of the
130.833 + * same file are required at the same time, then the {@link
130.834 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
130.835 + * Files.readAttributes} method may be used.
130.836 + *
130.837 + * @return <code>true</code> if and only if the file denoted by this
130.838 + * abstract pathname exists <em>and</em> is a normal file;
130.839 + * <code>false</code> otherwise
130.840 + *
130.841 + * @throws SecurityException
130.842 + * If a security manager exists and its <code>{@link
130.843 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.844 + * method denies read access to the file
130.845 + */
130.846 + public boolean isFile() {
130.847 + throw new SecurityException();
130.848 + }
130.849 +
130.850 + /**
130.851 + * Tests whether the file named by this abstract pathname is a hidden
130.852 + * file. The exact definition of <em>hidden</em> is system-dependent. On
130.853 + * UNIX systems, a file is considered to be hidden if its name begins with
130.854 + * a period character (<code>'.'</code>). On Microsoft Windows systems, a file is
130.855 + * considered to be hidden if it has been marked as such in the filesystem.
130.856 + *
130.857 + * @return <code>true</code> if and only if the file denoted by this
130.858 + * abstract pathname is hidden according to the conventions of the
130.859 + * underlying platform
130.860 + *
130.861 + * @throws SecurityException
130.862 + * If a security manager exists and its <code>{@link
130.863 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.864 + * method denies read access to the file
130.865 + *
130.866 + * @since 1.2
130.867 + */
130.868 + public boolean isHidden() {
130.869 + throw new SecurityException();
130.870 + }
130.871 +
130.872 + /**
130.873 + * Returns the time that the file denoted by this abstract pathname was
130.874 + * last modified.
130.875 + *
130.876 + * <p> Where it is required to distinguish an I/O exception from the case
130.877 + * where {@code 0L} is returned, or where several attributes of the
130.878 + * same file are required at the same time, or where the time of last
130.879 + * access or the creation time are required, then the {@link
130.880 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
130.881 + * Files.readAttributes} method may be used.
130.882 + *
130.883 + * @return A <code>long</code> value representing the time the file was
130.884 + * last modified, measured in milliseconds since the epoch
130.885 + * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
130.886 + * file does not exist or if an I/O error occurs
130.887 + *
130.888 + * @throws SecurityException
130.889 + * If a security manager exists and its <code>{@link
130.890 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.891 + * method denies read access to the file
130.892 + */
130.893 + public long lastModified() {
130.894 + throw new SecurityException();
130.895 + }
130.896 +
130.897 + /**
130.898 + * Returns the length of the file denoted by this abstract pathname.
130.899 + * The return value is unspecified if this pathname denotes a directory.
130.900 + *
130.901 + * <p> Where it is required to distinguish an I/O exception from the case
130.902 + * that {@code 0L} is returned, or where several attributes of the same file
130.903 + * are required at the same time, then the {@link
130.904 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
130.905 + * Files.readAttributes} method may be used.
130.906 + *
130.907 + * @return The length, in bytes, of the file denoted by this abstract
130.908 + * pathname, or <code>0L</code> if the file does not exist. Some
130.909 + * operating systems may return <code>0L</code> for pathnames
130.910 + * denoting system-dependent entities such as devices or pipes.
130.911 + *
130.912 + * @throws SecurityException
130.913 + * If a security manager exists and its <code>{@link
130.914 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.915 + * method denies read access to the file
130.916 + */
130.917 + public long length() {
130.918 + throw new SecurityException();
130.919 + }
130.920 +
130.921 +
130.922 + /* -- File operations -- */
130.923 +
130.924 + /**
130.925 + * Atomically creates a new, empty file named by this abstract pathname if
130.926 + * and only if a file with this name does not yet exist. The check for the
130.927 + * existence of the file and the creation of the file if it does not exist
130.928 + * are a single operation that is atomic with respect to all other
130.929 + * filesystem activities that might affect the file.
130.930 + * <P>
130.931 + * Note: this method should <i>not</i> be used for file-locking, as
130.932 + * the resulting protocol cannot be made to work reliably. The
130.933 + * {@link java.nio.channels.FileLock FileLock}
130.934 + * facility should be used instead.
130.935 + *
130.936 + * @return <code>true</code> if the named file does not exist and was
130.937 + * successfully created; <code>false</code> if the named file
130.938 + * already exists
130.939 + *
130.940 + * @throws IOException
130.941 + * If an I/O error occurred
130.942 + *
130.943 + * @throws SecurityException
130.944 + * If a security manager exists and its <code>{@link
130.945 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.946 + * method denies write access to the file
130.947 + *
130.948 + * @since 1.2
130.949 + */
130.950 + public boolean createNewFile() throws IOException {
130.951 + throw new SecurityException();
130.952 + }
130.953 +
130.954 + /**
130.955 + * Deletes the file or directory denoted by this abstract pathname. If
130.956 + * this pathname denotes a directory, then the directory must be empty in
130.957 + * order to be deleted.
130.958 + *
130.959 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
130.960 + * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException}
130.961 + * when a file cannot be deleted. This is useful for error reporting and to
130.962 + * diagnose why a file cannot be deleted.
130.963 + *
130.964 + * @return <code>true</code> if and only if the file or directory is
130.965 + * successfully deleted; <code>false</code> otherwise
130.966 + *
130.967 + * @throws SecurityException
130.968 + * If a security manager exists and its <code>{@link
130.969 + * java.lang.SecurityManager#checkDelete}</code> method denies
130.970 + * delete access to the file
130.971 + */
130.972 + public boolean delete() {
130.973 + throw new SecurityException();
130.974 + }
130.975 +
130.976 + /**
130.977 + * Requests that the file or directory denoted by this abstract
130.978 + * pathname be deleted when the virtual machine terminates.
130.979 + * Files (or directories) are deleted in the reverse order that
130.980 + * they are registered. Invoking this method to delete a file or
130.981 + * directory that is already registered for deletion has no effect.
130.982 + * Deletion will be attempted only for normal termination of the
130.983 + * virtual machine, as defined by the Java Language Specification.
130.984 + *
130.985 + * <p> Once deletion has been requested, it is not possible to cancel the
130.986 + * request. This method should therefore be used with care.
130.987 + *
130.988 + * <P>
130.989 + * Note: this method should <i>not</i> be used for file-locking, as
130.990 + * the resulting protocol cannot be made to work reliably. The
130.991 + * {@link java.nio.channels.FileLock FileLock}
130.992 + * facility should be used instead.
130.993 + *
130.994 + * @throws SecurityException
130.995 + * If a security manager exists and its <code>{@link
130.996 + * java.lang.SecurityManager#checkDelete}</code> method denies
130.997 + * delete access to the file
130.998 + *
130.999 + * @see #delete
130.1000 + *
130.1001 + * @since 1.2
130.1002 + */
130.1003 + public void deleteOnExit() {
130.1004 + throw new SecurityException();
130.1005 + }
130.1006 +
130.1007 + /**
130.1008 + * Returns an array of strings naming the files and directories in the
130.1009 + * directory denoted by this abstract pathname.
130.1010 + *
130.1011 + * <p> If this abstract pathname does not denote a directory, then this
130.1012 + * method returns {@code null}. Otherwise an array of strings is
130.1013 + * returned, one for each file or directory in the directory. Names
130.1014 + * denoting the directory itself and the directory's parent directory are
130.1015 + * not included in the result. Each string is a file name rather than a
130.1016 + * complete path.
130.1017 + *
130.1018 + * <p> There is no guarantee that the name strings in the resulting array
130.1019 + * will appear in any specific order; they are not, in particular,
130.1020 + * guaranteed to appear in alphabetical order.
130.1021 + *
130.1022 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
130.1023 + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to
130.1024 + * open a directory and iterate over the names of the files in the directory.
130.1025 + * This may use less resources when working with very large directories, and
130.1026 + * may be more responsive when working with remote directories.
130.1027 + *
130.1028 + * @return An array of strings naming the files and directories in the
130.1029 + * directory denoted by this abstract pathname. The array will be
130.1030 + * empty if the directory is empty. Returns {@code null} if
130.1031 + * this abstract pathname does not denote a directory, or if an
130.1032 + * I/O error occurs.
130.1033 + *
130.1034 + * @throws SecurityException
130.1035 + * If a security manager exists and its {@link
130.1036 + * SecurityManager#checkRead(String)} method denies read access to
130.1037 + * the directory
130.1038 + */
130.1039 + public String[] list() {
130.1040 + throw new SecurityException();
130.1041 + }
130.1042 +
130.1043 + /**
130.1044 + * Returns an array of strings naming the files and directories in the
130.1045 + * directory denoted by this abstract pathname that satisfy the specified
130.1046 + * filter. The behavior of this method is the same as that of the
130.1047 + * {@link #list()} method, except that the strings in the returned array
130.1048 + * must satisfy the filter. If the given {@code filter} is {@code null}
130.1049 + * then all names are accepted. Otherwise, a name satisfies the filter if
130.1050 + * and only if the value {@code true} results when the {@link
130.1051 + * FilenameFilter#accept FilenameFilter.accept(File, String)} method
130.1052 + * of the filter is invoked on this abstract pathname and the name of a
130.1053 + * file or directory in the directory that it denotes.
130.1054 + *
130.1055 + * @param filter
130.1056 + * A filename filter
130.1057 + *
130.1058 + * @return An array of strings naming the files and directories in the
130.1059 + * directory denoted by this abstract pathname that were accepted
130.1060 + * by the given {@code filter}. The array will be empty if the
130.1061 + * directory is empty or if no names were accepted by the filter.
130.1062 + * Returns {@code null} if this abstract pathname does not denote
130.1063 + * a directory, or if an I/O error occurs.
130.1064 + *
130.1065 + * @throws SecurityException
130.1066 + * If a security manager exists and its {@link
130.1067 + * SecurityManager#checkRead(String)} method denies read access to
130.1068 + * the directory
130.1069 + *
130.1070 + * @see java.nio.file.Files#newDirectoryStream(Path,String)
130.1071 + */
130.1072 + public String[] list(FilenameFilter filter) {
130.1073 + throw new SecurityException();
130.1074 + }
130.1075 +
130.1076 + /**
130.1077 + * Returns an array of abstract pathnames denoting the files in the
130.1078 + * directory denoted by this abstract pathname.
130.1079 + *
130.1080 + * <p> If this abstract pathname does not denote a directory, then this
130.1081 + * method returns {@code null}. Otherwise an array of {@code File} objects
130.1082 + * is returned, one for each file or directory in the directory. Pathnames
130.1083 + * denoting the directory itself and the directory's parent directory are
130.1084 + * not included in the result. Each resulting abstract pathname is
130.1085 + * constructed from this abstract pathname using the {@link #File(File,
130.1086 + * String) File(File, String)} constructor. Therefore if this
130.1087 + * pathname is absolute then each resulting pathname is absolute; if this
130.1088 + * pathname is relative then each resulting pathname will be relative to
130.1089 + * the same directory.
130.1090 + *
130.1091 + * <p> There is no guarantee that the name strings in the resulting array
130.1092 + * will appear in any specific order; they are not, in particular,
130.1093 + * guaranteed to appear in alphabetical order.
130.1094 + *
130.1095 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
130.1096 + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method
130.1097 + * to open a directory and iterate over the names of the files in the
130.1098 + * directory. This may use less resources when working with very large
130.1099 + * directories.
130.1100 + *
130.1101 + * @return An array of abstract pathnames denoting the files and
130.1102 + * directories in the directory denoted by this abstract pathname.
130.1103 + * The array will be empty if the directory is empty. Returns
130.1104 + * {@code null} if this abstract pathname does not denote a
130.1105 + * directory, or if an I/O error occurs.
130.1106 + *
130.1107 + * @throws SecurityException
130.1108 + * If a security manager exists and its {@link
130.1109 + * SecurityManager#checkRead(String)} method denies read access to
130.1110 + * the directory
130.1111 + *
130.1112 + * @since 1.2
130.1113 + */
130.1114 + public File[] listFiles() {
130.1115 + throw new SecurityException();
130.1116 + }
130.1117 +
130.1118 + /**
130.1119 + * Returns an array of abstract pathnames denoting the files and
130.1120 + * directories in the directory denoted by this abstract pathname that
130.1121 + * satisfy the specified filter. The behavior of this method is the same
130.1122 + * as that of the {@link #listFiles()} method, except that the pathnames in
130.1123 + * the returned array must satisfy the filter. If the given {@code filter}
130.1124 + * is {@code null} then all pathnames are accepted. Otherwise, a pathname
130.1125 + * satisfies the filter if and only if the value {@code true} results when
130.1126 + * the {@link FilenameFilter#accept
130.1127 + * FilenameFilter.accept(File, String)} method of the filter is
130.1128 + * invoked on this abstract pathname and the name of a file or directory in
130.1129 + * the directory that it denotes.
130.1130 + *
130.1131 + * @param filter
130.1132 + * A filename filter
130.1133 + *
130.1134 + * @return An array of abstract pathnames denoting the files and
130.1135 + * directories in the directory denoted by this abstract pathname.
130.1136 + * The array will be empty if the directory is empty. Returns
130.1137 + * {@code null} if this abstract pathname does not denote a
130.1138 + * directory, or if an I/O error occurs.
130.1139 + *
130.1140 + * @throws SecurityException
130.1141 + * If a security manager exists and its {@link
130.1142 + * SecurityManager#checkRead(String)} method denies read access to
130.1143 + * the directory
130.1144 + *
130.1145 + * @since 1.2
130.1146 + * @see java.nio.file.Files#newDirectoryStream(Path,String)
130.1147 + */
130.1148 + public File[] listFiles(FilenameFilter filter) {
130.1149 + throw new SecurityException();
130.1150 + }
130.1151 +
130.1152 + /**
130.1153 + * Returns an array of abstract pathnames denoting the files and
130.1154 + * directories in the directory denoted by this abstract pathname that
130.1155 + * satisfy the specified filter. The behavior of this method is the same
130.1156 + * as that of the {@link #listFiles()} method, except that the pathnames in
130.1157 + * the returned array must satisfy the filter. If the given {@code filter}
130.1158 + * is {@code null} then all pathnames are accepted. Otherwise, a pathname
130.1159 + * satisfies the filter if and only if the value {@code true} results when
130.1160 + * the {@link FileFilter#accept FileFilter.accept(File)} method of the
130.1161 + * filter is invoked on the pathname.
130.1162 + *
130.1163 + * @param filter
130.1164 + * A file filter
130.1165 + *
130.1166 + * @return An array of abstract pathnames denoting the files and
130.1167 + * directories in the directory denoted by this abstract pathname.
130.1168 + * The array will be empty if the directory is empty. Returns
130.1169 + * {@code null} if this abstract pathname does not denote a
130.1170 + * directory, or if an I/O error occurs.
130.1171 + *
130.1172 + * @throws SecurityException
130.1173 + * If a security manager exists and its {@link
130.1174 + * SecurityManager#checkRead(String)} method denies read access to
130.1175 + * the directory
130.1176 + *
130.1177 + * @since 1.2
130.1178 + * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter)
130.1179 + */
130.1180 + public File[] listFiles(FileFilter filter) {
130.1181 + throw new SecurityException();
130.1182 + }
130.1183 +
130.1184 + /**
130.1185 + * Creates the directory named by this abstract pathname.
130.1186 + *
130.1187 + * @return <code>true</code> if and only if the directory was
130.1188 + * created; <code>false</code> otherwise
130.1189 + *
130.1190 + * @throws SecurityException
130.1191 + * If a security manager exists and its <code>{@link
130.1192 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1193 + * method does not permit the named directory to be created
130.1194 + */
130.1195 + public boolean mkdir() {
130.1196 + throw new SecurityException();
130.1197 + }
130.1198 +
130.1199 + /**
130.1200 + * Creates the directory named by this abstract pathname, including any
130.1201 + * necessary but nonexistent parent directories. Note that if this
130.1202 + * operation fails it may have succeeded in creating some of the necessary
130.1203 + * parent directories.
130.1204 + *
130.1205 + * @return <code>true</code> if and only if the directory was created,
130.1206 + * along with all necessary parent directories; <code>false</code>
130.1207 + * otherwise
130.1208 + *
130.1209 + * @throws SecurityException
130.1210 + * If a security manager exists and its <code>{@link
130.1211 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
130.1212 + * method does not permit verification of the existence of the
130.1213 + * named directory and all necessary parent directories; or if
130.1214 + * the <code>{@link
130.1215 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1216 + * method does not permit the named directory and all necessary
130.1217 + * parent directories to be created
130.1218 + */
130.1219 + public boolean mkdirs() {
130.1220 + throw new SecurityException();
130.1221 + }
130.1222 +
130.1223 + /**
130.1224 + * Renames the file denoted by this abstract pathname.
130.1225 + *
130.1226 + * <p> Many aspects of the behavior of this method are inherently
130.1227 + * platform-dependent: The rename operation might not be able to move a
130.1228 + * file from one filesystem to another, it might not be atomic, and it
130.1229 + * might not succeed if a file with the destination abstract pathname
130.1230 + * already exists. The return value should always be checked to make sure
130.1231 + * that the rename operation was successful.
130.1232 + *
130.1233 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
130.1234 + * java.nio.file.Files#move move} method to move or rename a file in a
130.1235 + * platform independent manner.
130.1236 + *
130.1237 + * @param dest The new abstract pathname for the named file
130.1238 + *
130.1239 + * @return <code>true</code> if and only if the renaming succeeded;
130.1240 + * <code>false</code> otherwise
130.1241 + *
130.1242 + * @throws SecurityException
130.1243 + * If a security manager exists and its <code>{@link
130.1244 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1245 + * method denies write access to either the old or new pathnames
130.1246 + *
130.1247 + * @throws NullPointerException
130.1248 + * If parameter <code>dest</code> is <code>null</code>
130.1249 + */
130.1250 + public boolean renameTo(File dest) {
130.1251 + throw new SecurityException();
130.1252 + }
130.1253 +
130.1254 + /**
130.1255 + * Sets the last-modified time of the file or directory named by this
130.1256 + * abstract pathname.
130.1257 + *
130.1258 + * <p> All platforms support file-modification times to the nearest second,
130.1259 + * but some provide more precision. The argument will be truncated to fit
130.1260 + * the supported precision. If the operation succeeds and no intervening
130.1261 + * operations on the file take place, then the next invocation of the
130.1262 + * <code>{@link #lastModified}</code> method will return the (possibly
130.1263 + * truncated) <code>time</code> argument that was passed to this method.
130.1264 + *
130.1265 + * @param time The new last-modified time, measured in milliseconds since
130.1266 + * the epoch (00:00:00 GMT, January 1, 1970)
130.1267 + *
130.1268 + * @return <code>true</code> if and only if the operation succeeded;
130.1269 + * <code>false</code> otherwise
130.1270 + *
130.1271 + * @throws IllegalArgumentException If the argument is negative
130.1272 + *
130.1273 + * @throws SecurityException
130.1274 + * If a security manager exists and its <code>{@link
130.1275 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1276 + * method denies write access to the named file
130.1277 + *
130.1278 + * @since 1.2
130.1279 + */
130.1280 + public boolean setLastModified(long time) {
130.1281 + throw new SecurityException();
130.1282 + }
130.1283 +
130.1284 + /**
130.1285 + * Marks the file or directory named by this abstract pathname so that
130.1286 + * only read operations are allowed. After invoking this method the file
130.1287 + * or directory is guaranteed not to change until it is either deleted or
130.1288 + * marked to allow write access. Whether or not a read-only file or
130.1289 + * directory may be deleted depends upon the underlying system.
130.1290 + *
130.1291 + * @return <code>true</code> if and only if the operation succeeded;
130.1292 + * <code>false</code> otherwise
130.1293 + *
130.1294 + * @throws SecurityException
130.1295 + * If a security manager exists and its <code>{@link
130.1296 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1297 + * method denies write access to the named file
130.1298 + *
130.1299 + * @since 1.2
130.1300 + */
130.1301 + public boolean setReadOnly() {
130.1302 + throw new SecurityException();
130.1303 + }
130.1304 +
130.1305 + /**
130.1306 + * Sets the owner's or everybody's write permission for this abstract
130.1307 + * pathname.
130.1308 + *
130.1309 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
130.1310 + * file attributes including file permissions. This may be used when finer
130.1311 + * manipulation of file permissions is required.
130.1312 + *
130.1313 + * @param writable
130.1314 + * If <code>true</code>, sets the access permission to allow write
130.1315 + * operations; if <code>false</code> to disallow write operations
130.1316 + *
130.1317 + * @param ownerOnly
130.1318 + * If <code>true</code>, the write permission applies only to the
130.1319 + * owner's write permission; otherwise, it applies to everybody. If
130.1320 + * the underlying file system can not distinguish the owner's write
130.1321 + * permission from that of others, then the permission will apply to
130.1322 + * everybody, regardless of this value.
130.1323 + *
130.1324 + * @return <code>true</code> if and only if the operation succeeded. The
130.1325 + * operation will fail if the user does not have permission to change
130.1326 + * the access permissions of this abstract pathname.
130.1327 + *
130.1328 + * @throws SecurityException
130.1329 + * If a security manager exists and its <code>{@link
130.1330 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1331 + * method denies write access to the named file
130.1332 + *
130.1333 + * @since 1.6
130.1334 + */
130.1335 + public boolean setWritable(boolean writable, boolean ownerOnly) {
130.1336 + throw new SecurityException();
130.1337 + }
130.1338 +
130.1339 + /**
130.1340 + * A convenience method to set the owner's write permission for this abstract
130.1341 + * pathname.
130.1342 + *
130.1343 + * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt>
130.1344 + * behaves in exactly the same way as the invocation
130.1345 + *
130.1346 + * <pre>
130.1347 + * file.setWritable(arg, true) </pre>
130.1348 + *
130.1349 + * @param writable
130.1350 + * If <code>true</code>, sets the access permission to allow write
130.1351 + * operations; if <code>false</code> to disallow write operations
130.1352 + *
130.1353 + * @return <code>true</code> if and only if the operation succeeded. The
130.1354 + * operation will fail if the user does not have permission to
130.1355 + * change the access permissions of this abstract pathname.
130.1356 + *
130.1357 + * @throws SecurityException
130.1358 + * If a security manager exists and its <code>{@link
130.1359 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1360 + * method denies write access to the file
130.1361 + *
130.1362 + * @since 1.6
130.1363 + */
130.1364 + public boolean setWritable(boolean writable) {
130.1365 + return setWritable(writable, true);
130.1366 + }
130.1367 +
130.1368 + /**
130.1369 + * Sets the owner's or everybody's read permission for this abstract
130.1370 + * pathname.
130.1371 + *
130.1372 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
130.1373 + * file attributes including file permissions. This may be used when finer
130.1374 + * manipulation of file permissions is required.
130.1375 + *
130.1376 + * @param readable
130.1377 + * If <code>true</code>, sets the access permission to allow read
130.1378 + * operations; if <code>false</code> to disallow read operations
130.1379 + *
130.1380 + * @param ownerOnly
130.1381 + * If <code>true</code>, the read permission applies only to the
130.1382 + * owner's read permission; otherwise, it applies to everybody. If
130.1383 + * the underlying file system can not distinguish the owner's read
130.1384 + * permission from that of others, then the permission will apply to
130.1385 + * everybody, regardless of this value.
130.1386 + *
130.1387 + * @return <code>true</code> if and only if the operation succeeded. The
130.1388 + * operation will fail if the user does not have permission to
130.1389 + * change the access permissions of this abstract pathname. If
130.1390 + * <code>readable</code> is <code>false</code> and the underlying
130.1391 + * file system does not implement a read permission, then the
130.1392 + * operation will fail.
130.1393 + *
130.1394 + * @throws SecurityException
130.1395 + * If a security manager exists and its <code>{@link
130.1396 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1397 + * method denies write access to the file
130.1398 + *
130.1399 + * @since 1.6
130.1400 + */
130.1401 + public boolean setReadable(boolean readable, boolean ownerOnly) {
130.1402 + throw new SecurityException();
130.1403 + }
130.1404 +
130.1405 + /**
130.1406 + * A convenience method to set the owner's read permission for this abstract
130.1407 + * pathname.
130.1408 + *
130.1409 + * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>
130.1410 + * behaves in exactly the same way as the invocation
130.1411 + *
130.1412 + * <pre>
130.1413 + * file.setReadable(arg, true) </pre>
130.1414 + *
130.1415 + * @param readable
130.1416 + * If <code>true</code>, sets the access permission to allow read
130.1417 + * operations; if <code>false</code> to disallow read operations
130.1418 + *
130.1419 + * @return <code>true</code> if and only if the operation succeeded. The
130.1420 + * operation will fail if the user does not have permission to
130.1421 + * change the access permissions of this abstract pathname. If
130.1422 + * <code>readable</code> is <code>false</code> and the underlying
130.1423 + * file system does not implement a read permission, then the
130.1424 + * operation will fail.
130.1425 + *
130.1426 + * @throws SecurityException
130.1427 + * If a security manager exists and its <code>{@link
130.1428 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1429 + * method denies write access to the file
130.1430 + *
130.1431 + * @since 1.6
130.1432 + */
130.1433 + public boolean setReadable(boolean readable) {
130.1434 + return setReadable(readable, true);
130.1435 + }
130.1436 +
130.1437 + /**
130.1438 + * Sets the owner's or everybody's execute permission for this abstract
130.1439 + * pathname.
130.1440 + *
130.1441 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
130.1442 + * file attributes including file permissions. This may be used when finer
130.1443 + * manipulation of file permissions is required.
130.1444 + *
130.1445 + * @param executable
130.1446 + * If <code>true</code>, sets the access permission to allow execute
130.1447 + * operations; if <code>false</code> to disallow execute operations
130.1448 + *
130.1449 + * @param ownerOnly
130.1450 + * If <code>true</code>, the execute permission applies only to the
130.1451 + * owner's execute permission; otherwise, it applies to everybody.
130.1452 + * If the underlying file system can not distinguish the owner's
130.1453 + * execute permission from that of others, then the permission will
130.1454 + * apply to everybody, regardless of this value.
130.1455 + *
130.1456 + * @return <code>true</code> if and only if the operation succeeded. The
130.1457 + * operation will fail if the user does not have permission to
130.1458 + * change the access permissions of this abstract pathname. If
130.1459 + * <code>executable</code> is <code>false</code> and the underlying
130.1460 + * file system does not implement an execute permission, then the
130.1461 + * operation will fail.
130.1462 + *
130.1463 + * @throws SecurityException
130.1464 + * If a security manager exists and its <code>{@link
130.1465 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1466 + * method denies write access to the file
130.1467 + *
130.1468 + * @since 1.6
130.1469 + */
130.1470 + public boolean setExecutable(boolean executable, boolean ownerOnly) {
130.1471 + throw new SecurityException();
130.1472 + }
130.1473 +
130.1474 + /**
130.1475 + * A convenience method to set the owner's execute permission for this abstract
130.1476 + * pathname.
130.1477 + *
130.1478 + * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
130.1479 + * behaves in exactly the same way as the invocation
130.1480 + *
130.1481 + * <pre>
130.1482 + * file.setExecutable(arg, true) </pre>
130.1483 + *
130.1484 + * @param executable
130.1485 + * If <code>true</code>, sets the access permission to allow execute
130.1486 + * operations; if <code>false</code> to disallow execute operations
130.1487 + *
130.1488 + * @return <code>true</code> if and only if the operation succeeded. The
130.1489 + * operation will fail if the user does not have permission to
130.1490 + * change the access permissions of this abstract pathname. If
130.1491 + * <code>executable</code> is <code>false</code> and the underlying
130.1492 + * file system does not implement an excute permission, then the
130.1493 + * operation will fail.
130.1494 + *
130.1495 + * @throws SecurityException
130.1496 + * If a security manager exists and its <code>{@link
130.1497 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1498 + * method denies write access to the file
130.1499 + *
130.1500 + * @since 1.6
130.1501 + */
130.1502 + public boolean setExecutable(boolean executable) {
130.1503 + return setExecutable(executable, true);
130.1504 + }
130.1505 +
130.1506 + /**
130.1507 + * Tests whether the application can execute the file denoted by this
130.1508 + * abstract pathname.
130.1509 + *
130.1510 + * @return <code>true</code> if and only if the abstract pathname exists
130.1511 + * <em>and</em> the application is allowed to execute the file
130.1512 + *
130.1513 + * @throws SecurityException
130.1514 + * If a security manager exists and its <code>{@link
130.1515 + * java.lang.SecurityManager#checkExec(java.lang.String)}</code>
130.1516 + * method denies execute access to the file
130.1517 + *
130.1518 + * @since 1.6
130.1519 + */
130.1520 + public boolean canExecute() {
130.1521 + throw new SecurityException();
130.1522 + }
130.1523 +
130.1524 +
130.1525 + /* -- Filesystem interface -- */
130.1526 +
130.1527 + /**
130.1528 + * List the available filesystem roots.
130.1529 + *
130.1530 + * <p> A particular Java platform may support zero or more
130.1531 + * hierarchically-organized file systems. Each file system has a
130.1532 + * {@code root} directory from which all other files in that file system
130.1533 + * can be reached. Windows platforms, for example, have a root directory
130.1534 + * for each active drive; UNIX platforms have a single root directory,
130.1535 + * namely {@code "/"}. The set of available filesystem roots is affected
130.1536 + * by various system-level operations such as the insertion or ejection of
130.1537 + * removable media and the disconnecting or unmounting of physical or
130.1538 + * virtual disk drives.
130.1539 + *
130.1540 + * <p> This method returns an array of {@code File} objects that denote the
130.1541 + * root directories of the available filesystem roots. It is guaranteed
130.1542 + * that the canonical pathname of any file physically present on the local
130.1543 + * machine will begin with one of the roots returned by this method.
130.1544 + *
130.1545 + * <p> The canonical pathname of a file that resides on some other machine
130.1546 + * and is accessed via a remote-filesystem protocol such as SMB or NFS may
130.1547 + * or may not begin with one of the roots returned by this method. If the
130.1548 + * pathname of a remote file is syntactically indistinguishable from the
130.1549 + * pathname of a local file then it will begin with one of the roots
130.1550 + * returned by this method. Thus, for example, {@code File} objects
130.1551 + * denoting the root directories of the mapped network drives of a Windows
130.1552 + * platform will be returned by this method, while {@code File} objects
130.1553 + * containing UNC pathnames will not be returned by this method.
130.1554 + *
130.1555 + * <p> Unlike most methods in this class, this method does not throw
130.1556 + * security exceptions. If a security manager exists and its {@link
130.1557 + * SecurityManager#checkRead(String)} method denies read access to a
130.1558 + * particular root directory, then that directory will not appear in the
130.1559 + * result.
130.1560 + *
130.1561 + * @return An array of {@code File} objects denoting the available
130.1562 + * filesystem roots, or {@code null} if the set of roots could not
130.1563 + * be determined. The array will be empty if there are no
130.1564 + * filesystem roots.
130.1565 + *
130.1566 + * @since 1.2
130.1567 + * @see java.nio.file.FileStore
130.1568 + */
130.1569 + public static File[] listRoots() {
130.1570 + throw new SecurityException();
130.1571 + }
130.1572 +
130.1573 +
130.1574 + /* -- Disk usage -- */
130.1575 +
130.1576 + /**
130.1577 + * Returns the size of the partition <a href="#partName">named</a> by this
130.1578 + * abstract pathname.
130.1579 + *
130.1580 + * @return The size, in bytes, of the partition or <tt>0L</tt> if this
130.1581 + * abstract pathname does not name a partition
130.1582 + *
130.1583 + * @throws SecurityException
130.1584 + * If a security manager has been installed and it denies
130.1585 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
130.1586 + * or its {@link SecurityManager#checkRead(String)} method denies
130.1587 + * read access to the file named by this abstract pathname
130.1588 + *
130.1589 + * @since 1.6
130.1590 + */
130.1591 + public long getTotalSpace() {
130.1592 + throw new SecurityException();
130.1593 + }
130.1594 +
130.1595 + /**
130.1596 + * Returns the number of unallocated bytes in the partition <a
130.1597 + * href="#partName">named</a> by this abstract path name.
130.1598 + *
130.1599 + * <p> The returned number of unallocated bytes is a hint, but not
130.1600 + * a guarantee, that it is possible to use most or any of these
130.1601 + * bytes. The number of unallocated bytes is most likely to be
130.1602 + * accurate immediately after this call. It is likely to be made
130.1603 + * inaccurate by any external I/O operations including those made
130.1604 + * on the system outside of this virtual machine. This method
130.1605 + * makes no guarantee that write operations to this file system
130.1606 + * will succeed.
130.1607 + *
130.1608 + * @return The number of unallocated bytes on the partition <tt>0L</tt>
130.1609 + * if the abstract pathname does not name a partition. This
130.1610 + * value will be less than or equal to the total file system size
130.1611 + * returned by {@link #getTotalSpace}.
130.1612 + *
130.1613 + * @throws SecurityException
130.1614 + * If a security manager has been installed and it denies
130.1615 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
130.1616 + * or its {@link SecurityManager#checkRead(String)} method denies
130.1617 + * read access to the file named by this abstract pathname
130.1618 + *
130.1619 + * @since 1.6
130.1620 + */
130.1621 + public long getFreeSpace() {
130.1622 + throw new SecurityException();
130.1623 + }
130.1624 +
130.1625 + /**
130.1626 + * Returns the number of bytes available to this virtual machine on the
130.1627 + * partition <a href="#partName">named</a> by this abstract pathname. When
130.1628 + * possible, this method checks for write permissions and other operating
130.1629 + * system restrictions and will therefore usually provide a more accurate
130.1630 + * estimate of how much new data can actually be written than {@link
130.1631 + * #getFreeSpace}.
130.1632 + *
130.1633 + * <p> The returned number of available bytes is a hint, but not a
130.1634 + * guarantee, that it is possible to use most or any of these bytes. The
130.1635 + * number of unallocated bytes is most likely to be accurate immediately
130.1636 + * after this call. It is likely to be made inaccurate by any external
130.1637 + * I/O operations including those made on the system outside of this
130.1638 + * virtual machine. This method makes no guarantee that write operations
130.1639 + * to this file system will succeed.
130.1640 + *
130.1641 + * @return The number of available bytes on the partition or <tt>0L</tt>
130.1642 + * if the abstract pathname does not name a partition. On
130.1643 + * systems where this information is not available, this method
130.1644 + * will be equivalent to a call to {@link #getFreeSpace}.
130.1645 + *
130.1646 + * @throws SecurityException
130.1647 + * If a security manager has been installed and it denies
130.1648 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
130.1649 + * or its {@link SecurityManager#checkRead(String)} method denies
130.1650 + * read access to the file named by this abstract pathname
130.1651 + *
130.1652 + * @since 1.6
130.1653 + */
130.1654 + public long getUsableSpace() {
130.1655 + throw new SecurityException();
130.1656 + }
130.1657 +
130.1658 + /* -- Temporary files -- */
130.1659 +
130.1660 +
130.1661 + /**
130.1662 + * <p> Creates a new empty file in the specified directory, using the
130.1663 + * given prefix and suffix strings to generate its name. If this method
130.1664 + * returns successfully then it is guaranteed that:
130.1665 + *
130.1666 + * <ol>
130.1667 + * <li> The file denoted by the returned abstract pathname did not exist
130.1668 + * before this method was invoked, and
130.1669 + * <li> Neither this method nor any of its variants will return the same
130.1670 + * abstract pathname again in the current invocation of the virtual
130.1671 + * machine.
130.1672 + * </ol>
130.1673 + *
130.1674 + * This method provides only part of a temporary-file facility. To arrange
130.1675 + * for a file created by this method to be deleted automatically, use the
130.1676 + * <code>{@link #deleteOnExit}</code> method.
130.1677 + *
130.1678 + * <p> The <code>prefix</code> argument must be at least three characters
130.1679 + * long. It is recommended that the prefix be a short, meaningful string
130.1680 + * such as <code>"hjb"</code> or <code>"mail"</code>. The
130.1681 + * <code>suffix</code> argument may be <code>null</code>, in which case the
130.1682 + * suffix <code>".tmp"</code> will be used.
130.1683 + *
130.1684 + * <p> To create the new file, the prefix and the suffix may first be
130.1685 + * adjusted to fit the limitations of the underlying platform. If the
130.1686 + * prefix is too long then it will be truncated, but its first three
130.1687 + * characters will always be preserved. If the suffix is too long then it
130.1688 + * too will be truncated, but if it begins with a period character
130.1689 + * (<code>'.'</code>) then the period and the first three characters
130.1690 + * following it will always be preserved. Once these adjustments have been
130.1691 + * made the name of the new file will be generated by concatenating the
130.1692 + * prefix, five or more internally-generated characters, and the suffix.
130.1693 + *
130.1694 + * <p> If the <code>directory</code> argument is <code>null</code> then the
130.1695 + * system-dependent default temporary-file directory will be used. The
130.1696 + * default temporary-file directory is specified by the system property
130.1697 + * <code>java.io.tmpdir</code>. On UNIX systems the default value of this
130.1698 + * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
130.1699 + * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>. A different
130.1700 + * value may be given to this system property when the Java virtual machine
130.1701 + * is invoked, but programmatic changes to this property are not guaranteed
130.1702 + * to have any effect upon the temporary directory used by this method.
130.1703 + *
130.1704 + * @param prefix The prefix string to be used in generating the file's
130.1705 + * name; must be at least three characters long
130.1706 + *
130.1707 + * @param suffix The suffix string to be used in generating the file's
130.1708 + * name; may be <code>null</code>, in which case the
130.1709 + * suffix <code>".tmp"</code> will be used
130.1710 + *
130.1711 + * @param directory The directory in which the file is to be created, or
130.1712 + * <code>null</code> if the default temporary-file
130.1713 + * directory is to be used
130.1714 + *
130.1715 + * @return An abstract pathname denoting a newly-created empty file
130.1716 + *
130.1717 + * @throws IllegalArgumentException
130.1718 + * If the <code>prefix</code> argument contains fewer than three
130.1719 + * characters
130.1720 + *
130.1721 + * @throws IOException If a file could not be created
130.1722 + *
130.1723 + * @throws SecurityException
130.1724 + * If a security manager exists and its <code>{@link
130.1725 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1726 + * method does not allow a file to be created
130.1727 + *
130.1728 + * @since 1.2
130.1729 + */
130.1730 + public static File createTempFile(String prefix, String suffix,
130.1731 + File directory)
130.1732 + throws IOException
130.1733 + {
130.1734 + throw new SecurityException();
130.1735 + }
130.1736 +
130.1737 + /**
130.1738 + * Creates an empty file in the default temporary-file directory, using
130.1739 + * the given prefix and suffix to generate its name. Invoking this method
130.1740 + * is equivalent to invoking <code>{@link #createTempFile(java.lang.String,
130.1741 + * java.lang.String, java.io.File)
130.1742 + * createTempFile(prefix, suffix, null)}</code>.
130.1743 + *
130.1744 + * <p> The {@link
130.1745 + * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[])
130.1746 + * Files.createTempFile} method provides an alternative method to create an
130.1747 + * empty file in the temporary-file directory. Files created by that method
130.1748 + * may have more restrictive access permissions to files created by this
130.1749 + * method and so may be more suited to security-sensitive applications.
130.1750 + *
130.1751 + * @param prefix The prefix string to be used in generating the file's
130.1752 + * name; must be at least three characters long
130.1753 + *
130.1754 + * @param suffix The suffix string to be used in generating the file's
130.1755 + * name; may be <code>null</code>, in which case the
130.1756 + * suffix <code>".tmp"</code> will be used
130.1757 + *
130.1758 + * @return An abstract pathname denoting a newly-created empty file
130.1759 + *
130.1760 + * @throws IllegalArgumentException
130.1761 + * If the <code>prefix</code> argument contains fewer than three
130.1762 + * characters
130.1763 + *
130.1764 + * @throws IOException If a file could not be created
130.1765 + *
130.1766 + * @throws SecurityException
130.1767 + * If a security manager exists and its <code>{@link
130.1768 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
130.1769 + * method does not allow a file to be created
130.1770 + *
130.1771 + * @since 1.2
130.1772 + * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[])
130.1773 + */
130.1774 + public static File createTempFile(String prefix, String suffix)
130.1775 + throws IOException
130.1776 + {
130.1777 + return createTempFile(prefix, suffix, null);
130.1778 + }
130.1779 +
130.1780 + /* -- Basic infrastructure -- */
130.1781 +
130.1782 + /**
130.1783 + * Compares two abstract pathnames lexicographically. The ordering
130.1784 + * defined by this method depends upon the underlying system. On UNIX
130.1785 + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
130.1786 + * systems it is not.
130.1787 + *
130.1788 + * @param pathname The abstract pathname to be compared to this abstract
130.1789 + * pathname
130.1790 + *
130.1791 + * @return Zero if the argument is equal to this abstract pathname, a
130.1792 + * value less than zero if this abstract pathname is
130.1793 + * lexicographically less than the argument, or a value greater
130.1794 + * than zero if this abstract pathname is lexicographically
130.1795 + * greater than the argument
130.1796 + *
130.1797 + * @since 1.2
130.1798 + */
130.1799 + public int compareTo(File pathname) {
130.1800 + return fs.compare(this, pathname);
130.1801 + }
130.1802 +
130.1803 + /**
130.1804 + * Tests this abstract pathname for equality with the given object.
130.1805 + * Returns <code>true</code> if and only if the argument is not
130.1806 + * <code>null</code> and is an abstract pathname that denotes the same file
130.1807 + * or directory as this abstract pathname. Whether or not two abstract
130.1808 + * pathnames are equal depends upon the underlying system. On UNIX
130.1809 + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
130.1810 + * systems it is not.
130.1811 + *
130.1812 + * @param obj The object to be compared with this abstract pathname
130.1813 + *
130.1814 + * @return <code>true</code> if and only if the objects are the same;
130.1815 + * <code>false</code> otherwise
130.1816 + */
130.1817 + public boolean equals(Object obj) {
130.1818 + if ((obj != null) && (obj instanceof File)) {
130.1819 + return compareTo((File)obj) == 0;
130.1820 + }
130.1821 + return false;
130.1822 + }
130.1823 +
130.1824 + /**
130.1825 + * Computes a hash code for this abstract pathname. Because equality of
130.1826 + * abstract pathnames is inherently system-dependent, so is the computation
130.1827 + * of their hash codes. On UNIX systems, the hash code of an abstract
130.1828 + * pathname is equal to the exclusive <em>or</em> of the hash code
130.1829 + * of its pathname string and the decimal value
130.1830 + * <code>1234321</code>. On Microsoft Windows systems, the hash
130.1831 + * code is equal to the exclusive <em>or</em> of the hash code of
130.1832 + * its pathname string converted to lower case and the decimal
130.1833 + * value <code>1234321</code>. Locale is not taken into account on
130.1834 + * lowercasing the pathname string.
130.1835 + *
130.1836 + * @return A hash code for this abstract pathname
130.1837 + */
130.1838 + public int hashCode() {
130.1839 + return fs.hashCode(this);
130.1840 + }
130.1841 +
130.1842 + /**
130.1843 + * Returns the pathname string of this abstract pathname. This is just the
130.1844 + * string returned by the <code>{@link #getPath}</code> method.
130.1845 + *
130.1846 + * @return The string form of this abstract pathname
130.1847 + */
130.1848 + public String toString() {
130.1849 + return getPath();
130.1850 + }
130.1851 +
130.1852 + /**
130.1853 + * WriteObject is called to save this filename.
130.1854 + * The separator character is saved also so it can be replaced
130.1855 + * in case the path is reconstituted on a different host type.
130.1856 + * <p>
130.1857 + * @serialData Default fields followed by separator character.
130.1858 + */
130.1859 + private synchronized void writeObject(java.io.ObjectOutputStream s)
130.1860 + throws IOException
130.1861 + {
130.1862 + s.defaultWriteObject();
130.1863 + s.writeChar(this.separatorChar); // Add the separator character
130.1864 + }
130.1865 +
130.1866 + /**
130.1867 + * readObject is called to restore this filename.
130.1868 + * The original separator character is read. If it is different
130.1869 + * than the separator character on this system, then the old separator
130.1870 + * is replaced by the local separator.
130.1871 + */
130.1872 + private synchronized void readObject(java.io.ObjectInputStream s)
130.1873 + throws IOException, ClassNotFoundException
130.1874 + {
130.1875 + ObjectInputStream.GetField fields = s.readFields();
130.1876 + String pathField = (String)fields.get("path", null);
130.1877 + char sep = s.readChar(); // read the previous separator char
130.1878 + if (sep != separatorChar)
130.1879 + pathField = pathField.replace(sep, separatorChar);
130.1880 + this.path = fs.normalize(pathField);
130.1881 + this.prefixLength = fs.prefixLength(this.path);
130.1882 + }
130.1883 +
130.1884 + /** use serialVersionUID from JDK 1.0.2 for interoperability */
130.1885 + private static final long serialVersionUID = 301077366599181567L;
130.1886 +
130.1887 + // -- Integration with java.nio.file --
130.1888 +/*
130.1889 + private volatile transient Path filePath;
130.1890 +
130.1891 + /**
130.1892 + * Returns a {@link Path java.nio.file.Path} object constructed from the
130.1893 + * this abstract path. The resulting {@code Path} is associated with the
130.1894 + * {@link java.nio.file.FileSystems#getDefault default-filesystem}.
130.1895 + *
130.1896 + * <p> The first invocation of this method works as if invoking it were
130.1897 + * equivalent to evaluating the expression:
130.1898 + * <blockquote><pre>
130.1899 + * {@link java.nio.file.FileSystems#getDefault FileSystems.getDefault}().{@link
130.1900 + * java.nio.file.FileSystem#getPath getPath}(this.{@link #getPath getPath}());
130.1901 + * </pre></blockquote>
130.1902 + * Subsequent invocations of this method return the same {@code Path}.
130.1903 + *
130.1904 + * <p> If this abstract pathname is the empty abstract pathname then this
130.1905 + * method returns a {@code Path} that may be used to access the current
130.1906 + * user directory.
130.1907 + *
130.1908 + * @return a {@code Path} constructed from this abstract path
130.1909 + *
130.1910 + * @throws java.nio.file.InvalidPathException
130.1911 + * if a {@code Path} object cannot be constructed from the abstract
130.1912 + * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath})
130.1913 + *
130.1914 + * @since 1.7
130.1915 + * @see Path#toFile
130.1916 + */
130.1917 +// public Path toPath() {
130.1918 +// Path result = filePath;
130.1919 +// if (result == null) {
130.1920 +// synchronized (this) {
130.1921 +// result = filePath;
130.1922 +// if (result == null) {
130.1923 +// result = FileSystems.getDefault().getPath(path);
130.1924 +// filePath = result;
130.1925 +// }
130.1926 +// }
130.1927 +// }
130.1928 +// return result;
130.1929 +// }
130.1930 +}
131.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
131.2 +++ b/rt/emul/compact/src/main/java/java/io/FileFilter.java Mon Oct 07 14:20:58 2013 +0200
131.3 @@ -0,0 +1,50 @@
131.4 +/*
131.5 + * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved.
131.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
131.7 + *
131.8 + * This code is free software; you can redistribute it and/or modify it
131.9 + * under the terms of the GNU General Public License version 2 only, as
131.10 + * published by the Free Software Foundation. Oracle designates this
131.11 + * particular file as subject to the "Classpath" exception as provided
131.12 + * by Oracle in the LICENSE file that accompanied this code.
131.13 + *
131.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
131.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
131.17 + * version 2 for more details (a copy is included in the LICENSE file that
131.18 + * accompanied this code).
131.19 + *
131.20 + * You should have received a copy of the GNU General Public License version
131.21 + * 2 along with this work; if not, write to the Free Software Foundation,
131.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
131.23 + *
131.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
131.25 + * or visit www.oracle.com if you need additional information or have any
131.26 + * questions.
131.27 + */
131.28 +
131.29 +package java.io;
131.30 +
131.31 +
131.32 +/**
131.33 + * A filter for abstract pathnames.
131.34 + *
131.35 + * <p> Instances of this interface may be passed to the <code>{@link
131.36 + * File#listFiles(java.io.FileFilter) listFiles(FileFilter)}</code> method
131.37 + * of the <code>{@link java.io.File}</code> class.
131.38 + *
131.39 + * @since 1.2
131.40 + */
131.41 +public interface FileFilter {
131.42 +
131.43 + /**
131.44 + * Tests whether or not the specified abstract pathname should be
131.45 + * included in a pathname list.
131.46 + *
131.47 + * @param pathname The abstract pathname to be tested
131.48 + * @return <code>true</code> if and only if <code>pathname</code>
131.49 + * should be included
131.50 + */
131.51 + boolean accept(File pathname);
131.52 +
131.53 +}
132.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
132.2 +++ b/rt/emul/compact/src/main/java/java/io/FileNotFoundException.java Mon Oct 07 14:20:58 2013 +0200
132.3 @@ -0,0 +1,82 @@
132.4 +/*
132.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
132.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
132.7 + *
132.8 + * This code is free software; you can redistribute it and/or modify it
132.9 + * under the terms of the GNU General Public License version 2 only, as
132.10 + * published by the Free Software Foundation. Oracle designates this
132.11 + * particular file as subject to the "Classpath" exception as provided
132.12 + * by Oracle in the LICENSE file that accompanied this code.
132.13 + *
132.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
132.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
132.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
132.17 + * version 2 for more details (a copy is included in the LICENSE file that
132.18 + * accompanied this code).
132.19 + *
132.20 + * You should have received a copy of the GNU General Public License version
132.21 + * 2 along with this work; if not, write to the Free Software Foundation,
132.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
132.23 + *
132.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
132.25 + * or visit www.oracle.com if you need additional information or have any
132.26 + * questions.
132.27 + */
132.28 +
132.29 +package java.io;
132.30 +
132.31 +
132.32 +/**
132.33 + * Signals that an attempt to open the file denoted by a specified pathname
132.34 + * has failed.
132.35 + *
132.36 + * <p> This exception will be thrown by the {@link FileInputStream}, {@link
132.37 + * FileOutputStream}, and {@link RandomAccessFile} constructors when a file
132.38 + * with the specified pathname does not exist. It will also be thrown by these
132.39 + * constructors if the file does exist but for some reason is inaccessible, for
132.40 + * example when an attempt is made to open a read-only file for writing.
132.41 + *
132.42 + * @author unascribed
132.43 + * @since JDK1.0
132.44 + */
132.45 +
132.46 +public class FileNotFoundException extends IOException {
132.47 + private static final long serialVersionUID = -897856973823710492L;
132.48 +
132.49 + /**
132.50 + * Constructs a <code>FileNotFoundException</code> with
132.51 + * <code>null</code> as its error detail message.
132.52 + */
132.53 + public FileNotFoundException() {
132.54 + super();
132.55 + }
132.56 +
132.57 + /**
132.58 + * Constructs a <code>FileNotFoundException</code> with the
132.59 + * specified detail message. The string <code>s</code> can be
132.60 + * retrieved later by the
132.61 + * <code>{@link java.lang.Throwable#getMessage}</code>
132.62 + * method of class <code>java.lang.Throwable</code>.
132.63 + *
132.64 + * @param s the detail message.
132.65 + */
132.66 + public FileNotFoundException(String s) {
132.67 + super(s);
132.68 + }
132.69 +
132.70 + /**
132.71 + * Constructs a <code>FileNotFoundException</code> with a detail message
132.72 + * consisting of the given pathname string followed by the given reason
132.73 + * string. If the <code>reason</code> argument is <code>null</code> then
132.74 + * it will be omitted. This private constructor is invoked only by native
132.75 + * I/O methods.
132.76 + *
132.77 + * @since 1.2
132.78 + */
132.79 + private FileNotFoundException(String path, String reason) {
132.80 + super(path + ((reason == null)
132.81 + ? ""
132.82 + : " (" + reason + ")"));
132.83 + }
132.84 +
132.85 +}
133.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
133.2 +++ b/rt/emul/compact/src/main/java/java/io/FilenameFilter.java Mon Oct 07 14:20:58 2013 +0200
133.3 @@ -0,0 +1,53 @@
133.4 +/*
133.5 + * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
133.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
133.7 + *
133.8 + * This code is free software; you can redistribute it and/or modify it
133.9 + * under the terms of the GNU General Public License version 2 only, as
133.10 + * published by the Free Software Foundation. Oracle designates this
133.11 + * particular file as subject to the "Classpath" exception as provided
133.12 + * by Oracle in the LICENSE file that accompanied this code.
133.13 + *
133.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
133.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
133.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
133.17 + * version 2 for more details (a copy is included in the LICENSE file that
133.18 + * accompanied this code).
133.19 + *
133.20 + * You should have received a copy of the GNU General Public License version
133.21 + * 2 along with this work; if not, write to the Free Software Foundation,
133.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
133.23 + *
133.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
133.25 + * or visit www.oracle.com if you need additional information or have any
133.26 + * questions.
133.27 + */
133.28 +
133.29 +package java.io;
133.30 +
133.31 +/**
133.32 + * Instances of classes that implement this interface are used to
133.33 + * filter filenames. These instances are used to filter directory
133.34 + * listings in the <code>list</code> method of class
133.35 + * <code>File</code>, and by the Abstract Window Toolkit's file
133.36 + * dialog component.
133.37 + *
133.38 + * @author Arthur van Hoff
133.39 + * @author Jonathan Payne
133.40 + * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
133.41 + * @see java.io.File
133.42 + * @see java.io.File#list(java.io.FilenameFilter)
133.43 + * @since JDK1.0
133.44 + */
133.45 +public
133.46 +interface FilenameFilter {
133.47 + /**
133.48 + * Tests if a specified file should be included in a file list.
133.49 + *
133.50 + * @param dir the directory in which the file was found.
133.51 + * @param name the name of the file.
133.52 + * @return <code>true</code> if and only if the name should be
133.53 + * included in the file list; <code>false</code> otherwise.
133.54 + */
133.55 + boolean accept(File dir, String name);
133.56 +}
134.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
134.2 +++ b/rt/emul/compact/src/main/java/java/io/InterruptedIOException.java Mon Oct 07 14:20:58 2013 +0200
134.3 @@ -0,0 +1,74 @@
134.4 +/*
134.5 + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
134.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
134.7 + *
134.8 + * This code is free software; you can redistribute it and/or modify it
134.9 + * under the terms of the GNU General Public License version 2 only, as
134.10 + * published by the Free Software Foundation. Oracle designates this
134.11 + * particular file as subject to the "Classpath" exception as provided
134.12 + * by Oracle in the LICENSE file that accompanied this code.
134.13 + *
134.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
134.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
134.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
134.17 + * version 2 for more details (a copy is included in the LICENSE file that
134.18 + * accompanied this code).
134.19 + *
134.20 + * You should have received a copy of the GNU General Public License version
134.21 + * 2 along with this work; if not, write to the Free Software Foundation,
134.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
134.23 + *
134.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
134.25 + * or visit www.oracle.com if you need additional information or have any
134.26 + * questions.
134.27 + */
134.28 +
134.29 +package java.io;
134.30 +
134.31 +/**
134.32 + * Signals that an I/O operation has been interrupted. An
134.33 + * <code>InterruptedIOException</code> is thrown to indicate that an
134.34 + * input or output transfer has been terminated because the thread
134.35 + * performing it was interrupted. The field {@link #bytesTransferred}
134.36 + * indicates how many bytes were successfully transferred before
134.37 + * the interruption occurred.
134.38 + *
134.39 + * @author unascribed
134.40 + * @see java.io.InputStream
134.41 + * @see java.io.OutputStream
134.42 + * @see java.lang.Thread#interrupt()
134.43 + * @since JDK1.0
134.44 + */
134.45 +public
134.46 +class InterruptedIOException extends IOException {
134.47 + private static final long serialVersionUID = 4020568460727500567L;
134.48 +
134.49 + /**
134.50 + * Constructs an <code>InterruptedIOException</code> with
134.51 + * <code>null</code> as its error detail message.
134.52 + */
134.53 + public InterruptedIOException() {
134.54 + super();
134.55 + }
134.56 +
134.57 + /**
134.58 + * Constructs an <code>InterruptedIOException</code> with the
134.59 + * specified detail message. The string <code>s</code> can be
134.60 + * retrieved later by the
134.61 + * <code>{@link java.lang.Throwable#getMessage}</code>
134.62 + * method of class <code>java.lang.Throwable</code>.
134.63 + *
134.64 + * @param s the detail message.
134.65 + */
134.66 + public InterruptedIOException(String s) {
134.67 + super(s);
134.68 + }
134.69 +
134.70 + /**
134.71 + * Reports how many bytes had been transferred as part of the I/O
134.72 + * operation before it was interrupted.
134.73 + *
134.74 + * @serial
134.75 + */
134.76 + public int bytesTransferred = 0;
134.77 +}
135.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
135.2 +++ b/rt/emul/compact/src/main/java/java/io/OutputStreamWriter.java Mon Oct 07 14:20:58 2013 +0200
135.3 @@ -0,0 +1,242 @@
135.4 +/*
135.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
135.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
135.7 + *
135.8 + * This code is free software; you can redistribute it and/or modify it
135.9 + * under the terms of the GNU General Public License version 2 only, as
135.10 + * published by the Free Software Foundation. Oracle designates this
135.11 + * particular file as subject to the "Classpath" exception as provided
135.12 + * by Oracle in the LICENSE file that accompanied this code.
135.13 + *
135.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
135.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
135.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
135.17 + * version 2 for more details (a copy is included in the LICENSE file that
135.18 + * accompanied this code).
135.19 + *
135.20 + * You should have received a copy of the GNU General Public License version
135.21 + * 2 along with this work; if not, write to the Free Software Foundation,
135.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
135.23 + *
135.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
135.25 + * or visit www.oracle.com if you need additional information or have any
135.26 + * questions.
135.27 + */
135.28 +
135.29 +package java.io;
135.30 +
135.31 +/**
135.32 + * An OutputStreamWriter is a bridge from character streams to byte streams:
135.33 + * Characters written to it are encoded into bytes using a specified {@link
135.34 + * java.nio.charset.Charset <code>charset</code>}. The charset that it uses
135.35 + * may be specified by name or may be given explicitly, or the platform's
135.36 + * default charset may be accepted.
135.37 + *
135.38 + * <p> Each invocation of a write() method causes the encoding converter to be
135.39 + * invoked on the given character(s). The resulting bytes are accumulated in a
135.40 + * buffer before being written to the underlying output stream. The size of
135.41 + * this buffer may be specified, but by default it is large enough for most
135.42 + * purposes. Note that the characters passed to the write() methods are not
135.43 + * buffered.
135.44 + *
135.45 + * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
135.46 + * BufferedWriter so as to avoid frequent converter invocations. For example:
135.47 + *
135.48 + * <pre>
135.49 + * Writer out
135.50 + * = new BufferedWriter(new OutputStreamWriter(System.out));
135.51 + * </pre>
135.52 + *
135.53 + * <p> A <i>surrogate pair</i> is a character represented by a sequence of two
135.54 + * <tt>char</tt> values: A <i>high</i> surrogate in the range '\uD800' to
135.55 + * '\uDBFF' followed by a <i>low</i> surrogate in the range '\uDC00' to
135.56 + * '\uDFFF'.
135.57 + *
135.58 + * <p> A <i>malformed surrogate element</i> is a high surrogate that is not
135.59 + * followed by a low surrogate or a low surrogate that is not preceded by a
135.60 + * high surrogate.
135.61 + *
135.62 + * <p> This class always replaces malformed surrogate elements and unmappable
135.63 + * character sequences with the charset's default <i>substitution sequence</i>.
135.64 + * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
135.65 + * control over the encoding process is required.
135.66 + *
135.67 + * @see BufferedWriter
135.68 + * @see OutputStream
135.69 + * @see java.nio.charset.Charset
135.70 + *
135.71 + * @author Mark Reinhold
135.72 + * @since JDK1.1
135.73 + */
135.74 +
135.75 +public class OutputStreamWriter extends Writer {
135.76 +
135.77 + /**
135.78 + * Creates an OutputStreamWriter that uses the named charset.
135.79 + *
135.80 + * @param out
135.81 + * An OutputStream
135.82 + *
135.83 + * @param charsetName
135.84 + * The name of a supported
135.85 + * {@link java.nio.charset.Charset </code>charset<code>}
135.86 + *
135.87 + * @exception UnsupportedEncodingException
135.88 + * If the named encoding is not supported
135.89 + */
135.90 + public OutputStreamWriter(OutputStream out, String charsetName)
135.91 + throws UnsupportedEncodingException
135.92 + {
135.93 + super(out);
135.94 + if (charsetName == null)
135.95 + throw new NullPointerException("charsetName");
135.96 + if (!charsetName.toUpperCase().equals("UTF-8")) {
135.97 + throw new UnsupportedEncodingException(charsetName);
135.98 + }
135.99 + }
135.100 +
135.101 + /**
135.102 + * Creates an OutputStreamWriter that uses the default character encoding.
135.103 + *
135.104 + * @param out An OutputStream
135.105 + */
135.106 + public OutputStreamWriter(OutputStream out) {
135.107 + super(out);
135.108 + }
135.109 +
135.110 + /**
135.111 + * Creates an OutputStreamWriter that uses the given charset. </p>
135.112 + *
135.113 + * @param out
135.114 + * An OutputStream
135.115 + *
135.116 + * @param cs
135.117 + * A charset
135.118 + *
135.119 + * @since 1.4
135.120 + * @spec JSR-51
135.121 + */
135.122 +// public OutputStreamWriter(OutputStream out, Charset cs) {
135.123 +// super(out);
135.124 +// if (cs == null)
135.125 +// throw new NullPointerException("charset");
135.126 +// se = StreamEncoder.forOutputStreamWriter(out, this, cs);
135.127 +// }
135.128 +
135.129 + /**
135.130 + * Creates an OutputStreamWriter that uses the given charset encoder. </p>
135.131 + *
135.132 + * @param out
135.133 + * An OutputStream
135.134 + *
135.135 + * @param enc
135.136 + * A charset encoder
135.137 + *
135.138 + * @since 1.4
135.139 + * @spec JSR-51
135.140 + */
135.141 +// public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
135.142 +// super(out);
135.143 +// if (enc == null)
135.144 +// throw new NullPointerException("charset encoder");
135.145 +// se = StreamEncoder.forOutputStreamWriter(out, this, enc);
135.146 +// }
135.147 +
135.148 + /**
135.149 + * Returns the name of the character encoding being used by this stream.
135.150 + *
135.151 + * <p> If the encoding has an historical name then that name is returned;
135.152 + * otherwise the encoding's canonical name is returned.
135.153 + *
135.154 + * <p> If this instance was created with the {@link
135.155 + * #OutputStreamWriter(OutputStream, String)} constructor then the returned
135.156 + * name, being unique for the encoding, may differ from the name passed to
135.157 + * the constructor. This method may return <tt>null</tt> if the stream has
135.158 + * been closed. </p>
135.159 + *
135.160 + * @return The historical name of this encoding, or possibly
135.161 + * <code>null</code> if the stream has been closed
135.162 + *
135.163 + * @see java.nio.charset.Charset
135.164 + *
135.165 + * @revised 1.4
135.166 + * @spec JSR-51
135.167 + */
135.168 + public String getEncoding() {
135.169 + return "UTF-8";
135.170 + }
135.171 +
135.172 + /**
135.173 + * Flushes the output buffer to the underlying byte stream, without flushing
135.174 + * the byte stream itself. This method is non-private only so that it may
135.175 + * be invoked by PrintStream.
135.176 + */
135.177 + void flushBuffer() throws IOException {
135.178 + out().flush();
135.179 + }
135.180 +
135.181 + /**
135.182 + * Writes a single character.
135.183 + *
135.184 + * @exception IOException If an I/O error occurs
135.185 + */
135.186 + public void write(int c) throws IOException {
135.187 + if (c <= 0x7F) {
135.188 + out().write(c);
135.189 + } else if (c <= 0x7FF) {
135.190 + out().write(0xC0 | (c >> 6));
135.191 + out().write(0x80 | (c & 0x3F));
135.192 + } else {
135.193 + out().write(0xE0 | (c >> 12));
135.194 + out().write(0x80 | ((c >> 6) & 0x3F));
135.195 + out().write(0x80 | (c & 0x3F));
135.196 + }
135.197 + }
135.198 +
135.199 + /**
135.200 + * Writes a portion of an array of characters.
135.201 + *
135.202 + * @param cbuf Buffer of characters
135.203 + * @param off Offset from which to start writing characters
135.204 + * @param len Number of characters to write
135.205 + *
135.206 + * @exception IOException If an I/O error occurs
135.207 + */
135.208 + public void write(char cbuf[], int off, int len) throws IOException {
135.209 + while (len-- > 0) {
135.210 + write(cbuf[off++]);
135.211 + }
135.212 + }
135.213 +
135.214 + /**
135.215 + * Writes a portion of a string.
135.216 + *
135.217 + * @param str A String
135.218 + * @param off Offset from which to start writing characters
135.219 + * @param len Number of characters to write
135.220 + *
135.221 + * @exception IOException If an I/O error occurs
135.222 + */
135.223 + public void write(String str, int off, int len) throws IOException {
135.224 + while (len-- > 0) {
135.225 + write(str.charAt(off++));
135.226 + }
135.227 + }
135.228 +
135.229 + /**
135.230 + * Flushes the stream.
135.231 + *
135.232 + * @exception IOException If an I/O error occurs
135.233 + */
135.234 + public void flush() throws IOException {
135.235 + out().flush();
135.236 + }
135.237 +
135.238 + public void close() throws IOException {
135.239 + out().close();
135.240 + }
135.241 +
135.242 + private OutputStream out() {
135.243 + return (OutputStream) lock;
135.244 + }
135.245 +}
136.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintStream.java Mon Oct 07 14:20:58 2013 +0200
136.3 @@ -0,0 +1,1125 @@
136.4 +/*
136.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
136.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
136.7 + *
136.8 + * This code is free software; you can redistribute it and/or modify it
136.9 + * under the terms of the GNU General Public License version 2 only, as
136.10 + * published by the Free Software Foundation. Oracle designates this
136.11 + * particular file as subject to the "Classpath" exception as provided
136.12 + * by Oracle in the LICENSE file that accompanied this code.
136.13 + *
136.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
136.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
136.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
136.17 + * version 2 for more details (a copy is included in the LICENSE file that
136.18 + * accompanied this code).
136.19 + *
136.20 + * You should have received a copy of the GNU General Public License version
136.21 + * 2 along with this work; if not, write to the Free Software Foundation,
136.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
136.23 + *
136.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
136.25 + * or visit www.oracle.com if you need additional information or have any
136.26 + * questions.
136.27 + */
136.28 +
136.29 +package java.io;
136.30 +
136.31 +import java.util.Arrays;
136.32 +
136.33 +
136.34 +/**
136.35 + * A <code>PrintStream</code> adds functionality to another output stream,
136.36 + * namely the ability to print representations of various data values
136.37 + * conveniently. Two other features are provided as well. Unlike other output
136.38 + * streams, a <code>PrintStream</code> never throws an
136.39 + * <code>IOException</code>; instead, exceptional situations merely set an
136.40 + * internal flag that can be tested via the <code>checkError</code> method.
136.41 + * Optionally, a <code>PrintStream</code> can be created so as to flush
136.42 + * automatically; this means that the <code>flush</code> method is
136.43 + * automatically invoked after a byte array is written, one of the
136.44 + * <code>println</code> methods is invoked, or a newline character or byte
136.45 + * (<code>'\n'</code>) is written.
136.46 + *
136.47 + * <p> All characters printed by a <code>PrintStream</code> are converted into
136.48 + * bytes using the platform's default character encoding. The <code>{@link
136.49 + * PrintWriter}</code> class should be used in situations that require writing
136.50 + * characters rather than bytes.
136.51 + *
136.52 + * @author Frank Yellin
136.53 + * @author Mark Reinhold
136.54 + * @since JDK1.0
136.55 + */
136.56 +
136.57 +public class PrintStream extends FilterOutputStream
136.58 + implements Appendable, Closeable
136.59 +{
136.60 +
136.61 + private final boolean autoFlush;
136.62 + private boolean trouble = false;
136.63 + private Formatter formatter;
136.64 +
136.65 + /**
136.66 + * Track both the text- and character-output streams, so that their buffers
136.67 + * can be flushed without flushing the entire stream.
136.68 + */
136.69 + private BufferedWriter textOut;
136.70 + private OutputStreamWriter charOut;
136.71 +
136.72 + /**
136.73 + * requireNonNull is explicitly declared here so as not to create an extra
136.74 + * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
136.75 + * early during system initialization.
136.76 + */
136.77 + private static <T> T requireNonNull(T obj, String message) {
136.78 + if (obj == null)
136.79 + throw new NullPointerException(message);
136.80 + return obj;
136.81 + }
136.82 +
136.83 + /* Private constructors */
136.84 + private PrintStream(boolean autoFlush, OutputStream out) {
136.85 + super(out);
136.86 + this.autoFlush = autoFlush;
136.87 + this.charOut = new OutputStreamWriter(this);
136.88 + this.textOut = new BufferedWriter(charOut);
136.89 + }
136.90 +
136.91 + static final class Formatter {
136.92 + }
136.93 +
136.94 + static final class Charset {
136.95 + }
136.96 +
136.97 + static Charset toCharset(String ch) throws UnsupportedEncodingException {
136.98 + if (!"UTF-8".equals(ch)) {
136.99 + throw new UnsupportedEncodingException();
136.100 + }
136.101 + return null;
136.102 + }
136.103 +
136.104 + private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
136.105 + super(out);
136.106 + this.autoFlush = autoFlush;
136.107 + this.charOut = new OutputStreamWriter(this);
136.108 + this.textOut = new BufferedWriter(charOut);
136.109 + }
136.110 +
136.111 + /* Variant of the private constructor so that the given charset name
136.112 + * can be verified before evaluating the OutputStream argument. Used
136.113 + * by constructors creating a FileOutputStream that also take a
136.114 + * charset name.
136.115 + */
136.116 + private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
136.117 + throws UnsupportedEncodingException
136.118 + {
136.119 + this(autoFlush, out, charset);
136.120 + }
136.121 +
136.122 + /**
136.123 + * Creates a new print stream. This stream will not flush automatically.
136.124 + *
136.125 + * @param out The output stream to which values and objects will be
136.126 + * printed
136.127 + *
136.128 + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
136.129 + */
136.130 + public PrintStream(OutputStream out) {
136.131 + this(out, false);
136.132 + }
136.133 +
136.134 + /**
136.135 + * Creates a new print stream.
136.136 + *
136.137 + * @param out The output stream to which values and objects will be
136.138 + * printed
136.139 + * @param autoFlush A boolean; if true, the output buffer will be flushed
136.140 + * whenever a byte array is written, one of the
136.141 + * <code>println</code> methods is invoked, or a newline
136.142 + * character or byte (<code>'\n'</code>) is written
136.143 + *
136.144 + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
136.145 + */
136.146 + public PrintStream(OutputStream out, boolean autoFlush) {
136.147 + this(autoFlush, requireNonNull(out, "Null output stream"));
136.148 + }
136.149 +
136.150 + /**
136.151 + * Creates a new print stream.
136.152 + *
136.153 + * @param out The output stream to which values and objects will be
136.154 + * printed
136.155 + * @param autoFlush A boolean; if true, the output buffer will be flushed
136.156 + * whenever a byte array is written, one of the
136.157 + * <code>println</code> methods is invoked, or a newline
136.158 + * character or byte (<code>'\n'</code>) is written
136.159 + * @param encoding The name of a supported
136.160 + * <a href="../lang/package-summary.html#charenc">
136.161 + * character encoding</a>
136.162 + *
136.163 + * @throws UnsupportedEncodingException
136.164 + * If the named encoding is not supported
136.165 + *
136.166 + * @since 1.4
136.167 + */
136.168 + public PrintStream(OutputStream out, boolean autoFlush, String encoding)
136.169 + throws UnsupportedEncodingException
136.170 + {
136.171 + this(autoFlush,
136.172 + requireNonNull(out, "Null output stream"),
136.173 + toCharset(encoding));
136.174 + }
136.175 +
136.176 + /**
136.177 + * Creates a new print stream, without automatic line flushing, with the
136.178 + * specified file name. This convenience constructor creates
136.179 + * the necessary intermediate {@link java.io.OutputStreamWriter
136.180 + * OutputStreamWriter}, which will encode characters using the
136.181 + * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
136.182 + * for this instance of the Java virtual machine.
136.183 + *
136.184 + * @param fileName
136.185 + * The name of the file to use as the destination of this print
136.186 + * stream. If the file exists, then it will be truncated to
136.187 + * zero size; otherwise, a new file will be created. The output
136.188 + * will be written to the file and is buffered.
136.189 + *
136.190 + * @throws FileNotFoundException
136.191 + * If the given file object does not denote an existing, writable
136.192 + * regular file and a new regular file of that name cannot be
136.193 + * created, or if some other error occurs while opening or
136.194 + * creating the file
136.195 + *
136.196 + * @throws SecurityException
136.197 + * If a security manager is present and {@link
136.198 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
136.199 + * access to the file
136.200 + *
136.201 + * @since 1.5
136.202 + */
136.203 + public PrintStream(String fileName) throws FileNotFoundException {
136.204 + super(null);
136.205 + throw new FileNotFoundException();
136.206 + }
136.207 +
136.208 + /**
136.209 + * Creates a new print stream, without automatic line flushing, with the
136.210 + * specified file name and charset. This convenience constructor creates
136.211 + * the necessary intermediate {@link java.io.OutputStreamWriter
136.212 + * OutputStreamWriter}, which will encode characters using the provided
136.213 + * charset.
136.214 + *
136.215 + * @param fileName
136.216 + * The name of the file to use as the destination of this print
136.217 + * stream. If the file exists, then it will be truncated to
136.218 + * zero size; otherwise, a new file will be created. The output
136.219 + * will be written to the file and is buffered.
136.220 + *
136.221 + * @param csn
136.222 + * The name of a supported {@linkplain java.nio.charset.Charset
136.223 + * charset}
136.224 + *
136.225 + * @throws FileNotFoundException
136.226 + * If the given file object does not denote an existing, writable
136.227 + * regular file and a new regular file of that name cannot be
136.228 + * created, or if some other error occurs while opening or
136.229 + * creating the file
136.230 + *
136.231 + * @throws SecurityException
136.232 + * If a security manager is present and {@link
136.233 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
136.234 + * access to the file
136.235 + *
136.236 + * @throws UnsupportedEncodingException
136.237 + * If the named charset is not supported
136.238 + *
136.239 + * @since 1.5
136.240 + */
136.241 + public PrintStream(String fileName, String csn)
136.242 + throws FileNotFoundException, UnsupportedEncodingException
136.243 + {
136.244 + super(null);
136.245 + throw new FileNotFoundException();
136.246 + }
136.247 +
136.248 + /**
136.249 + * Creates a new print stream, without automatic line flushing, with the
136.250 + * specified file. This convenience constructor creates the necessary
136.251 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
136.252 + * which will encode characters using the {@linkplain
136.253 + * java.nio.charset.Charset#defaultCharset() default charset} for this
136.254 + * instance of the Java virtual machine.
136.255 + *
136.256 + * @param file
136.257 + * The file to use as the destination of this print stream. If the
136.258 + * file exists, then it will be truncated to zero size; otherwise,
136.259 + * a new file will be created. The output will be written to the
136.260 + * file and is buffered.
136.261 + *
136.262 + * @throws FileNotFoundException
136.263 + * If the given file object does not denote an existing, writable
136.264 + * regular file and a new regular file of that name cannot be
136.265 + * created, or if some other error occurs while opening or
136.266 + * creating the file
136.267 + *
136.268 + * @throws SecurityException
136.269 + * If a security manager is present and {@link
136.270 + * SecurityManager#checkWrite checkWrite(file.getPath())}
136.271 + * denies write access to the file
136.272 + *
136.273 + * @since 1.5
136.274 + */
136.275 + public PrintStream(File file) throws FileNotFoundException {
136.276 + super(null);
136.277 + throw new FileNotFoundException();
136.278 + }
136.279 +
136.280 + /**
136.281 + * Creates a new print stream, without automatic line flushing, with the
136.282 + * specified file and charset. This convenience constructor creates
136.283 + * the necessary intermediate {@link java.io.OutputStreamWriter
136.284 + * OutputStreamWriter}, which will encode characters using the provided
136.285 + * charset.
136.286 + *
136.287 + * @param file
136.288 + * The file to use as the destination of this print stream. If the
136.289 + * file exists, then it will be truncated to zero size; otherwise,
136.290 + * a new file will be created. The output will be written to the
136.291 + * file and is buffered.
136.292 + *
136.293 + * @param csn
136.294 + * The name of a supported {@linkplain java.nio.charset.Charset
136.295 + * charset}
136.296 + *
136.297 + * @throws FileNotFoundException
136.298 + * If the given file object does not denote an existing, writable
136.299 + * regular file and a new regular file of that name cannot be
136.300 + * created, or if some other error occurs while opening or
136.301 + * creating the file
136.302 + *
136.303 + * @throws SecurityException
136.304 + * If a security manager is presentand {@link
136.305 + * SecurityManager#checkWrite checkWrite(file.getPath())}
136.306 + * denies write access to the file
136.307 + *
136.308 + * @throws UnsupportedEncodingException
136.309 + * If the named charset is not supported
136.310 + *
136.311 + * @since 1.5
136.312 + */
136.313 + public PrintStream(File file, String csn)
136.314 + throws FileNotFoundException, UnsupportedEncodingException
136.315 + {
136.316 + super(null);
136.317 + throw new FileNotFoundException();
136.318 + }
136.319 +
136.320 + /** Check to make sure that the stream has not been closed */
136.321 + private void ensureOpen() throws IOException {
136.322 + if (out == null)
136.323 + throw new IOException("Stream closed");
136.324 + }
136.325 +
136.326 + /**
136.327 + * Flushes the stream. This is done by writing any buffered output bytes to
136.328 + * the underlying output stream and then flushing that stream.
136.329 + *
136.330 + * @see java.io.OutputStream#flush()
136.331 + */
136.332 + public void flush() {
136.333 + synchronized (this) {
136.334 + try {
136.335 + ensureOpen();
136.336 + out.flush();
136.337 + }
136.338 + catch (IOException x) {
136.339 + trouble = true;
136.340 + }
136.341 + }
136.342 + }
136.343 +
136.344 + private boolean closing = false; /* To avoid recursive closing */
136.345 +
136.346 + /**
136.347 + * Closes the stream. This is done by flushing the stream and then closing
136.348 + * the underlying output stream.
136.349 + *
136.350 + * @see java.io.OutputStream#close()
136.351 + */
136.352 + public void close() {
136.353 + synchronized (this) {
136.354 + if (! closing) {
136.355 + closing = true;
136.356 + try {
136.357 + textOut.close();
136.358 + out.close();
136.359 + }
136.360 + catch (IOException x) {
136.361 + trouble = true;
136.362 + }
136.363 + textOut = null;
136.364 + charOut = null;
136.365 + out = null;
136.366 + }
136.367 + }
136.368 + }
136.369 +
136.370 + /**
136.371 + * Flushes the stream and checks its error state. The internal error state
136.372 + * is set to <code>true</code> when the underlying output stream throws an
136.373 + * <code>IOException</code> other than <code>InterruptedIOException</code>,
136.374 + * and when the <code>setError</code> method is invoked. If an operation
136.375 + * on the underlying output stream throws an
136.376 + * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
136.377 + * converts the exception back into an interrupt by doing:
136.378 + * <pre>
136.379 + * Thread.currentThread().interrupt();
136.380 + * </pre>
136.381 + * or the equivalent.
136.382 + *
136.383 + * @return <code>true</code> if and only if this stream has encountered an
136.384 + * <code>IOException</code> other than
136.385 + * <code>InterruptedIOException</code>, or the
136.386 + * <code>setError</code> method has been invoked
136.387 + */
136.388 + public boolean checkError() {
136.389 + if (out != null)
136.390 + flush();
136.391 + if (out instanceof java.io.PrintStream) {
136.392 + PrintStream ps = (PrintStream) out;
136.393 + return ps.checkError();
136.394 + }
136.395 + return trouble;
136.396 + }
136.397 +
136.398 + /**
136.399 + * Sets the error state of the stream to <code>true</code>.
136.400 + *
136.401 + * <p> This method will cause subsequent invocations of {@link
136.402 + * #checkError()} to return <tt>true</tt> until {@link
136.403 + * #clearError()} is invoked.
136.404 + *
136.405 + * @since JDK1.1
136.406 + */
136.407 + protected void setError() {
136.408 + trouble = true;
136.409 + }
136.410 +
136.411 + /**
136.412 + * Clears the internal error state of this stream.
136.413 + *
136.414 + * <p> This method will cause subsequent invocations of {@link
136.415 + * #checkError()} to return <tt>false</tt> until another write
136.416 + * operation fails and invokes {@link #setError()}.
136.417 + *
136.418 + * @since 1.6
136.419 + */
136.420 + protected void clearError() {
136.421 + trouble = false;
136.422 + }
136.423 +
136.424 + /*
136.425 + * Exception-catching, synchronized output operations,
136.426 + * which also implement the write() methods of OutputStream
136.427 + */
136.428 +
136.429 + /**
136.430 + * Writes the specified byte to this stream. If the byte is a newline and
136.431 + * automatic flushing is enabled then the <code>flush</code> method will be
136.432 + * invoked.
136.433 + *
136.434 + * <p> Note that the byte is written as given; to write a character that
136.435 + * will be translated according to the platform's default character
136.436 + * encoding, use the <code>print(char)</code> or <code>println(char)</code>
136.437 + * methods.
136.438 + *
136.439 + * @param b The byte to be written
136.440 + * @see #print(char)
136.441 + * @see #println(char)
136.442 + */
136.443 + public void write(int b) {
136.444 + try {
136.445 + synchronized (this) {
136.446 + ensureOpen();
136.447 + out.write(b);
136.448 + if ((b == '\n') && autoFlush)
136.449 + out.flush();
136.450 + }
136.451 + }
136.452 + catch (InterruptedIOException x) {
136.453 + Thread.currentThread().interrupt();
136.454 + }
136.455 + catch (IOException x) {
136.456 + trouble = true;
136.457 + }
136.458 + }
136.459 +
136.460 + /**
136.461 + * Writes <code>len</code> bytes from the specified byte array starting at
136.462 + * offset <code>off</code> to this stream. If automatic flushing is
136.463 + * enabled then the <code>flush</code> method will be invoked.
136.464 + *
136.465 + * <p> Note that the bytes will be written as given; to write characters
136.466 + * that will be translated according to the platform's default character
136.467 + * encoding, use the <code>print(char)</code> or <code>println(char)</code>
136.468 + * methods.
136.469 + *
136.470 + * @param buf A byte array
136.471 + * @param off Offset from which to start taking bytes
136.472 + * @param len Number of bytes to write
136.473 + */
136.474 + public void write(byte buf[], int off, int len) {
136.475 + try {
136.476 + synchronized (this) {
136.477 + ensureOpen();
136.478 + out.write(buf, off, len);
136.479 + if (autoFlush)
136.480 + out.flush();
136.481 + }
136.482 + }
136.483 + catch (InterruptedIOException x) {
136.484 + Thread.currentThread().interrupt();
136.485 + }
136.486 + catch (IOException x) {
136.487 + trouble = true;
136.488 + }
136.489 + }
136.490 +
136.491 + /*
136.492 + * The following private methods on the text- and character-output streams
136.493 + * always flush the stream buffers, so that writes to the underlying byte
136.494 + * stream occur as promptly as with the original PrintStream.
136.495 + */
136.496 +
136.497 + private void write(char buf[]) {
136.498 + try {
136.499 + synchronized (this) {
136.500 + ensureOpen();
136.501 + textOut.write(buf);
136.502 + textOut.flushBuffer();
136.503 + charOut.flushBuffer();
136.504 + if (autoFlush) {
136.505 + for (int i = 0; i < buf.length; i++)
136.506 + if (buf[i] == '\n')
136.507 + out.flush();
136.508 + }
136.509 + }
136.510 + }
136.511 + catch (InterruptedIOException x) {
136.512 + Thread.currentThread().interrupt();
136.513 + }
136.514 + catch (IOException x) {
136.515 + trouble = true;
136.516 + }
136.517 + }
136.518 +
136.519 + private void write(String s) {
136.520 + try {
136.521 + synchronized (this) {
136.522 + ensureOpen();
136.523 + textOut.write(s);
136.524 + textOut.flushBuffer();
136.525 + charOut.flushBuffer();
136.526 + if (autoFlush && (s.indexOf('\n') >= 0))
136.527 + out.flush();
136.528 + }
136.529 + }
136.530 + catch (InterruptedIOException x) {
136.531 + Thread.currentThread().interrupt();
136.532 + }
136.533 + catch (IOException x) {
136.534 + trouble = true;
136.535 + }
136.536 + }
136.537 +
136.538 + private void newLine() {
136.539 + try {
136.540 + synchronized (this) {
136.541 + ensureOpen();
136.542 + textOut.newLine();
136.543 + textOut.flushBuffer();
136.544 + charOut.flushBuffer();
136.545 + if (autoFlush)
136.546 + out.flush();
136.547 + }
136.548 + }
136.549 + catch (InterruptedIOException x) {
136.550 + Thread.currentThread().interrupt();
136.551 + }
136.552 + catch (IOException x) {
136.553 + trouble = true;
136.554 + }
136.555 + }
136.556 +
136.557 + /* Methods that do not terminate lines */
136.558 +
136.559 + /**
136.560 + * Prints a boolean value. The string produced by <code>{@link
136.561 + * java.lang.String#valueOf(boolean)}</code> is translated into bytes
136.562 + * according to the platform's default character encoding, and these bytes
136.563 + * are written in exactly the manner of the
136.564 + * <code>{@link #write(int)}</code> method.
136.565 + *
136.566 + * @param b The <code>boolean</code> to be printed
136.567 + */
136.568 + public void print(boolean b) {
136.569 + write(b ? "true" : "false");
136.570 + }
136.571 +
136.572 + /**
136.573 + * Prints a character. The character is translated into one or more bytes
136.574 + * according to the platform's default character encoding, and these bytes
136.575 + * are written in exactly the manner of the
136.576 + * <code>{@link #write(int)}</code> method.
136.577 + *
136.578 + * @param c The <code>char</code> to be printed
136.579 + */
136.580 + public void print(char c) {
136.581 + write(String.valueOf(c));
136.582 + }
136.583 +
136.584 + /**
136.585 + * Prints an integer. The string produced by <code>{@link
136.586 + * java.lang.String#valueOf(int)}</code> is translated into bytes
136.587 + * according to the platform's default character encoding, and these bytes
136.588 + * are written in exactly the manner of the
136.589 + * <code>{@link #write(int)}</code> method.
136.590 + *
136.591 + * @param i The <code>int</code> to be printed
136.592 + * @see java.lang.Integer#toString(int)
136.593 + */
136.594 + public void print(int i) {
136.595 + write(String.valueOf(i));
136.596 + }
136.597 +
136.598 + /**
136.599 + * Prints a long integer. The string produced by <code>{@link
136.600 + * java.lang.String#valueOf(long)}</code> is translated into bytes
136.601 + * according to the platform's default character encoding, and these bytes
136.602 + * are written in exactly the manner of the
136.603 + * <code>{@link #write(int)}</code> method.
136.604 + *
136.605 + * @param l The <code>long</code> to be printed
136.606 + * @see java.lang.Long#toString(long)
136.607 + */
136.608 + public void print(long l) {
136.609 + write(String.valueOf(l));
136.610 + }
136.611 +
136.612 + /**
136.613 + * Prints a floating-point number. The string produced by <code>{@link
136.614 + * java.lang.String#valueOf(float)}</code> is translated into bytes
136.615 + * according to the platform's default character encoding, and these bytes
136.616 + * are written in exactly the manner of the
136.617 + * <code>{@link #write(int)}</code> method.
136.618 + *
136.619 + * @param f The <code>float</code> to be printed
136.620 + * @see java.lang.Float#toString(float)
136.621 + */
136.622 + public void print(float f) {
136.623 + write(String.valueOf(f));
136.624 + }
136.625 +
136.626 + /**
136.627 + * Prints a double-precision floating-point number. The string produced by
136.628 + * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
136.629 + * bytes according to the platform's default character encoding, and these
136.630 + * bytes are written in exactly the manner of the <code>{@link
136.631 + * #write(int)}</code> method.
136.632 + *
136.633 + * @param d The <code>double</code> to be printed
136.634 + * @see java.lang.Double#toString(double)
136.635 + */
136.636 + public void print(double d) {
136.637 + write(String.valueOf(d));
136.638 + }
136.639 +
136.640 + /**
136.641 + * Prints an array of characters. The characters are converted into bytes
136.642 + * according to the platform's default character encoding, and these bytes
136.643 + * are written in exactly the manner of the
136.644 + * <code>{@link #write(int)}</code> method.
136.645 + *
136.646 + * @param s The array of chars to be printed
136.647 + *
136.648 + * @throws NullPointerException If <code>s</code> is <code>null</code>
136.649 + */
136.650 + public void print(char s[]) {
136.651 + write(s);
136.652 + }
136.653 +
136.654 + /**
136.655 + * Prints a string. If the argument is <code>null</code> then the string
136.656 + * <code>"null"</code> is printed. Otherwise, the string's characters are
136.657 + * converted into bytes according to the platform's default character
136.658 + * encoding, and these bytes are written in exactly the manner of the
136.659 + * <code>{@link #write(int)}</code> method.
136.660 + *
136.661 + * @param s The <code>String</code> to be printed
136.662 + */
136.663 + public void print(String s) {
136.664 + if (s == null) {
136.665 + s = "null";
136.666 + }
136.667 + write(s);
136.668 + }
136.669 +
136.670 + /**
136.671 + * Prints an object. The string produced by the <code>{@link
136.672 + * java.lang.String#valueOf(Object)}</code> method is translated into bytes
136.673 + * according to the platform's default character encoding, and these bytes
136.674 + * are written in exactly the manner of the
136.675 + * <code>{@link #write(int)}</code> method.
136.676 + *
136.677 + * @param obj The <code>Object</code> to be printed
136.678 + * @see java.lang.Object#toString()
136.679 + */
136.680 + public void print(Object obj) {
136.681 + write(String.valueOf(obj));
136.682 + }
136.683 +
136.684 +
136.685 + /* Methods that do terminate lines */
136.686 +
136.687 + /**
136.688 + * Terminates the current line by writing the line separator string. The
136.689 + * line separator string is defined by the system property
136.690 + * <code>line.separator</code>, and is not necessarily a single newline
136.691 + * character (<code>'\n'</code>).
136.692 + */
136.693 + public void println() {
136.694 + newLine();
136.695 + }
136.696 +
136.697 + /**
136.698 + * Prints a boolean and then terminate the line. This method behaves as
136.699 + * though it invokes <code>{@link #print(boolean)}</code> and then
136.700 + * <code>{@link #println()}</code>.
136.701 + *
136.702 + * @param x The <code>boolean</code> to be printed
136.703 + */
136.704 + public void println(boolean x) {
136.705 + synchronized (this) {
136.706 + print(x);
136.707 + newLine();
136.708 + }
136.709 + }
136.710 +
136.711 + /**
136.712 + * Prints a character and then terminate the line. This method behaves as
136.713 + * though it invokes <code>{@link #print(char)}</code> and then
136.714 + * <code>{@link #println()}</code>.
136.715 + *
136.716 + * @param x The <code>char</code> to be printed.
136.717 + */
136.718 + public void println(char x) {
136.719 + synchronized (this) {
136.720 + print(x);
136.721 + newLine();
136.722 + }
136.723 + }
136.724 +
136.725 + /**
136.726 + * Prints an integer and then terminate the line. This method behaves as
136.727 + * though it invokes <code>{@link #print(int)}</code> and then
136.728 + * <code>{@link #println()}</code>.
136.729 + *
136.730 + * @param x The <code>int</code> to be printed.
136.731 + */
136.732 + public void println(int x) {
136.733 + synchronized (this) {
136.734 + print(x);
136.735 + newLine();
136.736 + }
136.737 + }
136.738 +
136.739 + /**
136.740 + * Prints a long and then terminate the line. This method behaves as
136.741 + * though it invokes <code>{@link #print(long)}</code> and then
136.742 + * <code>{@link #println()}</code>.
136.743 + *
136.744 + * @param x a The <code>long</code> to be printed.
136.745 + */
136.746 + public void println(long x) {
136.747 + synchronized (this) {
136.748 + print(x);
136.749 + newLine();
136.750 + }
136.751 + }
136.752 +
136.753 + /**
136.754 + * Prints a float and then terminate the line. This method behaves as
136.755 + * though it invokes <code>{@link #print(float)}</code> and then
136.756 + * <code>{@link #println()}</code>.
136.757 + *
136.758 + * @param x The <code>float</code> to be printed.
136.759 + */
136.760 + public void println(float x) {
136.761 + synchronized (this) {
136.762 + print(x);
136.763 + newLine();
136.764 + }
136.765 + }
136.766 +
136.767 + /**
136.768 + * Prints a double and then terminate the line. This method behaves as
136.769 + * though it invokes <code>{@link #print(double)}</code> and then
136.770 + * <code>{@link #println()}</code>.
136.771 + *
136.772 + * @param x The <code>double</code> to be printed.
136.773 + */
136.774 + public void println(double x) {
136.775 + synchronized (this) {
136.776 + print(x);
136.777 + newLine();
136.778 + }
136.779 + }
136.780 +
136.781 + /**
136.782 + * Prints an array of characters and then terminate the line. This method
136.783 + * behaves as though it invokes <code>{@link #print(char[])}</code> and
136.784 + * then <code>{@link #println()}</code>.
136.785 + *
136.786 + * @param x an array of chars to print.
136.787 + */
136.788 + public void println(char x[]) {
136.789 + synchronized (this) {
136.790 + print(x);
136.791 + newLine();
136.792 + }
136.793 + }
136.794 +
136.795 + /**
136.796 + * Prints a String and then terminate the line. This method behaves as
136.797 + * though it invokes <code>{@link #print(String)}</code> and then
136.798 + * <code>{@link #println()}</code>.
136.799 + *
136.800 + * @param x The <code>String</code> to be printed.
136.801 + */
136.802 + public void println(String x) {
136.803 + synchronized (this) {
136.804 + print(x);
136.805 + newLine();
136.806 + }
136.807 + }
136.808 +
136.809 + /**
136.810 + * Prints an Object and then terminate the line. This method calls
136.811 + * at first String.valueOf(x) to get the printed object's string value,
136.812 + * then behaves as
136.813 + * though it invokes <code>{@link #print(String)}</code> and then
136.814 + * <code>{@link #println()}</code>.
136.815 + *
136.816 + * @param x The <code>Object</code> to be printed.
136.817 + */
136.818 + public void println(Object x) {
136.819 + String s = String.valueOf(x);
136.820 + synchronized (this) {
136.821 + print(s);
136.822 + newLine();
136.823 + }
136.824 + }
136.825 +
136.826 +
136.827 + /**
136.828 + * A convenience method to write a formatted string to this output stream
136.829 + * using the specified format string and arguments.
136.830 + *
136.831 + * <p> An invocation of this method of the form <tt>out.printf(format,
136.832 + * args)</tt> behaves in exactly the same way as the invocation
136.833 + *
136.834 + * <pre>
136.835 + * out.format(format, args) </pre>
136.836 + *
136.837 + * @param format
136.838 + * A format string as described in <a
136.839 + * href="../util/Formatter.html#syntax">Format string syntax</a>
136.840 + *
136.841 + * @param args
136.842 + * Arguments referenced by the format specifiers in the format
136.843 + * string. If there are more arguments than format specifiers, the
136.844 + * extra arguments are ignored. The number of arguments is
136.845 + * variable and may be zero. The maximum number of arguments is
136.846 + * limited by the maximum dimension of a Java array as defined by
136.847 + * <cite>The Java™ Virtual Machine Specification</cite>.
136.848 + * The behaviour on a
136.849 + * <tt>null</tt> argument depends on the <a
136.850 + * href="../util/Formatter.html#syntax">conversion</a>.
136.851 + *
136.852 + * @throws IllegalFormatException
136.853 + * If a format string contains an illegal syntax, a format
136.854 + * specifier that is incompatible with the given arguments,
136.855 + * insufficient arguments given the format string, or other
136.856 + * illegal conditions. For specification of all possible
136.857 + * formatting errors, see the <a
136.858 + * href="../util/Formatter.html#detail">Details</a> section of the
136.859 + * formatter class specification.
136.860 + *
136.861 + * @throws NullPointerException
136.862 + * If the <tt>format</tt> is <tt>null</tt>
136.863 + *
136.864 + * @return This output stream
136.865 + *
136.866 + * @since 1.5
136.867 + */
136.868 + public PrintStream printf(String format, Object ... args) {
136.869 + append(format).append(Arrays.toString(args));
136.870 + return this;
136.871 + }
136.872 +
136.873 + /**
136.874 + * A convenience method to write a formatted string to this output stream
136.875 + * using the specified format string and arguments.
136.876 + *
136.877 + * <p> An invocation of this method of the form <tt>out.printf(l, format,
136.878 + * args)</tt> behaves in exactly the same way as the invocation
136.879 + *
136.880 + * <pre>
136.881 + * out.format(l, format, args) </pre>
136.882 + *
136.883 + * @param l
136.884 + * The {@linkplain java.util.Locale locale} to apply during
136.885 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
136.886 + * is applied.
136.887 + *
136.888 + * @param format
136.889 + * A format string as described in <a
136.890 + * href="../util/Formatter.html#syntax">Format string syntax</a>
136.891 + *
136.892 + * @param args
136.893 + * Arguments referenced by the format specifiers in the format
136.894 + * string. If there are more arguments than format specifiers, the
136.895 + * extra arguments are ignored. The number of arguments is
136.896 + * variable and may be zero. The maximum number of arguments is
136.897 + * limited by the maximum dimension of a Java array as defined by
136.898 + * <cite>The Java™ Virtual Machine Specification</cite>.
136.899 + * The behaviour on a
136.900 + * <tt>null</tt> argument depends on the <a
136.901 + * href="../util/Formatter.html#syntax">conversion</a>.
136.902 + *
136.903 + * @throws IllegalFormatException
136.904 + * If a format string contains an illegal syntax, a format
136.905 + * specifier that is incompatible with the given arguments,
136.906 + * insufficient arguments given the format string, or other
136.907 + * illegal conditions. For specification of all possible
136.908 + * formatting errors, see the <a
136.909 + * href="../util/Formatter.html#detail">Details</a> section of the
136.910 + * formatter class specification.
136.911 + *
136.912 + * @throws NullPointerException
136.913 + * If the <tt>format</tt> is <tt>null</tt>
136.914 + *
136.915 + * @return This output stream
136.916 + *
136.917 + * @since 1.5
136.918 + */
136.919 +// public PrintStream printf(Locale l, String format, Object ... args) {
136.920 +// return format(l, format, args);
136.921 +// }
136.922 +
136.923 + /**
136.924 + * Writes a formatted string to this output stream using the specified
136.925 + * format string and arguments.
136.926 + *
136.927 + * <p> The locale always used is the one returned by {@link
136.928 + * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
136.929 + * previous invocations of other formatting methods on this object.
136.930 + *
136.931 + * @param format
136.932 + * A format string as described in <a
136.933 + * href="../util/Formatter.html#syntax">Format string syntax</a>
136.934 + *
136.935 + * @param args
136.936 + * Arguments referenced by the format specifiers in the format
136.937 + * string. If there are more arguments than format specifiers, the
136.938 + * extra arguments are ignored. The number of arguments is
136.939 + * variable and may be zero. The maximum number of arguments is
136.940 + * limited by the maximum dimension of a Java array as defined by
136.941 + * <cite>The Java™ Virtual Machine Specification</cite>.
136.942 + * The behaviour on a
136.943 + * <tt>null</tt> argument depends on the <a
136.944 + * href="../util/Formatter.html#syntax">conversion</a>.
136.945 + *
136.946 + * @throws IllegalFormatException
136.947 + * If a format string contains an illegal syntax, a format
136.948 + * specifier that is incompatible with the given arguments,
136.949 + * insufficient arguments given the format string, or other
136.950 + * illegal conditions. For specification of all possible
136.951 + * formatting errors, see the <a
136.952 + * href="../util/Formatter.html#detail">Details</a> section of the
136.953 + * formatter class specification.
136.954 + *
136.955 + * @throws NullPointerException
136.956 + * If the <tt>format</tt> is <tt>null</tt>
136.957 + *
136.958 + * @return This output stream
136.959 + *
136.960 + * @since 1.5
136.961 + */
136.962 +// public PrintStream format(String format, Object ... args) {
136.963 +// try {
136.964 +// synchronized (this) {
136.965 +// ensureOpen();
136.966 +// if ((formatter == null)
136.967 +// || (formatter.locale() != Locale.getDefault()))
136.968 +// formatter = new Formatter((Appendable) this);
136.969 +// formatter.format(Locale.getDefault(), format, args);
136.970 +// }
136.971 +// } catch (InterruptedIOException x) {
136.972 +// Thread.currentThread().interrupt();
136.973 +// } catch (IOException x) {
136.974 +// trouble = true;
136.975 +// }
136.976 +// return this;
136.977 +// }
136.978 +
136.979 + /**
136.980 + * Writes a formatted string to this output stream using the specified
136.981 + * format string and arguments.
136.982 + *
136.983 + * @param l
136.984 + * The {@linkplain java.util.Locale locale} to apply during
136.985 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
136.986 + * is applied.
136.987 + *
136.988 + * @param format
136.989 + * A format string as described in <a
136.990 + * href="../util/Formatter.html#syntax">Format string syntax</a>
136.991 + *
136.992 + * @param args
136.993 + * Arguments referenced by the format specifiers in the format
136.994 + * string. If there are more arguments than format specifiers, the
136.995 + * extra arguments are ignored. The number of arguments is
136.996 + * variable and may be zero. The maximum number of arguments is
136.997 + * limited by the maximum dimension of a Java array as defined by
136.998 + * <cite>The Java™ Virtual Machine Specification</cite>.
136.999 + * The behaviour on a
136.1000 + * <tt>null</tt> argument depends on the <a
136.1001 + * href="../util/Formatter.html#syntax">conversion</a>.
136.1002 + *
136.1003 + * @throws IllegalFormatException
136.1004 + * If a format string contains an illegal syntax, a format
136.1005 + * specifier that is incompatible with the given arguments,
136.1006 + * insufficient arguments given the format string, or other
136.1007 + * illegal conditions. For specification of all possible
136.1008 + * formatting errors, see the <a
136.1009 + * href="../util/Formatter.html#detail">Details</a> section of the
136.1010 + * formatter class specification.
136.1011 + *
136.1012 + * @throws NullPointerException
136.1013 + * If the <tt>format</tt> is <tt>null</tt>
136.1014 + *
136.1015 + * @return This output stream
136.1016 + *
136.1017 + * @since 1.5
136.1018 + */
136.1019 +//// public PrintStream format(Locale l, String format, Object ... args) {
136.1020 +//// try {
136.1021 +//// synchronized (this) {
136.1022 +//// ensureOpen();
136.1023 +//// if ((formatter == null)
136.1024 +//// || (formatter.locale() != l))
136.1025 +//// formatter = new Formatter(this, l);
136.1026 +//// formatter.format(l, format, args);
136.1027 +//// }
136.1028 +//// } catch (InterruptedIOException x) {
136.1029 +//// Thread.currentThread().interrupt();
136.1030 +//// } catch (IOException x) {
136.1031 +//// trouble = true;
136.1032 +//// }
136.1033 +//// return this;
136.1034 +//// }
136.1035 +
136.1036 + /**
136.1037 + * Appends the specified character sequence to this output stream.
136.1038 + *
136.1039 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
136.1040 + * behaves in exactly the same way as the invocation
136.1041 + *
136.1042 + * <pre>
136.1043 + * out.print(csq.toString()) </pre>
136.1044 + *
136.1045 + * <p> Depending on the specification of <tt>toString</tt> for the
136.1046 + * character sequence <tt>csq</tt>, the entire sequence may not be
136.1047 + * appended. For instance, invoking then <tt>toString</tt> method of a
136.1048 + * character buffer will return a subsequence whose content depends upon
136.1049 + * the buffer's position and limit.
136.1050 + *
136.1051 + * @param csq
136.1052 + * The character sequence to append. If <tt>csq</tt> is
136.1053 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
136.1054 + * appended to this output stream.
136.1055 + *
136.1056 + * @return This output stream
136.1057 + *
136.1058 + * @since 1.5
136.1059 + */
136.1060 + public PrintStream append(CharSequence csq) {
136.1061 + if (csq == null)
136.1062 + print("null");
136.1063 + else
136.1064 + print(csq.toString());
136.1065 + return this;
136.1066 + }
136.1067 +
136.1068 + /**
136.1069 + * Appends a subsequence of the specified character sequence to this output
136.1070 + * stream.
136.1071 + *
136.1072 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
136.1073 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
136.1074 + * exactly the same way as the invocation
136.1075 + *
136.1076 + * <pre>
136.1077 + * out.print(csq.subSequence(start, end).toString()) </pre>
136.1078 + *
136.1079 + * @param csq
136.1080 + * The character sequence from which a subsequence will be
136.1081 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
136.1082 + * will be appended as if <tt>csq</tt> contained the four
136.1083 + * characters <tt>"null"</tt>.
136.1084 + *
136.1085 + * @param start
136.1086 + * The index of the first character in the subsequence
136.1087 + *
136.1088 + * @param end
136.1089 + * The index of the character following the last character in the
136.1090 + * subsequence
136.1091 + *
136.1092 + * @return This output stream
136.1093 + *
136.1094 + * @throws IndexOutOfBoundsException
136.1095 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
136.1096 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
136.1097 + * <tt>csq.length()</tt>
136.1098 + *
136.1099 + * @since 1.5
136.1100 + */
136.1101 + public PrintStream append(CharSequence csq, int start, int end) {
136.1102 + CharSequence cs = (csq == null ? "null" : csq);
136.1103 + write(cs.subSequence(start, end).toString());
136.1104 + return this;
136.1105 + }
136.1106 +
136.1107 + /**
136.1108 + * Appends the specified character to this output stream.
136.1109 + *
136.1110 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
136.1111 + * behaves in exactly the same way as the invocation
136.1112 + *
136.1113 + * <pre>
136.1114 + * out.print(c) </pre>
136.1115 + *
136.1116 + * @param c
136.1117 + * The 16-bit character to append
136.1118 + *
136.1119 + * @return This output stream
136.1120 + *
136.1121 + * @since 1.5
136.1122 + */
136.1123 + public PrintStream append(char c) {
136.1124 + print(c);
136.1125 + return this;
136.1126 + }
136.1127 +
136.1128 +}
137.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
137.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintWriter.java Mon Oct 07 14:20:58 2013 +0200
137.3 @@ -0,0 +1,1030 @@
137.4 +/*
137.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
137.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
137.7 + *
137.8 + * This code is free software; you can redistribute it and/or modify it
137.9 + * under the terms of the GNU General Public License version 2 only, as
137.10 + * published by the Free Software Foundation. Oracle designates this
137.11 + * particular file as subject to the "Classpath" exception as provided
137.12 + * by Oracle in the LICENSE file that accompanied this code.
137.13 + *
137.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
137.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
137.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
137.17 + * version 2 for more details (a copy is included in the LICENSE file that
137.18 + * accompanied this code).
137.19 + *
137.20 + * You should have received a copy of the GNU General Public License version
137.21 + * 2 along with this work; if not, write to the Free Software Foundation,
137.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
137.23 + *
137.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
137.25 + * or visit www.oracle.com if you need additional information or have any
137.26 + * questions.
137.27 + */
137.28 +
137.29 +package java.io;
137.30 +
137.31 +import java.io.PrintStream.Charset;
137.32 +import java.io.PrintStream.Formatter;
137.33 +import java.util.Arrays;
137.34 +import java.util.Objects;
137.35 +
137.36 +/**
137.37 + * Prints formatted representations of objects to a text-output stream. This
137.38 + * class implements all of the <tt>print</tt> methods found in {@link
137.39 + * PrintStream}. It does not contain methods for writing raw bytes, for which
137.40 + * a program should use unencoded byte streams.
137.41 + *
137.42 + * <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
137.43 + * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
137.44 + * <tt>format</tt> methods is invoked, rather than whenever a newline character
137.45 + * happens to be output. These methods use the platform's own notion of line
137.46 + * separator rather than the newline character.
137.47 + *
137.48 + * <p> Methods in this class never throw I/O exceptions, although some of its
137.49 + * constructors may. The client may inquire as to whether any errors have
137.50 + * occurred by invoking {@link #checkError checkError()}.
137.51 + *
137.52 + * @author Frank Yellin
137.53 + * @author Mark Reinhold
137.54 + * @since JDK1.1
137.55 + */
137.56 +
137.57 +public class PrintWriter extends Writer {
137.58 +
137.59 + /**
137.60 + * The underlying character-output stream of this
137.61 + * <code>PrintWriter</code>.
137.62 + *
137.63 + * @since 1.2
137.64 + */
137.65 + protected Writer out;
137.66 +
137.67 + private final boolean autoFlush;
137.68 + private boolean trouble = false;
137.69 + private Formatter formatter;
137.70 +// private PrintStream psOut = null;
137.71 +
137.72 + /**
137.73 + * Line separator string. This is the value of the line.separator
137.74 + * property at the moment that the stream was created.
137.75 + */
137.76 + private final String lineSeparator;
137.77 +
137.78 + /**
137.79 + * Returns a charset object for the given charset name.
137.80 + * @throws NullPointerException is csn is null
137.81 + * @throws UnsupportedEncodingException if the charset is not supported
137.82 + */
137.83 + private static Charset toCharset(String csn)
137.84 + throws UnsupportedEncodingException
137.85 + {
137.86 + return PrintStream.toCharset(csn);
137.87 + }
137.88 +
137.89 + /**
137.90 + * Creates a new PrintWriter, without automatic line flushing.
137.91 + *
137.92 + * @param out A character-output stream
137.93 + */
137.94 + public PrintWriter (Writer out) {
137.95 + this(out, false);
137.96 + }
137.97 +
137.98 + /**
137.99 + * Creates a new PrintWriter.
137.100 + *
137.101 + * @param out A character-output stream
137.102 + * @param autoFlush A boolean; if true, the <tt>println</tt>,
137.103 + * <tt>printf</tt>, or <tt>format</tt> methods will
137.104 + * flush the output buffer
137.105 + */
137.106 + public PrintWriter(Writer out,
137.107 + boolean autoFlush) {
137.108 + super(out);
137.109 + this.out = out;
137.110 + this.autoFlush = autoFlush;
137.111 + lineSeparator = "\n";
137.112 + }
137.113 +
137.114 + /**
137.115 + * Creates a new PrintWriter, without automatic line flushing, from an
137.116 + * existing OutputStream. This convenience constructor creates the
137.117 + * necessary intermediate OutputStreamWriter, which will convert characters
137.118 + * into bytes using the default character encoding.
137.119 + *
137.120 + * @param out An output stream
137.121 + *
137.122 + * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
137.123 + */
137.124 + public PrintWriter(OutputStream out) {
137.125 + this(out, false);
137.126 + }
137.127 +
137.128 + /**
137.129 + * Creates a new PrintWriter from an existing OutputStream. This
137.130 + * convenience constructor creates the necessary intermediate
137.131 + * OutputStreamWriter, which will convert characters into bytes using the
137.132 + * default character encoding.
137.133 + *
137.134 + * @param out An output stream
137.135 + * @param autoFlush A boolean; if true, the <tt>println</tt>,
137.136 + * <tt>printf</tt>, or <tt>format</tt> methods will
137.137 + * flush the output buffer
137.138 + *
137.139 + * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
137.140 + */
137.141 + public PrintWriter(OutputStream out, boolean autoFlush) {
137.142 + this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
137.143 +
137.144 + // save print stream for error propagation
137.145 +// if (out instanceof java.io.PrintStream) {
137.146 +// psOut = (PrintStream) out;
137.147 +// }
137.148 + }
137.149 +
137.150 + /**
137.151 + * Creates a new PrintWriter, without automatic line flushing, with the
137.152 + * specified file name. This convenience constructor creates the necessary
137.153 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
137.154 + * which will encode characters using the {@linkplain
137.155 + * java.nio.charset.Charset#defaultCharset() default charset} for this
137.156 + * instance of the Java virtual machine.
137.157 + *
137.158 + * @param fileName
137.159 + * The name of the file to use as the destination of this writer.
137.160 + * If the file exists then it will be truncated to zero size;
137.161 + * otherwise, a new file will be created. The output will be
137.162 + * written to the file and is buffered.
137.163 + *
137.164 + * @throws FileNotFoundException
137.165 + * If the given string does not denote an existing, writable
137.166 + * regular file and a new regular file of that name cannot be
137.167 + * created, or if some other error occurs while opening or
137.168 + * creating the file
137.169 + *
137.170 + * @throws SecurityException
137.171 + * If a security manager is present and {@link
137.172 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
137.173 + * access to the file
137.174 + *
137.175 + * @since 1.5
137.176 + */
137.177 + public PrintWriter(String fileName) throws FileNotFoundException {
137.178 + super();
137.179 + throw new FileNotFoundException();
137.180 + }
137.181 +
137.182 + /* Private constructor */
137.183 + private PrintWriter(Charset charset, File file)
137.184 + throws FileNotFoundException
137.185 + {
137.186 + super();
137.187 + throw new FileNotFoundException();
137.188 + }
137.189 +
137.190 + /**
137.191 + * Creates a new PrintWriter, without automatic line flushing, with the
137.192 + * specified file name and charset. This convenience constructor creates
137.193 + * the necessary intermediate {@link java.io.OutputStreamWriter
137.194 + * OutputStreamWriter}, which will encode characters using the provided
137.195 + * charset.
137.196 + *
137.197 + * @param fileName
137.198 + * The name of the file to use as the destination of this writer.
137.199 + * If the file exists then it will be truncated to zero size;
137.200 + * otherwise, a new file will be created. The output will be
137.201 + * written to the file and is buffered.
137.202 + *
137.203 + * @param csn
137.204 + * The name of a supported {@linkplain java.nio.charset.Charset
137.205 + * charset}
137.206 + *
137.207 + * @throws FileNotFoundException
137.208 + * If the given string does not denote an existing, writable
137.209 + * regular file and a new regular file of that name cannot be
137.210 + * created, or if some other error occurs while opening or
137.211 + * creating the file
137.212 + *
137.213 + * @throws SecurityException
137.214 + * If a security manager is present and {@link
137.215 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
137.216 + * access to the file
137.217 + *
137.218 + * @throws UnsupportedEncodingException
137.219 + * If the named charset is not supported
137.220 + *
137.221 + * @since 1.5
137.222 + */
137.223 + public PrintWriter(String fileName, String csn)
137.224 + throws FileNotFoundException, UnsupportedEncodingException
137.225 + {
137.226 + this(toCharset(csn), new File(fileName));
137.227 + }
137.228 +
137.229 + /**
137.230 + * Creates a new PrintWriter, without automatic line flushing, with the
137.231 + * specified file. This convenience constructor creates the necessary
137.232 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
137.233 + * which will encode characters using the {@linkplain
137.234 + * java.nio.charset.Charset#defaultCharset() default charset} for this
137.235 + * instance of the Java virtual machine.
137.236 + *
137.237 + * @param file
137.238 + * The file to use as the destination of this writer. If the file
137.239 + * exists then it will be truncated to zero size; otherwise, a new
137.240 + * file will be created. The output will be written to the file
137.241 + * and is buffered.
137.242 + *
137.243 + * @throws FileNotFoundException
137.244 + * If the given file object does not denote an existing, writable
137.245 + * regular file and a new regular file of that name cannot be
137.246 + * created, or if some other error occurs while opening or
137.247 + * creating the file
137.248 + *
137.249 + * @throws SecurityException
137.250 + * If a security manager is present and {@link
137.251 + * SecurityManager#checkWrite checkWrite(file.getPath())}
137.252 + * denies write access to the file
137.253 + *
137.254 + * @since 1.5
137.255 + */
137.256 + public PrintWriter(File file) throws FileNotFoundException {
137.257 + super();
137.258 + throw new FileNotFoundException();
137.259 + }
137.260 +
137.261 + /**
137.262 + * Creates a new PrintWriter, without automatic line flushing, with the
137.263 + * specified file and charset. This convenience constructor creates the
137.264 + * necessary intermediate {@link java.io.OutputStreamWriter
137.265 + * OutputStreamWriter}, which will encode characters using the provided
137.266 + * charset.
137.267 + *
137.268 + * @param file
137.269 + * The file to use as the destination of this writer. If the file
137.270 + * exists then it will be truncated to zero size; otherwise, a new
137.271 + * file will be created. The output will be written to the file
137.272 + * and is buffered.
137.273 + *
137.274 + * @param csn
137.275 + * The name of a supported {@linkplain java.nio.charset.Charset
137.276 + * charset}
137.277 + *
137.278 + * @throws FileNotFoundException
137.279 + * If the given file object does not denote an existing, writable
137.280 + * regular file and a new regular file of that name cannot be
137.281 + * created, or if some other error occurs while opening or
137.282 + * creating the file
137.283 + *
137.284 + * @throws SecurityException
137.285 + * If a security manager is present and {@link
137.286 + * SecurityManager#checkWrite checkWrite(file.getPath())}
137.287 + * denies write access to the file
137.288 + *
137.289 + * @throws UnsupportedEncodingException
137.290 + * If the named charset is not supported
137.291 + *
137.292 + * @since 1.5
137.293 + */
137.294 + public PrintWriter(File file, String csn)
137.295 + throws FileNotFoundException, UnsupportedEncodingException
137.296 + {
137.297 + this(toCharset(csn), file);
137.298 + }
137.299 +
137.300 + /** Checks to make sure that the stream has not been closed */
137.301 + private void ensureOpen() throws IOException {
137.302 + if (out == null)
137.303 + throw new IOException("Stream closed");
137.304 + }
137.305 +
137.306 + /**
137.307 + * Flushes the stream.
137.308 + * @see #checkError()
137.309 + */
137.310 + public void flush() {
137.311 + try {
137.312 + synchronized (lock) {
137.313 + ensureOpen();
137.314 + out.flush();
137.315 + }
137.316 + }
137.317 + catch (IOException x) {
137.318 + trouble = true;
137.319 + }
137.320 + }
137.321 +
137.322 + /**
137.323 + * Closes the stream and releases any system resources associated
137.324 + * with it. Closing a previously closed stream has no effect.
137.325 + *
137.326 + * @see #checkError()
137.327 + */
137.328 + public void close() {
137.329 + try {
137.330 + synchronized (lock) {
137.331 + if (out == null)
137.332 + return;
137.333 + out.close();
137.334 + out = null;
137.335 + }
137.336 + }
137.337 + catch (IOException x) {
137.338 + trouble = true;
137.339 + }
137.340 + }
137.341 +
137.342 + /**
137.343 + * Flushes the stream if it's not closed and checks its error state.
137.344 + *
137.345 + * @return <code>true</code> if the print stream has encountered an error,
137.346 + * either on the underlying output stream or during a format
137.347 + * conversion.
137.348 + */
137.349 + public boolean checkError() {
137.350 + if (out != null) {
137.351 + flush();
137.352 + }
137.353 + if (out instanceof java.io.PrintWriter) {
137.354 + PrintWriter pw = (PrintWriter) out;
137.355 + return pw.checkError();
137.356 + } else
137.357 +// if (psOut != null) {
137.358 +// return psOut.checkError();
137.359 +// }
137.360 + return trouble;
137.361 + }
137.362 +
137.363 + /**
137.364 + * Indicates that an error has occurred.
137.365 + *
137.366 + * <p> This method will cause subsequent invocations of {@link
137.367 + * #checkError()} to return <tt>true</tt> until {@link
137.368 + * #clearError()} is invoked.
137.369 + */
137.370 + protected void setError() {
137.371 + trouble = true;
137.372 + }
137.373 +
137.374 + /**
137.375 + * Clears the error state of this stream.
137.376 + *
137.377 + * <p> This method will cause subsequent invocations of {@link
137.378 + * #checkError()} to return <tt>false</tt> until another write
137.379 + * operation fails and invokes {@link #setError()}.
137.380 + *
137.381 + * @since 1.6
137.382 + */
137.383 + protected void clearError() {
137.384 + trouble = false;
137.385 + }
137.386 +
137.387 + /*
137.388 + * Exception-catching, synchronized output operations,
137.389 + * which also implement the write() methods of Writer
137.390 + */
137.391 +
137.392 + /**
137.393 + * Writes a single character.
137.394 + * @param c int specifying a character to be written.
137.395 + */
137.396 + public void write(int c) {
137.397 + try {
137.398 + synchronized (lock) {
137.399 + ensureOpen();
137.400 + out.write(c);
137.401 + }
137.402 + }
137.403 + catch (InterruptedIOException x) {
137.404 + Thread.currentThread().interrupt();
137.405 + }
137.406 + catch (IOException x) {
137.407 + trouble = true;
137.408 + }
137.409 + }
137.410 +
137.411 + /**
137.412 + * Writes A Portion of an array of characters.
137.413 + * @param buf Array of characters
137.414 + * @param off Offset from which to start writing characters
137.415 + * @param len Number of characters to write
137.416 + */
137.417 + public void write(char buf[], int off, int len) {
137.418 + try {
137.419 + synchronized (lock) {
137.420 + ensureOpen();
137.421 + out.write(buf, off, len);
137.422 + }
137.423 + }
137.424 + catch (InterruptedIOException x) {
137.425 + Thread.currentThread().interrupt();
137.426 + }
137.427 + catch (IOException x) {
137.428 + trouble = true;
137.429 + }
137.430 + }
137.431 +
137.432 + /**
137.433 + * Writes an array of characters. This method cannot be inherited from the
137.434 + * Writer class because it must suppress I/O exceptions.
137.435 + * @param buf Array of characters to be written
137.436 + */
137.437 + public void write(char buf[]) {
137.438 + write(buf, 0, buf.length);
137.439 + }
137.440 +
137.441 + /**
137.442 + * Writes a portion of a string.
137.443 + * @param s A String
137.444 + * @param off Offset from which to start writing characters
137.445 + * @param len Number of characters to write
137.446 + */
137.447 + public void write(String s, int off, int len) {
137.448 + try {
137.449 + synchronized (lock) {
137.450 + ensureOpen();
137.451 + out.write(s, off, len);
137.452 + }
137.453 + }
137.454 + catch (InterruptedIOException x) {
137.455 + Thread.currentThread().interrupt();
137.456 + }
137.457 + catch (IOException x) {
137.458 + trouble = true;
137.459 + }
137.460 + }
137.461 +
137.462 + /**
137.463 + * Writes a string. This method cannot be inherited from the Writer class
137.464 + * because it must suppress I/O exceptions.
137.465 + * @param s String to be written
137.466 + */
137.467 + public void write(String s) {
137.468 + write(s, 0, s.length());
137.469 + }
137.470 +
137.471 + private void newLine() {
137.472 + try {
137.473 + synchronized (lock) {
137.474 + ensureOpen();
137.475 + out.write(lineSeparator);
137.476 + if (autoFlush)
137.477 + out.flush();
137.478 + }
137.479 + }
137.480 + catch (InterruptedIOException x) {
137.481 + Thread.currentThread().interrupt();
137.482 + }
137.483 + catch (IOException x) {
137.484 + trouble = true;
137.485 + }
137.486 + }
137.487 +
137.488 + /* Methods that do not terminate lines */
137.489 +
137.490 + /**
137.491 + * Prints a boolean value. The string produced by <code>{@link
137.492 + * java.lang.String#valueOf(boolean)}</code> is translated into bytes
137.493 + * according to the platform's default character encoding, and these bytes
137.494 + * are written in exactly the manner of the <code>{@link
137.495 + * #write(int)}</code> method.
137.496 + *
137.497 + * @param b The <code>boolean</code> to be printed
137.498 + */
137.499 + public void print(boolean b) {
137.500 + write(b ? "true" : "false");
137.501 + }
137.502 +
137.503 + /**
137.504 + * Prints a character. The character is translated into one or more bytes
137.505 + * according to the platform's default character encoding, and these bytes
137.506 + * are written in exactly the manner of the <code>{@link
137.507 + * #write(int)}</code> method.
137.508 + *
137.509 + * @param c The <code>char</code> to be printed
137.510 + */
137.511 + public void print(char c) {
137.512 + write(c);
137.513 + }
137.514 +
137.515 + /**
137.516 + * Prints an integer. The string produced by <code>{@link
137.517 + * java.lang.String#valueOf(int)}</code> is translated into bytes according
137.518 + * to the platform's default character encoding, and these bytes are
137.519 + * written in exactly the manner of the <code>{@link #write(int)}</code>
137.520 + * method.
137.521 + *
137.522 + * @param i The <code>int</code> to be printed
137.523 + * @see java.lang.Integer#toString(int)
137.524 + */
137.525 + public void print(int i) {
137.526 + write(String.valueOf(i));
137.527 + }
137.528 +
137.529 + /**
137.530 + * Prints a long integer. The string produced by <code>{@link
137.531 + * java.lang.String#valueOf(long)}</code> is translated into bytes
137.532 + * according to the platform's default character encoding, and these bytes
137.533 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
137.534 + * method.
137.535 + *
137.536 + * @param l The <code>long</code> to be printed
137.537 + * @see java.lang.Long#toString(long)
137.538 + */
137.539 + public void print(long l) {
137.540 + write(String.valueOf(l));
137.541 + }
137.542 +
137.543 + /**
137.544 + * Prints a floating-point number. The string produced by <code>{@link
137.545 + * java.lang.String#valueOf(float)}</code> is translated into bytes
137.546 + * according to the platform's default character encoding, and these bytes
137.547 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
137.548 + * method.
137.549 + *
137.550 + * @param f The <code>float</code> to be printed
137.551 + * @see java.lang.Float#toString(float)
137.552 + */
137.553 + public void print(float f) {
137.554 + write(String.valueOf(f));
137.555 + }
137.556 +
137.557 + /**
137.558 + * Prints a double-precision floating-point number. The string produced by
137.559 + * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
137.560 + * bytes according to the platform's default character encoding, and these
137.561 + * bytes are written in exactly the manner of the <code>{@link
137.562 + * #write(int)}</code> method.
137.563 + *
137.564 + * @param d The <code>double</code> to be printed
137.565 + * @see java.lang.Double#toString(double)
137.566 + */
137.567 + public void print(double d) {
137.568 + write(String.valueOf(d));
137.569 + }
137.570 +
137.571 + /**
137.572 + * Prints an array of characters. The characters are converted into bytes
137.573 + * according to the platform's default character encoding, and these bytes
137.574 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
137.575 + * method.
137.576 + *
137.577 + * @param s The array of chars to be printed
137.578 + *
137.579 + * @throws NullPointerException If <code>s</code> is <code>null</code>
137.580 + */
137.581 + public void print(char s[]) {
137.582 + write(s);
137.583 + }
137.584 +
137.585 + /**
137.586 + * Prints a string. If the argument is <code>null</code> then the string
137.587 + * <code>"null"</code> is printed. Otherwise, the string's characters are
137.588 + * converted into bytes according to the platform's default character
137.589 + * encoding, and these bytes are written in exactly the manner of the
137.590 + * <code>{@link #write(int)}</code> method.
137.591 + *
137.592 + * @param s The <code>String</code> to be printed
137.593 + */
137.594 + public void print(String s) {
137.595 + if (s == null) {
137.596 + s = "null";
137.597 + }
137.598 + write(s);
137.599 + }
137.600 +
137.601 + /**
137.602 + * Prints an object. The string produced by the <code>{@link
137.603 + * java.lang.String#valueOf(Object)}</code> method is translated into bytes
137.604 + * according to the platform's default character encoding, and these bytes
137.605 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
137.606 + * method.
137.607 + *
137.608 + * @param obj The <code>Object</code> to be printed
137.609 + * @see java.lang.Object#toString()
137.610 + */
137.611 + public void print(Object obj) {
137.612 + write(String.valueOf(obj));
137.613 + }
137.614 +
137.615 + /* Methods that do terminate lines */
137.616 +
137.617 + /**
137.618 + * Terminates the current line by writing the line separator string. The
137.619 + * line separator string is defined by the system property
137.620 + * <code>line.separator</code>, and is not necessarily a single newline
137.621 + * character (<code>'\n'</code>).
137.622 + */
137.623 + public void println() {
137.624 + newLine();
137.625 + }
137.626 +
137.627 + /**
137.628 + * Prints a boolean value and then terminates the line. This method behaves
137.629 + * as though it invokes <code>{@link #print(boolean)}</code> and then
137.630 + * <code>{@link #println()}</code>.
137.631 + *
137.632 + * @param x the <code>boolean</code> value to be printed
137.633 + */
137.634 + public void println(boolean x) {
137.635 + synchronized (lock) {
137.636 + print(x);
137.637 + println();
137.638 + }
137.639 + }
137.640 +
137.641 + /**
137.642 + * Prints a character and then terminates the line. This method behaves as
137.643 + * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
137.644 + * #println()}</code>.
137.645 + *
137.646 + * @param x the <code>char</code> value to be printed
137.647 + */
137.648 + public void println(char x) {
137.649 + synchronized (lock) {
137.650 + print(x);
137.651 + println();
137.652 + }
137.653 + }
137.654 +
137.655 + /**
137.656 + * Prints an integer and then terminates the line. This method behaves as
137.657 + * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
137.658 + * #println()}</code>.
137.659 + *
137.660 + * @param x the <code>int</code> value to be printed
137.661 + */
137.662 + public void println(int x) {
137.663 + synchronized (lock) {
137.664 + print(x);
137.665 + println();
137.666 + }
137.667 + }
137.668 +
137.669 + /**
137.670 + * Prints a long integer and then terminates the line. This method behaves
137.671 + * as though it invokes <code>{@link #print(long)}</code> and then
137.672 + * <code>{@link #println()}</code>.
137.673 + *
137.674 + * @param x the <code>long</code> value to be printed
137.675 + */
137.676 + public void println(long x) {
137.677 + synchronized (lock) {
137.678 + print(x);
137.679 + println();
137.680 + }
137.681 + }
137.682 +
137.683 + /**
137.684 + * Prints a floating-point number and then terminates the line. This method
137.685 + * behaves as though it invokes <code>{@link #print(float)}</code> and then
137.686 + * <code>{@link #println()}</code>.
137.687 + *
137.688 + * @param x the <code>float</code> value to be printed
137.689 + */
137.690 + public void println(float x) {
137.691 + synchronized (lock) {
137.692 + print(x);
137.693 + println();
137.694 + }
137.695 + }
137.696 +
137.697 + /**
137.698 + * Prints a double-precision floating-point number and then terminates the
137.699 + * line. This method behaves as though it invokes <code>{@link
137.700 + * #print(double)}</code> and then <code>{@link #println()}</code>.
137.701 + *
137.702 + * @param x the <code>double</code> value to be printed
137.703 + */
137.704 + public void println(double x) {
137.705 + synchronized (lock) {
137.706 + print(x);
137.707 + println();
137.708 + }
137.709 + }
137.710 +
137.711 + /**
137.712 + * Prints an array of characters and then terminates the line. This method
137.713 + * behaves as though it invokes <code>{@link #print(char[])}</code> and then
137.714 + * <code>{@link #println()}</code>.
137.715 + *
137.716 + * @param x the array of <code>char</code> values to be printed
137.717 + */
137.718 + public void println(char x[]) {
137.719 + synchronized (lock) {
137.720 + print(x);
137.721 + println();
137.722 + }
137.723 + }
137.724 +
137.725 + /**
137.726 + * Prints a String and then terminates the line. This method behaves as
137.727 + * though it invokes <code>{@link #print(String)}</code> and then
137.728 + * <code>{@link #println()}</code>.
137.729 + *
137.730 + * @param x the <code>String</code> value to be printed
137.731 + */
137.732 + public void println(String x) {
137.733 + synchronized (lock) {
137.734 + print(x);
137.735 + println();
137.736 + }
137.737 + }
137.738 +
137.739 + /**
137.740 + * Prints an Object and then terminates the line. This method calls
137.741 + * at first String.valueOf(x) to get the printed object's string value,
137.742 + * then behaves as
137.743 + * though it invokes <code>{@link #print(String)}</code> and then
137.744 + * <code>{@link #println()}</code>.
137.745 + *
137.746 + * @param x The <code>Object</code> to be printed.
137.747 + */
137.748 + public void println(Object x) {
137.749 + String s = String.valueOf(x);
137.750 + synchronized (lock) {
137.751 + print(s);
137.752 + println();
137.753 + }
137.754 + }
137.755 +
137.756 + /**
137.757 + * A convenience method to write a formatted string to this writer using
137.758 + * the specified format string and arguments. If automatic flushing is
137.759 + * enabled, calls to this method will flush the output buffer.
137.760 + *
137.761 + * <p> An invocation of this method of the form <tt>out.printf(format,
137.762 + * args)</tt> behaves in exactly the same way as the invocation
137.763 + *
137.764 + * <pre>
137.765 + * out.format(format, args) </pre>
137.766 + *
137.767 + * @param format
137.768 + * A format string as described in <a
137.769 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
137.770 + *
137.771 + * @param args
137.772 + * Arguments referenced by the format specifiers in the format
137.773 + * string. If there are more arguments than format specifiers, the
137.774 + * extra arguments are ignored. The number of arguments is
137.775 + * variable and may be zero. The maximum number of arguments is
137.776 + * limited by the maximum dimension of a Java array as defined by
137.777 + * <cite>The Java™ Virtual Machine Specification</cite>.
137.778 + * The behaviour on a
137.779 + * <tt>null</tt> argument depends on the <a
137.780 + * href="../util/Formatter.html#syntax">conversion</a>.
137.781 + *
137.782 + * @throws IllegalFormatException
137.783 + * If a format string contains an illegal syntax, a format
137.784 + * specifier that is incompatible with the given arguments,
137.785 + * insufficient arguments given the format string, or other
137.786 + * illegal conditions. For specification of all possible
137.787 + * formatting errors, see the <a
137.788 + * href="../util/Formatter.html#detail">Details</a> section of the
137.789 + * formatter class specification.
137.790 + *
137.791 + * @throws NullPointerException
137.792 + * If the <tt>format</tt> is <tt>null</tt>
137.793 + *
137.794 + * @return This writer
137.795 + *
137.796 + * @since 1.5
137.797 + */
137.798 + public PrintWriter printf(String format, Object ... args) {
137.799 + return format(format, args);
137.800 + }
137.801 +
137.802 + /**
137.803 + * A convenience method to write a formatted string to this writer using
137.804 + * the specified format string and arguments. If automatic flushing is
137.805 + * enabled, calls to this method will flush the output buffer.
137.806 + *
137.807 + * <p> An invocation of this method of the form <tt>out.printf(l, format,
137.808 + * args)</tt> behaves in exactly the same way as the invocation
137.809 + *
137.810 + * <pre>
137.811 + * out.format(l, format, args) </pre>
137.812 + *
137.813 + * @param l
137.814 + * The {@linkplain java.util.Locale locale} to apply during
137.815 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
137.816 + * is applied.
137.817 + *
137.818 + * @param format
137.819 + * A format string as described in <a
137.820 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
137.821 + *
137.822 + * @param args
137.823 + * Arguments referenced by the format specifiers in the format
137.824 + * string. If there are more arguments than format specifiers, the
137.825 + * extra arguments are ignored. The number of arguments is
137.826 + * variable and may be zero. The maximum number of arguments is
137.827 + * limited by the maximum dimension of a Java array as defined by
137.828 + * <cite>The Java™ Virtual Machine Specification</cite>.
137.829 + * The behaviour on a
137.830 + * <tt>null</tt> argument depends on the <a
137.831 + * href="../util/Formatter.html#syntax">conversion</a>.
137.832 + *
137.833 + * @throws IllegalFormatException
137.834 + * If a format string contains an illegal syntax, a format
137.835 + * specifier that is incompatible with the given arguments,
137.836 + * insufficient arguments given the format string, or other
137.837 + * illegal conditions. For specification of all possible
137.838 + * formatting errors, see the <a
137.839 + * href="../util/Formatter.html#detail">Details</a> section of the
137.840 + * formatter class specification.
137.841 + *
137.842 + * @throws NullPointerException
137.843 + * If the <tt>format</tt> is <tt>null</tt>
137.844 + *
137.845 + * @return This writer
137.846 + *
137.847 + * @since 1.5
137.848 + */
137.849 +// public PrintWriter printf(Locale l, String format, Object ... args) {
137.850 +// return format(l, format, args);
137.851 +// }
137.852 +
137.853 + /**
137.854 + * Writes a formatted string to this writer using the specified format
137.855 + * string and arguments. If automatic flushing is enabled, calls to this
137.856 + * method will flush the output buffer.
137.857 + *
137.858 + * <p> The locale always used is the one returned by {@link
137.859 + * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
137.860 + * previous invocations of other formatting methods on this object.
137.861 + *
137.862 + * @param format
137.863 + * A format string as described in <a
137.864 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
137.865 + *
137.866 + * @param args
137.867 + * Arguments referenced by the format specifiers in the format
137.868 + * string. If there are more arguments than format specifiers, the
137.869 + * extra arguments are ignored. The number of arguments is
137.870 + * variable and may be zero. The maximum number of arguments is
137.871 + * limited by the maximum dimension of a Java array as defined by
137.872 + * <cite>The Java™ Virtual Machine Specification</cite>.
137.873 + * The behaviour on a
137.874 + * <tt>null</tt> argument depends on the <a
137.875 + * href="../util/Formatter.html#syntax">conversion</a>.
137.876 + *
137.877 + * @throws IllegalFormatException
137.878 + * If a format string contains an illegal syntax, a format
137.879 + * specifier that is incompatible with the given arguments,
137.880 + * insufficient arguments given the format string, or other
137.881 + * illegal conditions. For specification of all possible
137.882 + * formatting errors, see the <a
137.883 + * href="../util/Formatter.html#detail">Details</a> section of the
137.884 + * Formatter class specification.
137.885 + *
137.886 + * @throws NullPointerException
137.887 + * If the <tt>format</tt> is <tt>null</tt>
137.888 + *
137.889 + * @return This writer
137.890 + *
137.891 + * @since 1.5
137.892 + */
137.893 + public PrintWriter format(String format, Object ... args) {
137.894 + append(format).append(Arrays.toString(args));
137.895 + return this;
137.896 + }
137.897 +
137.898 + /**
137.899 + * Writes a formatted string to this writer using the specified format
137.900 + * string and arguments. If automatic flushing is enabled, calls to this
137.901 + * method will flush the output buffer.
137.902 + *
137.903 + * @param l
137.904 + * The {@linkplain java.util.Locale locale} to apply during
137.905 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
137.906 + * is applied.
137.907 + *
137.908 + * @param format
137.909 + * A format string as described in <a
137.910 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
137.911 + *
137.912 + * @param args
137.913 + * Arguments referenced by the format specifiers in the format
137.914 + * string. If there are more arguments than format specifiers, the
137.915 + * extra arguments are ignored. The number of arguments is
137.916 + * variable and may be zero. The maximum number of arguments is
137.917 + * limited by the maximum dimension of a Java array as defined by
137.918 + * <cite>The Java™ Virtual Machine Specification</cite>.
137.919 + * The behaviour on a
137.920 + * <tt>null</tt> argument depends on the <a
137.921 + * href="../util/Formatter.html#syntax">conversion</a>.
137.922 + *
137.923 + * @throws IllegalFormatException
137.924 + * If a format string contains an illegal syntax, a format
137.925 + * specifier that is incompatible with the given arguments,
137.926 + * insufficient arguments given the format string, or other
137.927 + * illegal conditions. For specification of all possible
137.928 + * formatting errors, see the <a
137.929 + * href="../util/Formatter.html#detail">Details</a> section of the
137.930 + * formatter class specification.
137.931 + *
137.932 + * @throws NullPointerException
137.933 + * If the <tt>format</tt> is <tt>null</tt>
137.934 + *
137.935 + * @return This writer
137.936 + *
137.937 + * @since 1.5
137.938 + */
137.939 +// public PrintWriter format(Locale l, String format, Object ... args) {
137.940 +// return format(format, args);
137.941 +// }
137.942 +
137.943 + /**
137.944 + * Appends the specified character sequence to this writer.
137.945 + *
137.946 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
137.947 + * behaves in exactly the same way as the invocation
137.948 + *
137.949 + * <pre>
137.950 + * out.write(csq.toString()) </pre>
137.951 + *
137.952 + * <p> Depending on the specification of <tt>toString</tt> for the
137.953 + * character sequence <tt>csq</tt>, the entire sequence may not be
137.954 + * appended. For instance, invoking the <tt>toString</tt> method of a
137.955 + * character buffer will return a subsequence whose content depends upon
137.956 + * the buffer's position and limit.
137.957 + *
137.958 + * @param csq
137.959 + * The character sequence to append. If <tt>csq</tt> is
137.960 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
137.961 + * appended to this writer.
137.962 + *
137.963 + * @return This writer
137.964 + *
137.965 + * @since 1.5
137.966 + */
137.967 + public PrintWriter append(CharSequence csq) {
137.968 + if (csq == null)
137.969 + write("null");
137.970 + else
137.971 + write(csq.toString());
137.972 + return this;
137.973 + }
137.974 +
137.975 + /**
137.976 + * Appends a subsequence of the specified character sequence to this writer.
137.977 + *
137.978 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
137.979 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
137.980 + * exactly the same way as the invocation
137.981 + *
137.982 + * <pre>
137.983 + * out.write(csq.subSequence(start, end).toString()) </pre>
137.984 + *
137.985 + * @param csq
137.986 + * The character sequence from which a subsequence will be
137.987 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
137.988 + * will be appended as if <tt>csq</tt> contained the four
137.989 + * characters <tt>"null"</tt>.
137.990 + *
137.991 + * @param start
137.992 + * The index of the first character in the subsequence
137.993 + *
137.994 + * @param end
137.995 + * The index of the character following the last character in the
137.996 + * subsequence
137.997 + *
137.998 + * @return This writer
137.999 + *
137.1000 + * @throws IndexOutOfBoundsException
137.1001 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
137.1002 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
137.1003 + * <tt>csq.length()</tt>
137.1004 + *
137.1005 + * @since 1.5
137.1006 + */
137.1007 + public PrintWriter append(CharSequence csq, int start, int end) {
137.1008 + CharSequence cs = (csq == null ? "null" : csq);
137.1009 + write(cs.subSequence(start, end).toString());
137.1010 + return this;
137.1011 + }
137.1012 +
137.1013 + /**
137.1014 + * Appends the specified character to this writer.
137.1015 + *
137.1016 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
137.1017 + * behaves in exactly the same way as the invocation
137.1018 + *
137.1019 + * <pre>
137.1020 + * out.write(c) </pre>
137.1021 + *
137.1022 + * @param c
137.1023 + * The 16-bit character to append
137.1024 + *
137.1025 + * @return This writer
137.1026 + *
137.1027 + * @since 1.5
137.1028 + */
137.1029 + public PrintWriter append(char c) {
137.1030 + write(c);
137.1031 + return this;
137.1032 + }
137.1033 +}
138.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
138.2 +++ b/rt/emul/compact/src/main/java/java/io/Writer.java Mon Oct 07 14:20:58 2013 +0200
138.3 @@ -0,0 +1,325 @@
138.4 +/*
138.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
138.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
138.7 + *
138.8 + * This code is free software; you can redistribute it and/or modify it
138.9 + * under the terms of the GNU General Public License version 2 only, as
138.10 + * published by the Free Software Foundation. Oracle designates this
138.11 + * particular file as subject to the "Classpath" exception as provided
138.12 + * by Oracle in the LICENSE file that accompanied this code.
138.13 + *
138.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
138.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
138.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
138.17 + * version 2 for more details (a copy is included in the LICENSE file that
138.18 + * accompanied this code).
138.19 + *
138.20 + * You should have received a copy of the GNU General Public License version
138.21 + * 2 along with this work; if not, write to the Free Software Foundation,
138.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
138.23 + *
138.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
138.25 + * or visit www.oracle.com if you need additional information or have any
138.26 + * questions.
138.27 + */
138.28 +
138.29 +package java.io;
138.30 +
138.31 +
138.32 +/**
138.33 + * Abstract class for writing to character streams. The only methods that a
138.34 + * subclass must implement are write(char[], int, int), flush(), and close().
138.35 + * Most subclasses, however, will override some of the methods defined here in
138.36 + * order to provide higher efficiency, additional functionality, or both.
138.37 + *
138.38 + * @see Writer
138.39 + * @see BufferedWriter
138.40 + * @see CharArrayWriter
138.41 + * @see FilterWriter
138.42 + * @see OutputStreamWriter
138.43 + * @see FileWriter
138.44 + * @see PipedWriter
138.45 + * @see PrintWriter
138.46 + * @see StringWriter
138.47 + * @see Reader
138.48 + *
138.49 + * @author Mark Reinhold
138.50 + * @since JDK1.1
138.51 + */
138.52 +
138.53 +public abstract class Writer implements Appendable, Closeable, Flushable {
138.54 +
138.55 + /**
138.56 + * Temporary buffer used to hold writes of strings and single characters
138.57 + */
138.58 + private char[] writeBuffer;
138.59 +
138.60 + /**
138.61 + * Size of writeBuffer, must be >= 1
138.62 + */
138.63 + private final int writeBufferSize = 1024;
138.64 +
138.65 + /**
138.66 + * The object used to synchronize operations on this stream. For
138.67 + * efficiency, a character-stream object may use an object other than
138.68 + * itself to protect critical sections. A subclass should therefore use
138.69 + * the object in this field rather than <tt>this</tt> or a synchronized
138.70 + * method.
138.71 + */
138.72 + protected Object lock;
138.73 +
138.74 + /**
138.75 + * Creates a new character-stream writer whose critical sections will
138.76 + * synchronize on the writer itself.
138.77 + */
138.78 + protected Writer() {
138.79 + this.lock = this;
138.80 + }
138.81 +
138.82 + /**
138.83 + * Creates a new character-stream writer whose critical sections will
138.84 + * synchronize on the given object.
138.85 + *
138.86 + * @param lock
138.87 + * Object to synchronize on
138.88 + */
138.89 + protected Writer(Object lock) {
138.90 + if (lock == null) {
138.91 + throw new NullPointerException();
138.92 + }
138.93 + this.lock = lock;
138.94 + }
138.95 +
138.96 + /**
138.97 + * Writes a single character. The character to be written is contained in
138.98 + * the 16 low-order bits of the given integer value; the 16 high-order bits
138.99 + * are ignored.
138.100 + *
138.101 + * <p> Subclasses that intend to support efficient single-character output
138.102 + * should override this method.
138.103 + *
138.104 + * @param c
138.105 + * int specifying a character to be written
138.106 + *
138.107 + * @throws IOException
138.108 + * If an I/O error occurs
138.109 + */
138.110 + public void write(int c) throws IOException {
138.111 + synchronized (lock) {
138.112 + if (writeBuffer == null){
138.113 + writeBuffer = new char[writeBufferSize];
138.114 + }
138.115 + writeBuffer[0] = (char) c;
138.116 + write(writeBuffer, 0, 1);
138.117 + }
138.118 + }
138.119 +
138.120 + /**
138.121 + * Writes an array of characters.
138.122 + *
138.123 + * @param cbuf
138.124 + * Array of characters to be written
138.125 + *
138.126 + * @throws IOException
138.127 + * If an I/O error occurs
138.128 + */
138.129 + public void write(char cbuf[]) throws IOException {
138.130 + write(cbuf, 0, cbuf.length);
138.131 + }
138.132 +
138.133 + /**
138.134 + * Writes a portion of an array of characters.
138.135 + *
138.136 + * @param cbuf
138.137 + * Array of characters
138.138 + *
138.139 + * @param off
138.140 + * Offset from which to start writing characters
138.141 + *
138.142 + * @param len
138.143 + * Number of characters to write
138.144 + *
138.145 + * @throws IOException
138.146 + * If an I/O error occurs
138.147 + */
138.148 + abstract public void write(char cbuf[], int off, int len) throws IOException;
138.149 +
138.150 + /**
138.151 + * Writes a string.
138.152 + *
138.153 + * @param str
138.154 + * String to be written
138.155 + *
138.156 + * @throws IOException
138.157 + * If an I/O error occurs
138.158 + */
138.159 + public void write(String str) throws IOException {
138.160 + write(str, 0, str.length());
138.161 + }
138.162 +
138.163 + /**
138.164 + * Writes a portion of a string.
138.165 + *
138.166 + * @param str
138.167 + * A String
138.168 + *
138.169 + * @param off
138.170 + * Offset from which to start writing characters
138.171 + *
138.172 + * @param len
138.173 + * Number of characters to write
138.174 + *
138.175 + * @throws IndexOutOfBoundsException
138.176 + * If <tt>off</tt> is negative, or <tt>len</tt> is negative,
138.177 + * or <tt>off+len</tt> is negative or greater than the length
138.178 + * of the given string
138.179 + *
138.180 + * @throws IOException
138.181 + * If an I/O error occurs
138.182 + */
138.183 + public void write(String str, int off, int len) throws IOException {
138.184 + synchronized (lock) {
138.185 + char cbuf[];
138.186 + if (len <= writeBufferSize) {
138.187 + if (writeBuffer == null) {
138.188 + writeBuffer = new char[writeBufferSize];
138.189 + }
138.190 + cbuf = writeBuffer;
138.191 + } else { // Don't permanently allocate very large buffers.
138.192 + cbuf = new char[len];
138.193 + }
138.194 + str.getChars(off, (off + len), cbuf, 0);
138.195 + write(cbuf, 0, len);
138.196 + }
138.197 + }
138.198 +
138.199 + /**
138.200 + * Appends the specified character sequence to this writer.
138.201 + *
138.202 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
138.203 + * behaves in exactly the same way as the invocation
138.204 + *
138.205 + * <pre>
138.206 + * out.write(csq.toString()) </pre>
138.207 + *
138.208 + * <p> Depending on the specification of <tt>toString</tt> for the
138.209 + * character sequence <tt>csq</tt>, the entire sequence may not be
138.210 + * appended. For instance, invoking the <tt>toString</tt> method of a
138.211 + * character buffer will return a subsequence whose content depends upon
138.212 + * the buffer's position and limit.
138.213 + *
138.214 + * @param csq
138.215 + * The character sequence to append. If <tt>csq</tt> is
138.216 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
138.217 + * appended to this writer.
138.218 + *
138.219 + * @return This writer
138.220 + *
138.221 + * @throws IOException
138.222 + * If an I/O error occurs
138.223 + *
138.224 + * @since 1.5
138.225 + */
138.226 + public Writer append(CharSequence csq) throws IOException {
138.227 + if (csq == null)
138.228 + write("null");
138.229 + else
138.230 + write(csq.toString());
138.231 + return this;
138.232 + }
138.233 +
138.234 + /**
138.235 + * Appends a subsequence of the specified character sequence to this writer.
138.236 + * <tt>Appendable</tt>.
138.237 + *
138.238 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
138.239 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
138.240 + * same way as the invocation
138.241 + *
138.242 + * <pre>
138.243 + * out.write(csq.subSequence(start, end).toString()) </pre>
138.244 + *
138.245 + * @param csq
138.246 + * The character sequence from which a subsequence will be
138.247 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
138.248 + * will be appended as if <tt>csq</tt> contained the four
138.249 + * characters <tt>"null"</tt>.
138.250 + *
138.251 + * @param start
138.252 + * The index of the first character in the subsequence
138.253 + *
138.254 + * @param end
138.255 + * The index of the character following the last character in the
138.256 + * subsequence
138.257 + *
138.258 + * @return This writer
138.259 + *
138.260 + * @throws IndexOutOfBoundsException
138.261 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
138.262 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
138.263 + * <tt>csq.length()</tt>
138.264 + *
138.265 + * @throws IOException
138.266 + * If an I/O error occurs
138.267 + *
138.268 + * @since 1.5
138.269 + */
138.270 + public Writer append(CharSequence csq, int start, int end) throws IOException {
138.271 + CharSequence cs = (csq == null ? "null" : csq);
138.272 + write(cs.subSequence(start, end).toString());
138.273 + return this;
138.274 + }
138.275 +
138.276 + /**
138.277 + * Appends the specified character to this writer.
138.278 + *
138.279 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
138.280 + * behaves in exactly the same way as the invocation
138.281 + *
138.282 + * <pre>
138.283 + * out.write(c) </pre>
138.284 + *
138.285 + * @param c
138.286 + * The 16-bit character to append
138.287 + *
138.288 + * @return This writer
138.289 + *
138.290 + * @throws IOException
138.291 + * If an I/O error occurs
138.292 + *
138.293 + * @since 1.5
138.294 + */
138.295 + public Writer append(char c) throws IOException {
138.296 + write(c);
138.297 + return this;
138.298 + }
138.299 +
138.300 + /**
138.301 + * Flushes the stream. If the stream has saved any characters from the
138.302 + * various write() methods in a buffer, write them immediately to their
138.303 + * intended destination. Then, if that destination is another character or
138.304 + * byte stream, flush it. Thus one flush() invocation will flush all the
138.305 + * buffers in a chain of Writers and OutputStreams.
138.306 + *
138.307 + * <p> If the intended destination of this stream is an abstraction provided
138.308 + * by the underlying operating system, for example a file, then flushing the
138.309 + * stream guarantees only that bytes previously written to the stream are
138.310 + * passed to the operating system for writing; it does not guarantee that
138.311 + * they are actually written to a physical device such as a disk drive.
138.312 + *
138.313 + * @throws IOException
138.314 + * If an I/O error occurs
138.315 + */
138.316 + abstract public void flush() throws IOException;
138.317 +
138.318 + /**
138.319 + * Closes the stream, flushing it first. Once the stream has been closed,
138.320 + * further write() or flush() invocations will cause an IOException to be
138.321 + * thrown. Closing a previously closed stream has no effect.
138.322 + *
138.323 + * @throws IOException
138.324 + * If an I/O error occurs
138.325 + */
138.326 + abstract public void close() throws IOException;
138.327 +
138.328 +}
139.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
139.2 +++ b/rt/emul/compact/src/main/java/java/lang/StackOverflowError.java Mon Oct 07 14:20:58 2013 +0200
139.3 @@ -0,0 +1,55 @@
139.4 +/*
139.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
139.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
139.7 + *
139.8 + * This code is free software; you can redistribute it and/or modify it
139.9 + * under the terms of the GNU General Public License version 2 only, as
139.10 + * published by the Free Software Foundation. Oracle designates this
139.11 + * particular file as subject to the "Classpath" exception as provided
139.12 + * by Oracle in the LICENSE file that accompanied this code.
139.13 + *
139.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
139.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
139.17 + * version 2 for more details (a copy is included in the LICENSE file that
139.18 + * accompanied this code).
139.19 + *
139.20 + * You should have received a copy of the GNU General Public License version
139.21 + * 2 along with this work; if not, write to the Free Software Foundation,
139.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
139.23 + *
139.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
139.25 + * or visit www.oracle.com if you need additional information or have any
139.26 + * questions.
139.27 + */
139.28 +
139.29 +package java.lang;
139.30 +
139.31 +/**
139.32 + * Thrown when a stack overflow occurs because an application
139.33 + * recurses too deeply.
139.34 + *
139.35 + * @author unascribed
139.36 + * @since JDK1.0
139.37 + */
139.38 +public
139.39 +class StackOverflowError extends VirtualMachineError {
139.40 + private static final long serialVersionUID = 8609175038441759607L;
139.41 +
139.42 + /**
139.43 + * Constructs a <code>StackOverflowError</code> with no detail message.
139.44 + */
139.45 + public StackOverflowError() {
139.46 + super();
139.47 + }
139.48 +
139.49 + /**
139.50 + * Constructs a <code>StackOverflowError</code> with the specified
139.51 + * detail message.
139.52 + *
139.53 + * @param s the detail message.
139.54 + */
139.55 + public StackOverflowError(String s) {
139.56 + super(s);
139.57 + }
139.58 +}
140.1 --- a/rt/emul/compact/src/main/java/java/lang/System.java Wed Feb 27 17:50:47 2013 +0100
140.2 +++ b/rt/emul/compact/src/main/java/java/lang/System.java Mon Oct 07 14:20:58 2013 +0200
140.3 @@ -17,6 +17,8 @@
140.4 */
140.5 package java.lang;
140.6
140.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
140.8 +
140.9 /** Poor man's re-implementation of most important System methods.
140.10 *
140.11 * @author Jaroslav Tulach <jtulach@netbeans.org>
140.12 @@ -33,4 +35,31 @@
140.13 return org.apidesign.bck2brwsr.emul.lang.System.currentTimeMillis();
140.14 }
140.15
140.16 + public static int identityHashCode(Object obj) {
140.17 + return obj.defaultHashCode();
140.18 + }
140.19 +
140.20 + public static String getProperty(String name) {
140.21 + return null;
140.22 + }
140.23 +
140.24 + public static String getProperty(String key, String def) {
140.25 + return def;
140.26 + }
140.27 +
140.28 + /**
140.29 + * Returns the system-dependent line separator string. It always
140.30 + * returns the same value - the initial value of the {@linkplain
140.31 + * #getProperty(String) system property} {@code line.separator}.
140.32 + *
140.33 + * <p>On UNIX systems, it returns {@code "\n"}; on Microsoft
140.34 + * Windows systems it returns {@code "\r\n"}.
140.35 + */
140.36 + public static String lineSeparator() {
140.37 + return "\n";
140.38 + }
140.39 +
140.40 + @JavaScriptBody(args = { "exitCode" }, body = "window.close();")
140.41 + public static void exit(int exitCode) {
140.42 + }
140.43 }
141.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
141.2 +++ b/rt/emul/compact/src/main/java/java/lang/Thread.java Mon Oct 07 14:20:58 2013 +0200
141.3 @@ -0,0 +1,1544 @@
141.4 +/*
141.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
141.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
141.7 + *
141.8 + * This code is free software; you can redistribute it and/or modify it
141.9 + * under the terms of the GNU General Public License version 2 only, as
141.10 + * published by the Free Software Foundation. Oracle designates this
141.11 + * particular file as subject to the "Classpath" exception as provided
141.12 + * by Oracle in the LICENSE file that accompanied this code.
141.13 + *
141.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
141.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
141.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141.17 + * version 2 for more details (a copy is included in the LICENSE file that
141.18 + * accompanied this code).
141.19 + *
141.20 + * You should have received a copy of the GNU General Public License version
141.21 + * 2 along with this work; if not, write to the Free Software Foundation,
141.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
141.23 + *
141.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
141.25 + * or visit www.oracle.com if you need additional information or have any
141.26 + * questions.
141.27 + */
141.28 +
141.29 +package java.lang;
141.30 +
141.31 +import java.util.Map;
141.32 +
141.33 +
141.34 +/**
141.35 + * A <i>thread</i> is a thread of execution in a program. The Java
141.36 + * Virtual Machine allows an application to have multiple threads of
141.37 + * execution running concurrently.
141.38 + * <p>
141.39 + * Every thread has a priority. Threads with higher priority are
141.40 + * executed in preference to threads with lower priority. Each thread
141.41 + * may or may not also be marked as a daemon. When code running in
141.42 + * some thread creates a new <code>Thread</code> object, the new
141.43 + * thread has its priority initially set equal to the priority of the
141.44 + * creating thread, and is a daemon thread if and only if the
141.45 + * creating thread is a daemon.
141.46 + * <p>
141.47 + * When a Java Virtual Machine starts up, there is usually a single
141.48 + * non-daemon thread (which typically calls the method named
141.49 + * <code>main</code> of some designated class). The Java Virtual
141.50 + * Machine continues to execute threads until either of the following
141.51 + * occurs:
141.52 + * <ul>
141.53 + * <li>The <code>exit</code> method of class <code>Runtime</code> has been
141.54 + * called and the security manager has permitted the exit operation
141.55 + * to take place.
141.56 + * <li>All threads that are not daemon threads have died, either by
141.57 + * returning from the call to the <code>run</code> method or by
141.58 + * throwing an exception that propagates beyond the <code>run</code>
141.59 + * method.
141.60 + * </ul>
141.61 + * <p>
141.62 + * There are two ways to create a new thread of execution. One is to
141.63 + * declare a class to be a subclass of <code>Thread</code>. This
141.64 + * subclass should override the <code>run</code> method of class
141.65 + * <code>Thread</code>. An instance of the subclass can then be
141.66 + * allocated and started. For example, a thread that computes primes
141.67 + * larger than a stated value could be written as follows:
141.68 + * <p><hr><blockquote><pre>
141.69 + * class PrimeThread extends Thread {
141.70 + * long minPrime;
141.71 + * PrimeThread(long minPrime) {
141.72 + * this.minPrime = minPrime;
141.73 + * }
141.74 + *
141.75 + * public void run() {
141.76 + * // compute primes larger than minPrime
141.77 + * . . .
141.78 + * }
141.79 + * }
141.80 + * </pre></blockquote><hr>
141.81 + * <p>
141.82 + * The following code would then create a thread and start it running:
141.83 + * <p><blockquote><pre>
141.84 + * PrimeThread p = new PrimeThread(143);
141.85 + * p.start();
141.86 + * </pre></blockquote>
141.87 + * <p>
141.88 + * The other way to create a thread is to declare a class that
141.89 + * implements the <code>Runnable</code> interface. That class then
141.90 + * implements the <code>run</code> method. An instance of the class can
141.91 + * then be allocated, passed as an argument when creating
141.92 + * <code>Thread</code>, and started. The same example in this other
141.93 + * style looks like the following:
141.94 + * <p><hr><blockquote><pre>
141.95 + * class PrimeRun implements Runnable {
141.96 + * long minPrime;
141.97 + * PrimeRun(long minPrime) {
141.98 + * this.minPrime = minPrime;
141.99 + * }
141.100 + *
141.101 + * public void run() {
141.102 + * // compute primes larger than minPrime
141.103 + * . . .
141.104 + * }
141.105 + * }
141.106 + * </pre></blockquote><hr>
141.107 + * <p>
141.108 + * The following code would then create a thread and start it running:
141.109 + * <p><blockquote><pre>
141.110 + * PrimeRun p = new PrimeRun(143);
141.111 + * new Thread(p).start();
141.112 + * </pre></blockquote>
141.113 + * <p>
141.114 + * Every thread has a name for identification purposes. More than
141.115 + * one thread may have the same name. If a name is not specified when
141.116 + * a thread is created, a new name is generated for it.
141.117 + * <p>
141.118 + * Unless otherwise noted, passing a {@code null} argument to a constructor
141.119 + * or method in this class will cause a {@link NullPointerException} to be
141.120 + * thrown.
141.121 + *
141.122 + * @author unascribed
141.123 + * @see Runnable
141.124 + * @see Runtime#exit(int)
141.125 + * @see #run()
141.126 + * @see #stop()
141.127 + * @since JDK1.0
141.128 + */
141.129 +public
141.130 +class Thread implements Runnable {
141.131 +
141.132 + /**
141.133 + * The minimum priority that a thread can have.
141.134 + */
141.135 + public final static int MIN_PRIORITY = 1;
141.136 +
141.137 + /**
141.138 + * The default priority that is assigned to a thread.
141.139 + */
141.140 + public final static int NORM_PRIORITY = 5;
141.141 +
141.142 + /**
141.143 + * The maximum priority that a thread can have.
141.144 + */
141.145 + public final static int MAX_PRIORITY = 10;
141.146 +
141.147 + private static final Thread ONE = new Thread("main");
141.148 + /**
141.149 + * Returns a reference to the currently executing thread object.
141.150 + *
141.151 + * @return the currently executing thread.
141.152 + */
141.153 + public static Thread currentThread() {
141.154 + return ONE;
141.155 + }
141.156 +
141.157 + /**
141.158 + * A hint to the scheduler that the current thread is willing to yield
141.159 + * its current use of a processor. The scheduler is free to ignore this
141.160 + * hint.
141.161 + *
141.162 + * <p> Yield is a heuristic attempt to improve relative progression
141.163 + * between threads that would otherwise over-utilise a CPU. Its use
141.164 + * should be combined with detailed profiling and benchmarking to
141.165 + * ensure that it actually has the desired effect.
141.166 + *
141.167 + * <p> It is rarely appropriate to use this method. It may be useful
141.168 + * for debugging or testing purposes, where it may help to reproduce
141.169 + * bugs due to race conditions. It may also be useful when designing
141.170 + * concurrency control constructs such as the ones in the
141.171 + * {@link java.util.concurrent.locks} package.
141.172 + */
141.173 + public static void yield() {
141.174 + }
141.175 +
141.176 + /**
141.177 + * Causes the currently executing thread to sleep (temporarily cease
141.178 + * execution) for the specified number of milliseconds, subject to
141.179 + * the precision and accuracy of system timers and schedulers. The thread
141.180 + * does not lose ownership of any monitors.
141.181 + *
141.182 + * @param millis
141.183 + * the length of time to sleep in milliseconds
141.184 + *
141.185 + * @throws IllegalArgumentException
141.186 + * if the value of {@code millis} is negative
141.187 + *
141.188 + * @throws InterruptedException
141.189 + * if any thread has interrupted the current thread. The
141.190 + * <i>interrupted status</i> of the current thread is
141.191 + * cleared when this exception is thrown.
141.192 + */
141.193 + public static native void sleep(long millis) throws InterruptedException;
141.194 +
141.195 + /**
141.196 + * Causes the currently executing thread to sleep (temporarily cease
141.197 + * execution) for the specified number of milliseconds plus the specified
141.198 + * number of nanoseconds, subject to the precision and accuracy of system
141.199 + * timers and schedulers. The thread does not lose ownership of any
141.200 + * monitors.
141.201 + *
141.202 + * @param millis
141.203 + * the length of time to sleep in milliseconds
141.204 + *
141.205 + * @param nanos
141.206 + * {@code 0-999999} additional nanoseconds to sleep
141.207 + *
141.208 + * @throws IllegalArgumentException
141.209 + * if the value of {@code millis} is negative, or the value of
141.210 + * {@code nanos} is not in the range {@code 0-999999}
141.211 + *
141.212 + * @throws InterruptedException
141.213 + * if any thread has interrupted the current thread. The
141.214 + * <i>interrupted status</i> of the current thread is
141.215 + * cleared when this exception is thrown.
141.216 + */
141.217 + public static void sleep(long millis, int nanos)
141.218 + throws InterruptedException {
141.219 + if (millis < 0) {
141.220 + throw new IllegalArgumentException("timeout value is negative");
141.221 + }
141.222 +
141.223 + if (nanos < 0 || nanos > 999999) {
141.224 + throw new IllegalArgumentException(
141.225 + "nanosecond timeout value out of range");
141.226 + }
141.227 +
141.228 + if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
141.229 + millis++;
141.230 + }
141.231 +
141.232 + sleep(millis);
141.233 + }
141.234 + private Runnable target;
141.235 + private String name;
141.236 +
141.237 + /**
141.238 + * Throws CloneNotSupportedException as a Thread can not be meaningfully
141.239 + * cloned. Construct a new Thread instead.
141.240 + *
141.241 + * @throws CloneNotSupportedException
141.242 + * always
141.243 + */
141.244 + @Override
141.245 + protected Object clone() throws CloneNotSupportedException {
141.246 + throw new CloneNotSupportedException();
141.247 + }
141.248 +
141.249 + /**
141.250 + * Allocates a new {@code Thread} object. This constructor has the same
141.251 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.252 + * {@code (null, null, gname)}, where {@code gname} is a newly generated
141.253 + * name. Automatically generated names are of the form
141.254 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
141.255 + */
141.256 + public Thread() {
141.257 + init(null, null, "Thread-" + nextThreadNum(), 0);
141.258 + }
141.259 +
141.260 + private static int nextThreadNum() {
141.261 + return -1;
141.262 + }
141.263 +
141.264 + /**
141.265 + * Allocates a new {@code Thread} object. This constructor has the same
141.266 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.267 + * {@code (null, target, gname)}, where {@code gname} is a newly generated
141.268 + * name. Automatically generated names are of the form
141.269 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
141.270 + *
141.271 + * @param target
141.272 + * the object whose {@code run} method is invoked when this thread
141.273 + * is started. If {@code null}, this classes {@code run} method does
141.274 + * nothing.
141.275 + */
141.276 + public Thread(Runnable target) {
141.277 + init(null, target, "Thread-" + nextThreadNum(), 0);
141.278 + }
141.279 +
141.280 + /**
141.281 + * Allocates a new {@code Thread} object. This constructor has the same
141.282 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.283 + * {@code (group, target, gname)} ,where {@code gname} is a newly generated
141.284 + * name. Automatically generated names are of the form
141.285 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
141.286 + *
141.287 + * @param group
141.288 + * the thread group. If {@code null} and there is a security
141.289 + * manager, the group is determined by {@linkplain
141.290 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
141.291 + * If there is not a security manager or {@code
141.292 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
141.293 + * is set to the current thread's thread group.
141.294 + *
141.295 + * @param target
141.296 + * the object whose {@code run} method is invoked when this thread
141.297 + * is started. If {@code null}, this thread's run method is invoked.
141.298 + *
141.299 + * @throws SecurityException
141.300 + * if the current thread cannot create a thread in the specified
141.301 + * thread group
141.302 + */
141.303 +// public Thread(ThreadGroup group, Runnable target) {
141.304 +// init(group, target, "Thread-" + nextThreadNum(), 0);
141.305 +// }
141.306 +
141.307 + /**
141.308 + * Allocates a new {@code Thread} object. This constructor has the same
141.309 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.310 + * {@code (null, null, name)}.
141.311 + *
141.312 + * @param name
141.313 + * the name of the new thread
141.314 + */
141.315 + public Thread(String name) {
141.316 + init(null, null, name, 0);
141.317 + }
141.318 +
141.319 + private void init(Object o1, Runnable trgt, String nm, int i4) {
141.320 + this.target = trgt;
141.321 + this.name = nm;
141.322 + }
141.323 +
141.324 + /**
141.325 + * Allocates a new {@code Thread} object. This constructor has the same
141.326 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.327 + * {@code (group, null, name)}.
141.328 + *
141.329 + * @param group
141.330 + * the thread group. If {@code null} and there is a security
141.331 + * manager, the group is determined by {@linkplain
141.332 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
141.333 + * If there is not a security manager or {@code
141.334 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
141.335 + * is set to the current thread's thread group.
141.336 + *
141.337 + * @param name
141.338 + * the name of the new thread
141.339 + *
141.340 + * @throws SecurityException
141.341 + * if the current thread cannot create a thread in the specified
141.342 + * thread group
141.343 + */
141.344 +// public Thread(ThreadGroup group, String name) {
141.345 +// init(group, null, name, 0);
141.346 +// }
141.347 +
141.348 + /**
141.349 + * Allocates a new {@code Thread} object. This constructor has the same
141.350 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
141.351 + * {@code (null, target, name)}.
141.352 + *
141.353 + * @param target
141.354 + * the object whose {@code run} method is invoked when this thread
141.355 + * is started. If {@code null}, this thread's run method is invoked.
141.356 + *
141.357 + * @param name
141.358 + * the name of the new thread
141.359 + */
141.360 + public Thread(Runnable target, String name) {
141.361 + init(null, target, name, 0);
141.362 + }
141.363 +
141.364 + /**
141.365 + * Allocates a new {@code Thread} object so that it has {@code target}
141.366 + * as its run object, has the specified {@code name} as its name,
141.367 + * and belongs to the thread group referred to by {@code group}.
141.368 + *
141.369 + * <p>If there is a security manager, its
141.370 + * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
141.371 + * method is invoked with the ThreadGroup as its argument.
141.372 + *
141.373 + * <p>In addition, its {@code checkPermission} method is invoked with
141.374 + * the {@code RuntimePermission("enableContextClassLoaderOverride")}
141.375 + * permission when invoked directly or indirectly by the constructor
141.376 + * of a subclass which overrides the {@code getContextClassLoader}
141.377 + * or {@code setContextClassLoader} methods.
141.378 + *
141.379 + * <p>The priority of the newly created thread is set equal to the
141.380 + * priority of the thread creating it, that is, the currently running
141.381 + * thread. The method {@linkplain #setPriority setPriority} may be
141.382 + * used to change the priority to a new value.
141.383 + *
141.384 + * <p>The newly created thread is initially marked as being a daemon
141.385 + * thread if and only if the thread creating it is currently marked
141.386 + * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
141.387 + * may be used to change whether or not a thread is a daemon.
141.388 + *
141.389 + * @param group
141.390 + * the thread group. If {@code null} and there is a security
141.391 + * manager, the group is determined by {@linkplain
141.392 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
141.393 + * If there is not a security manager or {@code
141.394 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
141.395 + * is set to the current thread's thread group.
141.396 + *
141.397 + * @param target
141.398 + * the object whose {@code run} method is invoked when this thread
141.399 + * is started. If {@code null}, this thread's run method is invoked.
141.400 + *
141.401 + * @param name
141.402 + * the name of the new thread
141.403 + *
141.404 + * @throws SecurityException
141.405 + * if the current thread cannot create a thread in the specified
141.406 + * thread group or cannot override the context class loader methods.
141.407 + */
141.408 +// public Thread(ThreadGroup group, Runnable target, String name) {
141.409 +// init(group, target, name, 0);
141.410 +// }
141.411 +
141.412 + /**
141.413 + * Allocates a new {@code Thread} object so that it has {@code target}
141.414 + * as its run object, has the specified {@code name} as its name,
141.415 + * and belongs to the thread group referred to by {@code group}, and has
141.416 + * the specified <i>stack size</i>.
141.417 + *
141.418 + * <p>This constructor is identical to {@link
141.419 + * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
141.420 + * that it allows the thread stack size to be specified. The stack size
141.421 + * is the approximate number of bytes of address space that the virtual
141.422 + * machine is to allocate for this thread's stack. <b>The effect of the
141.423 + * {@code stackSize} parameter, if any, is highly platform dependent.</b>
141.424 + *
141.425 + * <p>On some platforms, specifying a higher value for the
141.426 + * {@code stackSize} parameter may allow a thread to achieve greater
141.427 + * recursion depth before throwing a {@link StackOverflowError}.
141.428 + * Similarly, specifying a lower value may allow a greater number of
141.429 + * threads to exist concurrently without throwing an {@link
141.430 + * OutOfMemoryError} (or other internal error). The details of
141.431 + * the relationship between the value of the <tt>stackSize</tt> parameter
141.432 + * and the maximum recursion depth and concurrency level are
141.433 + * platform-dependent. <b>On some platforms, the value of the
141.434 + * {@code stackSize} parameter may have no effect whatsoever.</b>
141.435 + *
141.436 + * <p>The virtual machine is free to treat the {@code stackSize}
141.437 + * parameter as a suggestion. If the specified value is unreasonably low
141.438 + * for the platform, the virtual machine may instead use some
141.439 + * platform-specific minimum value; if the specified value is unreasonably
141.440 + * high, the virtual machine may instead use some platform-specific
141.441 + * maximum. Likewise, the virtual machine is free to round the specified
141.442 + * value up or down as it sees fit (or to ignore it completely).
141.443 + *
141.444 + * <p>Specifying a value of zero for the {@code stackSize} parameter will
141.445 + * cause this constructor to behave exactly like the
141.446 + * {@code Thread(ThreadGroup, Runnable, String)} constructor.
141.447 + *
141.448 + * <p><i>Due to the platform-dependent nature of the behavior of this
141.449 + * constructor, extreme care should be exercised in its use.
141.450 + * The thread stack size necessary to perform a given computation will
141.451 + * likely vary from one JRE implementation to another. In light of this
141.452 + * variation, careful tuning of the stack size parameter may be required,
141.453 + * and the tuning may need to be repeated for each JRE implementation on
141.454 + * which an application is to run.</i>
141.455 + *
141.456 + * <p>Implementation note: Java platform implementers are encouraged to
141.457 + * document their implementation's behavior with respect to the
141.458 + * {@code stackSize} parameter.
141.459 + *
141.460 + *
141.461 + * @param group
141.462 + * the thread group. If {@code null} and there is a security
141.463 + * manager, the group is determined by {@linkplain
141.464 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
141.465 + * If there is not a security manager or {@code
141.466 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
141.467 + * is set to the current thread's thread group.
141.468 + *
141.469 + * @param target
141.470 + * the object whose {@code run} method is invoked when this thread
141.471 + * is started. If {@code null}, this thread's run method is invoked.
141.472 + *
141.473 + * @param name
141.474 + * the name of the new thread
141.475 + *
141.476 + * @param stackSize
141.477 + * the desired stack size for the new thread, or zero to indicate
141.478 + * that this parameter is to be ignored.
141.479 + *
141.480 + * @throws SecurityException
141.481 + * if the current thread cannot create a thread in the specified
141.482 + * thread group
141.483 + *
141.484 + * @since 1.4
141.485 + */
141.486 +// public Thread(ThreadGroup group, Runnable target, String name,
141.487 +// long stackSize) {
141.488 +// init(group, target, name, stackSize);
141.489 +// }
141.490 +
141.491 + /**
141.492 + * Causes this thread to begin execution; the Java Virtual Machine
141.493 + * calls the <code>run</code> method of this thread.
141.494 + * <p>
141.495 + * The result is that two threads are running concurrently: the
141.496 + * current thread (which returns from the call to the
141.497 + * <code>start</code> method) and the other thread (which executes its
141.498 + * <code>run</code> method).
141.499 + * <p>
141.500 + * It is never legal to start a thread more than once.
141.501 + * In particular, a thread may not be restarted once it has completed
141.502 + * execution.
141.503 + *
141.504 + * @exception IllegalThreadStateException if the thread was already
141.505 + * started.
141.506 + * @see #run()
141.507 + * @see #stop()
141.508 + */
141.509 + public void start() {
141.510 + throw new SecurityException();
141.511 + }
141.512 +
141.513 + /**
141.514 + * If this thread was constructed using a separate
141.515 + * <code>Runnable</code> run object, then that
141.516 + * <code>Runnable</code> object's <code>run</code> method is called;
141.517 + * otherwise, this method does nothing and returns.
141.518 + * <p>
141.519 + * Subclasses of <code>Thread</code> should override this method.
141.520 + *
141.521 + * @see #start()
141.522 + * @see #stop()
141.523 + * @see #Thread(ThreadGroup, Runnable, String)
141.524 + */
141.525 + @Override
141.526 + public void run() {
141.527 + if (target != null) {
141.528 + target.run();
141.529 + }
141.530 + }
141.531 +
141.532 + /**
141.533 + * Forces the thread to stop executing.
141.534 + * <p>
141.535 + * If there is a security manager installed, its <code>checkAccess</code>
141.536 + * method is called with <code>this</code>
141.537 + * as its argument. This may result in a
141.538 + * <code>SecurityException</code> being raised (in the current thread).
141.539 + * <p>
141.540 + * If this thread is different from the current thread (that is, the current
141.541 + * thread is trying to stop a thread other than itself), the
141.542 + * security manager's <code>checkPermission</code> method (with a
141.543 + * <code>RuntimePermission("stopThread")</code> argument) is called in
141.544 + * addition.
141.545 + * Again, this may result in throwing a
141.546 + * <code>SecurityException</code> (in the current thread).
141.547 + * <p>
141.548 + * The thread represented by this thread is forced to stop whatever
141.549 + * it is doing abnormally and to throw a newly created
141.550 + * <code>ThreadDeath</code> object as an exception.
141.551 + * <p>
141.552 + * It is permitted to stop a thread that has not yet been started.
141.553 + * If the thread is eventually started, it immediately terminates.
141.554 + * <p>
141.555 + * An application should not normally try to catch
141.556 + * <code>ThreadDeath</code> unless it must do some extraordinary
141.557 + * cleanup operation (note that the throwing of
141.558 + * <code>ThreadDeath</code> causes <code>finally</code> clauses of
141.559 + * <code>try</code> statements to be executed before the thread
141.560 + * officially dies). If a <code>catch</code> clause catches a
141.561 + * <code>ThreadDeath</code> object, it is important to rethrow the
141.562 + * object so that the thread actually dies.
141.563 + * <p>
141.564 + * The top-level error handler that reacts to otherwise uncaught
141.565 + * exceptions does not print out a message or otherwise notify the
141.566 + * application if the uncaught exception is an instance of
141.567 + * <code>ThreadDeath</code>.
141.568 + *
141.569 + * @exception SecurityException if the current thread cannot
141.570 + * modify this thread.
141.571 + * @see #interrupt()
141.572 + * @see #checkAccess()
141.573 + * @see #run()
141.574 + * @see #start()
141.575 + * @see ThreadDeath
141.576 + * @see ThreadGroup#uncaughtException(Thread,Throwable)
141.577 + * @see SecurityManager#checkAccess(Thread)
141.578 + * @see SecurityManager#checkPermission
141.579 + * @deprecated This method is inherently unsafe. Stopping a thread with
141.580 + * Thread.stop causes it to unlock all of the monitors that it
141.581 + * has locked (as a natural consequence of the unchecked
141.582 + * <code>ThreadDeath</code> exception propagating up the stack). If
141.583 + * any of the objects previously protected by these monitors were in
141.584 + * an inconsistent state, the damaged objects become visible to
141.585 + * other threads, potentially resulting in arbitrary behavior. Many
141.586 + * uses of <code>stop</code> should be replaced by code that simply
141.587 + * modifies some variable to indicate that the target thread should
141.588 + * stop running. The target thread should check this variable
141.589 + * regularly, and return from its run method in an orderly fashion
141.590 + * if the variable indicates that it is to stop running. If the
141.591 + * target thread waits for long periods (on a condition variable,
141.592 + * for example), the <code>interrupt</code> method should be used to
141.593 + * interrupt the wait.
141.594 + * For more information, see
141.595 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
141.596 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
141.597 + */
141.598 + @Deprecated
141.599 + public final void stop() {
141.600 + stop(null);
141.601 + }
141.602 +
141.603 + /**
141.604 + * Forces the thread to stop executing.
141.605 + * <p>
141.606 + * If there is a security manager installed, the <code>checkAccess</code>
141.607 + * method of this thread is called, which may result in a
141.608 + * <code>SecurityException</code> being raised (in the current thread).
141.609 + * <p>
141.610 + * If this thread is different from the current thread (that is, the current
141.611 + * thread is trying to stop a thread other than itself) or
141.612 + * <code>obj</code> is not an instance of <code>ThreadDeath</code>, the
141.613 + * security manager's <code>checkPermission</code> method (with the
141.614 + * <code>RuntimePermission("stopThread")</code> argument) is called in
141.615 + * addition.
141.616 + * Again, this may result in throwing a
141.617 + * <code>SecurityException</code> (in the current thread).
141.618 + * <p>
141.619 + * If the argument <code>obj</code> is null, a
141.620 + * <code>NullPointerException</code> is thrown (in the current thread).
141.621 + * <p>
141.622 + * The thread represented by this thread is forced to stop
141.623 + * whatever it is doing abnormally and to throw the
141.624 + * <code>Throwable</code> object <code>obj</code> as an exception. This
141.625 + * is an unusual action to take; normally, the <code>stop</code> method
141.626 + * that takes no arguments should be used.
141.627 + * <p>
141.628 + * It is permitted to stop a thread that has not yet been started.
141.629 + * If the thread is eventually started, it immediately terminates.
141.630 + *
141.631 + * @param obj the Throwable object to be thrown.
141.632 + * @exception SecurityException if the current thread cannot modify
141.633 + * this thread.
141.634 + * @throws NullPointerException if obj is <tt>null</tt>.
141.635 + * @see #interrupt()
141.636 + * @see #checkAccess()
141.637 + * @see #run()
141.638 + * @see #start()
141.639 + * @see #stop()
141.640 + * @see SecurityManager#checkAccess(Thread)
141.641 + * @see SecurityManager#checkPermission
141.642 + * @deprecated This method is inherently unsafe. See {@link #stop()}
141.643 + * for details. An additional danger of this
141.644 + * method is that it may be used to generate exceptions that the
141.645 + * target thread is unprepared to handle (including checked
141.646 + * exceptions that the thread could not possibly throw, were it
141.647 + * not for this method).
141.648 + * For more information, see
141.649 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
141.650 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
141.651 + */
141.652 + @Deprecated
141.653 + public final synchronized void stop(Throwable obj) {
141.654 + throw new SecurityException();
141.655 + }
141.656 +
141.657 + /**
141.658 + * Interrupts this thread.
141.659 + *
141.660 + * <p> Unless the current thread is interrupting itself, which is
141.661 + * always permitted, the {@link #checkAccess() checkAccess} method
141.662 + * of this thread is invoked, which may cause a {@link
141.663 + * SecurityException} to be thrown.
141.664 + *
141.665 + * <p> If this thread is blocked in an invocation of the {@link
141.666 + * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
141.667 + * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
141.668 + * class, or of the {@link #join()}, {@link #join(long)}, {@link
141.669 + * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
141.670 + * methods of this class, then its interrupt status will be cleared and it
141.671 + * will receive an {@link InterruptedException}.
141.672 + *
141.673 + * <p> If this thread is blocked in an I/O operation upon an {@link
141.674 + * java.nio.channels.InterruptibleChannel </code>interruptible
141.675 + * channel<code>} then the channel will be closed, the thread's interrupt
141.676 + * status will be set, and the thread will receive a {@link
141.677 + * java.nio.channels.ClosedByInterruptException}.
141.678 + *
141.679 + * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
141.680 + * then the thread's interrupt status will be set and it will return
141.681 + * immediately from the selection operation, possibly with a non-zero
141.682 + * value, just as if the selector's {@link
141.683 + * java.nio.channels.Selector#wakeup wakeup} method were invoked.
141.684 + *
141.685 + * <p> If none of the previous conditions hold then this thread's interrupt
141.686 + * status will be set. </p>
141.687 + *
141.688 + * <p> Interrupting a thread that is not alive need not have any effect.
141.689 + *
141.690 + * @throws SecurityException
141.691 + * if the current thread cannot modify this thread
141.692 + *
141.693 + * @revised 6.0
141.694 + * @spec JSR-51
141.695 + */
141.696 + public void interrupt() {
141.697 + throw new SecurityException();
141.698 + }
141.699 +
141.700 + /**
141.701 + * Tests whether the current thread has been interrupted. The
141.702 + * <i>interrupted status</i> of the thread is cleared by this method. In
141.703 + * other words, if this method were to be called twice in succession, the
141.704 + * second call would return false (unless the current thread were
141.705 + * interrupted again, after the first call had cleared its interrupted
141.706 + * status and before the second call had examined it).
141.707 + *
141.708 + * <p>A thread interruption ignored because a thread was not alive
141.709 + * at the time of the interrupt will be reflected by this method
141.710 + * returning false.
141.711 + *
141.712 + * @return <code>true</code> if the current thread has been interrupted;
141.713 + * <code>false</code> otherwise.
141.714 + * @see #isInterrupted()
141.715 + * @revised 6.0
141.716 + */
141.717 + public static boolean interrupted() {
141.718 + return currentThread().isInterrupted();
141.719 + }
141.720 +
141.721 + /**
141.722 + * Tests whether this thread has been interrupted. The <i>interrupted
141.723 + * status</i> of the thread is unaffected by this method.
141.724 + *
141.725 + * <p>A thread interruption ignored because a thread was not alive
141.726 + * at the time of the interrupt will be reflected by this method
141.727 + * returning false.
141.728 + *
141.729 + * @return <code>true</code> if this thread has been interrupted;
141.730 + * <code>false</code> otherwise.
141.731 + * @see #interrupted()
141.732 + * @revised 6.0
141.733 + */
141.734 + public boolean isInterrupted() {
141.735 + return false;
141.736 + }
141.737 +
141.738 + /**
141.739 + * Throws {@link NoSuchMethodError}.
141.740 + *
141.741 + * @deprecated This method was originally designed to destroy this
141.742 + * thread without any cleanup. Any monitors it held would have
141.743 + * remained locked. However, the method was never implemented.
141.744 + * If if were to be implemented, it would be deadlock-prone in
141.745 + * much the manner of {@link #suspend}. If the target thread held
141.746 + * a lock protecting a critical system resource when it was
141.747 + * destroyed, no thread could ever access this resource again.
141.748 + * If another thread ever attempted to lock this resource, deadlock
141.749 + * would result. Such deadlocks typically manifest themselves as
141.750 + * "frozen" processes. For more information, see
141.751 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
141.752 + * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
141.753 + * @throws NoSuchMethodError always
141.754 + */
141.755 + @Deprecated
141.756 + public void destroy() {
141.757 + throw new SecurityException();
141.758 + }
141.759 +
141.760 + /**
141.761 + * Tests if this thread is alive. A thread is alive if it has
141.762 + * been started and has not yet died.
141.763 + *
141.764 + * @return <code>true</code> if this thread is alive;
141.765 + * <code>false</code> otherwise.
141.766 + */
141.767 + public final boolean isAlive() {
141.768 + return true;
141.769 + }
141.770 +
141.771 + /**
141.772 + * Suspends this thread.
141.773 + * <p>
141.774 + * First, the <code>checkAccess</code> method of this thread is called
141.775 + * with no arguments. This may result in throwing a
141.776 + * <code>SecurityException </code>(in the current thread).
141.777 + * <p>
141.778 + * If the thread is alive, it is suspended and makes no further
141.779 + * progress unless and until it is resumed.
141.780 + *
141.781 + * @exception SecurityException if the current thread cannot modify
141.782 + * this thread.
141.783 + * @see #checkAccess
141.784 + * @deprecated This method has been deprecated, as it is
141.785 + * inherently deadlock-prone. If the target thread holds a lock on the
141.786 + * monitor protecting a critical system resource when it is suspended, no
141.787 + * thread can access this resource until the target thread is resumed. If
141.788 + * the thread that would resume the target thread attempts to lock this
141.789 + * monitor prior to calling <code>resume</code>, deadlock results. Such
141.790 + * deadlocks typically manifest themselves as "frozen" processes.
141.791 + * For more information, see
141.792 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
141.793 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
141.794 + */
141.795 + @Deprecated
141.796 + public final void suspend() {
141.797 + checkAccess();
141.798 + }
141.799 +
141.800 + /**
141.801 + * Resumes a suspended thread.
141.802 + * <p>
141.803 + * First, the <code>checkAccess</code> method of this thread is called
141.804 + * with no arguments. This may result in throwing a
141.805 + * <code>SecurityException</code> (in the current thread).
141.806 + * <p>
141.807 + * If the thread is alive but suspended, it is resumed and is
141.808 + * permitted to make progress in its execution.
141.809 + *
141.810 + * @exception SecurityException if the current thread cannot modify this
141.811 + * thread.
141.812 + * @see #checkAccess
141.813 + * @see #suspend()
141.814 + * @deprecated This method exists solely for use with {@link #suspend},
141.815 + * which has been deprecated because it is deadlock-prone.
141.816 + * For more information, see
141.817 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
141.818 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
141.819 + */
141.820 + @Deprecated
141.821 + public final void resume() {
141.822 + checkAccess();
141.823 + }
141.824 +
141.825 + /**
141.826 + * Changes the priority of this thread.
141.827 + * <p>
141.828 + * First the <code>checkAccess</code> method of this thread is called
141.829 + * with no arguments. This may result in throwing a
141.830 + * <code>SecurityException</code>.
141.831 + * <p>
141.832 + * Otherwise, the priority of this thread is set to the smaller of
141.833 + * the specified <code>newPriority</code> and the maximum permitted
141.834 + * priority of the thread's thread group.
141.835 + *
141.836 + * @param newPriority priority to set this thread to
141.837 + * @exception IllegalArgumentException If the priority is not in the
141.838 + * range <code>MIN_PRIORITY</code> to
141.839 + * <code>MAX_PRIORITY</code>.
141.840 + * @exception SecurityException if the current thread cannot modify
141.841 + * this thread.
141.842 + * @see #getPriority
141.843 + * @see #checkAccess()
141.844 + * @see #getThreadGroup()
141.845 + * @see #MAX_PRIORITY
141.846 + * @see #MIN_PRIORITY
141.847 + * @see ThreadGroup#getMaxPriority()
141.848 + */
141.849 + public final void setPriority(int newPriority) {
141.850 + throw new SecurityException();
141.851 + }
141.852 +
141.853 + /**
141.854 + * Returns this thread's priority.
141.855 + *
141.856 + * @return this thread's priority.
141.857 + * @see #setPriority
141.858 + */
141.859 + public final int getPriority() {
141.860 + return Thread.NORM_PRIORITY;
141.861 + }
141.862 +
141.863 + /**
141.864 + * Changes the name of this thread to be equal to the argument
141.865 + * <code>name</code>.
141.866 + * <p>
141.867 + * First the <code>checkAccess</code> method of this thread is called
141.868 + * with no arguments. This may result in throwing a
141.869 + * <code>SecurityException</code>.
141.870 + *
141.871 + * @param name the new name for this thread.
141.872 + * @exception SecurityException if the current thread cannot modify this
141.873 + * thread.
141.874 + * @see #getName
141.875 + * @see #checkAccess()
141.876 + */
141.877 + public final void setName(String name) {
141.878 + throw new SecurityException();
141.879 + }
141.880 +
141.881 + /**
141.882 + * Returns this thread's name.
141.883 + *
141.884 + * @return this thread's name.
141.885 + * @see #setName(String)
141.886 + */
141.887 + public final String getName() {
141.888 + return String.valueOf(name);
141.889 + }
141.890 +
141.891 + /**
141.892 + * Returns the thread group to which this thread belongs.
141.893 + * This method returns null if this thread has died
141.894 + * (been stopped).
141.895 + *
141.896 + * @return this thread's thread group.
141.897 + */
141.898 +// public final ThreadGroup getThreadGroup() {
141.899 +// return group;
141.900 +// }
141.901 +
141.902 + /**
141.903 + * Returns an estimate of the number of active threads in the current
141.904 + * thread's {@linkplain java.lang.ThreadGroup thread group} and its
141.905 + * subgroups. Recursively iterates over all subgroups in the current
141.906 + * thread's thread group.
141.907 + *
141.908 + * <p> The value returned is only an estimate because the number of
141.909 + * threads may change dynamically while this method traverses internal
141.910 + * data structures, and might be affected by the presence of certain
141.911 + * system threads. This method is intended primarily for debugging
141.912 + * and monitoring purposes.
141.913 + *
141.914 + * @return an estimate of the number of active threads in the current
141.915 + * thread's thread group and in any other thread group that
141.916 + * has the current thread's thread group as an ancestor
141.917 + */
141.918 + public static int activeCount() {
141.919 + return 1;
141.920 + }
141.921 +
141.922 + /**
141.923 + * Copies into the specified array every active thread in the current
141.924 + * thread's thread group and its subgroups. This method simply
141.925 + * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
141.926 + * method of the current thread's thread group.
141.927 + *
141.928 + * <p> An application might use the {@linkplain #activeCount activeCount}
141.929 + * method to get an estimate of how big the array should be, however
141.930 + * <i>if the array is too short to hold all the threads, the extra threads
141.931 + * are silently ignored.</i> If it is critical to obtain every active
141.932 + * thread in the current thread's thread group and its subgroups, the
141.933 + * invoker should verify that the returned int value is strictly less
141.934 + * than the length of {@code tarray}.
141.935 + *
141.936 + * <p> Due to the inherent race condition in this method, it is recommended
141.937 + * that the method only be used for debugging and monitoring purposes.
141.938 + *
141.939 + * @param tarray
141.940 + * an array into which to put the list of threads
141.941 + *
141.942 + * @return the number of threads put into the array
141.943 + *
141.944 + * @throws SecurityException
141.945 + * if {@link java.lang.ThreadGroup#checkAccess} determines that
141.946 + * the current thread cannot access its thread group
141.947 + */
141.948 + public static int enumerate(Thread tarray[]) {
141.949 + throw new SecurityException();
141.950 + }
141.951 +
141.952 + /**
141.953 + * Counts the number of stack frames in this thread. The thread must
141.954 + * be suspended.
141.955 + *
141.956 + * @return the number of stack frames in this thread.
141.957 + * @exception IllegalThreadStateException if this thread is not
141.958 + * suspended.
141.959 + * @deprecated The definition of this call depends on {@link #suspend},
141.960 + * which is deprecated. Further, the results of this call
141.961 + * were never well-defined.
141.962 + */
141.963 + @Deprecated
141.964 + public native int countStackFrames();
141.965 +
141.966 + /**
141.967 + * Waits at most {@code millis} milliseconds for this thread to
141.968 + * die. A timeout of {@code 0} means to wait forever.
141.969 + *
141.970 + * <p> This implementation uses a loop of {@code this.wait} calls
141.971 + * conditioned on {@code this.isAlive}. As a thread terminates the
141.972 + * {@code this.notifyAll} method is invoked. It is recommended that
141.973 + * applications not use {@code wait}, {@code notify}, or
141.974 + * {@code notifyAll} on {@code Thread} instances.
141.975 + *
141.976 + * @param millis
141.977 + * the time to wait in milliseconds
141.978 + *
141.979 + * @throws IllegalArgumentException
141.980 + * if the value of {@code millis} is negative
141.981 + *
141.982 + * @throws InterruptedException
141.983 + * if any thread has interrupted the current thread. The
141.984 + * <i>interrupted status</i> of the current thread is
141.985 + * cleared when this exception is thrown.
141.986 + */
141.987 + public final synchronized void join(long millis)
141.988 + throws InterruptedException {
141.989 + long base = System.currentTimeMillis();
141.990 + long now = 0;
141.991 +
141.992 + if (millis < 0) {
141.993 + throw new IllegalArgumentException("timeout value is negative");
141.994 + }
141.995 +
141.996 + if (millis == 0) {
141.997 + while (isAlive()) {
141.998 + wait(0);
141.999 + }
141.1000 + } else {
141.1001 + while (isAlive()) {
141.1002 + long delay = millis - now;
141.1003 + if (delay <= 0) {
141.1004 + break;
141.1005 + }
141.1006 + wait(delay);
141.1007 + now = System.currentTimeMillis() - base;
141.1008 + }
141.1009 + }
141.1010 + }
141.1011 +
141.1012 + /**
141.1013 + * Waits at most {@code millis} milliseconds plus
141.1014 + * {@code nanos} nanoseconds for this thread to die.
141.1015 + *
141.1016 + * <p> This implementation uses a loop of {@code this.wait} calls
141.1017 + * conditioned on {@code this.isAlive}. As a thread terminates the
141.1018 + * {@code this.notifyAll} method is invoked. It is recommended that
141.1019 + * applications not use {@code wait}, {@code notify}, or
141.1020 + * {@code notifyAll} on {@code Thread} instances.
141.1021 + *
141.1022 + * @param millis
141.1023 + * the time to wait in milliseconds
141.1024 + *
141.1025 + * @param nanos
141.1026 + * {@code 0-999999} additional nanoseconds to wait
141.1027 + *
141.1028 + * @throws IllegalArgumentException
141.1029 + * if the value of {@code millis} is negative, or the value
141.1030 + * of {@code nanos} is not in the range {@code 0-999999}
141.1031 + *
141.1032 + * @throws InterruptedException
141.1033 + * if any thread has interrupted the current thread. The
141.1034 + * <i>interrupted status</i> of the current thread is
141.1035 + * cleared when this exception is thrown.
141.1036 + */
141.1037 + public final synchronized void join(long millis, int nanos)
141.1038 + throws InterruptedException {
141.1039 +
141.1040 + if (millis < 0) {
141.1041 + throw new IllegalArgumentException("timeout value is negative");
141.1042 + }
141.1043 +
141.1044 + if (nanos < 0 || nanos > 999999) {
141.1045 + throw new IllegalArgumentException(
141.1046 + "nanosecond timeout value out of range");
141.1047 + }
141.1048 +
141.1049 + if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
141.1050 + millis++;
141.1051 + }
141.1052 +
141.1053 + join(millis);
141.1054 + }
141.1055 +
141.1056 + /**
141.1057 + * Waits for this thread to die.
141.1058 + *
141.1059 + * <p> An invocation of this method behaves in exactly the same
141.1060 + * way as the invocation
141.1061 + *
141.1062 + * <blockquote>
141.1063 + * {@linkplain #join(long) join}{@code (0)}
141.1064 + * </blockquote>
141.1065 + *
141.1066 + * @throws InterruptedException
141.1067 + * if any thread has interrupted the current thread. The
141.1068 + * <i>interrupted status</i> of the current thread is
141.1069 + * cleared when this exception is thrown.
141.1070 + */
141.1071 + public final void join() throws InterruptedException {
141.1072 + join(0);
141.1073 + }
141.1074 +
141.1075 + /**
141.1076 + * Prints a stack trace of the current thread to the standard error stream.
141.1077 + * This method is used only for debugging.
141.1078 + *
141.1079 + * @see Throwable#printStackTrace()
141.1080 + */
141.1081 + public static void dumpStack() {
141.1082 + new Exception("Stack trace").printStackTrace();
141.1083 + }
141.1084 +
141.1085 + /**
141.1086 + * Marks this thread as either a {@linkplain #isDaemon daemon} thread
141.1087 + * or a user thread. The Java Virtual Machine exits when the only
141.1088 + * threads running are all daemon threads.
141.1089 + *
141.1090 + * <p> This method must be invoked before the thread is started.
141.1091 + *
141.1092 + * @param on
141.1093 + * if {@code true}, marks this thread as a daemon thread
141.1094 + *
141.1095 + * @throws IllegalThreadStateException
141.1096 + * if this thread is {@linkplain #isAlive alive}
141.1097 + *
141.1098 + * @throws SecurityException
141.1099 + * if {@link #checkAccess} determines that the current
141.1100 + * thread cannot modify this thread
141.1101 + */
141.1102 + public final void setDaemon(boolean on) {
141.1103 + throw new SecurityException();
141.1104 + }
141.1105 +
141.1106 + /**
141.1107 + * Tests if this thread is a daemon thread.
141.1108 + *
141.1109 + * @return <code>true</code> if this thread is a daemon thread;
141.1110 + * <code>false</code> otherwise.
141.1111 + * @see #setDaemon(boolean)
141.1112 + */
141.1113 + public final boolean isDaemon() {
141.1114 + return false;
141.1115 + }
141.1116 +
141.1117 + /**
141.1118 + * Determines if the currently running thread has permission to
141.1119 + * modify this thread.
141.1120 + * <p>
141.1121 + * If there is a security manager, its <code>checkAccess</code> method
141.1122 + * is called with this thread as its argument. This may result in
141.1123 + * throwing a <code>SecurityException</code>.
141.1124 + *
141.1125 + * @exception SecurityException if the current thread is not allowed to
141.1126 + * access this thread.
141.1127 + * @see SecurityManager#checkAccess(Thread)
141.1128 + */
141.1129 + public final void checkAccess() {
141.1130 + throw new SecurityException();
141.1131 + }
141.1132 +
141.1133 + /**
141.1134 + * Returns a string representation of this thread, including the
141.1135 + * thread's name, priority, and thread group.
141.1136 + *
141.1137 + * @return a string representation of this thread.
141.1138 + */
141.1139 + public String toString() {
141.1140 + return "Thread[" + getName() + "," + getPriority() + "," +
141.1141 + "" + "]";
141.1142 + }
141.1143 +
141.1144 + /**
141.1145 + * Returns the context ClassLoader for this Thread. The context
141.1146 + * ClassLoader is provided by the creator of the thread for use
141.1147 + * by code running in this thread when loading classes and resources.
141.1148 + * If not {@linkplain #setContextClassLoader set}, the default is the
141.1149 + * ClassLoader context of the parent Thread. The context ClassLoader of the
141.1150 + * primordial thread is typically set to the class loader used to load the
141.1151 + * application.
141.1152 + *
141.1153 + * <p>If a security manager is present, and the invoker's class loader is not
141.1154 + * {@code null} and is not the same as or an ancestor of the context class
141.1155 + * loader, then this method invokes the security manager's {@link
141.1156 + * SecurityManager#checkPermission(java.security.Permission) checkPermission}
141.1157 + * method with a {@link RuntimePermission RuntimePermission}{@code
141.1158 + * ("getClassLoader")} permission to verify that retrieval of the context
141.1159 + * class loader is permitted.
141.1160 + *
141.1161 + * @return the context ClassLoader for this Thread, or {@code null}
141.1162 + * indicating the system class loader (or, failing that, the
141.1163 + * bootstrap class loader)
141.1164 + *
141.1165 + * @throws SecurityException
141.1166 + * if the current thread cannot get the context ClassLoader
141.1167 + *
141.1168 + * @since 1.2
141.1169 + */
141.1170 + public ClassLoader getContextClassLoader() {
141.1171 + return null;
141.1172 + }
141.1173 +
141.1174 + /**
141.1175 + * Sets the context ClassLoader for this Thread. The context
141.1176 + * ClassLoader can be set when a thread is created, and allows
141.1177 + * the creator of the thread to provide the appropriate class loader,
141.1178 + * through {@code getContextClassLoader}, to code running in the thread
141.1179 + * when loading classes and resources.
141.1180 + *
141.1181 + * <p>If a security manager is present, its {@link
141.1182 + * SecurityManager#checkPermission(java.security.Permission) checkPermission}
141.1183 + * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
141.1184 + * ("setContextClassLoader")} permission to see if setting the context
141.1185 + * ClassLoader is permitted.
141.1186 + *
141.1187 + * @param cl
141.1188 + * the context ClassLoader for this Thread, or null indicating the
141.1189 + * system class loader (or, failing that, the bootstrap class loader)
141.1190 + *
141.1191 + * @throws SecurityException
141.1192 + * if the current thread cannot set the context ClassLoader
141.1193 + *
141.1194 + * @since 1.2
141.1195 + */
141.1196 + public void setContextClassLoader(ClassLoader cl) {
141.1197 + throw new SecurityException();
141.1198 + }
141.1199 +
141.1200 + /**
141.1201 + * Returns <tt>true</tt> if and only if the current thread holds the
141.1202 + * monitor lock on the specified object.
141.1203 + *
141.1204 + * <p>This method is designed to allow a program to assert that
141.1205 + * the current thread already holds a specified lock:
141.1206 + * <pre>
141.1207 + * assert Thread.holdsLock(obj);
141.1208 + * </pre>
141.1209 + *
141.1210 + * @param obj the object on which to test lock ownership
141.1211 + * @throws NullPointerException if obj is <tt>null</tt>
141.1212 + * @return <tt>true</tt> if the current thread holds the monitor lock on
141.1213 + * the specified object.
141.1214 + * @since 1.4
141.1215 + */
141.1216 + public static boolean holdsLock(Object obj) {
141.1217 + return true;
141.1218 + }
141.1219 +
141.1220 + /**
141.1221 + * Returns an array of stack trace elements representing the stack dump
141.1222 + * of this thread. This method will return a zero-length array if
141.1223 + * this thread has not started, has started but has not yet been
141.1224 + * scheduled to run by the system, or has terminated.
141.1225 + * If the returned array is of non-zero length then the first element of
141.1226 + * the array represents the top of the stack, which is the most recent
141.1227 + * method invocation in the sequence. The last element of the array
141.1228 + * represents the bottom of the stack, which is the least recent method
141.1229 + * invocation in the sequence.
141.1230 + *
141.1231 + * <p>If there is a security manager, and this thread is not
141.1232 + * the current thread, then the security manager's
141.1233 + * <tt>checkPermission</tt> method is called with a
141.1234 + * <tt>RuntimePermission("getStackTrace")</tt> permission
141.1235 + * to see if it's ok to get the stack trace.
141.1236 + *
141.1237 + * <p>Some virtual machines may, under some circumstances, omit one
141.1238 + * or more stack frames from the stack trace. In the extreme case,
141.1239 + * a virtual machine that has no stack trace information concerning
141.1240 + * this thread is permitted to return a zero-length array from this
141.1241 + * method.
141.1242 + *
141.1243 + * @return an array of <tt>StackTraceElement</tt>,
141.1244 + * each represents one stack frame.
141.1245 + *
141.1246 + * @throws SecurityException
141.1247 + * if a security manager exists and its
141.1248 + * <tt>checkPermission</tt> method doesn't allow
141.1249 + * getting the stack trace of thread.
141.1250 + * @see SecurityManager#checkPermission
141.1251 + * @see RuntimePermission
141.1252 + * @see Throwable#getStackTrace
141.1253 + *
141.1254 + * @since 1.5
141.1255 + */
141.1256 + public StackTraceElement[] getStackTrace() {
141.1257 + throw new SecurityException();
141.1258 + }
141.1259 +
141.1260 + /**
141.1261 + * Returns a map of stack traces for all live threads.
141.1262 + * The map keys are threads and each map value is an array of
141.1263 + * <tt>StackTraceElement</tt> that represents the stack dump
141.1264 + * of the corresponding <tt>Thread</tt>.
141.1265 + * The returned stack traces are in the format specified for
141.1266 + * the {@link #getStackTrace getStackTrace} method.
141.1267 + *
141.1268 + * <p>The threads may be executing while this method is called.
141.1269 + * The stack trace of each thread only represents a snapshot and
141.1270 + * each stack trace may be obtained at different time. A zero-length
141.1271 + * array will be returned in the map value if the virtual machine has
141.1272 + * no stack trace information about a thread.
141.1273 + *
141.1274 + * <p>If there is a security manager, then the security manager's
141.1275 + * <tt>checkPermission</tt> method is called with a
141.1276 + * <tt>RuntimePermission("getStackTrace")</tt> permission as well as
141.1277 + * <tt>RuntimePermission("modifyThreadGroup")</tt> permission
141.1278 + * to see if it is ok to get the stack trace of all threads.
141.1279 + *
141.1280 + * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of
141.1281 + * <tt>StackTraceElement</tt> that represents the stack trace of
141.1282 + * the corresponding thread.
141.1283 + *
141.1284 + * @throws SecurityException
141.1285 + * if a security manager exists and its
141.1286 + * <tt>checkPermission</tt> method doesn't allow
141.1287 + * getting the stack trace of thread.
141.1288 + * @see #getStackTrace
141.1289 + * @see SecurityManager#checkPermission
141.1290 + * @see RuntimePermission
141.1291 + * @see Throwable#getStackTrace
141.1292 + *
141.1293 + * @since 1.5
141.1294 + */
141.1295 + public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
141.1296 + throw new SecurityException();
141.1297 + }
141.1298 +
141.1299 + /**
141.1300 + * Returns the identifier of this Thread. The thread ID is a positive
141.1301 + * <tt>long</tt> number generated when this thread was created.
141.1302 + * The thread ID is unique and remains unchanged during its lifetime.
141.1303 + * When a thread is terminated, this thread ID may be reused.
141.1304 + *
141.1305 + * @return this thread's ID.
141.1306 + * @since 1.5
141.1307 + */
141.1308 + public long getId() {
141.1309 + return 0;
141.1310 + }
141.1311 +
141.1312 + /**
141.1313 + * A thread state. A thread can be in one of the following states:
141.1314 + * <ul>
141.1315 + * <li>{@link #NEW}<br>
141.1316 + * A thread that has not yet started is in this state.
141.1317 + * </li>
141.1318 + * <li>{@link #RUNNABLE}<br>
141.1319 + * A thread executing in the Java virtual machine is in this state.
141.1320 + * </li>
141.1321 + * <li>{@link #BLOCKED}<br>
141.1322 + * A thread that is blocked waiting for a monitor lock
141.1323 + * is in this state.
141.1324 + * </li>
141.1325 + * <li>{@link #WAITING}<br>
141.1326 + * A thread that is waiting indefinitely for another thread to
141.1327 + * perform a particular action is in this state.
141.1328 + * </li>
141.1329 + * <li>{@link #TIMED_WAITING}<br>
141.1330 + * A thread that is waiting for another thread to perform an action
141.1331 + * for up to a specified waiting time is in this state.
141.1332 + * </li>
141.1333 + * <li>{@link #TERMINATED}<br>
141.1334 + * A thread that has exited is in this state.
141.1335 + * </li>
141.1336 + * </ul>
141.1337 + *
141.1338 + * <p>
141.1339 + * A thread can be in only one state at a given point in time.
141.1340 + * These states are virtual machine states which do not reflect
141.1341 + * any operating system thread states.
141.1342 + *
141.1343 + * @since 1.5
141.1344 + * @see #getState
141.1345 + */
141.1346 + public enum State {
141.1347 + /**
141.1348 + * Thread state for a thread which has not yet started.
141.1349 + */
141.1350 + NEW,
141.1351 +
141.1352 + /**
141.1353 + * Thread state for a runnable thread. A thread in the runnable
141.1354 + * state is executing in the Java virtual machine but it may
141.1355 + * be waiting for other resources from the operating system
141.1356 + * such as processor.
141.1357 + */
141.1358 + RUNNABLE,
141.1359 +
141.1360 + /**
141.1361 + * Thread state for a thread blocked waiting for a monitor lock.
141.1362 + * A thread in the blocked state is waiting for a monitor lock
141.1363 + * to enter a synchronized block/method or
141.1364 + * reenter a synchronized block/method after calling
141.1365 + * {@link Object#wait() Object.wait}.
141.1366 + */
141.1367 + BLOCKED,
141.1368 +
141.1369 + /**
141.1370 + * Thread state for a waiting thread.
141.1371 + * A thread is in the waiting state due to calling one of the
141.1372 + * following methods:
141.1373 + * <ul>
141.1374 + * <li>{@link Object#wait() Object.wait} with no timeout</li>
141.1375 + * <li>{@link #join() Thread.join} with no timeout</li>
141.1376 + * <li>{@link LockSupport#park() LockSupport.park}</li>
141.1377 + * </ul>
141.1378 + *
141.1379 + * <p>A thread in the waiting state is waiting for another thread to
141.1380 + * perform a particular action.
141.1381 + *
141.1382 + * For example, a thread that has called <tt>Object.wait()</tt>
141.1383 + * on an object is waiting for another thread to call
141.1384 + * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
141.1385 + * that object. A thread that has called <tt>Thread.join()</tt>
141.1386 + * is waiting for a specified thread to terminate.
141.1387 + */
141.1388 + WAITING,
141.1389 +
141.1390 + /**
141.1391 + * Thread state for a waiting thread with a specified waiting time.
141.1392 + * A thread is in the timed waiting state due to calling one of
141.1393 + * the following methods with a specified positive waiting time:
141.1394 + * <ul>
141.1395 + * <li>{@link #sleep Thread.sleep}</li>
141.1396 + * <li>{@link Object#wait(long) Object.wait} with timeout</li>
141.1397 + * <li>{@link #join(long) Thread.join} with timeout</li>
141.1398 + * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
141.1399 + * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
141.1400 + * </ul>
141.1401 + */
141.1402 + TIMED_WAITING,
141.1403 +
141.1404 + /**
141.1405 + * Thread state for a terminated thread.
141.1406 + * The thread has completed execution.
141.1407 + */
141.1408 + TERMINATED;
141.1409 + }
141.1410 +
141.1411 + /**
141.1412 + * Returns the state of this thread.
141.1413 + * This method is designed for use in monitoring of the system state,
141.1414 + * not for synchronization control.
141.1415 + *
141.1416 + * @return this thread's state.
141.1417 + * @since 1.5
141.1418 + */
141.1419 + public State getState() {
141.1420 + // get current thread state
141.1421 + return State.RUNNABLE;
141.1422 + }
141.1423 +
141.1424 + // Added in JSR-166
141.1425 +
141.1426 + /**
141.1427 + * Interface for handlers invoked when a <tt>Thread</tt> abruptly
141.1428 + * terminates due to an uncaught exception.
141.1429 + * <p>When a thread is about to terminate due to an uncaught exception
141.1430 + * the Java Virtual Machine will query the thread for its
141.1431 + * <tt>UncaughtExceptionHandler</tt> using
141.1432 + * {@link #getUncaughtExceptionHandler} and will invoke the handler's
141.1433 + * <tt>uncaughtException</tt> method, passing the thread and the
141.1434 + * exception as arguments.
141.1435 + * If a thread has not had its <tt>UncaughtExceptionHandler</tt>
141.1436 + * explicitly set, then its <tt>ThreadGroup</tt> object acts as its
141.1437 + * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
141.1438 + * has no
141.1439 + * special requirements for dealing with the exception, it can forward
141.1440 + * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
141.1441 + * default uncaught exception handler}.
141.1442 + *
141.1443 + * @see #setDefaultUncaughtExceptionHandler
141.1444 + * @see #setUncaughtExceptionHandler
141.1445 + * @see ThreadGroup#uncaughtException
141.1446 + * @since 1.5
141.1447 + */
141.1448 + public interface UncaughtExceptionHandler {
141.1449 + /**
141.1450 + * Method invoked when the given thread terminates due to the
141.1451 + * given uncaught exception.
141.1452 + * <p>Any exception thrown by this method will be ignored by the
141.1453 + * Java Virtual Machine.
141.1454 + * @param t the thread
141.1455 + * @param e the exception
141.1456 + */
141.1457 + void uncaughtException(Thread t, Throwable e);
141.1458 + }
141.1459 +
141.1460 + // null unless explicitly set
141.1461 + private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
141.1462 +
141.1463 + // null unless explicitly set
141.1464 + private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
141.1465 +
141.1466 + /**
141.1467 + * Set the default handler invoked when a thread abruptly terminates
141.1468 + * due to an uncaught exception, and no other handler has been defined
141.1469 + * for that thread.
141.1470 + *
141.1471 + * <p>Uncaught exception handling is controlled first by the thread, then
141.1472 + * by the thread's {@link ThreadGroup} object and finally by the default
141.1473 + * uncaught exception handler. If the thread does not have an explicit
141.1474 + * uncaught exception handler set, and the thread's thread group
141.1475 + * (including parent thread groups) does not specialize its
141.1476 + * <tt>uncaughtException</tt> method, then the default handler's
141.1477 + * <tt>uncaughtException</tt> method will be invoked.
141.1478 + * <p>By setting the default uncaught exception handler, an application
141.1479 + * can change the way in which uncaught exceptions are handled (such as
141.1480 + * logging to a specific device, or file) for those threads that would
141.1481 + * already accept whatever "default" behavior the system
141.1482 + * provided.
141.1483 + *
141.1484 + * <p>Note that the default uncaught exception handler should not usually
141.1485 + * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
141.1486 + * infinite recursion.
141.1487 + *
141.1488 + * @param eh the object to use as the default uncaught exception handler.
141.1489 + * If <tt>null</tt> then there is no default handler.
141.1490 + *
141.1491 + * @throws SecurityException if a security manager is present and it
141.1492 + * denies <tt>{@link RuntimePermission}
141.1493 + * ("setDefaultUncaughtExceptionHandler")</tt>
141.1494 + *
141.1495 + * @see #setUncaughtExceptionHandler
141.1496 + * @see #getUncaughtExceptionHandler
141.1497 + * @see ThreadGroup#uncaughtException
141.1498 + * @since 1.5
141.1499 + */
141.1500 + public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
141.1501 + throw new SecurityException();
141.1502 + }
141.1503 +
141.1504 + /**
141.1505 + * Returns the default handler invoked when a thread abruptly terminates
141.1506 + * due to an uncaught exception. If the returned value is <tt>null</tt>,
141.1507 + * there is no default.
141.1508 + * @since 1.5
141.1509 + * @see #setDefaultUncaughtExceptionHandler
141.1510 + */
141.1511 + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
141.1512 + return defaultUncaughtExceptionHandler;
141.1513 + }
141.1514 +
141.1515 + /**
141.1516 + * Returns the handler invoked when this thread abruptly terminates
141.1517 + * due to an uncaught exception. If this thread has not had an
141.1518 + * uncaught exception handler explicitly set then this thread's
141.1519 + * <tt>ThreadGroup</tt> object is returned, unless this thread
141.1520 + * has terminated, in which case <tt>null</tt> is returned.
141.1521 + * @since 1.5
141.1522 + */
141.1523 + public UncaughtExceptionHandler getUncaughtExceptionHandler() {
141.1524 + return uncaughtExceptionHandler != null ?
141.1525 + uncaughtExceptionHandler : null;
141.1526 + }
141.1527 +
141.1528 + /**
141.1529 + * Set the handler invoked when this thread abruptly terminates
141.1530 + * due to an uncaught exception.
141.1531 + * <p>A thread can take full control of how it responds to uncaught
141.1532 + * exceptions by having its uncaught exception handler explicitly set.
141.1533 + * If no such handler is set then the thread's <tt>ThreadGroup</tt>
141.1534 + * object acts as its handler.
141.1535 + * @param eh the object to use as this thread's uncaught exception
141.1536 + * handler. If <tt>null</tt> then this thread has no explicit handler.
141.1537 + * @throws SecurityException if the current thread is not allowed to
141.1538 + * modify this thread.
141.1539 + * @see #setDefaultUncaughtExceptionHandler
141.1540 + * @see ThreadGroup#uncaughtException
141.1541 + * @since 1.5
141.1542 + */
141.1543 + public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
141.1544 + checkAccess();
141.1545 + uncaughtExceptionHandler = eh;
141.1546 + }
141.1547 +}
142.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
142.2 +++ b/rt/emul/compact/src/main/java/java/lang/ThreadLocal.java Mon Oct 07 14:20:58 2013 +0200
142.3 @@ -0,0 +1,157 @@
142.4 +/*
142.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
142.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
142.7 + *
142.8 + * This code is free software; you can redistribute it and/or modify it
142.9 + * under the terms of the GNU General Public License version 2 only, as
142.10 + * published by the Free Software Foundation. Oracle designates this
142.11 + * particular file as subject to the "Classpath" exception as provided
142.12 + * by Oracle in the LICENSE file that accompanied this code.
142.13 + *
142.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
142.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
142.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
142.17 + * version 2 for more details (a copy is included in the LICENSE file that
142.18 + * accompanied this code).
142.19 + *
142.20 + * You should have received a copy of the GNU General Public License version
142.21 + * 2 along with this work; if not, write to the Free Software Foundation,
142.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
142.23 + *
142.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
142.25 + * or visit www.oracle.com if you need additional information or have any
142.26 + * questions.
142.27 + */
142.28 +
142.29 +package java.lang;
142.30 +
142.31 +/**
142.32 + * This class provides thread-local variables. These variables differ from
142.33 + * their normal counterparts in that each thread that accesses one (via its
142.34 + * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
142.35 + * copy of the variable. <tt>ThreadLocal</tt> instances are typically private
142.36 + * static fields in classes that wish to associate state with a thread (e.g.,
142.37 + * a user ID or Transaction ID).
142.38 + *
142.39 + * <p>For example, the class below generates unique identifiers local to each
142.40 + * thread.
142.41 + * A thread's id is assigned the first time it invokes <tt>ThreadId.get()</tt>
142.42 + * and remains unchanged on subsequent calls.
142.43 + * <pre>
142.44 + * import java.util.concurrent.atomic.AtomicInteger;
142.45 + *
142.46 + * public class ThreadId {
142.47 + * // Atomic integer containing the next thread ID to be assigned
142.48 + * private static final AtomicInteger nextId = new AtomicInteger(0);
142.49 + *
142.50 + * // Thread local variable containing each thread's ID
142.51 + * private static final ThreadLocal<Integer> threadId =
142.52 + * new ThreadLocal<Integer>() {
142.53 + * @Override protected Integer initialValue() {
142.54 + * return nextId.getAndIncrement();
142.55 + * }
142.56 + * };
142.57 + *
142.58 + * // Returns the current thread's unique ID, assigning it if necessary
142.59 + * public static int get() {
142.60 + * return threadId.get();
142.61 + * }
142.62 + * }
142.63 + * </pre>
142.64 + * <p>Each thread holds an implicit reference to its copy of a thread-local
142.65 + * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
142.66 + * instance is accessible; after a thread goes away, all of its copies of
142.67 + * thread-local instances are subject to garbage collection (unless other
142.68 + * references to these copies exist).
142.69 + *
142.70 + * @author Josh Bloch and Doug Lea
142.71 + * @since 1.2
142.72 + */
142.73 +public class ThreadLocal<T> {
142.74 + private static final Object NONE = new Object();
142.75 + private Object value = NONE;
142.76 +
142.77 + /**
142.78 + * Returns the current thread's "initial value" for this
142.79 + * thread-local variable. This method will be invoked the first
142.80 + * time a thread accesses the variable with the {@link #get}
142.81 + * method, unless the thread previously invoked the {@link #set}
142.82 + * method, in which case the <tt>initialValue</tt> method will not
142.83 + * be invoked for the thread. Normally, this method is invoked at
142.84 + * most once per thread, but it may be invoked again in case of
142.85 + * subsequent invocations of {@link #remove} followed by {@link #get}.
142.86 + *
142.87 + * <p>This implementation simply returns <tt>null</tt>; if the
142.88 + * programmer desires thread-local variables to have an initial
142.89 + * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
142.90 + * subclassed, and this method overridden. Typically, an
142.91 + * anonymous inner class will be used.
142.92 + *
142.93 + * @return the initial value for this thread-local
142.94 + */
142.95 + protected T initialValue() {
142.96 + return null;
142.97 + }
142.98 +
142.99 + /**
142.100 + * Creates a thread local variable.
142.101 + */
142.102 + public ThreadLocal() {
142.103 + }
142.104 +
142.105 + /**
142.106 + * Returns the value in the current thread's copy of this
142.107 + * thread-local variable. If the variable has no value for the
142.108 + * current thread, it is first initialized to the value returned
142.109 + * by an invocation of the {@link #initialValue} method.
142.110 + *
142.111 + * @return the current thread's value of this thread-local
142.112 + */
142.113 + public T get() {
142.114 + if (value == NONE) {
142.115 + return setInitialValue();
142.116 + } else {
142.117 + return (T)value;
142.118 + }
142.119 + }
142.120 +
142.121 + /**
142.122 + * Variant of set() to establish initialValue. Used instead
142.123 + * of set() in case user has overridden the set() method.
142.124 + *
142.125 + * @return the initial value
142.126 + */
142.127 + private T setInitialValue() {
142.128 + T v = initialValue();
142.129 + this.value = v;
142.130 + return v;
142.131 + }
142.132 +
142.133 + /**
142.134 + * Sets the current thread's copy of this thread-local variable
142.135 + * to the specified value. Most subclasses will have no need to
142.136 + * override this method, relying solely on the {@link #initialValue}
142.137 + * method to set the values of thread-locals.
142.138 + *
142.139 + * @param value the value to be stored in the current thread's copy of
142.140 + * this thread-local.
142.141 + */
142.142 + public void set(T value) {
142.143 + this.value = value;
142.144 + }
142.145 +
142.146 + /**
142.147 + * Removes the current thread's value for this thread-local
142.148 + * variable. If this thread-local variable is subsequently
142.149 + * {@linkplain #get read} by the current thread, its value will be
142.150 + * reinitialized by invoking its {@link #initialValue} method,
142.151 + * unless its value is {@linkplain #set set} by the current thread
142.152 + * in the interim. This may result in multiple invocations of the
142.153 + * <tt>initialValue</tt> method in the current thread.
142.154 + *
142.155 + * @since 1.5
142.156 + */
142.157 + public void remove() {
142.158 + this.value = NONE;
142.159 + }
142.160 +}
143.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
143.2 +++ b/rt/emul/compact/src/main/java/java/math/BigDecimal.java Mon Oct 07 14:20:58 2013 +0200
143.3 @@ -0,0 +1,3842 @@
143.4 +/*
143.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
143.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
143.7 + *
143.8 + * This code is free software; you can redistribute it and/or modify it
143.9 + * under the terms of the GNU General Public License version 2 only, as
143.10 + * published by the Free Software Foundation. Oracle designates this
143.11 + * particular file as subject to the "Classpath" exception as provided
143.12 + * by Oracle in the LICENSE file that accompanied this code.
143.13 + *
143.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
143.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
143.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
143.17 + * version 2 for more details (a copy is included in the LICENSE file that
143.18 + * accompanied this code).
143.19 + *
143.20 + * You should have received a copy of the GNU General Public License version
143.21 + * 2 along with this work; if not, write to the Free Software Foundation,
143.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
143.23 + *
143.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
143.25 + * or visit www.oracle.com if you need additional information or have any
143.26 + * questions.
143.27 + */
143.28 +
143.29 +/*
143.30 + * Portions Copyright IBM Corporation, 2001. All Rights Reserved.
143.31 + */
143.32 +
143.33 +package java.math;
143.34 +
143.35 +import java.util.Arrays;
143.36 +import static java.math.BigInteger.LONG_MASK;
143.37 +
143.38 +/**
143.39 + * Immutable, arbitrary-precision signed decimal numbers. A
143.40 + * {@code BigDecimal} consists of an arbitrary precision integer
143.41 + * <i>unscaled value</i> and a 32-bit integer <i>scale</i>. If zero
143.42 + * or positive, the scale is the number of digits to the right of the
143.43 + * decimal point. If negative, the unscaled value of the number is
143.44 + * multiplied by ten to the power of the negation of the scale. The
143.45 + * value of the number represented by the {@code BigDecimal} is
143.46 + * therefore <tt>(unscaledValue × 10<sup>-scale</sup>)</tt>.
143.47 + *
143.48 + * <p>The {@code BigDecimal} class provides operations for
143.49 + * arithmetic, scale manipulation, rounding, comparison, hashing, and
143.50 + * format conversion. The {@link #toString} method provides a
143.51 + * canonical representation of a {@code BigDecimal}.
143.52 + *
143.53 + * <p>The {@code BigDecimal} class gives its user complete control
143.54 + * over rounding behavior. If no rounding mode is specified and the
143.55 + * exact result cannot be represented, an exception is thrown;
143.56 + * otherwise, calculations can be carried out to a chosen precision
143.57 + * and rounding mode by supplying an appropriate {@link MathContext}
143.58 + * object to the operation. In either case, eight <em>rounding
143.59 + * modes</em> are provided for the control of rounding. Using the
143.60 + * integer fields in this class (such as {@link #ROUND_HALF_UP}) to
143.61 + * represent rounding mode is largely obsolete; the enumeration values
143.62 + * of the {@code RoundingMode} {@code enum}, (such as {@link
143.63 + * RoundingMode#HALF_UP}) should be used instead.
143.64 + *
143.65 + * <p>When a {@code MathContext} object is supplied with a precision
143.66 + * setting of 0 (for example, {@link MathContext#UNLIMITED}),
143.67 + * arithmetic operations are exact, as are the arithmetic methods
143.68 + * which take no {@code MathContext} object. (This is the only
143.69 + * behavior that was supported in releases prior to 5.) As a
143.70 + * corollary of computing the exact result, the rounding mode setting
143.71 + * of a {@code MathContext} object with a precision setting of 0 is
143.72 + * not used and thus irrelevant. In the case of divide, the exact
143.73 + * quotient could have an infinitely long decimal expansion; for
143.74 + * example, 1 divided by 3. If the quotient has a nonterminating
143.75 + * decimal expansion and the operation is specified to return an exact
143.76 + * result, an {@code ArithmeticException} is thrown. Otherwise, the
143.77 + * exact result of the division is returned, as done for other
143.78 + * operations.
143.79 + *
143.80 + * <p>When the precision setting is not 0, the rules of
143.81 + * {@code BigDecimal} arithmetic are broadly compatible with selected
143.82 + * modes of operation of the arithmetic defined in ANSI X3.274-1996
143.83 + * and ANSI X3.274-1996/AM 1-2000 (section 7.4). Unlike those
143.84 + * standards, {@code BigDecimal} includes many rounding modes, which
143.85 + * were mandatory for division in {@code BigDecimal} releases prior
143.86 + * to 5. Any conflicts between these ANSI standards and the
143.87 + * {@code BigDecimal} specification are resolved in favor of
143.88 + * {@code BigDecimal}.
143.89 + *
143.90 + * <p>Since the same numerical value can have different
143.91 + * representations (with different scales), the rules of arithmetic
143.92 + * and rounding must specify both the numerical result and the scale
143.93 + * used in the result's representation.
143.94 + *
143.95 + *
143.96 + * <p>In general the rounding modes and precision setting determine
143.97 + * how operations return results with a limited number of digits when
143.98 + * the exact result has more digits (perhaps infinitely many in the
143.99 + * case of division) than the number of digits returned.
143.100 + *
143.101 + * First, the
143.102 + * total number of digits to return is specified by the
143.103 + * {@code MathContext}'s {@code precision} setting; this determines
143.104 + * the result's <i>precision</i>. The digit count starts from the
143.105 + * leftmost nonzero digit of the exact result. The rounding mode
143.106 + * determines how any discarded trailing digits affect the returned
143.107 + * result.
143.108 + *
143.109 + * <p>For all arithmetic operators , the operation is carried out as
143.110 + * though an exact intermediate result were first calculated and then
143.111 + * rounded to the number of digits specified by the precision setting
143.112 + * (if necessary), using the selected rounding mode. If the exact
143.113 + * result is not returned, some digit positions of the exact result
143.114 + * are discarded. When rounding increases the magnitude of the
143.115 + * returned result, it is possible for a new digit position to be
143.116 + * created by a carry propagating to a leading {@literal "9"} digit.
143.117 + * For example, rounding the value 999.9 to three digits rounding up
143.118 + * would be numerically equal to one thousand, represented as
143.119 + * 100×10<sup>1</sup>. In such cases, the new {@literal "1"} is
143.120 + * the leading digit position of the returned result.
143.121 + *
143.122 + * <p>Besides a logical exact result, each arithmetic operation has a
143.123 + * preferred scale for representing a result. The preferred
143.124 + * scale for each operation is listed in the table below.
143.125 + *
143.126 + * <table border>
143.127 + * <caption><b>Preferred Scales for Results of Arithmetic Operations
143.128 + * </b></caption>
143.129 + * <tr><th>Operation</th><th>Preferred Scale of Result</th></tr>
143.130 + * <tr><td>Add</td><td>max(addend.scale(), augend.scale())</td>
143.131 + * <tr><td>Subtract</td><td>max(minuend.scale(), subtrahend.scale())</td>
143.132 + * <tr><td>Multiply</td><td>multiplier.scale() + multiplicand.scale()</td>
143.133 + * <tr><td>Divide</td><td>dividend.scale() - divisor.scale()</td>
143.134 + * </table>
143.135 + *
143.136 + * These scales are the ones used by the methods which return exact
143.137 + * arithmetic results; except that an exact divide may have to use a
143.138 + * larger scale since the exact result may have more digits. For
143.139 + * example, {@code 1/32} is {@code 0.03125}.
143.140 + *
143.141 + * <p>Before rounding, the scale of the logical exact intermediate
143.142 + * result is the preferred scale for that operation. If the exact
143.143 + * numerical result cannot be represented in {@code precision}
143.144 + * digits, rounding selects the set of digits to return and the scale
143.145 + * of the result is reduced from the scale of the intermediate result
143.146 + * to the least scale which can represent the {@code precision}
143.147 + * digits actually returned. If the exact result can be represented
143.148 + * with at most {@code precision} digits, the representation
143.149 + * of the result with the scale closest to the preferred scale is
143.150 + * returned. In particular, an exactly representable quotient may be
143.151 + * represented in fewer than {@code precision} digits by removing
143.152 + * trailing zeros and decreasing the scale. For example, rounding to
143.153 + * three digits using the {@linkplain RoundingMode#FLOOR floor}
143.154 + * rounding mode, <br>
143.155 + *
143.156 + * {@code 19/100 = 0.19 // integer=19, scale=2} <br>
143.157 + *
143.158 + * but<br>
143.159 + *
143.160 + * {@code 21/110 = 0.190 // integer=190, scale=3} <br>
143.161 + *
143.162 + * <p>Note that for add, subtract, and multiply, the reduction in
143.163 + * scale will equal the number of digit positions of the exact result
143.164 + * which are discarded. If the rounding causes a carry propagation to
143.165 + * create a new high-order digit position, an additional digit of the
143.166 + * result is discarded than when no new digit position is created.
143.167 + *
143.168 + * <p>Other methods may have slightly different rounding semantics.
143.169 + * For example, the result of the {@code pow} method using the
143.170 + * {@linkplain #pow(int, MathContext) specified algorithm} can
143.171 + * occasionally differ from the rounded mathematical result by more
143.172 + * than one unit in the last place, one <i>{@linkplain #ulp() ulp}</i>.
143.173 + *
143.174 + * <p>Two types of operations are provided for manipulating the scale
143.175 + * of a {@code BigDecimal}: scaling/rounding operations and decimal
143.176 + * point motion operations. Scaling/rounding operations ({@link
143.177 + * #setScale setScale} and {@link #round round}) return a
143.178 + * {@code BigDecimal} whose value is approximately (or exactly) equal
143.179 + * to that of the operand, but whose scale or precision is the
143.180 + * specified value; that is, they increase or decrease the precision
143.181 + * of the stored number with minimal effect on its value. Decimal
143.182 + * point motion operations ({@link #movePointLeft movePointLeft} and
143.183 + * {@link #movePointRight movePointRight}) return a
143.184 + * {@code BigDecimal} created from the operand by moving the decimal
143.185 + * point a specified distance in the specified direction.
143.186 + *
143.187 + * <p>For the sake of brevity and clarity, pseudo-code is used
143.188 + * throughout the descriptions of {@code BigDecimal} methods. The
143.189 + * pseudo-code expression {@code (i + j)} is shorthand for "a
143.190 + * {@code BigDecimal} whose value is that of the {@code BigDecimal}
143.191 + * {@code i} added to that of the {@code BigDecimal}
143.192 + * {@code j}." The pseudo-code expression {@code (i == j)} is
143.193 + * shorthand for "{@code true} if and only if the
143.194 + * {@code BigDecimal} {@code i} represents the same value as the
143.195 + * {@code BigDecimal} {@code j}." Other pseudo-code expressions
143.196 + * are interpreted similarly. Square brackets are used to represent
143.197 + * the particular {@code BigInteger} and scale pair defining a
143.198 + * {@code BigDecimal} value; for example [19, 2] is the
143.199 + * {@code BigDecimal} numerically equal to 0.19 having a scale of 2.
143.200 + *
143.201 + * <p>Note: care should be exercised if {@code BigDecimal} objects
143.202 + * are used as keys in a {@link java.util.SortedMap SortedMap} or
143.203 + * elements in a {@link java.util.SortedSet SortedSet} since
143.204 + * {@code BigDecimal}'s <i>natural ordering</i> is <i>inconsistent
143.205 + * with equals</i>. See {@link Comparable}, {@link
143.206 + * java.util.SortedMap} or {@link java.util.SortedSet} for more
143.207 + * information.
143.208 + *
143.209 + * <p>All methods and constructors for this class throw
143.210 + * {@code NullPointerException} when passed a {@code null} object
143.211 + * reference for any input parameter.
143.212 + *
143.213 + * @see BigInteger
143.214 + * @see MathContext
143.215 + * @see RoundingMode
143.216 + * @see java.util.SortedMap
143.217 + * @see java.util.SortedSet
143.218 + * @author Josh Bloch
143.219 + * @author Mike Cowlishaw
143.220 + * @author Joseph D. Darcy
143.221 + */
143.222 +public class BigDecimal extends Number implements Comparable<BigDecimal> {
143.223 + /**
143.224 + * The unscaled value of this BigDecimal, as returned by {@link
143.225 + * #unscaledValue}.
143.226 + *
143.227 + * @serial
143.228 + * @see #unscaledValue
143.229 + */
143.230 + private volatile BigInteger intVal;
143.231 +
143.232 + /**
143.233 + * The scale of this BigDecimal, as returned by {@link #scale}.
143.234 + *
143.235 + * @serial
143.236 + * @see #scale
143.237 + */
143.238 + private int scale; // Note: this may have any value, so
143.239 + // calculations must be done in longs
143.240 + /**
143.241 + * The number of decimal digits in this BigDecimal, or 0 if the
143.242 + * number of digits are not known (lookaside information). If
143.243 + * nonzero, the value is guaranteed correct. Use the precision()
143.244 + * method to obtain and set the value if it might be 0. This
143.245 + * field is mutable until set nonzero.
143.246 + *
143.247 + * @since 1.5
143.248 + */
143.249 + private transient int precision;
143.250 +
143.251 + /**
143.252 + * Used to store the canonical string representation, if computed.
143.253 + */
143.254 + private transient String stringCache;
143.255 +
143.256 + /**
143.257 + * Sentinel value for {@link #intCompact} indicating the
143.258 + * significand information is only available from {@code intVal}.
143.259 + */
143.260 + static final long INFLATED = Long.MIN_VALUE;
143.261 +
143.262 + /**
143.263 + * If the absolute value of the significand of this BigDecimal is
143.264 + * less than or equal to {@code Long.MAX_VALUE}, the value can be
143.265 + * compactly stored in this field and used in computations.
143.266 + */
143.267 + private transient long intCompact;
143.268 +
143.269 + // All 18-digit base ten strings fit into a long; not all 19-digit
143.270 + // strings will
143.271 + private static final int MAX_COMPACT_DIGITS = 18;
143.272 +
143.273 + private static final int MAX_BIGINT_BITS = 62;
143.274 +
143.275 + /* Appease the serialization gods */
143.276 + private static final long serialVersionUID = 6108874887143696463L;
143.277 +
143.278 + // Cache of common small BigDecimal values.
143.279 + private static final BigDecimal zeroThroughTen[] = {
143.280 + new BigDecimal(BigInteger.ZERO, 0, 0, 1),
143.281 + new BigDecimal(BigInteger.ONE, 1, 0, 1),
143.282 + new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
143.283 + new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
143.284 + new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
143.285 + new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
143.286 + new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
143.287 + new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
143.288 + new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
143.289 + new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
143.290 + new BigDecimal(BigInteger.TEN, 10, 0, 2),
143.291 + };
143.292 +
143.293 + // Cache of zero scaled by 0 - 15
143.294 + private static final BigDecimal[] ZERO_SCALED_BY = {
143.295 + zeroThroughTen[0],
143.296 + new BigDecimal(BigInteger.ZERO, 0, 1, 1),
143.297 + new BigDecimal(BigInteger.ZERO, 0, 2, 1),
143.298 + new BigDecimal(BigInteger.ZERO, 0, 3, 1),
143.299 + new BigDecimal(BigInteger.ZERO, 0, 4, 1),
143.300 + new BigDecimal(BigInteger.ZERO, 0, 5, 1),
143.301 + new BigDecimal(BigInteger.ZERO, 0, 6, 1),
143.302 + new BigDecimal(BigInteger.ZERO, 0, 7, 1),
143.303 + new BigDecimal(BigInteger.ZERO, 0, 8, 1),
143.304 + new BigDecimal(BigInteger.ZERO, 0, 9, 1),
143.305 + new BigDecimal(BigInteger.ZERO, 0, 10, 1),
143.306 + new BigDecimal(BigInteger.ZERO, 0, 11, 1),
143.307 + new BigDecimal(BigInteger.ZERO, 0, 12, 1),
143.308 + new BigDecimal(BigInteger.ZERO, 0, 13, 1),
143.309 + new BigDecimal(BigInteger.ZERO, 0, 14, 1),
143.310 + new BigDecimal(BigInteger.ZERO, 0, 15, 1),
143.311 + };
143.312 +
143.313 + // Half of Long.MIN_VALUE & Long.MAX_VALUE.
143.314 + private static final long HALF_LONG_MAX_VALUE = Long.MAX_VALUE / 2;
143.315 + private static final long HALF_LONG_MIN_VALUE = Long.MIN_VALUE / 2;
143.316 +
143.317 + // Constants
143.318 + /**
143.319 + * The value 0, with a scale of 0.
143.320 + *
143.321 + * @since 1.5
143.322 + */
143.323 + public static final BigDecimal ZERO =
143.324 + zeroThroughTen[0];
143.325 +
143.326 + /**
143.327 + * The value 1, with a scale of 0.
143.328 + *
143.329 + * @since 1.5
143.330 + */
143.331 + public static final BigDecimal ONE =
143.332 + zeroThroughTen[1];
143.333 +
143.334 + /**
143.335 + * The value 10, with a scale of 0.
143.336 + *
143.337 + * @since 1.5
143.338 + */
143.339 + public static final BigDecimal TEN =
143.340 + zeroThroughTen[10];
143.341 +
143.342 + // Constructors
143.343 +
143.344 + /**
143.345 + * Trusted package private constructor.
143.346 + * Trusted simply means if val is INFLATED, intVal could not be null and
143.347 + * if intVal is null, val could not be INFLATED.
143.348 + */
143.349 + BigDecimal(BigInteger intVal, long val, int scale, int prec) {
143.350 + this.scale = scale;
143.351 + this.precision = prec;
143.352 + this.intCompact = val;
143.353 + this.intVal = intVal;
143.354 + }
143.355 +
143.356 + /**
143.357 + * Translates a character array representation of a
143.358 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
143.359 + * same sequence of characters as the {@link #BigDecimal(String)}
143.360 + * constructor, while allowing a sub-array to be specified.
143.361 + *
143.362 + * <p>Note that if the sequence of characters is already available
143.363 + * within a character array, using this constructor is faster than
143.364 + * converting the {@code char} array to string and using the
143.365 + * {@code BigDecimal(String)} constructor .
143.366 + *
143.367 + * @param in {@code char} array that is the source of characters.
143.368 + * @param offset first character in the array to inspect.
143.369 + * @param len number of characters to consider.
143.370 + * @throws NumberFormatException if {@code in} is not a valid
143.371 + * representation of a {@code BigDecimal} or the defined subarray
143.372 + * is not wholly within {@code in}.
143.373 + * @since 1.5
143.374 + */
143.375 + public BigDecimal(char[] in, int offset, int len) {
143.376 + // protect against huge length.
143.377 + if (offset+len > in.length || offset < 0)
143.378 + throw new NumberFormatException();
143.379 + // This is the primary string to BigDecimal constructor; all
143.380 + // incoming strings end up here; it uses explicit (inline)
143.381 + // parsing for speed and generates at most one intermediate
143.382 + // (temporary) object (a char[] array) for non-compact case.
143.383 +
143.384 + // Use locals for all fields values until completion
143.385 + int prec = 0; // record precision value
143.386 + int scl = 0; // record scale value
143.387 + long rs = 0; // the compact value in long
143.388 + BigInteger rb = null; // the inflated value in BigInteger
143.389 +
143.390 + // use array bounds checking to handle too-long, len == 0,
143.391 + // bad offset, etc.
143.392 + try {
143.393 + // handle the sign
143.394 + boolean isneg = false; // assume positive
143.395 + if (in[offset] == '-') {
143.396 + isneg = true; // leading minus means negative
143.397 + offset++;
143.398 + len--;
143.399 + } else if (in[offset] == '+') { // leading + allowed
143.400 + offset++;
143.401 + len--;
143.402 + }
143.403 +
143.404 + // should now be at numeric part of the significand
143.405 + boolean dot = false; // true when there is a '.'
143.406 + int cfirst = offset; // record start of integer
143.407 + long exp = 0; // exponent
143.408 + char c; // current character
143.409 +
143.410 + boolean isCompact = (len <= MAX_COMPACT_DIGITS);
143.411 + // integer significand array & idx is the index to it. The array
143.412 + // is ONLY used when we can't use a compact representation.
143.413 + char coeff[] = isCompact ? null : new char[len];
143.414 + int idx = 0;
143.415 +
143.416 + for (; len > 0; offset++, len--) {
143.417 + c = in[offset];
143.418 + // have digit
143.419 + if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
143.420 + // First compact case, we need not to preserve the character
143.421 + // and we can just compute the value in place.
143.422 + if (isCompact) {
143.423 + int digit = Character.digit(c, 10);
143.424 + if (digit == 0) {
143.425 + if (prec == 0)
143.426 + prec = 1;
143.427 + else if (rs != 0) {
143.428 + rs *= 10;
143.429 + ++prec;
143.430 + } // else digit is a redundant leading zero
143.431 + } else {
143.432 + if (prec != 1 || rs != 0)
143.433 + ++prec; // prec unchanged if preceded by 0s
143.434 + rs = rs * 10 + digit;
143.435 + }
143.436 + } else { // the unscaled value is likely a BigInteger object.
143.437 + if (c == '0' || Character.digit(c, 10) == 0) {
143.438 + if (prec == 0) {
143.439 + coeff[idx] = c;
143.440 + prec = 1;
143.441 + } else if (idx != 0) {
143.442 + coeff[idx++] = c;
143.443 + ++prec;
143.444 + } // else c must be a redundant leading zero
143.445 + } else {
143.446 + if (prec != 1 || idx != 0)
143.447 + ++prec; // prec unchanged if preceded by 0s
143.448 + coeff[idx++] = c;
143.449 + }
143.450 + }
143.451 + if (dot)
143.452 + ++scl;
143.453 + continue;
143.454 + }
143.455 + // have dot
143.456 + if (c == '.') {
143.457 + // have dot
143.458 + if (dot) // two dots
143.459 + throw new NumberFormatException();
143.460 + dot = true;
143.461 + continue;
143.462 + }
143.463 + // exponent expected
143.464 + if ((c != 'e') && (c != 'E'))
143.465 + throw new NumberFormatException();
143.466 + offset++;
143.467 + c = in[offset];
143.468 + len--;
143.469 + boolean negexp = (c == '-');
143.470 + // optional sign
143.471 + if (negexp || c == '+') {
143.472 + offset++;
143.473 + c = in[offset];
143.474 + len--;
143.475 + }
143.476 + if (len <= 0) // no exponent digits
143.477 + throw new NumberFormatException();
143.478 + // skip leading zeros in the exponent
143.479 + while (len > 10 && Character.digit(c, 10) == 0) {
143.480 + offset++;
143.481 + c = in[offset];
143.482 + len--;
143.483 + }
143.484 + if (len > 10) // too many nonzero exponent digits
143.485 + throw new NumberFormatException();
143.486 + // c now holds first digit of exponent
143.487 + for (;; len--) {
143.488 + int v;
143.489 + if (c >= '0' && c <= '9') {
143.490 + v = c - '0';
143.491 + } else {
143.492 + v = Character.digit(c, 10);
143.493 + if (v < 0) // not a digit
143.494 + throw new NumberFormatException();
143.495 + }
143.496 + exp = exp * 10 + v;
143.497 + if (len == 1)
143.498 + break; // that was final character
143.499 + offset++;
143.500 + c = in[offset];
143.501 + }
143.502 + if (negexp) // apply sign
143.503 + exp = -exp;
143.504 + // Next test is required for backwards compatibility
143.505 + if ((int)exp != exp) // overflow
143.506 + throw new NumberFormatException();
143.507 + break; // [saves a test]
143.508 + }
143.509 + // here when no characters left
143.510 + if (prec == 0) // no digits found
143.511 + throw new NumberFormatException();
143.512 +
143.513 + // Adjust scale if exp is not zero.
143.514 + if (exp != 0) { // had significant exponent
143.515 + // Can't call checkScale which relies on proper fields value
143.516 + long adjustedScale = scl - exp;
143.517 + if (adjustedScale > Integer.MAX_VALUE ||
143.518 + adjustedScale < Integer.MIN_VALUE)
143.519 + throw new NumberFormatException("Scale out of range.");
143.520 + scl = (int)adjustedScale;
143.521 + }
143.522 +
143.523 + // Remove leading zeros from precision (digits count)
143.524 + if (isCompact) {
143.525 + rs = isneg ? -rs : rs;
143.526 + } else {
143.527 + char quick[];
143.528 + if (!isneg) {
143.529 + quick = (coeff.length != prec) ?
143.530 + Arrays.copyOf(coeff, prec) : coeff;
143.531 + } else {
143.532 + quick = new char[prec + 1];
143.533 + quick[0] = '-';
143.534 + System.arraycopy(coeff, 0, quick, 1, prec);
143.535 + }
143.536 + rb = new BigInteger(quick);
143.537 + rs = compactValFor(rb);
143.538 + }
143.539 + } catch (ArrayIndexOutOfBoundsException e) {
143.540 + throw new NumberFormatException();
143.541 + } catch (NegativeArraySizeException e) {
143.542 + throw new NumberFormatException();
143.543 + }
143.544 + this.scale = scl;
143.545 + this.precision = prec;
143.546 + this.intCompact = rs;
143.547 + this.intVal = (rs != INFLATED) ? null : rb;
143.548 + }
143.549 +
143.550 + /**
143.551 + * Translates a character array representation of a
143.552 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
143.553 + * same sequence of characters as the {@link #BigDecimal(String)}
143.554 + * constructor, while allowing a sub-array to be specified and
143.555 + * with rounding according to the context settings.
143.556 + *
143.557 + * <p>Note that if the sequence of characters is already available
143.558 + * within a character array, using this constructor is faster than
143.559 + * converting the {@code char} array to string and using the
143.560 + * {@code BigDecimal(String)} constructor .
143.561 + *
143.562 + * @param in {@code char} array that is the source of characters.
143.563 + * @param offset first character in the array to inspect.
143.564 + * @param len number of characters to consider..
143.565 + * @param mc the context to use.
143.566 + * @throws ArithmeticException if the result is inexact but the
143.567 + * rounding mode is {@code UNNECESSARY}.
143.568 + * @throws NumberFormatException if {@code in} is not a valid
143.569 + * representation of a {@code BigDecimal} or the defined subarray
143.570 + * is not wholly within {@code in}.
143.571 + * @since 1.5
143.572 + */
143.573 + public BigDecimal(char[] in, int offset, int len, MathContext mc) {
143.574 + this(in, offset, len);
143.575 + if (mc.precision > 0)
143.576 + roundThis(mc);
143.577 + }
143.578 +
143.579 + /**
143.580 + * Translates a character array representation of a
143.581 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
143.582 + * same sequence of characters as the {@link #BigDecimal(String)}
143.583 + * constructor.
143.584 + *
143.585 + * <p>Note that if the sequence of characters is already available
143.586 + * as a character array, using this constructor is faster than
143.587 + * converting the {@code char} array to string and using the
143.588 + * {@code BigDecimal(String)} constructor .
143.589 + *
143.590 + * @param in {@code char} array that is the source of characters.
143.591 + * @throws NumberFormatException if {@code in} is not a valid
143.592 + * representation of a {@code BigDecimal}.
143.593 + * @since 1.5
143.594 + */
143.595 + public BigDecimal(char[] in) {
143.596 + this(in, 0, in.length);
143.597 + }
143.598 +
143.599 + /**
143.600 + * Translates a character array representation of a
143.601 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
143.602 + * same sequence of characters as the {@link #BigDecimal(String)}
143.603 + * constructor and with rounding according to the context
143.604 + * settings.
143.605 + *
143.606 + * <p>Note that if the sequence of characters is already available
143.607 + * as a character array, using this constructor is faster than
143.608 + * converting the {@code char} array to string and using the
143.609 + * {@code BigDecimal(String)} constructor .
143.610 + *
143.611 + * @param in {@code char} array that is the source of characters.
143.612 + * @param mc the context to use.
143.613 + * @throws ArithmeticException if the result is inexact but the
143.614 + * rounding mode is {@code UNNECESSARY}.
143.615 + * @throws NumberFormatException if {@code in} is not a valid
143.616 + * representation of a {@code BigDecimal}.
143.617 + * @since 1.5
143.618 + */
143.619 + public BigDecimal(char[] in, MathContext mc) {
143.620 + this(in, 0, in.length, mc);
143.621 + }
143.622 +
143.623 + /**
143.624 + * Translates the string representation of a {@code BigDecimal}
143.625 + * into a {@code BigDecimal}. The string representation consists
143.626 + * of an optional sign, {@code '+'} (<tt> '\u002B'</tt>) or
143.627 + * {@code '-'} (<tt>'\u002D'</tt>), followed by a sequence of
143.628 + * zero or more decimal digits ("the integer"), optionally
143.629 + * followed by a fraction, optionally followed by an exponent.
143.630 + *
143.631 + * <p>The fraction consists of a decimal point followed by zero
143.632 + * or more decimal digits. The string must contain at least one
143.633 + * digit in either the integer or the fraction. The number formed
143.634 + * by the sign, the integer and the fraction is referred to as the
143.635 + * <i>significand</i>.
143.636 + *
143.637 + * <p>The exponent consists of the character {@code 'e'}
143.638 + * (<tt>'\u0065'</tt>) or {@code 'E'} (<tt>'\u0045'</tt>)
143.639 + * followed by one or more decimal digits. The value of the
143.640 + * exponent must lie between -{@link Integer#MAX_VALUE} ({@link
143.641 + * Integer#MIN_VALUE}+1) and {@link Integer#MAX_VALUE}, inclusive.
143.642 + *
143.643 + * <p>More formally, the strings this constructor accepts are
143.644 + * described by the following grammar:
143.645 + * <blockquote>
143.646 + * <dl>
143.647 + * <dt><i>BigDecimalString:</i>
143.648 + * <dd><i>Sign<sub>opt</sub> Significand Exponent<sub>opt</sub></i>
143.649 + * <p>
143.650 + * <dt><i>Sign:</i>
143.651 + * <dd>{@code +}
143.652 + * <dd>{@code -}
143.653 + * <p>
143.654 + * <dt><i>Significand:</i>
143.655 + * <dd><i>IntegerPart</i> {@code .} <i>FractionPart<sub>opt</sub></i>
143.656 + * <dd>{@code .} <i>FractionPart</i>
143.657 + * <dd><i>IntegerPart</i>
143.658 + * <p>
143.659 + * <dt><i>IntegerPart:</i>
143.660 + * <dd><i>Digits</i>
143.661 + * <p>
143.662 + * <dt><i>FractionPart:</i>
143.663 + * <dd><i>Digits</i>
143.664 + * <p>
143.665 + * <dt><i>Exponent:</i>
143.666 + * <dd><i>ExponentIndicator SignedInteger</i>
143.667 + * <p>
143.668 + * <dt><i>ExponentIndicator:</i>
143.669 + * <dd>{@code e}
143.670 + * <dd>{@code E}
143.671 + * <p>
143.672 + * <dt><i>SignedInteger:</i>
143.673 + * <dd><i>Sign<sub>opt</sub> Digits</i>
143.674 + * <p>
143.675 + * <dt><i>Digits:</i>
143.676 + * <dd><i>Digit</i>
143.677 + * <dd><i>Digits Digit</i>
143.678 + * <p>
143.679 + * <dt><i>Digit:</i>
143.680 + * <dd>any character for which {@link Character#isDigit}
143.681 + * returns {@code true}, including 0, 1, 2 ...
143.682 + * </dl>
143.683 + * </blockquote>
143.684 + *
143.685 + * <p>The scale of the returned {@code BigDecimal} will be the
143.686 + * number of digits in the fraction, or zero if the string
143.687 + * contains no decimal point, subject to adjustment for any
143.688 + * exponent; if the string contains an exponent, the exponent is
143.689 + * subtracted from the scale. The value of the resulting scale
143.690 + * must lie between {@code Integer.MIN_VALUE} and
143.691 + * {@code Integer.MAX_VALUE}, inclusive.
143.692 + *
143.693 + * <p>The character-to-digit mapping is provided by {@link
143.694 + * java.lang.Character#digit} set to convert to radix 10. The
143.695 + * String may not contain any extraneous characters (whitespace,
143.696 + * for example).
143.697 + *
143.698 + * <p><b>Examples:</b><br>
143.699 + * The value of the returned {@code BigDecimal} is equal to
143.700 + * <i>significand</i> × 10<sup> <i>exponent</i></sup>.
143.701 + * For each string on the left, the resulting representation
143.702 + * [{@code BigInteger}, {@code scale}] is shown on the right.
143.703 + * <pre>
143.704 + * "0" [0,0]
143.705 + * "0.00" [0,2]
143.706 + * "123" [123,0]
143.707 + * "-123" [-123,0]
143.708 + * "1.23E3" [123,-1]
143.709 + * "1.23E+3" [123,-1]
143.710 + * "12.3E+7" [123,-6]
143.711 + * "12.0" [120,1]
143.712 + * "12.3" [123,1]
143.713 + * "0.00123" [123,5]
143.714 + * "-1.23E-12" [-123,14]
143.715 + * "1234.5E-4" [12345,5]
143.716 + * "0E+7" [0,-7]
143.717 + * "-0" [0,0]
143.718 + * </pre>
143.719 + *
143.720 + * <p>Note: For values other than {@code float} and
143.721 + * {@code double} NaN and ±Infinity, this constructor is
143.722 + * compatible with the values returned by {@link Float#toString}
143.723 + * and {@link Double#toString}. This is generally the preferred
143.724 + * way to convert a {@code float} or {@code double} into a
143.725 + * BigDecimal, as it doesn't suffer from the unpredictability of
143.726 + * the {@link #BigDecimal(double)} constructor.
143.727 + *
143.728 + * @param val String representation of {@code BigDecimal}.
143.729 + *
143.730 + * @throws NumberFormatException if {@code val} is not a valid
143.731 + * representation of a {@code BigDecimal}.
143.732 + */
143.733 + public BigDecimal(String val) {
143.734 + this(val.toCharArray(), 0, val.length());
143.735 + }
143.736 +
143.737 + /**
143.738 + * Translates the string representation of a {@code BigDecimal}
143.739 + * into a {@code BigDecimal}, accepting the same strings as the
143.740 + * {@link #BigDecimal(String)} constructor, with rounding
143.741 + * according to the context settings.
143.742 + *
143.743 + * @param val string representation of a {@code BigDecimal}.
143.744 + * @param mc the context to use.
143.745 + * @throws ArithmeticException if the result is inexact but the
143.746 + * rounding mode is {@code UNNECESSARY}.
143.747 + * @throws NumberFormatException if {@code val} is not a valid
143.748 + * representation of a BigDecimal.
143.749 + * @since 1.5
143.750 + */
143.751 + public BigDecimal(String val, MathContext mc) {
143.752 + this(val.toCharArray(), 0, val.length());
143.753 + if (mc.precision > 0)
143.754 + roundThis(mc);
143.755 + }
143.756 +
143.757 + /**
143.758 + * Translates a {@code double} into a {@code BigDecimal} which
143.759 + * is the exact decimal representation of the {@code double}'s
143.760 + * binary floating-point value. The scale of the returned
143.761 + * {@code BigDecimal} is the smallest value such that
143.762 + * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
143.763 + * <p>
143.764 + * <b>Notes:</b>
143.765 + * <ol>
143.766 + * <li>
143.767 + * The results of this constructor can be somewhat unpredictable.
143.768 + * One might assume that writing {@code new BigDecimal(0.1)} in
143.769 + * Java creates a {@code BigDecimal} which is exactly equal to
143.770 + * 0.1 (an unscaled value of 1, with a scale of 1), but it is
143.771 + * actually equal to
143.772 + * 0.1000000000000000055511151231257827021181583404541015625.
143.773 + * This is because 0.1 cannot be represented exactly as a
143.774 + * {@code double} (or, for that matter, as a binary fraction of
143.775 + * any finite length). Thus, the value that is being passed
143.776 + * <i>in</i> to the constructor is not exactly equal to 0.1,
143.777 + * appearances notwithstanding.
143.778 + *
143.779 + * <li>
143.780 + * The {@code String} constructor, on the other hand, is
143.781 + * perfectly predictable: writing {@code new BigDecimal("0.1")}
143.782 + * creates a {@code BigDecimal} which is <i>exactly</i> equal to
143.783 + * 0.1, as one would expect. Therefore, it is generally
143.784 + * recommended that the {@linkplain #BigDecimal(String)
143.785 + * <tt>String</tt> constructor} be used in preference to this one.
143.786 + *
143.787 + * <li>
143.788 + * When a {@code double} must be used as a source for a
143.789 + * {@code BigDecimal}, note that this constructor provides an
143.790 + * exact conversion; it does not give the same result as
143.791 + * converting the {@code double} to a {@code String} using the
143.792 + * {@link Double#toString(double)} method and then using the
143.793 + * {@link #BigDecimal(String)} constructor. To get that result,
143.794 + * use the {@code static} {@link #valueOf(double)} method.
143.795 + * </ol>
143.796 + *
143.797 + * @param val {@code double} value to be converted to
143.798 + * {@code BigDecimal}.
143.799 + * @throws NumberFormatException if {@code val} is infinite or NaN.
143.800 + */
143.801 + public BigDecimal(double val) {
143.802 + if (Double.isInfinite(val) || Double.isNaN(val))
143.803 + throw new NumberFormatException("Infinite or NaN");
143.804 +
143.805 + // Translate the double into sign, exponent and significand, according
143.806 + // to the formulae in JLS, Section 20.10.22.
143.807 + long valBits = Double.doubleToLongBits(val);
143.808 + int sign = ((valBits >> 63)==0 ? 1 : -1);
143.809 + int exponent = (int) ((valBits >> 52) & 0x7ffL);
143.810 + long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
143.811 + : (valBits & ((1L<<52) - 1)) | (1L<<52));
143.812 + exponent -= 1075;
143.813 + // At this point, val == sign * significand * 2**exponent.
143.814 +
143.815 + /*
143.816 + * Special case zero to supress nonterminating normalization
143.817 + * and bogus scale calculation.
143.818 + */
143.819 + if (significand == 0) {
143.820 + intVal = BigInteger.ZERO;
143.821 + intCompact = 0;
143.822 + precision = 1;
143.823 + return;
143.824 + }
143.825 +
143.826 + // Normalize
143.827 + while((significand & 1) == 0) { // i.e., significand is even
143.828 + significand >>= 1;
143.829 + exponent++;
143.830 + }
143.831 +
143.832 + // Calculate intVal and scale
143.833 + long s = sign * significand;
143.834 + BigInteger b;
143.835 + if (exponent < 0) {
143.836 + b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
143.837 + scale = -exponent;
143.838 + } else if (exponent > 0) {
143.839 + b = BigInteger.valueOf(2).pow(exponent).multiply(s);
143.840 + } else {
143.841 + b = BigInteger.valueOf(s);
143.842 + }
143.843 + intCompact = compactValFor(b);
143.844 + intVal = (intCompact != INFLATED) ? null : b;
143.845 + }
143.846 +
143.847 + /**
143.848 + * Translates a {@code double} into a {@code BigDecimal}, with
143.849 + * rounding according to the context settings. The scale of the
143.850 + * {@code BigDecimal} is the smallest value such that
143.851 + * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
143.852 + *
143.853 + * <p>The results of this constructor can be somewhat unpredictable
143.854 + * and its use is generally not recommended; see the notes under
143.855 + * the {@link #BigDecimal(double)} constructor.
143.856 + *
143.857 + * @param val {@code double} value to be converted to
143.858 + * {@code BigDecimal}.
143.859 + * @param mc the context to use.
143.860 + * @throws ArithmeticException if the result is inexact but the
143.861 + * RoundingMode is UNNECESSARY.
143.862 + * @throws NumberFormatException if {@code val} is infinite or NaN.
143.863 + * @since 1.5
143.864 + */
143.865 + public BigDecimal(double val, MathContext mc) {
143.866 + this(val);
143.867 + if (mc.precision > 0)
143.868 + roundThis(mc);
143.869 + }
143.870 +
143.871 + /**
143.872 + * Translates a {@code BigInteger} into a {@code BigDecimal}.
143.873 + * The scale of the {@code BigDecimal} is zero.
143.874 + *
143.875 + * @param val {@code BigInteger} value to be converted to
143.876 + * {@code BigDecimal}.
143.877 + */
143.878 + public BigDecimal(BigInteger val) {
143.879 + intCompact = compactValFor(val);
143.880 + intVal = (intCompact != INFLATED) ? null : val;
143.881 + }
143.882 +
143.883 + /**
143.884 + * Translates a {@code BigInteger} into a {@code BigDecimal}
143.885 + * rounding according to the context settings. The scale of the
143.886 + * {@code BigDecimal} is zero.
143.887 + *
143.888 + * @param val {@code BigInteger} value to be converted to
143.889 + * {@code BigDecimal}.
143.890 + * @param mc the context to use.
143.891 + * @throws ArithmeticException if the result is inexact but the
143.892 + * rounding mode is {@code UNNECESSARY}.
143.893 + * @since 1.5
143.894 + */
143.895 + public BigDecimal(BigInteger val, MathContext mc) {
143.896 + this(val);
143.897 + if (mc.precision > 0)
143.898 + roundThis(mc);
143.899 + }
143.900 +
143.901 + /**
143.902 + * Translates a {@code BigInteger} unscaled value and an
143.903 + * {@code int} scale into a {@code BigDecimal}. The value of
143.904 + * the {@code BigDecimal} is
143.905 + * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
143.906 + *
143.907 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
143.908 + * @param scale scale of the {@code BigDecimal}.
143.909 + */
143.910 + public BigDecimal(BigInteger unscaledVal, int scale) {
143.911 + // Negative scales are now allowed
143.912 + this(unscaledVal);
143.913 + this.scale = scale;
143.914 + }
143.915 +
143.916 + /**
143.917 + * Translates a {@code BigInteger} unscaled value and an
143.918 + * {@code int} scale into a {@code BigDecimal}, with rounding
143.919 + * according to the context settings. The value of the
143.920 + * {@code BigDecimal} is <tt>(unscaledVal ×
143.921 + * 10<sup>-scale</sup>)</tt>, rounded according to the
143.922 + * {@code precision} and rounding mode settings.
143.923 + *
143.924 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
143.925 + * @param scale scale of the {@code BigDecimal}.
143.926 + * @param mc the context to use.
143.927 + * @throws ArithmeticException if the result is inexact but the
143.928 + * rounding mode is {@code UNNECESSARY}.
143.929 + * @since 1.5
143.930 + */
143.931 + public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
143.932 + this(unscaledVal);
143.933 + this.scale = scale;
143.934 + if (mc.precision > 0)
143.935 + roundThis(mc);
143.936 + }
143.937 +
143.938 + /**
143.939 + * Translates an {@code int} into a {@code BigDecimal}. The
143.940 + * scale of the {@code BigDecimal} is zero.
143.941 + *
143.942 + * @param val {@code int} value to be converted to
143.943 + * {@code BigDecimal}.
143.944 + * @since 1.5
143.945 + */
143.946 + public BigDecimal(int val) {
143.947 + intCompact = val;
143.948 + }
143.949 +
143.950 + /**
143.951 + * Translates an {@code int} into a {@code BigDecimal}, with
143.952 + * rounding according to the context settings. The scale of the
143.953 + * {@code BigDecimal}, before any rounding, is zero.
143.954 + *
143.955 + * @param val {@code int} value to be converted to {@code BigDecimal}.
143.956 + * @param mc the context to use.
143.957 + * @throws ArithmeticException if the result is inexact but the
143.958 + * rounding mode is {@code UNNECESSARY}.
143.959 + * @since 1.5
143.960 + */
143.961 + public BigDecimal(int val, MathContext mc) {
143.962 + intCompact = val;
143.963 + if (mc.precision > 0)
143.964 + roundThis(mc);
143.965 + }
143.966 +
143.967 + /**
143.968 + * Translates a {@code long} into a {@code BigDecimal}. The
143.969 + * scale of the {@code BigDecimal} is zero.
143.970 + *
143.971 + * @param val {@code long} value to be converted to {@code BigDecimal}.
143.972 + * @since 1.5
143.973 + */
143.974 + public BigDecimal(long val) {
143.975 + this.intCompact = val;
143.976 + this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
143.977 + }
143.978 +
143.979 + /**
143.980 + * Translates a {@code long} into a {@code BigDecimal}, with
143.981 + * rounding according to the context settings. The scale of the
143.982 + * {@code BigDecimal}, before any rounding, is zero.
143.983 + *
143.984 + * @param val {@code long} value to be converted to {@code BigDecimal}.
143.985 + * @param mc the context to use.
143.986 + * @throws ArithmeticException if the result is inexact but the
143.987 + * rounding mode is {@code UNNECESSARY}.
143.988 + * @since 1.5
143.989 + */
143.990 + public BigDecimal(long val, MathContext mc) {
143.991 + this(val);
143.992 + if (mc.precision > 0)
143.993 + roundThis(mc);
143.994 + }
143.995 +
143.996 + // Static Factory Methods
143.997 +
143.998 + /**
143.999 + * Translates a {@code long} unscaled value and an
143.1000 + * {@code int} scale into a {@code BigDecimal}. This
143.1001 + * {@literal "static factory method"} is provided in preference to
143.1002 + * a ({@code long}, {@code int}) constructor because it
143.1003 + * allows for reuse of frequently used {@code BigDecimal} values..
143.1004 + *
143.1005 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
143.1006 + * @param scale scale of the {@code BigDecimal}.
143.1007 + * @return a {@code BigDecimal} whose value is
143.1008 + * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
143.1009 + */
143.1010 + public static BigDecimal valueOf(long unscaledVal, int scale) {
143.1011 + if (scale == 0)
143.1012 + return valueOf(unscaledVal);
143.1013 + else if (unscaledVal == 0) {
143.1014 + if (scale > 0 && scale < ZERO_SCALED_BY.length)
143.1015 + return ZERO_SCALED_BY[scale];
143.1016 + else
143.1017 + return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
143.1018 + }
143.1019 + return new BigDecimal(unscaledVal == INFLATED ?
143.1020 + BigInteger.valueOf(unscaledVal) : null,
143.1021 + unscaledVal, scale, 0);
143.1022 + }
143.1023 +
143.1024 + /**
143.1025 + * Translates a {@code long} value into a {@code BigDecimal}
143.1026 + * with a scale of zero. This {@literal "static factory method"}
143.1027 + * is provided in preference to a ({@code long}) constructor
143.1028 + * because it allows for reuse of frequently used
143.1029 + * {@code BigDecimal} values.
143.1030 + *
143.1031 + * @param val value of the {@code BigDecimal}.
143.1032 + * @return a {@code BigDecimal} whose value is {@code val}.
143.1033 + */
143.1034 + public static BigDecimal valueOf(long val) {
143.1035 + if (val >= 0 && val < zeroThroughTen.length)
143.1036 + return zeroThroughTen[(int)val];
143.1037 + else if (val != INFLATED)
143.1038 + return new BigDecimal(null, val, 0, 0);
143.1039 + return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
143.1040 + }
143.1041 +
143.1042 + /**
143.1043 + * Translates a {@code double} into a {@code BigDecimal}, using
143.1044 + * the {@code double}'s canonical string representation provided
143.1045 + * by the {@link Double#toString(double)} method.
143.1046 + *
143.1047 + * <p><b>Note:</b> This is generally the preferred way to convert
143.1048 + * a {@code double} (or {@code float}) into a
143.1049 + * {@code BigDecimal}, as the value returned is equal to that
143.1050 + * resulting from constructing a {@code BigDecimal} from the
143.1051 + * result of using {@link Double#toString(double)}.
143.1052 + *
143.1053 + * @param val {@code double} to convert to a {@code BigDecimal}.
143.1054 + * @return a {@code BigDecimal} whose value is equal to or approximately
143.1055 + * equal to the value of {@code val}.
143.1056 + * @throws NumberFormatException if {@code val} is infinite or NaN.
143.1057 + * @since 1.5
143.1058 + */
143.1059 + public static BigDecimal valueOf(double val) {
143.1060 + // Reminder: a zero double returns '0.0', so we cannot fastpath
143.1061 + // to use the constant ZERO. This might be important enough to
143.1062 + // justify a factory approach, a cache, or a few private
143.1063 + // constants, later.
143.1064 + return new BigDecimal(Double.toString(val));
143.1065 + }
143.1066 +
143.1067 + // Arithmetic Operations
143.1068 + /**
143.1069 + * Returns a {@code BigDecimal} whose value is {@code (this +
143.1070 + * augend)}, and whose scale is {@code max(this.scale(),
143.1071 + * augend.scale())}.
143.1072 + *
143.1073 + * @param augend value to be added to this {@code BigDecimal}.
143.1074 + * @return {@code this + augend}
143.1075 + */
143.1076 + public BigDecimal add(BigDecimal augend) {
143.1077 + long xs = this.intCompact;
143.1078 + long ys = augend.intCompact;
143.1079 + BigInteger fst = (xs != INFLATED) ? null : this.intVal;
143.1080 + BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
143.1081 + int rscale = this.scale;
143.1082 +
143.1083 + long sdiff = (long)rscale - augend.scale;
143.1084 + if (sdiff != 0) {
143.1085 + if (sdiff < 0) {
143.1086 + int raise = checkScale(-sdiff);
143.1087 + rscale = augend.scale;
143.1088 + if (xs == INFLATED ||
143.1089 + (xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
143.1090 + fst = bigMultiplyPowerTen(raise);
143.1091 + } else {
143.1092 + int raise = augend.checkScale(sdiff);
143.1093 + if (ys == INFLATED ||
143.1094 + (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
143.1095 + snd = augend.bigMultiplyPowerTen(raise);
143.1096 + }
143.1097 + }
143.1098 + if (xs != INFLATED && ys != INFLATED) {
143.1099 + long sum = xs + ys;
143.1100 + // See "Hacker's Delight" section 2-12 for explanation of
143.1101 + // the overflow test.
143.1102 + if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
143.1103 + return BigDecimal.valueOf(sum, rscale);
143.1104 + }
143.1105 + if (fst == null)
143.1106 + fst = BigInteger.valueOf(xs);
143.1107 + if (snd == null)
143.1108 + snd = BigInteger.valueOf(ys);
143.1109 + BigInteger sum = fst.add(snd);
143.1110 + return (fst.signum == snd.signum) ?
143.1111 + new BigDecimal(sum, INFLATED, rscale, 0) :
143.1112 + new BigDecimal(sum, rscale);
143.1113 + }
143.1114 +
143.1115 + /**
143.1116 + * Returns a {@code BigDecimal} whose value is {@code (this + augend)},
143.1117 + * with rounding according to the context settings.
143.1118 + *
143.1119 + * If either number is zero and the precision setting is nonzero then
143.1120 + * the other number, rounded if necessary, is used as the result.
143.1121 + *
143.1122 + * @param augend value to be added to this {@code BigDecimal}.
143.1123 + * @param mc the context to use.
143.1124 + * @return {@code this + augend}, rounded as necessary.
143.1125 + * @throws ArithmeticException if the result is inexact but the
143.1126 + * rounding mode is {@code UNNECESSARY}.
143.1127 + * @since 1.5
143.1128 + */
143.1129 + public BigDecimal add(BigDecimal augend, MathContext mc) {
143.1130 + if (mc.precision == 0)
143.1131 + return add(augend);
143.1132 + BigDecimal lhs = this;
143.1133 +
143.1134 + // Could optimize if values are compact
143.1135 + this.inflate();
143.1136 + augend.inflate();
143.1137 +
143.1138 + // If either number is zero then the other number, rounded and
143.1139 + // scaled if necessary, is used as the result.
143.1140 + {
143.1141 + boolean lhsIsZero = lhs.signum() == 0;
143.1142 + boolean augendIsZero = augend.signum() == 0;
143.1143 +
143.1144 + if (lhsIsZero || augendIsZero) {
143.1145 + int preferredScale = Math.max(lhs.scale(), augend.scale());
143.1146 + BigDecimal result;
143.1147 +
143.1148 + // Could use a factory for zero instead of a new object
143.1149 + if (lhsIsZero && augendIsZero)
143.1150 + return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
143.1151 +
143.1152 + result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
143.1153 +
143.1154 + if (result.scale() == preferredScale)
143.1155 + return result;
143.1156 + else if (result.scale() > preferredScale) {
143.1157 + BigDecimal scaledResult =
143.1158 + new BigDecimal(result.intVal, result.intCompact,
143.1159 + result.scale, 0);
143.1160 + scaledResult.stripZerosToMatchScale(preferredScale);
143.1161 + return scaledResult;
143.1162 + } else { // result.scale < preferredScale
143.1163 + int precisionDiff = mc.precision - result.precision();
143.1164 + int scaleDiff = preferredScale - result.scale();
143.1165 +
143.1166 + if (precisionDiff >= scaleDiff)
143.1167 + return result.setScale(preferredScale); // can achieve target scale
143.1168 + else
143.1169 + return result.setScale(result.scale() + precisionDiff);
143.1170 + }
143.1171 + }
143.1172 + }
143.1173 +
143.1174 + long padding = (long)lhs.scale - augend.scale;
143.1175 + if (padding != 0) { // scales differ; alignment needed
143.1176 + BigDecimal arg[] = preAlign(lhs, augend, padding, mc);
143.1177 + matchScale(arg);
143.1178 + lhs = arg[0];
143.1179 + augend = arg[1];
143.1180 + }
143.1181 +
143.1182 + BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
143.1183 + lhs.scale);
143.1184 + return doRound(d, mc);
143.1185 + }
143.1186 +
143.1187 + /**
143.1188 + * Returns an array of length two, the sum of whose entries is
143.1189 + * equal to the rounded sum of the {@code BigDecimal} arguments.
143.1190 + *
143.1191 + * <p>If the digit positions of the arguments have a sufficient
143.1192 + * gap between them, the value smaller in magnitude can be
143.1193 + * condensed into a {@literal "sticky bit"} and the end result will
143.1194 + * round the same way <em>if</em> the precision of the final
143.1195 + * result does not include the high order digit of the small
143.1196 + * magnitude operand.
143.1197 + *
143.1198 + * <p>Note that while strictly speaking this is an optimization,
143.1199 + * it makes a much wider range of additions practical.
143.1200 + *
143.1201 + * <p>This corresponds to a pre-shift operation in a fixed
143.1202 + * precision floating-point adder; this method is complicated by
143.1203 + * variable precision of the result as determined by the
143.1204 + * MathContext. A more nuanced operation could implement a
143.1205 + * {@literal "right shift"} on the smaller magnitude operand so
143.1206 + * that the number of digits of the smaller operand could be
143.1207 + * reduced even though the significands partially overlapped.
143.1208 + */
143.1209 + private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend,
143.1210 + long padding, MathContext mc) {
143.1211 + assert padding != 0;
143.1212 + BigDecimal big;
143.1213 + BigDecimal small;
143.1214 +
143.1215 + if (padding < 0) { // lhs is big; augend is small
143.1216 + big = lhs;
143.1217 + small = augend;
143.1218 + } else { // lhs is small; augend is big
143.1219 + big = augend;
143.1220 + small = lhs;
143.1221 + }
143.1222 +
143.1223 + /*
143.1224 + * This is the estimated scale of an ulp of the result; it
143.1225 + * assumes that the result doesn't have a carry-out on a true
143.1226 + * add (e.g. 999 + 1 => 1000) or any subtractive cancellation
143.1227 + * on borrowing (e.g. 100 - 1.2 => 98.8)
143.1228 + */
143.1229 + long estResultUlpScale = (long)big.scale - big.precision() + mc.precision;
143.1230 +
143.1231 + /*
143.1232 + * The low-order digit position of big is big.scale(). This
143.1233 + * is true regardless of whether big has a positive or
143.1234 + * negative scale. The high-order digit position of small is
143.1235 + * small.scale - (small.precision() - 1). To do the full
143.1236 + * condensation, the digit positions of big and small must be
143.1237 + * disjoint *and* the digit positions of small should not be
143.1238 + * directly visible in the result.
143.1239 + */
143.1240 + long smallHighDigitPos = (long)small.scale - small.precision() + 1;
143.1241 + if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
143.1242 + smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible
143.1243 + small = BigDecimal.valueOf(small.signum(),
143.1244 + this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
143.1245 + }
143.1246 +
143.1247 + // Since addition is symmetric, preserving input order in
143.1248 + // returned operands doesn't matter
143.1249 + BigDecimal[] result = {big, small};
143.1250 + return result;
143.1251 + }
143.1252 +
143.1253 + /**
143.1254 + * Returns a {@code BigDecimal} whose value is {@code (this -
143.1255 + * subtrahend)}, and whose scale is {@code max(this.scale(),
143.1256 + * subtrahend.scale())}.
143.1257 + *
143.1258 + * @param subtrahend value to be subtracted from this {@code BigDecimal}.
143.1259 + * @return {@code this - subtrahend}
143.1260 + */
143.1261 + public BigDecimal subtract(BigDecimal subtrahend) {
143.1262 + return add(subtrahend.negate());
143.1263 + }
143.1264 +
143.1265 + /**
143.1266 + * Returns a {@code BigDecimal} whose value is {@code (this - subtrahend)},
143.1267 + * with rounding according to the context settings.
143.1268 + *
143.1269 + * If {@code subtrahend} is zero then this, rounded if necessary, is used as the
143.1270 + * result. If this is zero then the result is {@code subtrahend.negate(mc)}.
143.1271 + *
143.1272 + * @param subtrahend value to be subtracted from this {@code BigDecimal}.
143.1273 + * @param mc the context to use.
143.1274 + * @return {@code this - subtrahend}, rounded as necessary.
143.1275 + * @throws ArithmeticException if the result is inexact but the
143.1276 + * rounding mode is {@code UNNECESSARY}.
143.1277 + * @since 1.5
143.1278 + */
143.1279 + public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
143.1280 + BigDecimal nsubtrahend = subtrahend.negate();
143.1281 + if (mc.precision == 0)
143.1282 + return add(nsubtrahend);
143.1283 + // share the special rounding code in add()
143.1284 + return add(nsubtrahend, mc);
143.1285 + }
143.1286 +
143.1287 + /**
143.1288 + * Returns a {@code BigDecimal} whose value is <tt>(this ×
143.1289 + * multiplicand)</tt>, and whose scale is {@code (this.scale() +
143.1290 + * multiplicand.scale())}.
143.1291 + *
143.1292 + * @param multiplicand value to be multiplied by this {@code BigDecimal}.
143.1293 + * @return {@code this * multiplicand}
143.1294 + */
143.1295 + public BigDecimal multiply(BigDecimal multiplicand) {
143.1296 + long x = this.intCompact;
143.1297 + long y = multiplicand.intCompact;
143.1298 + int productScale = checkScale((long)scale + multiplicand.scale);
143.1299 +
143.1300 + // Might be able to do a more clever check incorporating the
143.1301 + // inflated check into the overflow computation.
143.1302 + if (x != INFLATED && y != INFLATED) {
143.1303 + /*
143.1304 + * If the product is not an overflowed value, continue
143.1305 + * to use the compact representation. if either of x or y
143.1306 + * is INFLATED, the product should also be regarded as
143.1307 + * an overflow. Before using the overflow test suggested in
143.1308 + * "Hacker's Delight" section 2-12, we perform quick checks
143.1309 + * using the precision information to see whether the overflow
143.1310 + * would occur since division is expensive on most CPUs.
143.1311 + */
143.1312 + long product = x * y;
143.1313 + long prec = this.precision() + multiplicand.precision();
143.1314 + if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
143.1315 + return BigDecimal.valueOf(product, productScale);
143.1316 + return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
143.1317 + productScale, 0);
143.1318 + }
143.1319 + BigInteger rb;
143.1320 + if (x == INFLATED && y == INFLATED)
143.1321 + rb = this.intVal.multiply(multiplicand.intVal);
143.1322 + else if (x != INFLATED)
143.1323 + rb = multiplicand.intVal.multiply(x);
143.1324 + else
143.1325 + rb = this.intVal.multiply(y);
143.1326 + return new BigDecimal(rb, INFLATED, productScale, 0);
143.1327 + }
143.1328 +
143.1329 + /**
143.1330 + * Returns a {@code BigDecimal} whose value is <tt>(this ×
143.1331 + * multiplicand)</tt>, with rounding according to the context settings.
143.1332 + *
143.1333 + * @param multiplicand value to be multiplied by this {@code BigDecimal}.
143.1334 + * @param mc the context to use.
143.1335 + * @return {@code this * multiplicand}, rounded as necessary.
143.1336 + * @throws ArithmeticException if the result is inexact but the
143.1337 + * rounding mode is {@code UNNECESSARY}.
143.1338 + * @since 1.5
143.1339 + */
143.1340 + public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
143.1341 + if (mc.precision == 0)
143.1342 + return multiply(multiplicand);
143.1343 + return doRound(this.multiply(multiplicand), mc);
143.1344 + }
143.1345 +
143.1346 + /**
143.1347 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1348 + * divisor)}, and whose scale is as specified. If rounding must
143.1349 + * be performed to generate a result with the specified scale, the
143.1350 + * specified rounding mode is applied.
143.1351 + *
143.1352 + * <p>The new {@link #divide(BigDecimal, int, RoundingMode)} method
143.1353 + * should be used in preference to this legacy method.
143.1354 + *
143.1355 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1356 + * @param scale scale of the {@code BigDecimal} quotient to be returned.
143.1357 + * @param roundingMode rounding mode to apply.
143.1358 + * @return {@code this / divisor}
143.1359 + * @throws ArithmeticException if {@code divisor} is zero,
143.1360 + * {@code roundingMode==ROUND_UNNECESSARY} and
143.1361 + * the specified scale is insufficient to represent the result
143.1362 + * of the division exactly.
143.1363 + * @throws IllegalArgumentException if {@code roundingMode} does not
143.1364 + * represent a valid rounding mode.
143.1365 + * @see #ROUND_UP
143.1366 + * @see #ROUND_DOWN
143.1367 + * @see #ROUND_CEILING
143.1368 + * @see #ROUND_FLOOR
143.1369 + * @see #ROUND_HALF_UP
143.1370 + * @see #ROUND_HALF_DOWN
143.1371 + * @see #ROUND_HALF_EVEN
143.1372 + * @see #ROUND_UNNECESSARY
143.1373 + */
143.1374 + public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
143.1375 + /*
143.1376 + * IMPLEMENTATION NOTE: This method *must* return a new object
143.1377 + * since divideAndRound uses divide to generate a value whose
143.1378 + * scale is then modified.
143.1379 + */
143.1380 + if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
143.1381 + throw new IllegalArgumentException("Invalid rounding mode");
143.1382 + /*
143.1383 + * Rescale dividend or divisor (whichever can be "upscaled" to
143.1384 + * produce correctly scaled quotient).
143.1385 + * Take care to detect out-of-range scales
143.1386 + */
143.1387 + BigDecimal dividend = this;
143.1388 + if (checkScale((long)scale + divisor.scale) > this.scale)
143.1389 + dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
143.1390 + else
143.1391 + divisor = divisor.setScale(checkScale((long)this.scale - scale),
143.1392 + ROUND_UNNECESSARY);
143.1393 + return divideAndRound(dividend.intCompact, dividend.intVal,
143.1394 + divisor.intCompact, divisor.intVal,
143.1395 + scale, roundingMode, scale);
143.1396 + }
143.1397 +
143.1398 + /**
143.1399 + * Internally used for division operation. The dividend and divisor are
143.1400 + * passed both in {@code long} format and {@code BigInteger} format. The
143.1401 + * returned {@code BigDecimal} object is the quotient whose scale is set to
143.1402 + * the passed in scale. If the remainder is not zero, it will be rounded
143.1403 + * based on the passed in roundingMode. Also, if the remainder is zero and
143.1404 + * the last parameter, i.e. preferredScale is NOT equal to scale, the
143.1405 + * trailing zeros of the result is stripped to match the preferredScale.
143.1406 + */
143.1407 + private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
143.1408 + long ldivisor, BigInteger bdivisor,
143.1409 + int scale, int roundingMode,
143.1410 + int preferredScale) {
143.1411 + boolean isRemainderZero; // record remainder is zero or not
143.1412 + int qsign; // quotient sign
143.1413 + long q = 0, r = 0; // store quotient & remainder in long
143.1414 + MutableBigInteger mq = null; // store quotient
143.1415 + MutableBigInteger mr = null; // store remainder
143.1416 + MutableBigInteger mdivisor = null;
143.1417 + boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
143.1418 + if (isLongDivision) {
143.1419 + q = ldividend / ldivisor;
143.1420 + if (roundingMode == ROUND_DOWN && scale == preferredScale)
143.1421 + return new BigDecimal(null, q, scale, 0);
143.1422 + r = ldividend % ldivisor;
143.1423 + isRemainderZero = (r == 0);
143.1424 + qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
143.1425 + } else {
143.1426 + if (bdividend == null)
143.1427 + bdividend = BigInteger.valueOf(ldividend);
143.1428 + // Descend into mutables for faster remainder checks
143.1429 + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
143.1430 + mq = new MutableBigInteger();
143.1431 + if (ldivisor != INFLATED) {
143.1432 + r = mdividend.divide(ldivisor, mq);
143.1433 + isRemainderZero = (r == 0);
143.1434 + qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
143.1435 + } else {
143.1436 + mdivisor = new MutableBigInteger(bdivisor.mag);
143.1437 + mr = mdividend.divide(mdivisor, mq);
143.1438 + isRemainderZero = mr.isZero();
143.1439 + qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
143.1440 + }
143.1441 + }
143.1442 + boolean increment = false;
143.1443 + if (!isRemainderZero) {
143.1444 + int cmpFracHalf;
143.1445 + /* Round as appropriate */
143.1446 + if (roundingMode == ROUND_UNNECESSARY) { // Rounding prohibited
143.1447 + throw new ArithmeticException("Rounding necessary");
143.1448 + } else if (roundingMode == ROUND_UP) { // Away from zero
143.1449 + increment = true;
143.1450 + } else if (roundingMode == ROUND_DOWN) { // Towards zero
143.1451 + increment = false;
143.1452 + } else if (roundingMode == ROUND_CEILING) { // Towards +infinity
143.1453 + increment = (qsign > 0);
143.1454 + } else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
143.1455 + increment = (qsign < 0);
143.1456 + } else {
143.1457 + if (isLongDivision || ldivisor != INFLATED) {
143.1458 + if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
143.1459 + cmpFracHalf = 1; // 2 * r can't fit into long
143.1460 + } else {
143.1461 + cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
143.1462 + }
143.1463 + } else {
143.1464 + cmpFracHalf = mr.compareHalf(mdivisor);
143.1465 + }
143.1466 + if (cmpFracHalf < 0)
143.1467 + increment = false; // We're closer to higher digit
143.1468 + else if (cmpFracHalf > 0) // We're closer to lower digit
143.1469 + increment = true;
143.1470 + else if (roundingMode == ROUND_HALF_UP)
143.1471 + increment = true;
143.1472 + else if (roundingMode == ROUND_HALF_DOWN)
143.1473 + increment = false;
143.1474 + else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
143.1475 + increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
143.1476 + }
143.1477 + }
143.1478 + BigDecimal res;
143.1479 + if (isLongDivision)
143.1480 + res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
143.1481 + else {
143.1482 + if (increment)
143.1483 + mq.add(MutableBigInteger.ONE);
143.1484 + res = mq.toBigDecimal(qsign, scale);
143.1485 + }
143.1486 + if (isRemainderZero && preferredScale != scale)
143.1487 + res.stripZerosToMatchScale(preferredScale);
143.1488 + return res;
143.1489 + }
143.1490 +
143.1491 + /**
143.1492 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1493 + * divisor)}, and whose scale is as specified. If rounding must
143.1494 + * be performed to generate a result with the specified scale, the
143.1495 + * specified rounding mode is applied.
143.1496 + *
143.1497 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1498 + * @param scale scale of the {@code BigDecimal} quotient to be returned.
143.1499 + * @param roundingMode rounding mode to apply.
143.1500 + * @return {@code this / divisor}
143.1501 + * @throws ArithmeticException if {@code divisor} is zero,
143.1502 + * {@code roundingMode==RoundingMode.UNNECESSARY} and
143.1503 + * the specified scale is insufficient to represent the result
143.1504 + * of the division exactly.
143.1505 + * @since 1.5
143.1506 + */
143.1507 + public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
143.1508 + return divide(divisor, scale, roundingMode.oldMode);
143.1509 + }
143.1510 +
143.1511 + /**
143.1512 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1513 + * divisor)}, and whose scale is {@code this.scale()}. If
143.1514 + * rounding must be performed to generate a result with the given
143.1515 + * scale, the specified rounding mode is applied.
143.1516 + *
143.1517 + * <p>The new {@link #divide(BigDecimal, RoundingMode)} method
143.1518 + * should be used in preference to this legacy method.
143.1519 + *
143.1520 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1521 + * @param roundingMode rounding mode to apply.
143.1522 + * @return {@code this / divisor}
143.1523 + * @throws ArithmeticException if {@code divisor==0}, or
143.1524 + * {@code roundingMode==ROUND_UNNECESSARY} and
143.1525 + * {@code this.scale()} is insufficient to represent the result
143.1526 + * of the division exactly.
143.1527 + * @throws IllegalArgumentException if {@code roundingMode} does not
143.1528 + * represent a valid rounding mode.
143.1529 + * @see #ROUND_UP
143.1530 + * @see #ROUND_DOWN
143.1531 + * @see #ROUND_CEILING
143.1532 + * @see #ROUND_FLOOR
143.1533 + * @see #ROUND_HALF_UP
143.1534 + * @see #ROUND_HALF_DOWN
143.1535 + * @see #ROUND_HALF_EVEN
143.1536 + * @see #ROUND_UNNECESSARY
143.1537 + */
143.1538 + public BigDecimal divide(BigDecimal divisor, int roundingMode) {
143.1539 + return this.divide(divisor, scale, roundingMode);
143.1540 + }
143.1541 +
143.1542 + /**
143.1543 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1544 + * divisor)}, and whose scale is {@code this.scale()}. If
143.1545 + * rounding must be performed to generate a result with the given
143.1546 + * scale, the specified rounding mode is applied.
143.1547 + *
143.1548 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1549 + * @param roundingMode rounding mode to apply.
143.1550 + * @return {@code this / divisor}
143.1551 + * @throws ArithmeticException if {@code divisor==0}, or
143.1552 + * {@code roundingMode==RoundingMode.UNNECESSARY} and
143.1553 + * {@code this.scale()} is insufficient to represent the result
143.1554 + * of the division exactly.
143.1555 + * @since 1.5
143.1556 + */
143.1557 + public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) {
143.1558 + return this.divide(divisor, scale, roundingMode.oldMode);
143.1559 + }
143.1560 +
143.1561 + /**
143.1562 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1563 + * divisor)}, and whose preferred scale is {@code (this.scale() -
143.1564 + * divisor.scale())}; if the exact quotient cannot be
143.1565 + * represented (because it has a non-terminating decimal
143.1566 + * expansion) an {@code ArithmeticException} is thrown.
143.1567 + *
143.1568 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1569 + * @throws ArithmeticException if the exact quotient does not have a
143.1570 + * terminating decimal expansion
143.1571 + * @return {@code this / divisor}
143.1572 + * @since 1.5
143.1573 + * @author Joseph D. Darcy
143.1574 + */
143.1575 + public BigDecimal divide(BigDecimal divisor) {
143.1576 + /*
143.1577 + * Handle zero cases first.
143.1578 + */
143.1579 + if (divisor.signum() == 0) { // x/0
143.1580 + if (this.signum() == 0) // 0/0
143.1581 + throw new ArithmeticException("Division undefined"); // NaN
143.1582 + throw new ArithmeticException("Division by zero");
143.1583 + }
143.1584 +
143.1585 + // Calculate preferred scale
143.1586 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
143.1587 + if (this.signum() == 0) // 0/y
143.1588 + return (preferredScale >= 0 &&
143.1589 + preferredScale < ZERO_SCALED_BY.length) ?
143.1590 + ZERO_SCALED_BY[preferredScale] :
143.1591 + BigDecimal.valueOf(0, preferredScale);
143.1592 + else {
143.1593 + this.inflate();
143.1594 + divisor.inflate();
143.1595 + /*
143.1596 + * If the quotient this/divisor has a terminating decimal
143.1597 + * expansion, the expansion can have no more than
143.1598 + * (a.precision() + ceil(10*b.precision)/3) digits.
143.1599 + * Therefore, create a MathContext object with this
143.1600 + * precision and do a divide with the UNNECESSARY rounding
143.1601 + * mode.
143.1602 + */
143.1603 + MathContext mc = new MathContext( (int)Math.min(this.precision() +
143.1604 + (long)Math.ceil(10.0*divisor.precision()/3.0),
143.1605 + Integer.MAX_VALUE),
143.1606 + RoundingMode.UNNECESSARY);
143.1607 + BigDecimal quotient;
143.1608 + try {
143.1609 + quotient = this.divide(divisor, mc);
143.1610 + } catch (ArithmeticException e) {
143.1611 + throw new ArithmeticException("Non-terminating decimal expansion; " +
143.1612 + "no exact representable decimal result.");
143.1613 + }
143.1614 +
143.1615 + int quotientScale = quotient.scale();
143.1616 +
143.1617 + // divide(BigDecimal, mc) tries to adjust the quotient to
143.1618 + // the desired one by removing trailing zeros; since the
143.1619 + // exact divide method does not have an explicit digit
143.1620 + // limit, we can add zeros too.
143.1621 +
143.1622 + if (preferredScale > quotientScale)
143.1623 + return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
143.1624 +
143.1625 + return quotient;
143.1626 + }
143.1627 + }
143.1628 +
143.1629 + /**
143.1630 + * Returns a {@code BigDecimal} whose value is {@code (this /
143.1631 + * divisor)}, with rounding according to the context settings.
143.1632 + *
143.1633 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1634 + * @param mc the context to use.
143.1635 + * @return {@code this / divisor}, rounded as necessary.
143.1636 + * @throws ArithmeticException if the result is inexact but the
143.1637 + * rounding mode is {@code UNNECESSARY} or
143.1638 + * {@code mc.precision == 0} and the quotient has a
143.1639 + * non-terminating decimal expansion.
143.1640 + * @since 1.5
143.1641 + */
143.1642 + public BigDecimal divide(BigDecimal divisor, MathContext mc) {
143.1643 + int mcp = mc.precision;
143.1644 + if (mcp == 0)
143.1645 + return divide(divisor);
143.1646 +
143.1647 + BigDecimal dividend = this;
143.1648 + long preferredScale = (long)dividend.scale - divisor.scale;
143.1649 + // Now calculate the answer. We use the existing
143.1650 + // divide-and-round method, but as this rounds to scale we have
143.1651 + // to normalize the values here to achieve the desired result.
143.1652 + // For x/y we first handle y=0 and x=0, and then normalize x and
143.1653 + // y to give x' and y' with the following constraints:
143.1654 + // (a) 0.1 <= x' < 1
143.1655 + // (b) x' <= y' < 10*x'
143.1656 + // Dividing x'/y' with the required scale set to mc.precision then
143.1657 + // will give a result in the range 0.1 to 1 rounded to exactly
143.1658 + // the right number of digits (except in the case of a result of
143.1659 + // 1.000... which can arise when x=y, or when rounding overflows
143.1660 + // The 1.000... case will reduce properly to 1.
143.1661 + if (divisor.signum() == 0) { // x/0
143.1662 + if (dividend.signum() == 0) // 0/0
143.1663 + throw new ArithmeticException("Division undefined"); // NaN
143.1664 + throw new ArithmeticException("Division by zero");
143.1665 + }
143.1666 + if (dividend.signum() == 0) // 0/y
143.1667 + return new BigDecimal(BigInteger.ZERO, 0,
143.1668 + saturateLong(preferredScale), 1);
143.1669 +
143.1670 + // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
143.1671 + int xscale = dividend.precision();
143.1672 + int yscale = divisor.precision();
143.1673 + dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
143.1674 + xscale, xscale);
143.1675 + divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
143.1676 + yscale, yscale);
143.1677 + if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
143.1678 + yscale = divisor.scale -= 1; // [that is, divisor *= 10]
143.1679 +
143.1680 + // In order to find out whether the divide generates the exact result,
143.1681 + // we avoid calling the above divide method. 'quotient' holds the
143.1682 + // return BigDecimal object whose scale will be set to 'scl'.
143.1683 + BigDecimal quotient;
143.1684 + int scl = checkScale(preferredScale + yscale - xscale + mcp);
143.1685 + if (checkScale((long)mcp + yscale) > xscale)
143.1686 + dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
143.1687 + else
143.1688 + divisor = divisor.setScale(checkScale((long)xscale - mcp),
143.1689 + ROUND_UNNECESSARY);
143.1690 + quotient = divideAndRound(dividend.intCompact, dividend.intVal,
143.1691 + divisor.intCompact, divisor.intVal,
143.1692 + scl, mc.roundingMode.oldMode,
143.1693 + checkScale(preferredScale));
143.1694 + // doRound, here, only affects 1000000000 case.
143.1695 + quotient = doRound(quotient, mc);
143.1696 +
143.1697 + return quotient;
143.1698 + }
143.1699 +
143.1700 + /**
143.1701 + * Returns a {@code BigDecimal} whose value is the integer part
143.1702 + * of the quotient {@code (this / divisor)} rounded down. The
143.1703 + * preferred scale of the result is {@code (this.scale() -
143.1704 + * divisor.scale())}.
143.1705 + *
143.1706 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1707 + * @return The integer part of {@code this / divisor}.
143.1708 + * @throws ArithmeticException if {@code divisor==0}
143.1709 + * @since 1.5
143.1710 + */
143.1711 + public BigDecimal divideToIntegralValue(BigDecimal divisor) {
143.1712 + // Calculate preferred scale
143.1713 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
143.1714 + if (this.compareMagnitude(divisor) < 0) {
143.1715 + // much faster when this << divisor
143.1716 + return BigDecimal.valueOf(0, preferredScale);
143.1717 + }
143.1718 +
143.1719 + if(this.signum() == 0 && divisor.signum() != 0)
143.1720 + return this.setScale(preferredScale, ROUND_UNNECESSARY);
143.1721 +
143.1722 + // Perform a divide with enough digits to round to a correct
143.1723 + // integer value; then remove any fractional digits
143.1724 +
143.1725 + int maxDigits = (int)Math.min(this.precision() +
143.1726 + (long)Math.ceil(10.0*divisor.precision()/3.0) +
143.1727 + Math.abs((long)this.scale() - divisor.scale()) + 2,
143.1728 + Integer.MAX_VALUE);
143.1729 + BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
143.1730 + RoundingMode.DOWN));
143.1731 + if (quotient.scale > 0) {
143.1732 + quotient = quotient.setScale(0, RoundingMode.DOWN);
143.1733 + quotient.stripZerosToMatchScale(preferredScale);
143.1734 + }
143.1735 +
143.1736 + if (quotient.scale < preferredScale) {
143.1737 + // pad with zeros if necessary
143.1738 + quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
143.1739 + }
143.1740 + return quotient;
143.1741 + }
143.1742 +
143.1743 + /**
143.1744 + * Returns a {@code BigDecimal} whose value is the integer part
143.1745 + * of {@code (this / divisor)}. Since the integer part of the
143.1746 + * exact quotient does not depend on the rounding mode, the
143.1747 + * rounding mode does not affect the values returned by this
143.1748 + * method. The preferred scale of the result is
143.1749 + * {@code (this.scale() - divisor.scale())}. An
143.1750 + * {@code ArithmeticException} is thrown if the integer part of
143.1751 + * the exact quotient needs more than {@code mc.precision}
143.1752 + * digits.
143.1753 + *
143.1754 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1755 + * @param mc the context to use.
143.1756 + * @return The integer part of {@code this / divisor}.
143.1757 + * @throws ArithmeticException if {@code divisor==0}
143.1758 + * @throws ArithmeticException if {@code mc.precision} {@literal >} 0 and the result
143.1759 + * requires a precision of more than {@code mc.precision} digits.
143.1760 + * @since 1.5
143.1761 + * @author Joseph D. Darcy
143.1762 + */
143.1763 + public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
143.1764 + if (mc.precision == 0 || // exact result
143.1765 + (this.compareMagnitude(divisor) < 0) ) // zero result
143.1766 + return divideToIntegralValue(divisor);
143.1767 +
143.1768 + // Calculate preferred scale
143.1769 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
143.1770 +
143.1771 + /*
143.1772 + * Perform a normal divide to mc.precision digits. If the
143.1773 + * remainder has absolute value less than the divisor, the
143.1774 + * integer portion of the quotient fits into mc.precision
143.1775 + * digits. Next, remove any fractional digits from the
143.1776 + * quotient and adjust the scale to the preferred value.
143.1777 + */
143.1778 + BigDecimal result = this.
143.1779 + divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
143.1780 +
143.1781 + if (result.scale() < 0) {
143.1782 + /*
143.1783 + * Result is an integer. See if quotient represents the
143.1784 + * full integer portion of the exact quotient; if it does,
143.1785 + * the computed remainder will be less than the divisor.
143.1786 + */
143.1787 + BigDecimal product = result.multiply(divisor);
143.1788 + // If the quotient is the full integer value,
143.1789 + // |dividend-product| < |divisor|.
143.1790 + if (this.subtract(product).compareMagnitude(divisor) >= 0) {
143.1791 + throw new ArithmeticException("Division impossible");
143.1792 + }
143.1793 + } else if (result.scale() > 0) {
143.1794 + /*
143.1795 + * Integer portion of quotient will fit into precision
143.1796 + * digits; recompute quotient to scale 0 to avoid double
143.1797 + * rounding and then try to adjust, if necessary.
143.1798 + */
143.1799 + result = result.setScale(0, RoundingMode.DOWN);
143.1800 + }
143.1801 + // else result.scale() == 0;
143.1802 +
143.1803 + int precisionDiff;
143.1804 + if ((preferredScale > result.scale()) &&
143.1805 + (precisionDiff = mc.precision - result.precision()) > 0) {
143.1806 + return result.setScale(result.scale() +
143.1807 + Math.min(precisionDiff, preferredScale - result.scale) );
143.1808 + } else {
143.1809 + result.stripZerosToMatchScale(preferredScale);
143.1810 + return result;
143.1811 + }
143.1812 + }
143.1813 +
143.1814 + /**
143.1815 + * Returns a {@code BigDecimal} whose value is {@code (this % divisor)}.
143.1816 + *
143.1817 + * <p>The remainder is given by
143.1818 + * {@code this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))}.
143.1819 + * Note that this is not the modulo operation (the result can be
143.1820 + * negative).
143.1821 + *
143.1822 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1823 + * @return {@code this % divisor}.
143.1824 + * @throws ArithmeticException if {@code divisor==0}
143.1825 + * @since 1.5
143.1826 + */
143.1827 + public BigDecimal remainder(BigDecimal divisor) {
143.1828 + BigDecimal divrem[] = this.divideAndRemainder(divisor);
143.1829 + return divrem[1];
143.1830 + }
143.1831 +
143.1832 +
143.1833 + /**
143.1834 + * Returns a {@code BigDecimal} whose value is {@code (this %
143.1835 + * divisor)}, with rounding according to the context settings.
143.1836 + * The {@code MathContext} settings affect the implicit divide
143.1837 + * used to compute the remainder. The remainder computation
143.1838 + * itself is by definition exact. Therefore, the remainder may
143.1839 + * contain more than {@code mc.getPrecision()} digits.
143.1840 + *
143.1841 + * <p>The remainder is given by
143.1842 + * {@code this.subtract(this.divideToIntegralValue(divisor,
143.1843 + * mc).multiply(divisor))}. Note that this is not the modulo
143.1844 + * operation (the result can be negative).
143.1845 + *
143.1846 + * @param divisor value by which this {@code BigDecimal} is to be divided.
143.1847 + * @param mc the context to use.
143.1848 + * @return {@code this % divisor}, rounded as necessary.
143.1849 + * @throws ArithmeticException if {@code divisor==0}
143.1850 + * @throws ArithmeticException if the result is inexact but the
143.1851 + * rounding mode is {@code UNNECESSARY}, or {@code mc.precision}
143.1852 + * {@literal >} 0 and the result of {@code this.divideToIntgralValue(divisor)} would
143.1853 + * require a precision of more than {@code mc.precision} digits.
143.1854 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
143.1855 + * @since 1.5
143.1856 + */
143.1857 + public BigDecimal remainder(BigDecimal divisor, MathContext mc) {
143.1858 + BigDecimal divrem[] = this.divideAndRemainder(divisor, mc);
143.1859 + return divrem[1];
143.1860 + }
143.1861 +
143.1862 + /**
143.1863 + * Returns a two-element {@code BigDecimal} array containing the
143.1864 + * result of {@code divideToIntegralValue} followed by the result of
143.1865 + * {@code remainder} on the two operands.
143.1866 + *
143.1867 + * <p>Note that if both the integer quotient and remainder are
143.1868 + * needed, this method is faster than using the
143.1869 + * {@code divideToIntegralValue} and {@code remainder} methods
143.1870 + * separately because the division need only be carried out once.
143.1871 + *
143.1872 + * @param divisor value by which this {@code BigDecimal} is to be divided,
143.1873 + * and the remainder computed.
143.1874 + * @return a two element {@code BigDecimal} array: the quotient
143.1875 + * (the result of {@code divideToIntegralValue}) is the initial element
143.1876 + * and the remainder is the final element.
143.1877 + * @throws ArithmeticException if {@code divisor==0}
143.1878 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
143.1879 + * @see #remainder(java.math.BigDecimal, java.math.MathContext)
143.1880 + * @since 1.5
143.1881 + */
143.1882 + public BigDecimal[] divideAndRemainder(BigDecimal divisor) {
143.1883 + // we use the identity x = i * y + r to determine r
143.1884 + BigDecimal[] result = new BigDecimal[2];
143.1885 +
143.1886 + result[0] = this.divideToIntegralValue(divisor);
143.1887 + result[1] = this.subtract(result[0].multiply(divisor));
143.1888 + return result;
143.1889 + }
143.1890 +
143.1891 + /**
143.1892 + * Returns a two-element {@code BigDecimal} array containing the
143.1893 + * result of {@code divideToIntegralValue} followed by the result of
143.1894 + * {@code remainder} on the two operands calculated with rounding
143.1895 + * according to the context settings.
143.1896 + *
143.1897 + * <p>Note that if both the integer quotient and remainder are
143.1898 + * needed, this method is faster than using the
143.1899 + * {@code divideToIntegralValue} and {@code remainder} methods
143.1900 + * separately because the division need only be carried out once.
143.1901 + *
143.1902 + * @param divisor value by which this {@code BigDecimal} is to be divided,
143.1903 + * and the remainder computed.
143.1904 + * @param mc the context to use.
143.1905 + * @return a two element {@code BigDecimal} array: the quotient
143.1906 + * (the result of {@code divideToIntegralValue}) is the
143.1907 + * initial element and the remainder is the final element.
143.1908 + * @throws ArithmeticException if {@code divisor==0}
143.1909 + * @throws ArithmeticException if the result is inexact but the
143.1910 + * rounding mode is {@code UNNECESSARY}, or {@code mc.precision}
143.1911 + * {@literal >} 0 and the result of {@code this.divideToIntgralValue(divisor)} would
143.1912 + * require a precision of more than {@code mc.precision} digits.
143.1913 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
143.1914 + * @see #remainder(java.math.BigDecimal, java.math.MathContext)
143.1915 + * @since 1.5
143.1916 + */
143.1917 + public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) {
143.1918 + if (mc.precision == 0)
143.1919 + return divideAndRemainder(divisor);
143.1920 +
143.1921 + BigDecimal[] result = new BigDecimal[2];
143.1922 + BigDecimal lhs = this;
143.1923 +
143.1924 + result[0] = lhs.divideToIntegralValue(divisor, mc);
143.1925 + result[1] = lhs.subtract(result[0].multiply(divisor));
143.1926 + return result;
143.1927 + }
143.1928 +
143.1929 + /**
143.1930 + * Returns a {@code BigDecimal} whose value is
143.1931 + * <tt>(this<sup>n</sup>)</tt>, The power is computed exactly, to
143.1932 + * unlimited precision.
143.1933 + *
143.1934 + * <p>The parameter {@code n} must be in the range 0 through
143.1935 + * 999999999, inclusive. {@code ZERO.pow(0)} returns {@link
143.1936 + * #ONE}.
143.1937 + *
143.1938 + * Note that future releases may expand the allowable exponent
143.1939 + * range of this method.
143.1940 + *
143.1941 + * @param n power to raise this {@code BigDecimal} to.
143.1942 + * @return <tt>this<sup>n</sup></tt>
143.1943 + * @throws ArithmeticException if {@code n} is out of range.
143.1944 + * @since 1.5
143.1945 + */
143.1946 + public BigDecimal pow(int n) {
143.1947 + if (n < 0 || n > 999999999)
143.1948 + throw new ArithmeticException("Invalid operation");
143.1949 + // No need to calculate pow(n) if result will over/underflow.
143.1950 + // Don't attempt to support "supernormal" numbers.
143.1951 + int newScale = checkScale((long)scale * n);
143.1952 + this.inflate();
143.1953 + return new BigDecimal(intVal.pow(n), newScale);
143.1954 + }
143.1955 +
143.1956 +
143.1957 + /**
143.1958 + * Returns a {@code BigDecimal} whose value is
143.1959 + * <tt>(this<sup>n</sup>)</tt>. The current implementation uses
143.1960 + * the core algorithm defined in ANSI standard X3.274-1996 with
143.1961 + * rounding according to the context settings. In general, the
143.1962 + * returned numerical value is within two ulps of the exact
143.1963 + * numerical value for the chosen precision. Note that future
143.1964 + * releases may use a different algorithm with a decreased
143.1965 + * allowable error bound and increased allowable exponent range.
143.1966 + *
143.1967 + * <p>The X3.274-1996 algorithm is:
143.1968 + *
143.1969 + * <ul>
143.1970 + * <li> An {@code ArithmeticException} exception is thrown if
143.1971 + * <ul>
143.1972 + * <li>{@code abs(n) > 999999999}
143.1973 + * <li>{@code mc.precision == 0} and {@code n < 0}
143.1974 + * <li>{@code mc.precision > 0} and {@code n} has more than
143.1975 + * {@code mc.precision} decimal digits
143.1976 + * </ul>
143.1977 + *
143.1978 + * <li> if {@code n} is zero, {@link #ONE} is returned even if
143.1979 + * {@code this} is zero, otherwise
143.1980 + * <ul>
143.1981 + * <li> if {@code n} is positive, the result is calculated via
143.1982 + * the repeated squaring technique into a single accumulator.
143.1983 + * The individual multiplications with the accumulator use the
143.1984 + * same math context settings as in {@code mc} except for a
143.1985 + * precision increased to {@code mc.precision + elength + 1}
143.1986 + * where {@code elength} is the number of decimal digits in
143.1987 + * {@code n}.
143.1988 + *
143.1989 + * <li> if {@code n} is negative, the result is calculated as if
143.1990 + * {@code n} were positive; this value is then divided into one
143.1991 + * using the working precision specified above.
143.1992 + *
143.1993 + * <li> The final value from either the positive or negative case
143.1994 + * is then rounded to the destination precision.
143.1995 + * </ul>
143.1996 + * </ul>
143.1997 + *
143.1998 + * @param n power to raise this {@code BigDecimal} to.
143.1999 + * @param mc the context to use.
143.2000 + * @return <tt>this<sup>n</sup></tt> using the ANSI standard X3.274-1996
143.2001 + * algorithm
143.2002 + * @throws ArithmeticException if the result is inexact but the
143.2003 + * rounding mode is {@code UNNECESSARY}, or {@code n} is out
143.2004 + * of range.
143.2005 + * @since 1.5
143.2006 + */
143.2007 + public BigDecimal pow(int n, MathContext mc) {
143.2008 + if (mc.precision == 0)
143.2009 + return pow(n);
143.2010 + if (n < -999999999 || n > 999999999)
143.2011 + throw new ArithmeticException("Invalid operation");
143.2012 + if (n == 0)
143.2013 + return ONE; // x**0 == 1 in X3.274
143.2014 + this.inflate();
143.2015 + BigDecimal lhs = this;
143.2016 + MathContext workmc = mc; // working settings
143.2017 + int mag = Math.abs(n); // magnitude of n
143.2018 + if (mc.precision > 0) {
143.2019 +
143.2020 + int elength = longDigitLength(mag); // length of n in digits
143.2021 + if (elength > mc.precision) // X3.274 rule
143.2022 + throw new ArithmeticException("Invalid operation");
143.2023 + workmc = new MathContext(mc.precision + elength + 1,
143.2024 + mc.roundingMode);
143.2025 + }
143.2026 + // ready to carry out power calculation...
143.2027 + BigDecimal acc = ONE; // accumulator
143.2028 + boolean seenbit = false; // set once we've seen a 1-bit
143.2029 + for (int i=1;;i++) { // for each bit [top bit ignored]
143.2030 + mag += mag; // shift left 1 bit
143.2031 + if (mag < 0) { // top bit is set
143.2032 + seenbit = true; // OK, we're off
143.2033 + acc = acc.multiply(lhs, workmc); // acc=acc*x
143.2034 + }
143.2035 + if (i == 31)
143.2036 + break; // that was the last bit
143.2037 + if (seenbit)
143.2038 + acc=acc.multiply(acc, workmc); // acc=acc*acc [square]
143.2039 + // else (!seenbit) no point in squaring ONE
143.2040 + }
143.2041 + // if negative n, calculate the reciprocal using working precision
143.2042 + if (n<0) // [hence mc.precision>0]
143.2043 + acc=ONE.divide(acc, workmc);
143.2044 + // round to final precision and strip zeros
143.2045 + return doRound(acc, mc);
143.2046 + }
143.2047 +
143.2048 + /**
143.2049 + * Returns a {@code BigDecimal} whose value is the absolute value
143.2050 + * of this {@code BigDecimal}, and whose scale is
143.2051 + * {@code this.scale()}.
143.2052 + *
143.2053 + * @return {@code abs(this)}
143.2054 + */
143.2055 + public BigDecimal abs() {
143.2056 + return (signum() < 0 ? negate() : this);
143.2057 + }
143.2058 +
143.2059 + /**
143.2060 + * Returns a {@code BigDecimal} whose value is the absolute value
143.2061 + * of this {@code BigDecimal}, with rounding according to the
143.2062 + * context settings.
143.2063 + *
143.2064 + * @param mc the context to use.
143.2065 + * @return {@code abs(this)}, rounded as necessary.
143.2066 + * @throws ArithmeticException if the result is inexact but the
143.2067 + * rounding mode is {@code UNNECESSARY}.
143.2068 + * @since 1.5
143.2069 + */
143.2070 + public BigDecimal abs(MathContext mc) {
143.2071 + return (signum() < 0 ? negate(mc) : plus(mc));
143.2072 + }
143.2073 +
143.2074 + /**
143.2075 + * Returns a {@code BigDecimal} whose value is {@code (-this)},
143.2076 + * and whose scale is {@code this.scale()}.
143.2077 + *
143.2078 + * @return {@code -this}.
143.2079 + */
143.2080 + public BigDecimal negate() {
143.2081 + BigDecimal result;
143.2082 + if (intCompact != INFLATED)
143.2083 + result = BigDecimal.valueOf(-intCompact, scale);
143.2084 + else {
143.2085 + result = new BigDecimal(intVal.negate(), scale);
143.2086 + result.precision = precision;
143.2087 + }
143.2088 + return result;
143.2089 + }
143.2090 +
143.2091 + /**
143.2092 + * Returns a {@code BigDecimal} whose value is {@code (-this)},
143.2093 + * with rounding according to the context settings.
143.2094 + *
143.2095 + * @param mc the context to use.
143.2096 + * @return {@code -this}, rounded as necessary.
143.2097 + * @throws ArithmeticException if the result is inexact but the
143.2098 + * rounding mode is {@code UNNECESSARY}.
143.2099 + * @since 1.5
143.2100 + */
143.2101 + public BigDecimal negate(MathContext mc) {
143.2102 + return negate().plus(mc);
143.2103 + }
143.2104 +
143.2105 + /**
143.2106 + * Returns a {@code BigDecimal} whose value is {@code (+this)}, and whose
143.2107 + * scale is {@code this.scale()}.
143.2108 + *
143.2109 + * <p>This method, which simply returns this {@code BigDecimal}
143.2110 + * is included for symmetry with the unary minus method {@link
143.2111 + * #negate()}.
143.2112 + *
143.2113 + * @return {@code this}.
143.2114 + * @see #negate()
143.2115 + * @since 1.5
143.2116 + */
143.2117 + public BigDecimal plus() {
143.2118 + return this;
143.2119 + }
143.2120 +
143.2121 + /**
143.2122 + * Returns a {@code BigDecimal} whose value is {@code (+this)},
143.2123 + * with rounding according to the context settings.
143.2124 + *
143.2125 + * <p>The effect of this method is identical to that of the {@link
143.2126 + * #round(MathContext)} method.
143.2127 + *
143.2128 + * @param mc the context to use.
143.2129 + * @return {@code this}, rounded as necessary. A zero result will
143.2130 + * have a scale of 0.
143.2131 + * @throws ArithmeticException if the result is inexact but the
143.2132 + * rounding mode is {@code UNNECESSARY}.
143.2133 + * @see #round(MathContext)
143.2134 + * @since 1.5
143.2135 + */
143.2136 + public BigDecimal plus(MathContext mc) {
143.2137 + if (mc.precision == 0) // no rounding please
143.2138 + return this;
143.2139 + return doRound(this, mc);
143.2140 + }
143.2141 +
143.2142 + /**
143.2143 + * Returns the signum function of this {@code BigDecimal}.
143.2144 + *
143.2145 + * @return -1, 0, or 1 as the value of this {@code BigDecimal}
143.2146 + * is negative, zero, or positive.
143.2147 + */
143.2148 + public int signum() {
143.2149 + return (intCompact != INFLATED)?
143.2150 + Long.signum(intCompact):
143.2151 + intVal.signum();
143.2152 + }
143.2153 +
143.2154 + /**
143.2155 + * Returns the <i>scale</i> of this {@code BigDecimal}. If zero
143.2156 + * or positive, the scale is the number of digits to the right of
143.2157 + * the decimal point. If negative, the unscaled value of the
143.2158 + * number is multiplied by ten to the power of the negation of the
143.2159 + * scale. For example, a scale of {@code -3} means the unscaled
143.2160 + * value is multiplied by 1000.
143.2161 + *
143.2162 + * @return the scale of this {@code BigDecimal}.
143.2163 + */
143.2164 + public int scale() {
143.2165 + return scale;
143.2166 + }
143.2167 +
143.2168 + /**
143.2169 + * Returns the <i>precision</i> of this {@code BigDecimal}. (The
143.2170 + * precision is the number of digits in the unscaled value.)
143.2171 + *
143.2172 + * <p>The precision of a zero value is 1.
143.2173 + *
143.2174 + * @return the precision of this {@code BigDecimal}.
143.2175 + * @since 1.5
143.2176 + */
143.2177 + public int precision() {
143.2178 + int result = precision;
143.2179 + if (result == 0) {
143.2180 + long s = intCompact;
143.2181 + if (s != INFLATED)
143.2182 + result = longDigitLength(s);
143.2183 + else
143.2184 + result = bigDigitLength(inflate());
143.2185 + precision = result;
143.2186 + }
143.2187 + return result;
143.2188 + }
143.2189 +
143.2190 +
143.2191 + /**
143.2192 + * Returns a {@code BigInteger} whose value is the <i>unscaled
143.2193 + * value</i> of this {@code BigDecimal}. (Computes <tt>(this *
143.2194 + * 10<sup>this.scale()</sup>)</tt>.)
143.2195 + *
143.2196 + * @return the unscaled value of this {@code BigDecimal}.
143.2197 + * @since 1.2
143.2198 + */
143.2199 + public BigInteger unscaledValue() {
143.2200 + return this.inflate();
143.2201 + }
143.2202 +
143.2203 + // Rounding Modes
143.2204 +
143.2205 + /**
143.2206 + * Rounding mode to round away from zero. Always increments the
143.2207 + * digit prior to a nonzero discarded fraction. Note that this rounding
143.2208 + * mode never decreases the magnitude of the calculated value.
143.2209 + */
143.2210 + public final static int ROUND_UP = 0;
143.2211 +
143.2212 + /**
143.2213 + * Rounding mode to round towards zero. Never increments the digit
143.2214 + * prior to a discarded fraction (i.e., truncates). Note that this
143.2215 + * rounding mode never increases the magnitude of the calculated value.
143.2216 + */
143.2217 + public final static int ROUND_DOWN = 1;
143.2218 +
143.2219 + /**
143.2220 + * Rounding mode to round towards positive infinity. If the
143.2221 + * {@code BigDecimal} is positive, behaves as for
143.2222 + * {@code ROUND_UP}; if negative, behaves as for
143.2223 + * {@code ROUND_DOWN}. Note that this rounding mode never
143.2224 + * decreases the calculated value.
143.2225 + */
143.2226 + public final static int ROUND_CEILING = 2;
143.2227 +
143.2228 + /**
143.2229 + * Rounding mode to round towards negative infinity. If the
143.2230 + * {@code BigDecimal} is positive, behave as for
143.2231 + * {@code ROUND_DOWN}; if negative, behave as for
143.2232 + * {@code ROUND_UP}. Note that this rounding mode never
143.2233 + * increases the calculated value.
143.2234 + */
143.2235 + public final static int ROUND_FLOOR = 3;
143.2236 +
143.2237 + /**
143.2238 + * Rounding mode to round towards {@literal "nearest neighbor"}
143.2239 + * unless both neighbors are equidistant, in which case round up.
143.2240 + * Behaves as for {@code ROUND_UP} if the discarded fraction is
143.2241 + * ≥ 0.5; otherwise, behaves as for {@code ROUND_DOWN}. Note
143.2242 + * that this is the rounding mode that most of us were taught in
143.2243 + * grade school.
143.2244 + */
143.2245 + public final static int ROUND_HALF_UP = 4;
143.2246 +
143.2247 + /**
143.2248 + * Rounding mode to round towards {@literal "nearest neighbor"}
143.2249 + * unless both neighbors are equidistant, in which case round
143.2250 + * down. Behaves as for {@code ROUND_UP} if the discarded
143.2251 + * fraction is {@literal >} 0.5; otherwise, behaves as for
143.2252 + * {@code ROUND_DOWN}.
143.2253 + */
143.2254 + public final static int ROUND_HALF_DOWN = 5;
143.2255 +
143.2256 + /**
143.2257 + * Rounding mode to round towards the {@literal "nearest neighbor"}
143.2258 + * unless both neighbors are equidistant, in which case, round
143.2259 + * towards the even neighbor. Behaves as for
143.2260 + * {@code ROUND_HALF_UP} if the digit to the left of the
143.2261 + * discarded fraction is odd; behaves as for
143.2262 + * {@code ROUND_HALF_DOWN} if it's even. Note that this is the
143.2263 + * rounding mode that minimizes cumulative error when applied
143.2264 + * repeatedly over a sequence of calculations.
143.2265 + */
143.2266 + public final static int ROUND_HALF_EVEN = 6;
143.2267 +
143.2268 + /**
143.2269 + * Rounding mode to assert that the requested operation has an exact
143.2270 + * result, hence no rounding is necessary. If this rounding mode is
143.2271 + * specified on an operation that yields an inexact result, an
143.2272 + * {@code ArithmeticException} is thrown.
143.2273 + */
143.2274 + public final static int ROUND_UNNECESSARY = 7;
143.2275 +
143.2276 +
143.2277 + // Scaling/Rounding Operations
143.2278 +
143.2279 + /**
143.2280 + * Returns a {@code BigDecimal} rounded according to the
143.2281 + * {@code MathContext} settings. If the precision setting is 0 then
143.2282 + * no rounding takes place.
143.2283 + *
143.2284 + * <p>The effect of this method is identical to that of the
143.2285 + * {@link #plus(MathContext)} method.
143.2286 + *
143.2287 + * @param mc the context to use.
143.2288 + * @return a {@code BigDecimal} rounded according to the
143.2289 + * {@code MathContext} settings.
143.2290 + * @throws ArithmeticException if the rounding mode is
143.2291 + * {@code UNNECESSARY} and the
143.2292 + * {@code BigDecimal} operation would require rounding.
143.2293 + * @see #plus(MathContext)
143.2294 + * @since 1.5
143.2295 + */
143.2296 + public BigDecimal round(MathContext mc) {
143.2297 + return plus(mc);
143.2298 + }
143.2299 +
143.2300 + /**
143.2301 + * Returns a {@code BigDecimal} whose scale is the specified
143.2302 + * value, and whose unscaled value is determined by multiplying or
143.2303 + * dividing this {@code BigDecimal}'s unscaled value by the
143.2304 + * appropriate power of ten to maintain its overall value. If the
143.2305 + * scale is reduced by the operation, the unscaled value must be
143.2306 + * divided (rather than multiplied), and the value may be changed;
143.2307 + * in this case, the specified rounding mode is applied to the
143.2308 + * division.
143.2309 + *
143.2310 + * <p>Note that since BigDecimal objects are immutable, calls of
143.2311 + * this method do <i>not</i> result in the original object being
143.2312 + * modified, contrary to the usual convention of having methods
143.2313 + * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
143.2314 + * Instead, {@code setScale} returns an object with the proper
143.2315 + * scale; the returned object may or may not be newly allocated.
143.2316 + *
143.2317 + * @param newScale scale of the {@code BigDecimal} value to be returned.
143.2318 + * @param roundingMode The rounding mode to apply.
143.2319 + * @return a {@code BigDecimal} whose scale is the specified value,
143.2320 + * and whose unscaled value is determined by multiplying or
143.2321 + * dividing this {@code BigDecimal}'s unscaled value by the
143.2322 + * appropriate power of ten to maintain its overall value.
143.2323 + * @throws ArithmeticException if {@code roundingMode==UNNECESSARY}
143.2324 + * and the specified scaling operation would require
143.2325 + * rounding.
143.2326 + * @see RoundingMode
143.2327 + * @since 1.5
143.2328 + */
143.2329 + public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
143.2330 + return setScale(newScale, roundingMode.oldMode);
143.2331 + }
143.2332 +
143.2333 + /**
143.2334 + * Returns a {@code BigDecimal} whose scale is the specified
143.2335 + * value, and whose unscaled value is determined by multiplying or
143.2336 + * dividing this {@code BigDecimal}'s unscaled value by the
143.2337 + * appropriate power of ten to maintain its overall value. If the
143.2338 + * scale is reduced by the operation, the unscaled value must be
143.2339 + * divided (rather than multiplied), and the value may be changed;
143.2340 + * in this case, the specified rounding mode is applied to the
143.2341 + * division.
143.2342 + *
143.2343 + * <p>Note that since BigDecimal objects are immutable, calls of
143.2344 + * this method do <i>not</i> result in the original object being
143.2345 + * modified, contrary to the usual convention of having methods
143.2346 + * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
143.2347 + * Instead, {@code setScale} returns an object with the proper
143.2348 + * scale; the returned object may or may not be newly allocated.
143.2349 + *
143.2350 + * <p>The new {@link #setScale(int, RoundingMode)} method should
143.2351 + * be used in preference to this legacy method.
143.2352 + *
143.2353 + * @param newScale scale of the {@code BigDecimal} value to be returned.
143.2354 + * @param roundingMode The rounding mode to apply.
143.2355 + * @return a {@code BigDecimal} whose scale is the specified value,
143.2356 + * and whose unscaled value is determined by multiplying or
143.2357 + * dividing this {@code BigDecimal}'s unscaled value by the
143.2358 + * appropriate power of ten to maintain its overall value.
143.2359 + * @throws ArithmeticException if {@code roundingMode==ROUND_UNNECESSARY}
143.2360 + * and the specified scaling operation would require
143.2361 + * rounding.
143.2362 + * @throws IllegalArgumentException if {@code roundingMode} does not
143.2363 + * represent a valid rounding mode.
143.2364 + * @see #ROUND_UP
143.2365 + * @see #ROUND_DOWN
143.2366 + * @see #ROUND_CEILING
143.2367 + * @see #ROUND_FLOOR
143.2368 + * @see #ROUND_HALF_UP
143.2369 + * @see #ROUND_HALF_DOWN
143.2370 + * @see #ROUND_HALF_EVEN
143.2371 + * @see #ROUND_UNNECESSARY
143.2372 + */
143.2373 + public BigDecimal setScale(int newScale, int roundingMode) {
143.2374 + if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
143.2375 + throw new IllegalArgumentException("Invalid rounding mode");
143.2376 +
143.2377 + int oldScale = this.scale;
143.2378 + if (newScale == oldScale) // easy case
143.2379 + return this;
143.2380 + if (this.signum() == 0) // zero can have any scale
143.2381 + return BigDecimal.valueOf(0, newScale);
143.2382 +
143.2383 + long rs = this.intCompact;
143.2384 + if (newScale > oldScale) {
143.2385 + int raise = checkScale((long)newScale - oldScale);
143.2386 + BigInteger rb = null;
143.2387 + if (rs == INFLATED ||
143.2388 + (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
143.2389 + rb = bigMultiplyPowerTen(raise);
143.2390 + return new BigDecimal(rb, rs, newScale,
143.2391 + (precision > 0) ? precision + raise : 0);
143.2392 + } else {
143.2393 + // newScale < oldScale -- drop some digits
143.2394 + // Can't predict the precision due to the effect of rounding.
143.2395 + int drop = checkScale((long)oldScale - newScale);
143.2396 + if (drop < LONG_TEN_POWERS_TABLE.length)
143.2397 + return divideAndRound(rs, this.intVal,
143.2398 + LONG_TEN_POWERS_TABLE[drop], null,
143.2399 + newScale, roundingMode, newScale);
143.2400 + else
143.2401 + return divideAndRound(rs, this.intVal,
143.2402 + INFLATED, bigTenToThe(drop),
143.2403 + newScale, roundingMode, newScale);
143.2404 + }
143.2405 + }
143.2406 +
143.2407 + /**
143.2408 + * Returns a {@code BigDecimal} whose scale is the specified
143.2409 + * value, and whose value is numerically equal to this
143.2410 + * {@code BigDecimal}'s. Throws an {@code ArithmeticException}
143.2411 + * if this is not possible.
143.2412 + *
143.2413 + * <p>This call is typically used to increase the scale, in which
143.2414 + * case it is guaranteed that there exists a {@code BigDecimal}
143.2415 + * of the specified scale and the correct value. The call can
143.2416 + * also be used to reduce the scale if the caller knows that the
143.2417 + * {@code BigDecimal} has sufficiently many zeros at the end of
143.2418 + * its fractional part (i.e., factors of ten in its integer value)
143.2419 + * to allow for the rescaling without changing its value.
143.2420 + *
143.2421 + * <p>This method returns the same result as the two-argument
143.2422 + * versions of {@code setScale}, but saves the caller the trouble
143.2423 + * of specifying a rounding mode in cases where it is irrelevant.
143.2424 + *
143.2425 + * <p>Note that since {@code BigDecimal} objects are immutable,
143.2426 + * calls of this method do <i>not</i> result in the original
143.2427 + * object being modified, contrary to the usual convention of
143.2428 + * having methods named <tt>set<i>X</i></tt> mutate field
143.2429 + * <i>{@code X}</i>. Instead, {@code setScale} returns an
143.2430 + * object with the proper scale; the returned object may or may
143.2431 + * not be newly allocated.
143.2432 + *
143.2433 + * @param newScale scale of the {@code BigDecimal} value to be returned.
143.2434 + * @return a {@code BigDecimal} whose scale is the specified value, and
143.2435 + * whose unscaled value is determined by multiplying or dividing
143.2436 + * this {@code BigDecimal}'s unscaled value by the appropriate
143.2437 + * power of ten to maintain its overall value.
143.2438 + * @throws ArithmeticException if the specified scaling operation would
143.2439 + * require rounding.
143.2440 + * @see #setScale(int, int)
143.2441 + * @see #setScale(int, RoundingMode)
143.2442 + */
143.2443 + public BigDecimal setScale(int newScale) {
143.2444 + return setScale(newScale, ROUND_UNNECESSARY);
143.2445 + }
143.2446 +
143.2447 + // Decimal Point Motion Operations
143.2448 +
143.2449 + /**
143.2450 + * Returns a {@code BigDecimal} which is equivalent to this one
143.2451 + * with the decimal point moved {@code n} places to the left. If
143.2452 + * {@code n} is non-negative, the call merely adds {@code n} to
143.2453 + * the scale. If {@code n} is negative, the call is equivalent
143.2454 + * to {@code movePointRight(-n)}. The {@code BigDecimal}
143.2455 + * returned by this call has value <tt>(this ×
143.2456 + * 10<sup>-n</sup>)</tt> and scale {@code max(this.scale()+n,
143.2457 + * 0)}.
143.2458 + *
143.2459 + * @param n number of places to move the decimal point to the left.
143.2460 + * @return a {@code BigDecimal} which is equivalent to this one with the
143.2461 + * decimal point moved {@code n} places to the left.
143.2462 + * @throws ArithmeticException if scale overflows.
143.2463 + */
143.2464 + public BigDecimal movePointLeft(int n) {
143.2465 + // Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
143.2466 + int newScale = checkScale((long)scale + n);
143.2467 + BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
143.2468 + return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
143.2469 + }
143.2470 +
143.2471 + /**
143.2472 + * Returns a {@code BigDecimal} which is equivalent to this one
143.2473 + * with the decimal point moved {@code n} places to the right.
143.2474 + * If {@code n} is non-negative, the call merely subtracts
143.2475 + * {@code n} from the scale. If {@code n} is negative, the call
143.2476 + * is equivalent to {@code movePointLeft(-n)}. The
143.2477 + * {@code BigDecimal} returned by this call has value <tt>(this
143.2478 + * × 10<sup>n</sup>)</tt> and scale {@code max(this.scale()-n,
143.2479 + * 0)}.
143.2480 + *
143.2481 + * @param n number of places to move the decimal point to the right.
143.2482 + * @return a {@code BigDecimal} which is equivalent to this one
143.2483 + * with the decimal point moved {@code n} places to the right.
143.2484 + * @throws ArithmeticException if scale overflows.
143.2485 + */
143.2486 + public BigDecimal movePointRight(int n) {
143.2487 + // Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
143.2488 + int newScale = checkScale((long)scale - n);
143.2489 + BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
143.2490 + return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
143.2491 + }
143.2492 +
143.2493 + /**
143.2494 + * Returns a BigDecimal whose numerical value is equal to
143.2495 + * ({@code this} * 10<sup>n</sup>). The scale of
143.2496 + * the result is {@code (this.scale() - n)}.
143.2497 + *
143.2498 + * @throws ArithmeticException if the scale would be
143.2499 + * outside the range of a 32-bit integer.
143.2500 + *
143.2501 + * @since 1.5
143.2502 + */
143.2503 + public BigDecimal scaleByPowerOfTen(int n) {
143.2504 + return new BigDecimal(intVal, intCompact,
143.2505 + checkScale((long)scale - n), precision);
143.2506 + }
143.2507 +
143.2508 + /**
143.2509 + * Returns a {@code BigDecimal} which is numerically equal to
143.2510 + * this one but with any trailing zeros removed from the
143.2511 + * representation. For example, stripping the trailing zeros from
143.2512 + * the {@code BigDecimal} value {@code 600.0}, which has
143.2513 + * [{@code BigInteger}, {@code scale}] components equals to
143.2514 + * [6000, 1], yields {@code 6E2} with [{@code BigInteger},
143.2515 + * {@code scale}] components equals to [6, -2]
143.2516 + *
143.2517 + * @return a numerically equal {@code BigDecimal} with any
143.2518 + * trailing zeros removed.
143.2519 + * @since 1.5
143.2520 + */
143.2521 + public BigDecimal stripTrailingZeros() {
143.2522 + this.inflate();
143.2523 + BigDecimal result = new BigDecimal(intVal, scale);
143.2524 + result.stripZerosToMatchScale(Long.MIN_VALUE);
143.2525 + return result;
143.2526 + }
143.2527 +
143.2528 + // Comparison Operations
143.2529 +
143.2530 + /**
143.2531 + * Compares this {@code BigDecimal} with the specified
143.2532 + * {@code BigDecimal}. Two {@code BigDecimal} objects that are
143.2533 + * equal in value but have a different scale (like 2.0 and 2.00)
143.2534 + * are considered equal by this method. This method is provided
143.2535 + * in preference to individual methods for each of the six boolean
143.2536 + * comparison operators ({@literal <}, ==,
143.2537 + * {@literal >}, {@literal >=}, !=, {@literal <=}). The
143.2538 + * suggested idiom for performing these comparisons is:
143.2539 + * {@code (x.compareTo(y)} <<i>op</i>> {@code 0)}, where
143.2540 + * <<i>op</i>> is one of the six comparison operators.
143.2541 + *
143.2542 + * @param val {@code BigDecimal} to which this {@code BigDecimal} is
143.2543 + * to be compared.
143.2544 + * @return -1, 0, or 1 as this {@code BigDecimal} is numerically
143.2545 + * less than, equal to, or greater than {@code val}.
143.2546 + */
143.2547 + public int compareTo(BigDecimal val) {
143.2548 + // Quick path for equal scale and non-inflated case.
143.2549 + if (scale == val.scale) {
143.2550 + long xs = intCompact;
143.2551 + long ys = val.intCompact;
143.2552 + if (xs != INFLATED && ys != INFLATED)
143.2553 + return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
143.2554 + }
143.2555 + int xsign = this.signum();
143.2556 + int ysign = val.signum();
143.2557 + if (xsign != ysign)
143.2558 + return (xsign > ysign) ? 1 : -1;
143.2559 + if (xsign == 0)
143.2560 + return 0;
143.2561 + int cmp = compareMagnitude(val);
143.2562 + return (xsign > 0) ? cmp : -cmp;
143.2563 + }
143.2564 +
143.2565 + /**
143.2566 + * Version of compareTo that ignores sign.
143.2567 + */
143.2568 + private int compareMagnitude(BigDecimal val) {
143.2569 + // Match scales, avoid unnecessary inflation
143.2570 + long ys = val.intCompact;
143.2571 + long xs = this.intCompact;
143.2572 + if (xs == 0)
143.2573 + return (ys == 0) ? 0 : -1;
143.2574 + if (ys == 0)
143.2575 + return 1;
143.2576 +
143.2577 + int sdiff = this.scale - val.scale;
143.2578 + if (sdiff != 0) {
143.2579 + // Avoid matching scales if the (adjusted) exponents differ
143.2580 + int xae = this.precision() - this.scale; // [-1]
143.2581 + int yae = val.precision() - val.scale; // [-1]
143.2582 + if (xae < yae)
143.2583 + return -1;
143.2584 + if (xae > yae)
143.2585 + return 1;
143.2586 + BigInteger rb = null;
143.2587 + if (sdiff < 0) {
143.2588 + if ( (xs == INFLATED ||
143.2589 + (xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
143.2590 + ys == INFLATED) {
143.2591 + rb = bigMultiplyPowerTen(-sdiff);
143.2592 + return rb.compareMagnitude(val.intVal);
143.2593 + }
143.2594 + } else { // sdiff > 0
143.2595 + if ( (ys == INFLATED ||
143.2596 + (ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
143.2597 + xs == INFLATED) {
143.2598 + rb = val.bigMultiplyPowerTen(sdiff);
143.2599 + return this.intVal.compareMagnitude(rb);
143.2600 + }
143.2601 + }
143.2602 + }
143.2603 + if (xs != INFLATED)
143.2604 + return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
143.2605 + else if (ys != INFLATED)
143.2606 + return 1;
143.2607 + else
143.2608 + return this.intVal.compareMagnitude(val.intVal);
143.2609 + }
143.2610 +
143.2611 + /**
143.2612 + * Compares this {@code BigDecimal} with the specified
143.2613 + * {@code Object} for equality. Unlike {@link
143.2614 + * #compareTo(BigDecimal) compareTo}, this method considers two
143.2615 + * {@code BigDecimal} objects equal only if they are equal in
143.2616 + * value and scale (thus 2.0 is not equal to 2.00 when compared by
143.2617 + * this method).
143.2618 + *
143.2619 + * @param x {@code Object} to which this {@code BigDecimal} is
143.2620 + * to be compared.
143.2621 + * @return {@code true} if and only if the specified {@code Object} is a
143.2622 + * {@code BigDecimal} whose value and scale are equal to this
143.2623 + * {@code BigDecimal}'s.
143.2624 + * @see #compareTo(java.math.BigDecimal)
143.2625 + * @see #hashCode
143.2626 + */
143.2627 + @Override
143.2628 + public boolean equals(Object x) {
143.2629 + if (!(x instanceof BigDecimal))
143.2630 + return false;
143.2631 + BigDecimal xDec = (BigDecimal) x;
143.2632 + if (x == this)
143.2633 + return true;
143.2634 + if (scale != xDec.scale)
143.2635 + return false;
143.2636 + long s = this.intCompact;
143.2637 + long xs = xDec.intCompact;
143.2638 + if (s != INFLATED) {
143.2639 + if (xs == INFLATED)
143.2640 + xs = compactValFor(xDec.intVal);
143.2641 + return xs == s;
143.2642 + } else if (xs != INFLATED)
143.2643 + return xs == compactValFor(this.intVal);
143.2644 +
143.2645 + return this.inflate().equals(xDec.inflate());
143.2646 + }
143.2647 +
143.2648 + /**
143.2649 + * Returns the minimum of this {@code BigDecimal} and
143.2650 + * {@code val}.
143.2651 + *
143.2652 + * @param val value with which the minimum is to be computed.
143.2653 + * @return the {@code BigDecimal} whose value is the lesser of this
143.2654 + * {@code BigDecimal} and {@code val}. If they are equal,
143.2655 + * as defined by the {@link #compareTo(BigDecimal) compareTo}
143.2656 + * method, {@code this} is returned.
143.2657 + * @see #compareTo(java.math.BigDecimal)
143.2658 + */
143.2659 + public BigDecimal min(BigDecimal val) {
143.2660 + return (compareTo(val) <= 0 ? this : val);
143.2661 + }
143.2662 +
143.2663 + /**
143.2664 + * Returns the maximum of this {@code BigDecimal} and {@code val}.
143.2665 + *
143.2666 + * @param val value with which the maximum is to be computed.
143.2667 + * @return the {@code BigDecimal} whose value is the greater of this
143.2668 + * {@code BigDecimal} and {@code val}. If they are equal,
143.2669 + * as defined by the {@link #compareTo(BigDecimal) compareTo}
143.2670 + * method, {@code this} is returned.
143.2671 + * @see #compareTo(java.math.BigDecimal)
143.2672 + */
143.2673 + public BigDecimal max(BigDecimal val) {
143.2674 + return (compareTo(val) >= 0 ? this : val);
143.2675 + }
143.2676 +
143.2677 + // Hash Function
143.2678 +
143.2679 + /**
143.2680 + * Returns the hash code for this {@code BigDecimal}. Note that
143.2681 + * two {@code BigDecimal} objects that are numerically equal but
143.2682 + * differ in scale (like 2.0 and 2.00) will generally <i>not</i>
143.2683 + * have the same hash code.
143.2684 + *
143.2685 + * @return hash code for this {@code BigDecimal}.
143.2686 + * @see #equals(Object)
143.2687 + */
143.2688 + @Override
143.2689 + public int hashCode() {
143.2690 + if (intCompact != INFLATED) {
143.2691 + long val2 = (intCompact < 0)? -intCompact : intCompact;
143.2692 + int temp = (int)( ((int)(val2 >>> 32)) * 31 +
143.2693 + (val2 & LONG_MASK));
143.2694 + return 31*((intCompact < 0) ?-temp:temp) + scale;
143.2695 + } else
143.2696 + return 31*intVal.hashCode() + scale;
143.2697 + }
143.2698 +
143.2699 + // Format Converters
143.2700 +
143.2701 + /**
143.2702 + * Returns the string representation of this {@code BigDecimal},
143.2703 + * using scientific notation if an exponent is needed.
143.2704 + *
143.2705 + * <p>A standard canonical string form of the {@code BigDecimal}
143.2706 + * is created as though by the following steps: first, the
143.2707 + * absolute value of the unscaled value of the {@code BigDecimal}
143.2708 + * is converted to a string in base ten using the characters
143.2709 + * {@code '0'} through {@code '9'} with no leading zeros (except
143.2710 + * if its value is zero, in which case a single {@code '0'}
143.2711 + * character is used).
143.2712 + *
143.2713 + * <p>Next, an <i>adjusted exponent</i> is calculated; this is the
143.2714 + * negated scale, plus the number of characters in the converted
143.2715 + * unscaled value, less one. That is,
143.2716 + * {@code -scale+(ulength-1)}, where {@code ulength} is the
143.2717 + * length of the absolute value of the unscaled value in decimal
143.2718 + * digits (its <i>precision</i>).
143.2719 + *
143.2720 + * <p>If the scale is greater than or equal to zero and the
143.2721 + * adjusted exponent is greater than or equal to {@code -6}, the
143.2722 + * number will be converted to a character form without using
143.2723 + * exponential notation. In this case, if the scale is zero then
143.2724 + * no decimal point is added and if the scale is positive a
143.2725 + * decimal point will be inserted with the scale specifying the
143.2726 + * number of characters to the right of the decimal point.
143.2727 + * {@code '0'} characters are added to the left of the converted
143.2728 + * unscaled value as necessary. If no character precedes the
143.2729 + * decimal point after this insertion then a conventional
143.2730 + * {@code '0'} character is prefixed.
143.2731 + *
143.2732 + * <p>Otherwise (that is, if the scale is negative, or the
143.2733 + * adjusted exponent is less than {@code -6}), the number will be
143.2734 + * converted to a character form using exponential notation. In
143.2735 + * this case, if the converted {@code BigInteger} has more than
143.2736 + * one digit a decimal point is inserted after the first digit.
143.2737 + * An exponent in character form is then suffixed to the converted
143.2738 + * unscaled value (perhaps with inserted decimal point); this
143.2739 + * comprises the letter {@code 'E'} followed immediately by the
143.2740 + * adjusted exponent converted to a character form. The latter is
143.2741 + * in base ten, using the characters {@code '0'} through
143.2742 + * {@code '9'} with no leading zeros, and is always prefixed by a
143.2743 + * sign character {@code '-'} (<tt>'\u002D'</tt>) if the
143.2744 + * adjusted exponent is negative, {@code '+'}
143.2745 + * (<tt>'\u002B'</tt>) otherwise).
143.2746 + *
143.2747 + * <p>Finally, the entire string is prefixed by a minus sign
143.2748 + * character {@code '-'} (<tt>'\u002D'</tt>) if the unscaled
143.2749 + * value is less than zero. No sign character is prefixed if the
143.2750 + * unscaled value is zero or positive.
143.2751 + *
143.2752 + * <p><b>Examples:</b>
143.2753 + * <p>For each representation [<i>unscaled value</i>, <i>scale</i>]
143.2754 + * on the left, the resulting string is shown on the right.
143.2755 + * <pre>
143.2756 + * [123,0] "123"
143.2757 + * [-123,0] "-123"
143.2758 + * [123,-1] "1.23E+3"
143.2759 + * [123,-3] "1.23E+5"
143.2760 + * [123,1] "12.3"
143.2761 + * [123,5] "0.00123"
143.2762 + * [123,10] "1.23E-8"
143.2763 + * [-123,12] "-1.23E-10"
143.2764 + * </pre>
143.2765 + *
143.2766 + * <b>Notes:</b>
143.2767 + * <ol>
143.2768 + *
143.2769 + * <li>There is a one-to-one mapping between the distinguishable
143.2770 + * {@code BigDecimal} values and the result of this conversion.
143.2771 + * That is, every distinguishable {@code BigDecimal} value
143.2772 + * (unscaled value and scale) has a unique string representation
143.2773 + * as a result of using {@code toString}. If that string
143.2774 + * representation is converted back to a {@code BigDecimal} using
143.2775 + * the {@link #BigDecimal(String)} constructor, then the original
143.2776 + * value will be recovered.
143.2777 + *
143.2778 + * <li>The string produced for a given number is always the same;
143.2779 + * it is not affected by locale. This means that it can be used
143.2780 + * as a canonical string representation for exchanging decimal
143.2781 + * data, or as a key for a Hashtable, etc. Locale-sensitive
143.2782 + * number formatting and parsing is handled by the {@link
143.2783 + * java.text.NumberFormat} class and its subclasses.
143.2784 + *
143.2785 + * <li>The {@link #toEngineeringString} method may be used for
143.2786 + * presenting numbers with exponents in engineering notation, and the
143.2787 + * {@link #setScale(int,RoundingMode) setScale} method may be used for
143.2788 + * rounding a {@code BigDecimal} so it has a known number of digits after
143.2789 + * the decimal point.
143.2790 + *
143.2791 + * <li>The digit-to-character mapping provided by
143.2792 + * {@code Character.forDigit} is used.
143.2793 + *
143.2794 + * </ol>
143.2795 + *
143.2796 + * @return string representation of this {@code BigDecimal}.
143.2797 + * @see Character#forDigit
143.2798 + * @see #BigDecimal(java.lang.String)
143.2799 + */
143.2800 + @Override
143.2801 + public String toString() {
143.2802 + String sc = stringCache;
143.2803 + if (sc == null)
143.2804 + stringCache = sc = layoutChars(true);
143.2805 + return sc;
143.2806 + }
143.2807 +
143.2808 + /**
143.2809 + * Returns a string representation of this {@code BigDecimal},
143.2810 + * using engineering notation if an exponent is needed.
143.2811 + *
143.2812 + * <p>Returns a string that represents the {@code BigDecimal} as
143.2813 + * described in the {@link #toString()} method, except that if
143.2814 + * exponential notation is used, the power of ten is adjusted to
143.2815 + * be a multiple of three (engineering notation) such that the
143.2816 + * integer part of nonzero values will be in the range 1 through
143.2817 + * 999. If exponential notation is used for zero values, a
143.2818 + * decimal point and one or two fractional zero digits are used so
143.2819 + * that the scale of the zero value is preserved. Note that
143.2820 + * unlike the output of {@link #toString()}, the output of this
143.2821 + * method is <em>not</em> guaranteed to recover the same [integer,
143.2822 + * scale] pair of this {@code BigDecimal} if the output string is
143.2823 + * converting back to a {@code BigDecimal} using the {@linkplain
143.2824 + * #BigDecimal(String) string constructor}. The result of this method meets
143.2825 + * the weaker constraint of always producing a numerically equal
143.2826 + * result from applying the string constructor to the method's output.
143.2827 + *
143.2828 + * @return string representation of this {@code BigDecimal}, using
143.2829 + * engineering notation if an exponent is needed.
143.2830 + * @since 1.5
143.2831 + */
143.2832 + public String toEngineeringString() {
143.2833 + return layoutChars(false);
143.2834 + }
143.2835 +
143.2836 + /**
143.2837 + * Returns a string representation of this {@code BigDecimal}
143.2838 + * without an exponent field. For values with a positive scale,
143.2839 + * the number of digits to the right of the decimal point is used
143.2840 + * to indicate scale. For values with a zero or negative scale,
143.2841 + * the resulting string is generated as if the value were
143.2842 + * converted to a numerically equal value with zero scale and as
143.2843 + * if all the trailing zeros of the zero scale value were present
143.2844 + * in the result.
143.2845 + *
143.2846 + * The entire string is prefixed by a minus sign character '-'
143.2847 + * (<tt>'\u002D'</tt>) if the unscaled value is less than
143.2848 + * zero. No sign character is prefixed if the unscaled value is
143.2849 + * zero or positive.
143.2850 + *
143.2851 + * Note that if the result of this method is passed to the
143.2852 + * {@linkplain #BigDecimal(String) string constructor}, only the
143.2853 + * numerical value of this {@code BigDecimal} will necessarily be
143.2854 + * recovered; the representation of the new {@code BigDecimal}
143.2855 + * may have a different scale. In particular, if this
143.2856 + * {@code BigDecimal} has a negative scale, the string resulting
143.2857 + * from this method will have a scale of zero when processed by
143.2858 + * the string constructor.
143.2859 + *
143.2860 + * (This method behaves analogously to the {@code toString}
143.2861 + * method in 1.4 and earlier releases.)
143.2862 + *
143.2863 + * @return a string representation of this {@code BigDecimal}
143.2864 + * without an exponent field.
143.2865 + * @since 1.5
143.2866 + * @see #toString()
143.2867 + * @see #toEngineeringString()
143.2868 + */
143.2869 + public String toPlainString() {
143.2870 + BigDecimal bd = this;
143.2871 + if (bd.scale < 0)
143.2872 + bd = bd.setScale(0);
143.2873 + bd.inflate();
143.2874 + if (bd.scale == 0) // No decimal point
143.2875 + return bd.intVal.toString();
143.2876 + return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale);
143.2877 + }
143.2878 +
143.2879 + /* Returns a digit.digit string */
143.2880 + private String getValueString(int signum, String intString, int scale) {
143.2881 + /* Insert decimal point */
143.2882 + StringBuilder buf;
143.2883 + int insertionPoint = intString.length() - scale;
143.2884 + if (insertionPoint == 0) { /* Point goes right before intVal */
143.2885 + return (signum<0 ? "-0." : "0.") + intString;
143.2886 + } else if (insertionPoint > 0) { /* Point goes inside intVal */
143.2887 + buf = new StringBuilder(intString);
143.2888 + buf.insert(insertionPoint, '.');
143.2889 + if (signum < 0)
143.2890 + buf.insert(0, '-');
143.2891 + } else { /* We must insert zeros between point and intVal */
143.2892 + buf = new StringBuilder(3-insertionPoint + intString.length());
143.2893 + buf.append(signum<0 ? "-0." : "0.");
143.2894 + for (int i=0; i<-insertionPoint; i++)
143.2895 + buf.append('0');
143.2896 + buf.append(intString);
143.2897 + }
143.2898 + return buf.toString();
143.2899 + }
143.2900 +
143.2901 + /**
143.2902 + * Converts this {@code BigDecimal} to a {@code BigInteger}.
143.2903 + * This conversion is analogous to the
143.2904 + * <i>narrowing primitive conversion</i> from {@code double} to
143.2905 + * {@code long} as defined in section 5.1.3 of
143.2906 + * <cite>The Java™ Language Specification</cite>:
143.2907 + * any fractional part of this
143.2908 + * {@code BigDecimal} will be discarded. Note that this
143.2909 + * conversion can lose information about the precision of the
143.2910 + * {@code BigDecimal} value.
143.2911 + * <p>
143.2912 + * To have an exception thrown if the conversion is inexact (in
143.2913 + * other words if a nonzero fractional part is discarded), use the
143.2914 + * {@link #toBigIntegerExact()} method.
143.2915 + *
143.2916 + * @return this {@code BigDecimal} converted to a {@code BigInteger}.
143.2917 + */
143.2918 + public BigInteger toBigInteger() {
143.2919 + // force to an integer, quietly
143.2920 + return this.setScale(0, ROUND_DOWN).inflate();
143.2921 + }
143.2922 +
143.2923 + /**
143.2924 + * Converts this {@code BigDecimal} to a {@code BigInteger},
143.2925 + * checking for lost information. An exception is thrown if this
143.2926 + * {@code BigDecimal} has a nonzero fractional part.
143.2927 + *
143.2928 + * @return this {@code BigDecimal} converted to a {@code BigInteger}.
143.2929 + * @throws ArithmeticException if {@code this} has a nonzero
143.2930 + * fractional part.
143.2931 + * @since 1.5
143.2932 + */
143.2933 + public BigInteger toBigIntegerExact() {
143.2934 + // round to an integer, with Exception if decimal part non-0
143.2935 + return this.setScale(0, ROUND_UNNECESSARY).inflate();
143.2936 + }
143.2937 +
143.2938 + /**
143.2939 + * Converts this {@code BigDecimal} to a {@code long}.
143.2940 + * This conversion is analogous to the
143.2941 + * <i>narrowing primitive conversion</i> from {@code double} to
143.2942 + * {@code short} as defined in section 5.1.3 of
143.2943 + * <cite>The Java™ Language Specification</cite>:
143.2944 + * any fractional part of this
143.2945 + * {@code BigDecimal} will be discarded, and if the resulting
143.2946 + * "{@code BigInteger}" is too big to fit in a
143.2947 + * {@code long}, only the low-order 64 bits are returned.
143.2948 + * Note that this conversion can lose information about the
143.2949 + * overall magnitude and precision of this {@code BigDecimal} value as well
143.2950 + * as return a result with the opposite sign.
143.2951 + *
143.2952 + * @return this {@code BigDecimal} converted to a {@code long}.
143.2953 + */
143.2954 + public long longValue(){
143.2955 + return (intCompact != INFLATED && scale == 0) ?
143.2956 + intCompact:
143.2957 + toBigInteger().longValue();
143.2958 + }
143.2959 +
143.2960 + /**
143.2961 + * Converts this {@code BigDecimal} to a {@code long}, checking
143.2962 + * for lost information. If this {@code BigDecimal} has a
143.2963 + * nonzero fractional part or is out of the possible range for a
143.2964 + * {@code long} result then an {@code ArithmeticException} is
143.2965 + * thrown.
143.2966 + *
143.2967 + * @return this {@code BigDecimal} converted to a {@code long}.
143.2968 + * @throws ArithmeticException if {@code this} has a nonzero
143.2969 + * fractional part, or will not fit in a {@code long}.
143.2970 + * @since 1.5
143.2971 + */
143.2972 + public long longValueExact() {
143.2973 + if (intCompact != INFLATED && scale == 0)
143.2974 + return intCompact;
143.2975 + // If more than 19 digits in integer part it cannot possibly fit
143.2976 + if ((precision() - scale) > 19) // [OK for negative scale too]
143.2977 + throw new java.lang.ArithmeticException("Overflow");
143.2978 + // Fastpath zero and < 1.0 numbers (the latter can be very slow
143.2979 + // to round if very small)
143.2980 + if (this.signum() == 0)
143.2981 + return 0;
143.2982 + if ((this.precision() - this.scale) <= 0)
143.2983 + throw new ArithmeticException("Rounding necessary");
143.2984 + // round to an integer, with Exception if decimal part non-0
143.2985 + BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
143.2986 + if (num.precision() >= 19) // need to check carefully
143.2987 + LongOverflow.check(num);
143.2988 + return num.inflate().longValue();
143.2989 + }
143.2990 +
143.2991 + private static class LongOverflow {
143.2992 + /** BigInteger equal to Long.MIN_VALUE. */
143.2993 + private static final BigInteger LONGMIN = BigInteger.valueOf(Long.MIN_VALUE);
143.2994 +
143.2995 + /** BigInteger equal to Long.MAX_VALUE. */
143.2996 + private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
143.2997 +
143.2998 + public static void check(BigDecimal num) {
143.2999 + num.inflate();
143.3000 + if ((num.intVal.compareTo(LONGMIN) < 0) ||
143.3001 + (num.intVal.compareTo(LONGMAX) > 0))
143.3002 + throw new java.lang.ArithmeticException("Overflow");
143.3003 + }
143.3004 + }
143.3005 +
143.3006 + /**
143.3007 + * Converts this {@code BigDecimal} to an {@code int}.
143.3008 + * This conversion is analogous to the
143.3009 + * <i>narrowing primitive conversion</i> from {@code double} to
143.3010 + * {@code short} as defined in section 5.1.3 of
143.3011 + * <cite>The Java™ Language Specification</cite>:
143.3012 + * any fractional part of this
143.3013 + * {@code BigDecimal} will be discarded, and if the resulting
143.3014 + * "{@code BigInteger}" is too big to fit in an
143.3015 + * {@code int}, only the low-order 32 bits are returned.
143.3016 + * Note that this conversion can lose information about the
143.3017 + * overall magnitude and precision of this {@code BigDecimal}
143.3018 + * value as well as return a result with the opposite sign.
143.3019 + *
143.3020 + * @return this {@code BigDecimal} converted to an {@code int}.
143.3021 + */
143.3022 + public int intValue() {
143.3023 + return (intCompact != INFLATED && scale == 0) ?
143.3024 + (int)intCompact :
143.3025 + toBigInteger().intValue();
143.3026 + }
143.3027 +
143.3028 + /**
143.3029 + * Converts this {@code BigDecimal} to an {@code int}, checking
143.3030 + * for lost information. If this {@code BigDecimal} has a
143.3031 + * nonzero fractional part or is out of the possible range for an
143.3032 + * {@code int} result then an {@code ArithmeticException} is
143.3033 + * thrown.
143.3034 + *
143.3035 + * @return this {@code BigDecimal} converted to an {@code int}.
143.3036 + * @throws ArithmeticException if {@code this} has a nonzero
143.3037 + * fractional part, or will not fit in an {@code int}.
143.3038 + * @since 1.5
143.3039 + */
143.3040 + public int intValueExact() {
143.3041 + long num;
143.3042 + num = this.longValueExact(); // will check decimal part
143.3043 + if ((int)num != num)
143.3044 + throw new java.lang.ArithmeticException("Overflow");
143.3045 + return (int)num;
143.3046 + }
143.3047 +
143.3048 + /**
143.3049 + * Converts this {@code BigDecimal} to a {@code short}, checking
143.3050 + * for lost information. If this {@code BigDecimal} has a
143.3051 + * nonzero fractional part or is out of the possible range for a
143.3052 + * {@code short} result then an {@code ArithmeticException} is
143.3053 + * thrown.
143.3054 + *
143.3055 + * @return this {@code BigDecimal} converted to a {@code short}.
143.3056 + * @throws ArithmeticException if {@code this} has a nonzero
143.3057 + * fractional part, or will not fit in a {@code short}.
143.3058 + * @since 1.5
143.3059 + */
143.3060 + public short shortValueExact() {
143.3061 + long num;
143.3062 + num = this.longValueExact(); // will check decimal part
143.3063 + if ((short)num != num)
143.3064 + throw new java.lang.ArithmeticException("Overflow");
143.3065 + return (short)num;
143.3066 + }
143.3067 +
143.3068 + /**
143.3069 + * Converts this {@code BigDecimal} to a {@code byte}, checking
143.3070 + * for lost information. If this {@code BigDecimal} has a
143.3071 + * nonzero fractional part or is out of the possible range for a
143.3072 + * {@code byte} result then an {@code ArithmeticException} is
143.3073 + * thrown.
143.3074 + *
143.3075 + * @return this {@code BigDecimal} converted to a {@code byte}.
143.3076 + * @throws ArithmeticException if {@code this} has a nonzero
143.3077 + * fractional part, or will not fit in a {@code byte}.
143.3078 + * @since 1.5
143.3079 + */
143.3080 + public byte byteValueExact() {
143.3081 + long num;
143.3082 + num = this.longValueExact(); // will check decimal part
143.3083 + if ((byte)num != num)
143.3084 + throw new java.lang.ArithmeticException("Overflow");
143.3085 + return (byte)num;
143.3086 + }
143.3087 +
143.3088 + /**
143.3089 + * Converts this {@code BigDecimal} to a {@code float}.
143.3090 + * This conversion is similar to the
143.3091 + * <i>narrowing primitive conversion</i> from {@code double} to
143.3092 + * {@code float} as defined in section 5.1.3 of
143.3093 + * <cite>The Java™ Language Specification</cite>:
143.3094 + * if this {@code BigDecimal} has too great a
143.3095 + * magnitude to represent as a {@code float}, it will be
143.3096 + * converted to {@link Float#NEGATIVE_INFINITY} or {@link
143.3097 + * Float#POSITIVE_INFINITY} as appropriate. Note that even when
143.3098 + * the return value is finite, this conversion can lose
143.3099 + * information about the precision of the {@code BigDecimal}
143.3100 + * value.
143.3101 + *
143.3102 + * @return this {@code BigDecimal} converted to a {@code float}.
143.3103 + */
143.3104 + public float floatValue(){
143.3105 + if (scale == 0 && intCompact != INFLATED)
143.3106 + return (float)intCompact;
143.3107 + // Somewhat inefficient, but guaranteed to work.
143.3108 + return Float.parseFloat(this.toString());
143.3109 + }
143.3110 +
143.3111 + /**
143.3112 + * Converts this {@code BigDecimal} to a {@code double}.
143.3113 + * This conversion is similar to the
143.3114 + * <i>narrowing primitive conversion</i> from {@code double} to
143.3115 + * {@code float} as defined in section 5.1.3 of
143.3116 + * <cite>The Java™ Language Specification</cite>:
143.3117 + * if this {@code BigDecimal} has too great a
143.3118 + * magnitude represent as a {@code double}, it will be
143.3119 + * converted to {@link Double#NEGATIVE_INFINITY} or {@link
143.3120 + * Double#POSITIVE_INFINITY} as appropriate. Note that even when
143.3121 + * the return value is finite, this conversion can lose
143.3122 + * information about the precision of the {@code BigDecimal}
143.3123 + * value.
143.3124 + *
143.3125 + * @return this {@code BigDecimal} converted to a {@code double}.
143.3126 + */
143.3127 + public double doubleValue(){
143.3128 + if (scale == 0 && intCompact != INFLATED)
143.3129 + return (double)intCompact;
143.3130 + // Somewhat inefficient, but guaranteed to work.
143.3131 + return Double.parseDouble(this.toString());
143.3132 + }
143.3133 +
143.3134 + /**
143.3135 + * Returns the size of an ulp, a unit in the last place, of this
143.3136 + * {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal}
143.3137 + * value is the positive distance between this value and the
143.3138 + * {@code BigDecimal} value next larger in magnitude with the
143.3139 + * same number of digits. An ulp of a zero value is numerically
143.3140 + * equal to 1 with the scale of {@code this}. The result is
143.3141 + * stored with the same scale as {@code this} so the result
143.3142 + * for zero and nonzero values is equal to {@code [1,
143.3143 + * this.scale()]}.
143.3144 + *
143.3145 + * @return the size of an ulp of {@code this}
143.3146 + * @since 1.5
143.3147 + */
143.3148 + public BigDecimal ulp() {
143.3149 + return BigDecimal.valueOf(1, this.scale());
143.3150 + }
143.3151 +
143.3152 +
143.3153 + // Private class to build a string representation for BigDecimal object.
143.3154 + // "StringBuilderHelper" is constructed as a thread local variable so it is
143.3155 + // thread safe. The StringBuilder field acts as a buffer to hold the temporary
143.3156 + // representation of BigDecimal. The cmpCharArray holds all the characters for
143.3157 + // the compact representation of BigDecimal (except for '-' sign' if it is
143.3158 + // negative) if its intCompact field is not INFLATED. It is shared by all
143.3159 + // calls to toString() and its variants in that particular thread.
143.3160 + static class StringBuilderHelper {
143.3161 + private static StringBuilderHelper INSTANCE = new StringBuilderHelper();
143.3162 + final StringBuilder sb; // Placeholder for BigDecimal string
143.3163 + final char[] cmpCharArray; // character array to place the intCompact
143.3164 +
143.3165 + StringBuilderHelper() {
143.3166 + sb = new StringBuilder();
143.3167 + // All non negative longs can be made to fit into 19 character array.
143.3168 + cmpCharArray = new char[19];
143.3169 + }
143.3170 +
143.3171 + // Accessors.
143.3172 + StringBuilder getStringBuilder() {
143.3173 + sb.setLength(0);
143.3174 + return sb;
143.3175 + }
143.3176 +
143.3177 + char[] getCompactCharArray() {
143.3178 + return cmpCharArray;
143.3179 + }
143.3180 +
143.3181 + /**
143.3182 + * Places characters representing the intCompact in {@code long} into
143.3183 + * cmpCharArray and returns the offset to the array where the
143.3184 + * representation starts.
143.3185 + *
143.3186 + * @param intCompact the number to put into the cmpCharArray.
143.3187 + * @return offset to the array where the representation starts.
143.3188 + * Note: intCompact must be greater or equal to zero.
143.3189 + */
143.3190 + int putIntCompact(long intCompact) {
143.3191 + assert intCompact >= 0;
143.3192 +
143.3193 + long q;
143.3194 + int r;
143.3195 + // since we start from the least significant digit, charPos points to
143.3196 + // the last character in cmpCharArray.
143.3197 + int charPos = cmpCharArray.length;
143.3198 +
143.3199 + // Get 2 digits/iteration using longs until quotient fits into an int
143.3200 + while (intCompact > Integer.MAX_VALUE) {
143.3201 + q = intCompact / 100;
143.3202 + r = (int)(intCompact - q * 100);
143.3203 + intCompact = q;
143.3204 + cmpCharArray[--charPos] = DIGIT_ONES[r];
143.3205 + cmpCharArray[--charPos] = DIGIT_TENS[r];
143.3206 + }
143.3207 +
143.3208 + // Get 2 digits/iteration using ints when i2 >= 100
143.3209 + int q2;
143.3210 + int i2 = (int)intCompact;
143.3211 + while (i2 >= 100) {
143.3212 + q2 = i2 / 100;
143.3213 + r = i2 - q2 * 100;
143.3214 + i2 = q2;
143.3215 + cmpCharArray[--charPos] = DIGIT_ONES[r];
143.3216 + cmpCharArray[--charPos] = DIGIT_TENS[r];
143.3217 + }
143.3218 +
143.3219 + cmpCharArray[--charPos] = DIGIT_ONES[i2];
143.3220 + if (i2 >= 10)
143.3221 + cmpCharArray[--charPos] = DIGIT_TENS[i2];
143.3222 +
143.3223 + return charPos;
143.3224 + }
143.3225 +
143.3226 + final static char[] DIGIT_TENS = {
143.3227 + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
143.3228 + '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
143.3229 + '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
143.3230 + '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
143.3231 + '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
143.3232 + '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
143.3233 + '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
143.3234 + '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
143.3235 + '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
143.3236 + '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
143.3237 + };
143.3238 +
143.3239 + final static char[] DIGIT_ONES = {
143.3240 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3241 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3242 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3243 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3244 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3245 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3246 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3247 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3248 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3249 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
143.3250 + };
143.3251 + }
143.3252 +
143.3253 + /**
143.3254 + * Lay out this {@code BigDecimal} into a {@code char[]} array.
143.3255 + * The Java 1.2 equivalent to this was called {@code getValueString}.
143.3256 + *
143.3257 + * @param sci {@code true} for Scientific exponential notation;
143.3258 + * {@code false} for Engineering
143.3259 + * @return string with canonical string representation of this
143.3260 + * {@code BigDecimal}
143.3261 + */
143.3262 + private String layoutChars(boolean sci) {
143.3263 + if (scale == 0) // zero scale is trivial
143.3264 + return (intCompact != INFLATED) ?
143.3265 + Long.toString(intCompact):
143.3266 + intVal.toString();
143.3267 +
143.3268 + StringBuilderHelper sbHelper = StringBuilderHelper.INSTANCE;
143.3269 + char[] coeff;
143.3270 + int offset; // offset is the starting index for coeff array
143.3271 + // Get the significand as an absolute value
143.3272 + if (intCompact != INFLATED) {
143.3273 + offset = sbHelper.putIntCompact(Math.abs(intCompact));
143.3274 + coeff = sbHelper.getCompactCharArray();
143.3275 + } else {
143.3276 + offset = 0;
143.3277 + coeff = intVal.abs().toString().toCharArray();
143.3278 + }
143.3279 +
143.3280 + // Construct a buffer, with sufficient capacity for all cases.
143.3281 + // If E-notation is needed, length will be: +1 if negative, +1
143.3282 + // if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
143.3283 + // Otherwise it could have +1 if negative, plus leading "0.00000"
143.3284 + StringBuilder buf = sbHelper.getStringBuilder();
143.3285 + if (signum() < 0) // prefix '-' if negative
143.3286 + buf.append('-');
143.3287 + int coeffLen = coeff.length - offset;
143.3288 + long adjusted = -(long)scale + (coeffLen -1);
143.3289 + if ((scale >= 0) && (adjusted >= -6)) { // plain number
143.3290 + int pad = scale - coeffLen; // count of padding zeros
143.3291 + if (pad >= 0) { // 0.xxx form
143.3292 + buf.append('0');
143.3293 + buf.append('.');
143.3294 + for (; pad>0; pad--) {
143.3295 + buf.append('0');
143.3296 + }
143.3297 + buf.append(coeff, offset, coeffLen);
143.3298 + } else { // xx.xx form
143.3299 + buf.append(coeff, offset, -pad);
143.3300 + buf.append('.');
143.3301 + buf.append(coeff, -pad + offset, scale);
143.3302 + }
143.3303 + } else { // E-notation is needed
143.3304 + if (sci) { // Scientific notation
143.3305 + buf.append(coeff[offset]); // first character
143.3306 + if (coeffLen > 1) { // more to come
143.3307 + buf.append('.');
143.3308 + buf.append(coeff, offset + 1, coeffLen - 1);
143.3309 + }
143.3310 + } else { // Engineering notation
143.3311 + int sig = (int)(adjusted % 3);
143.3312 + if (sig < 0)
143.3313 + sig += 3; // [adjusted was negative]
143.3314 + adjusted -= sig; // now a multiple of 3
143.3315 + sig++;
143.3316 + if (signum() == 0) {
143.3317 + switch (sig) {
143.3318 + case 1:
143.3319 + buf.append('0'); // exponent is a multiple of three
143.3320 + break;
143.3321 + case 2:
143.3322 + buf.append("0.00");
143.3323 + adjusted += 3;
143.3324 + break;
143.3325 + case 3:
143.3326 + buf.append("0.0");
143.3327 + adjusted += 3;
143.3328 + break;
143.3329 + default:
143.3330 + throw new AssertionError("Unexpected sig value " + sig);
143.3331 + }
143.3332 + } else if (sig >= coeffLen) { // significand all in integer
143.3333 + buf.append(coeff, offset, coeffLen);
143.3334 + // may need some zeros, too
143.3335 + for (int i = sig - coeffLen; i > 0; i--)
143.3336 + buf.append('0');
143.3337 + } else { // xx.xxE form
143.3338 + buf.append(coeff, offset, sig);
143.3339 + buf.append('.');
143.3340 + buf.append(coeff, offset + sig, coeffLen - sig);
143.3341 + }
143.3342 + }
143.3343 + if (adjusted != 0) { // [!sci could have made 0]
143.3344 + buf.append('E');
143.3345 + if (adjusted > 0) // force sign for positive
143.3346 + buf.append('+');
143.3347 + buf.append(adjusted);
143.3348 + }
143.3349 + }
143.3350 + return buf.toString();
143.3351 + }
143.3352 +
143.3353 + /**
143.3354 + * Return 10 to the power n, as a {@code BigInteger}.
143.3355 + *
143.3356 + * @param n the power of ten to be returned (>=0)
143.3357 + * @return a {@code BigInteger} with the value (10<sup>n</sup>)
143.3358 + */
143.3359 + private static BigInteger bigTenToThe(int n) {
143.3360 + if (n < 0)
143.3361 + return BigInteger.ZERO;
143.3362 +
143.3363 + if (n < BIG_TEN_POWERS_TABLE_MAX) {
143.3364 + BigInteger[] pows = BIG_TEN_POWERS_TABLE;
143.3365 + if (n < pows.length)
143.3366 + return pows[n];
143.3367 + else
143.3368 + return expandBigIntegerTenPowers(n);
143.3369 + }
143.3370 + // BigInteger.pow is slow, so make 10**n by constructing a
143.3371 + // BigInteger from a character string (still not very fast)
143.3372 + char tenpow[] = new char[n + 1];
143.3373 + tenpow[0] = '1';
143.3374 + for (int i = 1; i <= n; i++)
143.3375 + tenpow[i] = '0';
143.3376 + return new BigInteger(tenpow);
143.3377 + }
143.3378 +
143.3379 + /**
143.3380 + * Expand the BIG_TEN_POWERS_TABLE array to contain at least 10**n.
143.3381 + *
143.3382 + * @param n the power of ten to be returned (>=0)
143.3383 + * @return a {@code BigDecimal} with the value (10<sup>n</sup>) and
143.3384 + * in the meantime, the BIG_TEN_POWERS_TABLE array gets
143.3385 + * expanded to the size greater than n.
143.3386 + */
143.3387 + private static BigInteger expandBigIntegerTenPowers(int n) {
143.3388 + synchronized(BigDecimal.class) {
143.3389 + BigInteger[] pows = BIG_TEN_POWERS_TABLE;
143.3390 + int curLen = pows.length;
143.3391 + // The following comparison and the above synchronized statement is
143.3392 + // to prevent multiple threads from expanding the same array.
143.3393 + if (curLen <= n) {
143.3394 + int newLen = curLen << 1;
143.3395 + while (newLen <= n)
143.3396 + newLen <<= 1;
143.3397 + pows = Arrays.copyOf(pows, newLen);
143.3398 + for (int i = curLen; i < newLen; i++)
143.3399 + pows[i] = pows[i - 1].multiply(BigInteger.TEN);
143.3400 + // Based on the following facts:
143.3401 + // 1. pows is a private local varible;
143.3402 + // 2. the following store is a volatile store.
143.3403 + // the newly created array elements can be safely published.
143.3404 + BIG_TEN_POWERS_TABLE = pows;
143.3405 + }
143.3406 + return pows[n];
143.3407 + }
143.3408 + }
143.3409 +
143.3410 + private static final long[] LONG_TEN_POWERS_TABLE = {
143.3411 + 1, // 0 / 10^0
143.3412 + 10, // 1 / 10^1
143.3413 + 100, // 2 / 10^2
143.3414 + 1000, // 3 / 10^3
143.3415 + 10000, // 4 / 10^4
143.3416 + 100000, // 5 / 10^5
143.3417 + 1000000, // 6 / 10^6
143.3418 + 10000000, // 7 / 10^7
143.3419 + 100000000, // 8 / 10^8
143.3420 + 1000000000, // 9 / 10^9
143.3421 + 10000000000L, // 10 / 10^10
143.3422 + 100000000000L, // 11 / 10^11
143.3423 + 1000000000000L, // 12 / 10^12
143.3424 + 10000000000000L, // 13 / 10^13
143.3425 + 100000000000000L, // 14 / 10^14
143.3426 + 1000000000000000L, // 15 / 10^15
143.3427 + 10000000000000000L, // 16 / 10^16
143.3428 + 100000000000000000L, // 17 / 10^17
143.3429 + 1000000000000000000L // 18 / 10^18
143.3430 + };
143.3431 +
143.3432 + private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
143.3433 + BigInteger.valueOf(10), BigInteger.valueOf(100),
143.3434 + BigInteger.valueOf(1000), BigInteger.valueOf(10000),
143.3435 + BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
143.3436 + BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
143.3437 + BigInteger.valueOf(1000000000),
143.3438 + BigInteger.valueOf(10000000000L),
143.3439 + BigInteger.valueOf(100000000000L),
143.3440 + BigInteger.valueOf(1000000000000L),
143.3441 + BigInteger.valueOf(10000000000000L),
143.3442 + BigInteger.valueOf(100000000000000L),
143.3443 + BigInteger.valueOf(1000000000000000L),
143.3444 + BigInteger.valueOf(10000000000000000L),
143.3445 + BigInteger.valueOf(100000000000000000L),
143.3446 + BigInteger.valueOf(1000000000000000000L)
143.3447 + };
143.3448 +
143.3449 + private static final int BIG_TEN_POWERS_TABLE_INITLEN =
143.3450 + BIG_TEN_POWERS_TABLE.length;
143.3451 + private static final int BIG_TEN_POWERS_TABLE_MAX =
143.3452 + 16 * BIG_TEN_POWERS_TABLE_INITLEN;
143.3453 +
143.3454 + private static final long THRESHOLDS_TABLE[] = {
143.3455 + Long.MAX_VALUE, // 0
143.3456 + Long.MAX_VALUE/10L, // 1
143.3457 + Long.MAX_VALUE/100L, // 2
143.3458 + Long.MAX_VALUE/1000L, // 3
143.3459 + Long.MAX_VALUE/10000L, // 4
143.3460 + Long.MAX_VALUE/100000L, // 5
143.3461 + Long.MAX_VALUE/1000000L, // 6
143.3462 + Long.MAX_VALUE/10000000L, // 7
143.3463 + Long.MAX_VALUE/100000000L, // 8
143.3464 + Long.MAX_VALUE/1000000000L, // 9
143.3465 + Long.MAX_VALUE/10000000000L, // 10
143.3466 + Long.MAX_VALUE/100000000000L, // 11
143.3467 + Long.MAX_VALUE/1000000000000L, // 12
143.3468 + Long.MAX_VALUE/10000000000000L, // 13
143.3469 + Long.MAX_VALUE/100000000000000L, // 14
143.3470 + Long.MAX_VALUE/1000000000000000L, // 15
143.3471 + Long.MAX_VALUE/10000000000000000L, // 16
143.3472 + Long.MAX_VALUE/100000000000000000L, // 17
143.3473 + Long.MAX_VALUE/1000000000000000000L // 18
143.3474 + };
143.3475 +
143.3476 + /**
143.3477 + * Compute val * 10 ^ n; return this product if it is
143.3478 + * representable as a long, INFLATED otherwise.
143.3479 + */
143.3480 + private static long longMultiplyPowerTen(long val, int n) {
143.3481 + if (val == 0 || n <= 0)
143.3482 + return val;
143.3483 + long[] tab = LONG_TEN_POWERS_TABLE;
143.3484 + long[] bounds = THRESHOLDS_TABLE;
143.3485 + if (n < tab.length && n < bounds.length) {
143.3486 + long tenpower = tab[n];
143.3487 + if (val == 1)
143.3488 + return tenpower;
143.3489 + if (Math.abs(val) <= bounds[n])
143.3490 + return val * tenpower;
143.3491 + }
143.3492 + return INFLATED;
143.3493 + }
143.3494 +
143.3495 + /**
143.3496 + * Compute this * 10 ^ n.
143.3497 + * Needed mainly to allow special casing to trap zero value
143.3498 + */
143.3499 + private BigInteger bigMultiplyPowerTen(int n) {
143.3500 + if (n <= 0)
143.3501 + return this.inflate();
143.3502 +
143.3503 + if (intCompact != INFLATED)
143.3504 + return bigTenToThe(n).multiply(intCompact);
143.3505 + else
143.3506 + return intVal.multiply(bigTenToThe(n));
143.3507 + }
143.3508 +
143.3509 + /**
143.3510 + * Assign appropriate BigInteger to intVal field if intVal is
143.3511 + * null, i.e. the compact representation is in use.
143.3512 + */
143.3513 + private BigInteger inflate() {
143.3514 + if (intVal == null)
143.3515 + intVal = BigInteger.valueOf(intCompact);
143.3516 + return intVal;
143.3517 + }
143.3518 +
143.3519 + /**
143.3520 + * Match the scales of two {@code BigDecimal}s to align their
143.3521 + * least significant digits.
143.3522 + *
143.3523 + * <p>If the scales of val[0] and val[1] differ, rescale
143.3524 + * (non-destructively) the lower-scaled {@code BigDecimal} so
143.3525 + * they match. That is, the lower-scaled reference will be
143.3526 + * replaced by a reference to a new object with the same scale as
143.3527 + * the other {@code BigDecimal}.
143.3528 + *
143.3529 + * @param val array of two elements referring to the two
143.3530 + * {@code BigDecimal}s to be aligned.
143.3531 + */
143.3532 + private static void matchScale(BigDecimal[] val) {
143.3533 + if (val[0].scale == val[1].scale) {
143.3534 + return;
143.3535 + } else if (val[0].scale < val[1].scale) {
143.3536 + val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
143.3537 + } else if (val[1].scale < val[0].scale) {
143.3538 + val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
143.3539 + }
143.3540 + }
143.3541 +
143.3542 + /**
143.3543 + * Reconstitute the {@code BigDecimal} instance from a stream (that is,
143.3544 + * deserialize it).
143.3545 + *
143.3546 + * @param s the stream being read.
143.3547 + */
143.3548 + private void readObject(java.io.ObjectInputStream s)
143.3549 + throws java.io.IOException, ClassNotFoundException {
143.3550 + // Read in all fields
143.3551 + s.defaultReadObject();
143.3552 + // validate possibly bad fields
143.3553 + if (intVal == null) {
143.3554 + String message = "BigDecimal: null intVal in stream";
143.3555 + throw new java.io.StreamCorruptedException(message);
143.3556 + // [all values of scale are now allowed]
143.3557 + }
143.3558 + intCompact = compactValFor(intVal);
143.3559 + }
143.3560 +
143.3561 + /**
143.3562 + * Serialize this {@code BigDecimal} to the stream in question
143.3563 + *
143.3564 + * @param s the stream to serialize to.
143.3565 + */
143.3566 + private void writeObject(java.io.ObjectOutputStream s)
143.3567 + throws java.io.IOException {
143.3568 + // Must inflate to maintain compatible serial form.
143.3569 + this.inflate();
143.3570 +
143.3571 + // Write proper fields
143.3572 + s.defaultWriteObject();
143.3573 + }
143.3574 +
143.3575 +
143.3576 + /**
143.3577 + * Returns the length of the absolute value of a {@code long}, in decimal
143.3578 + * digits.
143.3579 + *
143.3580 + * @param x the {@code long}
143.3581 + * @return the length of the unscaled value, in deciaml digits.
143.3582 + */
143.3583 + private static int longDigitLength(long x) {
143.3584 + /*
143.3585 + * As described in "Bit Twiddling Hacks" by Sean Anderson,
143.3586 + * (http://graphics.stanford.edu/~seander/bithacks.html)
143.3587 + * integer log 10 of x is within 1 of
143.3588 + * (1233/4096)* (1 + integer log 2 of x).
143.3589 + * The fraction 1233/4096 approximates log10(2). So we first
143.3590 + * do a version of log2 (a variant of Long class with
143.3591 + * pre-checks and opposite directionality) and then scale and
143.3592 + * check against powers table. This is a little simpler in
143.3593 + * present context than the version in Hacker's Delight sec
143.3594 + * 11-4. Adding one to bit length allows comparing downward
143.3595 + * from the LONG_TEN_POWERS_TABLE that we need anyway.
143.3596 + */
143.3597 + assert x != INFLATED;
143.3598 + if (x < 0)
143.3599 + x = -x;
143.3600 + if (x < 10) // must screen for 0, might as well 10
143.3601 + return 1;
143.3602 + int n = 64; // not 63, to avoid needing to add 1 later
143.3603 + int y = (int)(x >>> 32);
143.3604 + if (y == 0) { n -= 32; y = (int)x; }
143.3605 + if (y >>> 16 == 0) { n -= 16; y <<= 16; }
143.3606 + if (y >>> 24 == 0) { n -= 8; y <<= 8; }
143.3607 + if (y >>> 28 == 0) { n -= 4; y <<= 4; }
143.3608 + if (y >>> 30 == 0) { n -= 2; y <<= 2; }
143.3609 + int r = (((y >>> 31) + n) * 1233) >>> 12;
143.3610 + long[] tab = LONG_TEN_POWERS_TABLE;
143.3611 + // if r >= length, must have max possible digits for long
143.3612 + return (r >= tab.length || x < tab[r])? r : r+1;
143.3613 + }
143.3614 +
143.3615 + /**
143.3616 + * Returns the length of the absolute value of a BigInteger, in
143.3617 + * decimal digits.
143.3618 + *
143.3619 + * @param b the BigInteger
143.3620 + * @return the length of the unscaled value, in decimal digits
143.3621 + */
143.3622 + private static int bigDigitLength(BigInteger b) {
143.3623 + /*
143.3624 + * Same idea as the long version, but we need a better
143.3625 + * approximation of log10(2). Using 646456993/2^31
143.3626 + * is accurate up to max possible reported bitLength.
143.3627 + */
143.3628 + if (b.signum == 0)
143.3629 + return 1;
143.3630 + int r = (int)((((long)b.bitLength() + 1) * 646456993) >>> 31);
143.3631 + return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
143.3632 + }
143.3633 +
143.3634 +
143.3635 + /**
143.3636 + * Remove insignificant trailing zeros from this
143.3637 + * {@code BigDecimal} until the preferred scale is reached or no
143.3638 + * more zeros can be removed. If the preferred scale is less than
143.3639 + * Integer.MIN_VALUE, all the trailing zeros will be removed.
143.3640 + *
143.3641 + * {@code BigInteger} assistance could help, here?
143.3642 + *
143.3643 + * <p>WARNING: This method should only be called on new objects as
143.3644 + * it mutates the value fields.
143.3645 + *
143.3646 + * @return this {@code BigDecimal} with a scale possibly reduced
143.3647 + * to be closed to the preferred scale.
143.3648 + */
143.3649 + private BigDecimal stripZerosToMatchScale(long preferredScale) {
143.3650 + this.inflate();
143.3651 + BigInteger qr[]; // quotient-remainder pair
143.3652 + while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
143.3653 + scale > preferredScale) {
143.3654 + if (intVal.testBit(0))
143.3655 + break; // odd number cannot end in 0
143.3656 + qr = intVal.divideAndRemainder(BigInteger.TEN);
143.3657 + if (qr[1].signum() != 0)
143.3658 + break; // non-0 remainder
143.3659 + intVal=qr[0];
143.3660 + scale = checkScale((long)scale-1); // could Overflow
143.3661 + if (precision > 0) // adjust precision if known
143.3662 + precision--;
143.3663 + }
143.3664 + if (intVal != null)
143.3665 + intCompact = compactValFor(intVal);
143.3666 + return this;
143.3667 + }
143.3668 +
143.3669 + /**
143.3670 + * Check a scale for Underflow or Overflow. If this BigDecimal is
143.3671 + * nonzero, throw an exception if the scale is outof range. If this
143.3672 + * is zero, saturate the scale to the extreme value of the right
143.3673 + * sign if the scale is out of range.
143.3674 + *
143.3675 + * @param val The new scale.
143.3676 + * @throws ArithmeticException (overflow or underflow) if the new
143.3677 + * scale is out of range.
143.3678 + * @return validated scale as an int.
143.3679 + */
143.3680 + private int checkScale(long val) {
143.3681 + int asInt = (int)val;
143.3682 + if (asInt != val) {
143.3683 + asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
143.3684 + BigInteger b;
143.3685 + if (intCompact != 0 &&
143.3686 + ((b = intVal) == null || b.signum() != 0))
143.3687 + throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
143.3688 + }
143.3689 + return asInt;
143.3690 + }
143.3691 +
143.3692 + /**
143.3693 + * Round an operand; used only if digits > 0. Does not change
143.3694 + * {@code this}; if rounding is needed a new {@code BigDecimal}
143.3695 + * is created and returned.
143.3696 + *
143.3697 + * @param mc the context to use.
143.3698 + * @throws ArithmeticException if the result is inexact but the
143.3699 + * rounding mode is {@code UNNECESSARY}.
143.3700 + */
143.3701 + private BigDecimal roundOp(MathContext mc) {
143.3702 + BigDecimal rounded = doRound(this, mc);
143.3703 + return rounded;
143.3704 + }
143.3705 +
143.3706 + /** Round this BigDecimal according to the MathContext settings;
143.3707 + * used only if precision {@literal >} 0.
143.3708 + *
143.3709 + * <p>WARNING: This method should only be called on new objects as
143.3710 + * it mutates the value fields.
143.3711 + *
143.3712 + * @param mc the context to use.
143.3713 + * @throws ArithmeticException if the rounding mode is
143.3714 + * {@code RoundingMode.UNNECESSARY} and the
143.3715 + * {@code BigDecimal} operation would require rounding.
143.3716 + */
143.3717 + private void roundThis(MathContext mc) {
143.3718 + BigDecimal rounded = doRound(this, mc);
143.3719 + if (rounded == this) // wasn't rounded
143.3720 + return;
143.3721 + this.intVal = rounded.intVal;
143.3722 + this.intCompact = rounded.intCompact;
143.3723 + this.scale = rounded.scale;
143.3724 + this.precision = rounded.precision;
143.3725 + }
143.3726 +
143.3727 + /**
143.3728 + * Returns a {@code BigDecimal} rounded according to the
143.3729 + * MathContext settings; used only if {@code mc.precision > 0}.
143.3730 + * Does not change {@code this}; if rounding is needed a new
143.3731 + * {@code BigDecimal} is created and returned.
143.3732 + *
143.3733 + * @param mc the context to use.
143.3734 + * @return a {@code BigDecimal} rounded according to the MathContext
143.3735 + * settings. May return this, if no rounding needed.
143.3736 + * @throws ArithmeticException if the rounding mode is
143.3737 + * {@code RoundingMode.UNNECESSARY} and the
143.3738 + * result is inexact.
143.3739 + */
143.3740 + private static BigDecimal doRound(BigDecimal d, MathContext mc) {
143.3741 + int mcp = mc.precision;
143.3742 + int drop;
143.3743 + // This might (rarely) iterate to cover the 999=>1000 case
143.3744 + while ((drop = d.precision() - mcp) > 0) {
143.3745 + int newScale = d.checkScale((long)d.scale - drop);
143.3746 + int mode = mc.roundingMode.oldMode;
143.3747 + if (drop < LONG_TEN_POWERS_TABLE.length)
143.3748 + d = divideAndRound(d.intCompact, d.intVal,
143.3749 + LONG_TEN_POWERS_TABLE[drop], null,
143.3750 + newScale, mode, newScale);
143.3751 + else
143.3752 + d = divideAndRound(d.intCompact, d.intVal,
143.3753 + INFLATED, bigTenToThe(drop),
143.3754 + newScale, mode, newScale);
143.3755 + }
143.3756 + return d;
143.3757 + }
143.3758 +
143.3759 + /**
143.3760 + * Returns the compact value for given {@code BigInteger}, or
143.3761 + * INFLATED if too big. Relies on internal representation of
143.3762 + * {@code BigInteger}.
143.3763 + */
143.3764 + private static long compactValFor(BigInteger b) {
143.3765 + int[] m = b.mag;
143.3766 + int len = m.length;
143.3767 + if (len == 0)
143.3768 + return 0;
143.3769 + int d = m[0];
143.3770 + if (len > 2 || (len == 2 && d < 0))
143.3771 + return INFLATED;
143.3772 +
143.3773 + long u = (len == 2)?
143.3774 + (((long) m[1] & LONG_MASK) + (((long)d) << 32)) :
143.3775 + (((long)d) & LONG_MASK);
143.3776 + return (b.signum < 0)? -u : u;
143.3777 + }
143.3778 +
143.3779 + private static int longCompareMagnitude(long x, long y) {
143.3780 + if (x < 0)
143.3781 + x = -x;
143.3782 + if (y < 0)
143.3783 + y = -y;
143.3784 + return (x < y) ? -1 : ((x == y) ? 0 : 1);
143.3785 + }
143.3786 +
143.3787 + private static int saturateLong(long s) {
143.3788 + int i = (int)s;
143.3789 + return (s == i) ? i : (s < 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE);
143.3790 + }
143.3791 +
143.3792 + /*
143.3793 + * Internal printing routine
143.3794 + */
143.3795 + private static void print(String name, BigDecimal bd) {
143.3796 + }
143.3797 +
143.3798 + /**
143.3799 + * Check internal invariants of this BigDecimal. These invariants
143.3800 + * include:
143.3801 + *
143.3802 + * <ul>
143.3803 + *
143.3804 + * <li>The object must be initialized; either intCompact must not be
143.3805 + * INFLATED or intVal is non-null. Both of these conditions may
143.3806 + * be true.
143.3807 + *
143.3808 + * <li>If both intCompact and intVal and set, their values must be
143.3809 + * consistent.
143.3810 + *
143.3811 + * <li>If precision is nonzero, it must have the right value.
143.3812 + * </ul>
143.3813 + *
143.3814 + * Note: Since this is an audit method, we are not supposed to change the
143.3815 + * state of this BigDecimal object.
143.3816 + */
143.3817 + private BigDecimal audit() {
143.3818 + if (intCompact == INFLATED) {
143.3819 + if (intVal == null) {
143.3820 + print("audit", this);
143.3821 + throw new AssertionError("null intVal");
143.3822 + }
143.3823 + // Check precision
143.3824 + if (precision > 0 && precision != bigDigitLength(intVal)) {
143.3825 + print("audit", this);
143.3826 + throw new AssertionError("precision mismatch");
143.3827 + }
143.3828 + } else {
143.3829 + if (intVal != null) {
143.3830 + long val = intVal.longValue();
143.3831 + if (val != intCompact) {
143.3832 + print("audit", this);
143.3833 + throw new AssertionError("Inconsistent state, intCompact=" +
143.3834 + intCompact + "\t intVal=" + val);
143.3835 + }
143.3836 + }
143.3837 + // Check precision
143.3838 + if (precision > 0 && precision != longDigitLength(intCompact)) {
143.3839 + print("audit", this);
143.3840 + throw new AssertionError("precision mismatch");
143.3841 + }
143.3842 + }
143.3843 + return this;
143.3844 + }
143.3845 +}
144.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
144.2 +++ b/rt/emul/compact/src/main/java/java/math/BigInteger.java Mon Oct 07 14:20:58 2013 +0200
144.3 @@ -0,0 +1,3122 @@
144.4 +/*
144.5 + * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
144.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
144.7 + *
144.8 + * This code is free software; you can redistribute it and/or modify it
144.9 + * under the terms of the GNU General Public License version 2 only, as
144.10 + * published by the Free Software Foundation. Oracle designates this
144.11 + * particular file as subject to the "Classpath" exception as provided
144.12 + * by Oracle in the LICENSE file that accompanied this code.
144.13 + *
144.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
144.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
144.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
144.17 + * version 2 for more details (a copy is included in the LICENSE file that
144.18 + * accompanied this code).
144.19 + *
144.20 + * You should have received a copy of the GNU General Public License version
144.21 + * 2 along with this work; if not, write to the Free Software Foundation,
144.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
144.23 + *
144.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
144.25 + * or visit www.oracle.com if you need additional information or have any
144.26 + * questions.
144.27 + */
144.28 +
144.29 +/*
144.30 + * Portions Copyright (c) 1995 Colin Plumb. All rights reserved.
144.31 + */
144.32 +
144.33 +package java.math;
144.34 +
144.35 +import java.util.Random;
144.36 +import java.io.*;
144.37 +
144.38 +/**
144.39 + * Immutable arbitrary-precision integers. All operations behave as if
144.40 + * BigIntegers were represented in two's-complement notation (like Java's
144.41 + * primitive integer types). BigInteger provides analogues to all of Java's
144.42 + * primitive integer operators, and all relevant methods from java.lang.Math.
144.43 + * Additionally, BigInteger provides operations for modular arithmetic, GCD
144.44 + * calculation, primality testing, prime generation, bit manipulation,
144.45 + * and a few other miscellaneous operations.
144.46 + *
144.47 + * <p>Semantics of arithmetic operations exactly mimic those of Java's integer
144.48 + * arithmetic operators, as defined in <i>The Java Language Specification</i>.
144.49 + * For example, division by zero throws an {@code ArithmeticException}, and
144.50 + * division of a negative by a positive yields a negative (or zero) remainder.
144.51 + * All of the details in the Spec concerning overflow are ignored, as
144.52 + * BigIntegers are made as large as necessary to accommodate the results of an
144.53 + * operation.
144.54 + *
144.55 + * <p>Semantics of shift operations extend those of Java's shift operators
144.56 + * to allow for negative shift distances. A right-shift with a negative
144.57 + * shift distance results in a left shift, and vice-versa. The unsigned
144.58 + * right shift operator ({@code >>>}) is omitted, as this operation makes
144.59 + * little sense in combination with the "infinite word size" abstraction
144.60 + * provided by this class.
144.61 + *
144.62 + * <p>Semantics of bitwise logical operations exactly mimic those of Java's
144.63 + * bitwise integer operators. The binary operators ({@code and},
144.64 + * {@code or}, {@code xor}) implicitly perform sign extension on the shorter
144.65 + * of the two operands prior to performing the operation.
144.66 + *
144.67 + * <p>Comparison operations perform signed integer comparisons, analogous to
144.68 + * those performed by Java's relational and equality operators.
144.69 + *
144.70 + * <p>Modular arithmetic operations are provided to compute residues, perform
144.71 + * exponentiation, and compute multiplicative inverses. These methods always
144.72 + * return a non-negative result, between {@code 0} and {@code (modulus - 1)},
144.73 + * inclusive.
144.74 + *
144.75 + * <p>Bit operations operate on a single bit of the two's-complement
144.76 + * representation of their operand. If necessary, the operand is sign-
144.77 + * extended so that it contains the designated bit. None of the single-bit
144.78 + * operations can produce a BigInteger with a different sign from the
144.79 + * BigInteger being operated on, as they affect only a single bit, and the
144.80 + * "infinite word size" abstraction provided by this class ensures that there
144.81 + * are infinitely many "virtual sign bits" preceding each BigInteger.
144.82 + *
144.83 + * <p>For the sake of brevity and clarity, pseudo-code is used throughout the
144.84 + * descriptions of BigInteger methods. The pseudo-code expression
144.85 + * {@code (i + j)} is shorthand for "a BigInteger whose value is
144.86 + * that of the BigInteger {@code i} plus that of the BigInteger {@code j}."
144.87 + * The pseudo-code expression {@code (i == j)} is shorthand for
144.88 + * "{@code true} if and only if the BigInteger {@code i} represents the same
144.89 + * value as the BigInteger {@code j}." Other pseudo-code expressions are
144.90 + * interpreted similarly.
144.91 + *
144.92 + * <p>All methods and constructors in this class throw
144.93 + * {@code NullPointerException} when passed
144.94 + * a null object reference for any input parameter.
144.95 + *
144.96 + * @see BigDecimal
144.97 + * @author Josh Bloch
144.98 + * @author Michael McCloskey
144.99 + * @since JDK1.1
144.100 + */
144.101 +
144.102 +public class BigInteger extends Number implements Comparable<BigInteger> {
144.103 + /**
144.104 + * The signum of this BigInteger: -1 for negative, 0 for zero, or
144.105 + * 1 for positive. Note that the BigInteger zero <i>must</i> have
144.106 + * a signum of 0. This is necessary to ensures that there is exactly one
144.107 + * representation for each BigInteger value.
144.108 + *
144.109 + * @serial
144.110 + */
144.111 + final int signum;
144.112 +
144.113 + /**
144.114 + * The magnitude of this BigInteger, in <i>big-endian</i> order: the
144.115 + * zeroth element of this array is the most-significant int of the
144.116 + * magnitude. The magnitude must be "minimal" in that the most-significant
144.117 + * int ({@code mag[0]}) must be non-zero. This is necessary to
144.118 + * ensure that there is exactly one representation for each BigInteger
144.119 + * value. Note that this implies that the BigInteger zero has a
144.120 + * zero-length mag array.
144.121 + */
144.122 + final int[] mag;
144.123 +
144.124 + // These "redundant fields" are initialized with recognizable nonsense
144.125 + // values, and cached the first time they are needed (or never, if they
144.126 + // aren't needed).
144.127 +
144.128 + /**
144.129 + * One plus the bitCount of this BigInteger. Zeros means unitialized.
144.130 + *
144.131 + * @serial
144.132 + * @see #bitCount
144.133 + * @deprecated Deprecated since logical value is offset from stored
144.134 + * value and correction factor is applied in accessor method.
144.135 + */
144.136 + @Deprecated
144.137 + private int bitCount;
144.138 +
144.139 + /**
144.140 + * One plus the bitLength of this BigInteger. Zeros means unitialized.
144.141 + * (either value is acceptable).
144.142 + *
144.143 + * @serial
144.144 + * @see #bitLength()
144.145 + * @deprecated Deprecated since logical value is offset from stored
144.146 + * value and correction factor is applied in accessor method.
144.147 + */
144.148 + @Deprecated
144.149 + private int bitLength;
144.150 +
144.151 + /**
144.152 + * Two plus the lowest set bit of this BigInteger, as returned by
144.153 + * getLowestSetBit().
144.154 + *
144.155 + * @serial
144.156 + * @see #getLowestSetBit
144.157 + * @deprecated Deprecated since logical value is offset from stored
144.158 + * value and correction factor is applied in accessor method.
144.159 + */
144.160 + @Deprecated
144.161 + private int lowestSetBit;
144.162 +
144.163 + /**
144.164 + * Two plus the index of the lowest-order int in the magnitude of this
144.165 + * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
144.166 + * The least significant int has int-number 0, the next int in order of
144.167 + * increasing significance has int-number 1, and so forth.
144.168 + * @deprecated Deprecated since logical value is offset from stored
144.169 + * value and correction factor is applied in accessor method.
144.170 + */
144.171 + @Deprecated
144.172 + private int firstNonzeroIntNum;
144.173 +
144.174 + /**
144.175 + * This mask is used to obtain the value of an int as if it were unsigned.
144.176 + */
144.177 + final static long LONG_MASK = 0xffffffffL;
144.178 +
144.179 + //Constructors
144.180 +
144.181 + /**
144.182 + * Translates a byte array containing the two's-complement binary
144.183 + * representation of a BigInteger into a BigInteger. The input array is
144.184 + * assumed to be in <i>big-endian</i> byte-order: the most significant
144.185 + * byte is in the zeroth element.
144.186 + *
144.187 + * @param val big-endian two's-complement binary representation of
144.188 + * BigInteger.
144.189 + * @throws NumberFormatException {@code val} is zero bytes long.
144.190 + */
144.191 + public BigInteger(byte[] val) {
144.192 + if (val.length == 0)
144.193 + throw new NumberFormatException("Zero length BigInteger");
144.194 +
144.195 + if (val[0] < 0) {
144.196 + mag = makePositive(val);
144.197 + signum = -1;
144.198 + } else {
144.199 + mag = stripLeadingZeroBytes(val);
144.200 + signum = (mag.length == 0 ? 0 : 1);
144.201 + }
144.202 + }
144.203 +
144.204 + /**
144.205 + * This private constructor translates an int array containing the
144.206 + * two's-complement binary representation of a BigInteger into a
144.207 + * BigInteger. The input array is assumed to be in <i>big-endian</i>
144.208 + * int-order: the most significant int is in the zeroth element.
144.209 + */
144.210 + private BigInteger(int[] val) {
144.211 + if (val.length == 0)
144.212 + throw new NumberFormatException("Zero length BigInteger");
144.213 +
144.214 + if (val[0] < 0) {
144.215 + mag = makePositive(val);
144.216 + signum = -1;
144.217 + } else {
144.218 + mag = trustedStripLeadingZeroInts(val);
144.219 + signum = (mag.length == 0 ? 0 : 1);
144.220 + }
144.221 + }
144.222 +
144.223 + /**
144.224 + * Translates the sign-magnitude representation of a BigInteger into a
144.225 + * BigInteger. The sign is represented as an integer signum value: -1 for
144.226 + * negative, 0 for zero, or 1 for positive. The magnitude is a byte array
144.227 + * in <i>big-endian</i> byte-order: the most significant byte is in the
144.228 + * zeroth element. A zero-length magnitude array is permissible, and will
144.229 + * result in a BigInteger value of 0, whether signum is -1, 0 or 1.
144.230 + *
144.231 + * @param signum signum of the number (-1 for negative, 0 for zero, 1
144.232 + * for positive).
144.233 + * @param magnitude big-endian binary representation of the magnitude of
144.234 + * the number.
144.235 + * @throws NumberFormatException {@code signum} is not one of the three
144.236 + * legal values (-1, 0, and 1), or {@code signum} is 0 and
144.237 + * {@code magnitude} contains one or more non-zero bytes.
144.238 + */
144.239 + public BigInteger(int signum, byte[] magnitude) {
144.240 + this.mag = stripLeadingZeroBytes(magnitude);
144.241 +
144.242 + if (signum < -1 || signum > 1)
144.243 + throw(new NumberFormatException("Invalid signum value"));
144.244 +
144.245 + if (this.mag.length==0) {
144.246 + this.signum = 0;
144.247 + } else {
144.248 + if (signum == 0)
144.249 + throw(new NumberFormatException("signum-magnitude mismatch"));
144.250 + this.signum = signum;
144.251 + }
144.252 + }
144.253 +
144.254 + /**
144.255 + * A constructor for internal use that translates the sign-magnitude
144.256 + * representation of a BigInteger into a BigInteger. It checks the
144.257 + * arguments and copies the magnitude so this constructor would be
144.258 + * safe for external use.
144.259 + */
144.260 + private BigInteger(int signum, int[] magnitude) {
144.261 + this.mag = stripLeadingZeroInts(magnitude);
144.262 +
144.263 + if (signum < -1 || signum > 1)
144.264 + throw(new NumberFormatException("Invalid signum value"));
144.265 +
144.266 + if (this.mag.length==0) {
144.267 + this.signum = 0;
144.268 + } else {
144.269 + if (signum == 0)
144.270 + throw(new NumberFormatException("signum-magnitude mismatch"));
144.271 + this.signum = signum;
144.272 + }
144.273 + }
144.274 +
144.275 + /**
144.276 + * Translates the String representation of a BigInteger in the
144.277 + * specified radix into a BigInteger. The String representation
144.278 + * consists of an optional minus or plus sign followed by a
144.279 + * sequence of one or more digits in the specified radix. The
144.280 + * character-to-digit mapping is provided by {@code
144.281 + * Character.digit}. The String may not contain any extraneous
144.282 + * characters (whitespace, for example).
144.283 + *
144.284 + * @param val String representation of BigInteger.
144.285 + * @param radix radix to be used in interpreting {@code val}.
144.286 + * @throws NumberFormatException {@code val} is not a valid representation
144.287 + * of a BigInteger in the specified radix, or {@code radix} is
144.288 + * outside the range from {@link Character#MIN_RADIX} to
144.289 + * {@link Character#MAX_RADIX}, inclusive.
144.290 + * @see Character#digit
144.291 + */
144.292 + public BigInteger(String val, int radix) {
144.293 + int cursor = 0, numDigits;
144.294 + final int len = val.length();
144.295 +
144.296 + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
144.297 + throw new NumberFormatException("Radix out of range");
144.298 + if (len == 0)
144.299 + throw new NumberFormatException("Zero length BigInteger");
144.300 +
144.301 + // Check for at most one leading sign
144.302 + int sign = 1;
144.303 + int index1 = val.lastIndexOf('-');
144.304 + int index2 = val.lastIndexOf('+');
144.305 + if ((index1 + index2) <= -1) {
144.306 + // No leading sign character or at most one leading sign character
144.307 + if (index1 == 0 || index2 == 0) {
144.308 + cursor = 1;
144.309 + if (len == 1)
144.310 + throw new NumberFormatException("Zero length BigInteger");
144.311 + }
144.312 + if (index1 == 0)
144.313 + sign = -1;
144.314 + } else
144.315 + throw new NumberFormatException("Illegal embedded sign character");
144.316 +
144.317 + // Skip leading zeros and compute number of digits in magnitude
144.318 + while (cursor < len &&
144.319 + Character.digit(val.charAt(cursor), radix) == 0)
144.320 + cursor++;
144.321 + if (cursor == len) {
144.322 + signum = 0;
144.323 + mag = ZERO.mag;
144.324 + return;
144.325 + }
144.326 +
144.327 + numDigits = len - cursor;
144.328 + signum = sign;
144.329 +
144.330 + // Pre-allocate array of expected size. May be too large but can
144.331 + // never be too small. Typically exact.
144.332 + int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);
144.333 + int numWords = (numBits + 31) >>> 5;
144.334 + int[] magnitude = new int[numWords];
144.335 +
144.336 + // Process first (potentially short) digit group
144.337 + int firstGroupLen = numDigits % digitsPerInt[radix];
144.338 + if (firstGroupLen == 0)
144.339 + firstGroupLen = digitsPerInt[radix];
144.340 + String group = val.substring(cursor, cursor += firstGroupLen);
144.341 + magnitude[numWords - 1] = Integer.parseInt(group, radix);
144.342 + if (magnitude[numWords - 1] < 0)
144.343 + throw new NumberFormatException("Illegal digit");
144.344 +
144.345 + // Process remaining digit groups
144.346 + int superRadix = intRadix[radix];
144.347 + int groupVal = 0;
144.348 + while (cursor < len) {
144.349 + group = val.substring(cursor, cursor += digitsPerInt[radix]);
144.350 + groupVal = Integer.parseInt(group, radix);
144.351 + if (groupVal < 0)
144.352 + throw new NumberFormatException("Illegal digit");
144.353 + destructiveMulAdd(magnitude, superRadix, groupVal);
144.354 + }
144.355 + // Required for cases where the array was overallocated.
144.356 + mag = trustedStripLeadingZeroInts(magnitude);
144.357 + }
144.358 +
144.359 + // Constructs a new BigInteger using a char array with radix=10
144.360 + BigInteger(char[] val) {
144.361 + int cursor = 0, numDigits;
144.362 + int len = val.length;
144.363 +
144.364 + // Check for leading minus sign
144.365 + int sign = 1;
144.366 + if (val[0] == '-') {
144.367 + if (len == 1)
144.368 + throw new NumberFormatException("Zero length BigInteger");
144.369 + sign = -1;
144.370 + cursor = 1;
144.371 + } else if (val[0] == '+') {
144.372 + if (len == 1)
144.373 + throw new NumberFormatException("Zero length BigInteger");
144.374 + cursor = 1;
144.375 + }
144.376 +
144.377 + // Skip leading zeros and compute number of digits in magnitude
144.378 + while (cursor < len && Character.digit(val[cursor], 10) == 0)
144.379 + cursor++;
144.380 + if (cursor == len) {
144.381 + signum = 0;
144.382 + mag = ZERO.mag;
144.383 + return;
144.384 + }
144.385 +
144.386 + numDigits = len - cursor;
144.387 + signum = sign;
144.388 +
144.389 + // Pre-allocate array of expected size
144.390 + int numWords;
144.391 + if (len < 10) {
144.392 + numWords = 1;
144.393 + } else {
144.394 + int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1);
144.395 + numWords = (numBits + 31) >>> 5;
144.396 + }
144.397 + int[] magnitude = new int[numWords];
144.398 +
144.399 + // Process first (potentially short) digit group
144.400 + int firstGroupLen = numDigits % digitsPerInt[10];
144.401 + if (firstGroupLen == 0)
144.402 + firstGroupLen = digitsPerInt[10];
144.403 + magnitude[numWords - 1] = parseInt(val, cursor, cursor += firstGroupLen);
144.404 +
144.405 + // Process remaining digit groups
144.406 + while (cursor < len) {
144.407 + int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]);
144.408 + destructiveMulAdd(magnitude, intRadix[10], groupVal);
144.409 + }
144.410 + mag = trustedStripLeadingZeroInts(magnitude);
144.411 + }
144.412 +
144.413 + // Create an integer with the digits between the two indexes
144.414 + // Assumes start < end. The result may be negative, but it
144.415 + // is to be treated as an unsigned value.
144.416 + private int parseInt(char[] source, int start, int end) {
144.417 + int result = Character.digit(source[start++], 10);
144.418 + if (result == -1)
144.419 + throw new NumberFormatException(new String(source));
144.420 +
144.421 + for (int index = start; index<end; index++) {
144.422 + int nextVal = Character.digit(source[index], 10);
144.423 + if (nextVal == -1)
144.424 + throw new NumberFormatException(new String(source));
144.425 + result = 10*result + nextVal;
144.426 + }
144.427 +
144.428 + return result;
144.429 + }
144.430 +
144.431 + // bitsPerDigit in the given radix times 1024
144.432 + // Rounded up to avoid underallocation.
144.433 + private static long bitsPerDigit[] = { 0, 0,
144.434 + 1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, 3543, 3672,
144.435 + 3790, 3899, 4001, 4096, 4186, 4271, 4350, 4426, 4498, 4567, 4633,
144.436 + 4696, 4756, 4814, 4870, 4923, 4975, 5025, 5074, 5120, 5166, 5210,
144.437 + 5253, 5295};
144.438 +
144.439 + // Multiply x array times word y in place, and add word z
144.440 + private static void destructiveMulAdd(int[] x, int y, int z) {
144.441 + // Perform the multiplication word by word
144.442 + long ylong = y & LONG_MASK;
144.443 + long zlong = z & LONG_MASK;
144.444 + int len = x.length;
144.445 +
144.446 + long product = 0;
144.447 + long carry = 0;
144.448 + for (int i = len-1; i >= 0; i--) {
144.449 + product = ylong * (x[i] & LONG_MASK) + carry;
144.450 + x[i] = (int)product;
144.451 + carry = product >>> 32;
144.452 + }
144.453 +
144.454 + // Perform the addition
144.455 + long sum = (x[len-1] & LONG_MASK) + zlong;
144.456 + x[len-1] = (int)sum;
144.457 + carry = sum >>> 32;
144.458 + for (int i = len-2; i >= 0; i--) {
144.459 + sum = (x[i] & LONG_MASK) + carry;
144.460 + x[i] = (int)sum;
144.461 + carry = sum >>> 32;
144.462 + }
144.463 + }
144.464 +
144.465 + /**
144.466 + * Translates the decimal String representation of a BigInteger into a
144.467 + * BigInteger. The String representation consists of an optional minus
144.468 + * sign followed by a sequence of one or more decimal digits. The
144.469 + * character-to-digit mapping is provided by {@code Character.digit}.
144.470 + * The String may not contain any extraneous characters (whitespace, for
144.471 + * example).
144.472 + *
144.473 + * @param val decimal String representation of BigInteger.
144.474 + * @throws NumberFormatException {@code val} is not a valid representation
144.475 + * of a BigInteger.
144.476 + * @see Character#digit
144.477 + */
144.478 + public BigInteger(String val) {
144.479 + this(val, 10);
144.480 + }
144.481 +
144.482 + /**
144.483 + * Constructs a randomly generated BigInteger, uniformly distributed over
144.484 + * the range 0 to (2<sup>{@code numBits}</sup> - 1), inclusive.
144.485 + * The uniformity of the distribution assumes that a fair source of random
144.486 + * bits is provided in {@code rnd}. Note that this constructor always
144.487 + * constructs a non-negative BigInteger.
144.488 + *
144.489 + * @param numBits maximum bitLength of the new BigInteger.
144.490 + * @param rnd source of randomness to be used in computing the new
144.491 + * BigInteger.
144.492 + * @throws IllegalArgumentException {@code numBits} is negative.
144.493 + * @see #bitLength()
144.494 + */
144.495 + public BigInteger(int numBits, Random rnd) {
144.496 + this(1, randomBits(numBits, rnd));
144.497 + }
144.498 +
144.499 + private static byte[] randomBits(int numBits, Random rnd) {
144.500 + if (numBits < 0)
144.501 + throw new IllegalArgumentException("numBits must be non-negative");
144.502 + int numBytes = (int)(((long)numBits+7)/8); // avoid overflow
144.503 + byte[] randomBits = new byte[numBytes];
144.504 +
144.505 + // Generate random bytes and mask out any excess bits
144.506 + if (numBytes > 0) {
144.507 + rnd.nextBytes(randomBits);
144.508 + int excessBits = 8*numBytes - numBits;
144.509 + randomBits[0] &= (1 << (8-excessBits)) - 1;
144.510 + }
144.511 + return randomBits;
144.512 + }
144.513 +
144.514 + /**
144.515 + * Constructs a randomly generated positive BigInteger that is probably
144.516 + * prime, with the specified bitLength.
144.517 + *
144.518 + * <p>It is recommended that the {@link #probablePrime probablePrime}
144.519 + * method be used in preference to this constructor unless there
144.520 + * is a compelling need to specify a certainty.
144.521 + *
144.522 + * @param bitLength bitLength of the returned BigInteger.
144.523 + * @param certainty a measure of the uncertainty that the caller is
144.524 + * willing to tolerate. The probability that the new BigInteger
144.525 + * represents a prime number will exceed
144.526 + * (1 - 1/2<sup>{@code certainty}</sup>). The execution time of
144.527 + * this constructor is proportional to the value of this parameter.
144.528 + * @param rnd source of random bits used to select candidates to be
144.529 + * tested for primality.
144.530 + * @throws ArithmeticException {@code bitLength < 2}.
144.531 + * @see #bitLength()
144.532 + */
144.533 + public BigInteger(int bitLength, int certainty, Random rnd) {
144.534 + BigInteger prime;
144.535 +
144.536 + if (bitLength < 2)
144.537 + throw new ArithmeticException("bitLength < 2");
144.538 + // The cutoff of 95 was chosen empirically for best performance
144.539 + prime = (bitLength < 95 ? smallPrime(bitLength, certainty, rnd)
144.540 + : largePrime(bitLength, certainty, rnd));
144.541 + signum = 1;
144.542 + mag = prime.mag;
144.543 + }
144.544 +
144.545 + // Minimum size in bits that the requested prime number has
144.546 + // before we use the large prime number generating algorithms
144.547 + private static final int SMALL_PRIME_THRESHOLD = 95;
144.548 +
144.549 + // Certainty required to meet the spec of probablePrime
144.550 + private static final int DEFAULT_PRIME_CERTAINTY = 100;
144.551 +
144.552 + /**
144.553 + * Returns a positive BigInteger that is probably prime, with the
144.554 + * specified bitLength. The probability that a BigInteger returned
144.555 + * by this method is composite does not exceed 2<sup>-100</sup>.
144.556 + *
144.557 + * @param bitLength bitLength of the returned BigInteger.
144.558 + * @param rnd source of random bits used to select candidates to be
144.559 + * tested for primality.
144.560 + * @return a BigInteger of {@code bitLength} bits that is probably prime
144.561 + * @throws ArithmeticException {@code bitLength < 2}.
144.562 + * @see #bitLength()
144.563 + * @since 1.4
144.564 + */
144.565 + public static BigInteger probablePrime(int bitLength, Random rnd) {
144.566 + if (bitLength < 2)
144.567 + throw new ArithmeticException("bitLength < 2");
144.568 +
144.569 + // The cutoff of 95 was chosen empirically for best performance
144.570 + return (bitLength < SMALL_PRIME_THRESHOLD ?
144.571 + smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
144.572 + largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
144.573 + }
144.574 +
144.575 + /**
144.576 + * Find a random number of the specified bitLength that is probably prime.
144.577 + * This method is used for smaller primes, its performance degrades on
144.578 + * larger bitlengths.
144.579 + *
144.580 + * This method assumes bitLength > 1.
144.581 + */
144.582 + private static BigInteger smallPrime(int bitLength, int certainty, Random rnd) {
144.583 + int magLen = (bitLength + 31) >>> 5;
144.584 + int temp[] = new int[magLen];
144.585 + int highBit = 1 << ((bitLength+31) & 0x1f); // High bit of high int
144.586 + int highMask = (highBit << 1) - 1; // Bits to keep in high int
144.587 +
144.588 + while(true) {
144.589 + // Construct a candidate
144.590 + for (int i=0; i<magLen; i++)
144.591 + temp[i] = rnd.nextInt();
144.592 + temp[0] = (temp[0] & highMask) | highBit; // Ensure exact length
144.593 + if (bitLength > 2)
144.594 + temp[magLen-1] |= 1; // Make odd if bitlen > 2
144.595 +
144.596 + BigInteger p = new BigInteger(temp, 1);
144.597 +
144.598 + // Do cheap "pre-test" if applicable
144.599 + if (bitLength > 6) {
144.600 + long r = p.remainder(SMALL_PRIME_PRODUCT).longValue();
144.601 + if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) ||
144.602 + (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) ||
144.603 + (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0))
144.604 + continue; // Candidate is composite; try another
144.605 + }
144.606 +
144.607 + // All candidates of bitLength 2 and 3 are prime by this point
144.608 + if (bitLength < 4)
144.609 + return p;
144.610 +
144.611 + // Do expensive test if we survive pre-test (or it's inapplicable)
144.612 + if (p.primeToCertainty(certainty, rnd))
144.613 + return p;
144.614 + }
144.615 + }
144.616 +
144.617 + private static final BigInteger SMALL_PRIME_PRODUCT
144.618 + = valueOf(3L*5*7*11*13*17*19*23*29*31*37*41);
144.619 +
144.620 + /**
144.621 + * Find a random number of the specified bitLength that is probably prime.
144.622 + * This method is more appropriate for larger bitlengths since it uses
144.623 + * a sieve to eliminate most composites before using a more expensive
144.624 + * test.
144.625 + */
144.626 + private static BigInteger largePrime(int bitLength, int certainty, Random rnd) {
144.627 + BigInteger p;
144.628 + p = new BigInteger(bitLength, rnd).setBit(bitLength-1);
144.629 + p.mag[p.mag.length-1] &= 0xfffffffe;
144.630 +
144.631 + // Use a sieve length likely to contain the next prime number
144.632 + int searchLen = (bitLength / 20) * 64;
144.633 + BitSieve searchSieve = new BitSieve(p, searchLen);
144.634 + BigInteger candidate = searchSieve.retrieve(p, certainty, rnd);
144.635 +
144.636 + while ((candidate == null) || (candidate.bitLength() != bitLength)) {
144.637 + p = p.add(BigInteger.valueOf(2*searchLen));
144.638 + if (p.bitLength() != bitLength)
144.639 + p = new BigInteger(bitLength, rnd).setBit(bitLength-1);
144.640 + p.mag[p.mag.length-1] &= 0xfffffffe;
144.641 + searchSieve = new BitSieve(p, searchLen);
144.642 + candidate = searchSieve.retrieve(p, certainty, rnd);
144.643 + }
144.644 + return candidate;
144.645 + }
144.646 +
144.647 + /**
144.648 + * Returns the first integer greater than this {@code BigInteger} that
144.649 + * is probably prime. The probability that the number returned by this
144.650 + * method is composite does not exceed 2<sup>-100</sup>. This method will
144.651 + * never skip over a prime when searching: if it returns {@code p}, there
144.652 + * is no prime {@code q} such that {@code this < q < p}.
144.653 + *
144.654 + * @return the first integer greater than this {@code BigInteger} that
144.655 + * is probably prime.
144.656 + * @throws ArithmeticException {@code this < 0}.
144.657 + * @since 1.5
144.658 + */
144.659 + public BigInteger nextProbablePrime() {
144.660 + if (this.signum < 0)
144.661 + throw new ArithmeticException("start < 0: " + this);
144.662 +
144.663 + // Handle trivial cases
144.664 + if ((this.signum == 0) || this.equals(ONE))
144.665 + return TWO;
144.666 +
144.667 + BigInteger result = this.add(ONE);
144.668 +
144.669 + // Fastpath for small numbers
144.670 + if (result.bitLength() < SMALL_PRIME_THRESHOLD) {
144.671 +
144.672 + // Ensure an odd number
144.673 + if (!result.testBit(0))
144.674 + result = result.add(ONE);
144.675 +
144.676 + while(true) {
144.677 + // Do cheap "pre-test" if applicable
144.678 + if (result.bitLength() > 6) {
144.679 + long r = result.remainder(SMALL_PRIME_PRODUCT).longValue();
144.680 + if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) ||
144.681 + (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) ||
144.682 + (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0)) {
144.683 + result = result.add(TWO);
144.684 + continue; // Candidate is composite; try another
144.685 + }
144.686 + }
144.687 +
144.688 + // All candidates of bitLength 2 and 3 are prime by this point
144.689 + if (result.bitLength() < 4)
144.690 + return result;
144.691 +
144.692 + // The expensive test
144.693 + if (result.primeToCertainty(DEFAULT_PRIME_CERTAINTY, null))
144.694 + return result;
144.695 +
144.696 + result = result.add(TWO);
144.697 + }
144.698 + }
144.699 +
144.700 + // Start at previous even number
144.701 + if (result.testBit(0))
144.702 + result = result.subtract(ONE);
144.703 +
144.704 + // Looking for the next large prime
144.705 + int searchLen = (result.bitLength() / 20) * 64;
144.706 +
144.707 + while(true) {
144.708 + BitSieve searchSieve = new BitSieve(result, searchLen);
144.709 + BigInteger candidate = searchSieve.retrieve(result,
144.710 + DEFAULT_PRIME_CERTAINTY, null);
144.711 + if (candidate != null)
144.712 + return candidate;
144.713 + result = result.add(BigInteger.valueOf(2 * searchLen));
144.714 + }
144.715 + }
144.716 +
144.717 + /**
144.718 + * Returns {@code true} if this BigInteger is probably prime,
144.719 + * {@code false} if it's definitely composite.
144.720 + *
144.721 + * This method assumes bitLength > 2.
144.722 + *
144.723 + * @param certainty a measure of the uncertainty that the caller is
144.724 + * willing to tolerate: if the call returns {@code true}
144.725 + * the probability that this BigInteger is prime exceeds
144.726 + * {@code (1 - 1/2<sup>certainty</sup>)}. The execution time of
144.727 + * this method is proportional to the value of this parameter.
144.728 + * @return {@code true} if this BigInteger is probably prime,
144.729 + * {@code false} if it's definitely composite.
144.730 + */
144.731 + boolean primeToCertainty(int certainty, Random random) {
144.732 + int rounds = 0;
144.733 + int n = (Math.min(certainty, Integer.MAX_VALUE-1)+1)/2;
144.734 +
144.735 + // The relationship between the certainty and the number of rounds
144.736 + // we perform is given in the draft standard ANSI X9.80, "PRIME
144.737 + // NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES".
144.738 + int sizeInBits = this.bitLength();
144.739 + if (sizeInBits < 100) {
144.740 + rounds = 50;
144.741 + rounds = n < rounds ? n : rounds;
144.742 + return passesMillerRabin(rounds, random);
144.743 + }
144.744 +
144.745 + if (sizeInBits < 256) {
144.746 + rounds = 27;
144.747 + } else if (sizeInBits < 512) {
144.748 + rounds = 15;
144.749 + } else if (sizeInBits < 768) {
144.750 + rounds = 8;
144.751 + } else if (sizeInBits < 1024) {
144.752 + rounds = 4;
144.753 + } else {
144.754 + rounds = 2;
144.755 + }
144.756 + rounds = n < rounds ? n : rounds;
144.757 +
144.758 + return passesMillerRabin(rounds, random) && passesLucasLehmer();
144.759 + }
144.760 +
144.761 + /**
144.762 + * Returns true iff this BigInteger is a Lucas-Lehmer probable prime.
144.763 + *
144.764 + * The following assumptions are made:
144.765 + * This BigInteger is a positive, odd number.
144.766 + */
144.767 + private boolean passesLucasLehmer() {
144.768 + BigInteger thisPlusOne = this.add(ONE);
144.769 +
144.770 + // Step 1
144.771 + int d = 5;
144.772 + while (jacobiSymbol(d, this) != -1) {
144.773 + // 5, -7, 9, -11, ...
144.774 + d = (d<0) ? Math.abs(d)+2 : -(d+2);
144.775 + }
144.776 +
144.777 + // Step 2
144.778 + BigInteger u = lucasLehmerSequence(d, thisPlusOne, this);
144.779 +
144.780 + // Step 3
144.781 + return u.mod(this).equals(ZERO);
144.782 + }
144.783 +
144.784 + /**
144.785 + * Computes Jacobi(p,n).
144.786 + * Assumes n positive, odd, n>=3.
144.787 + */
144.788 + private static int jacobiSymbol(int p, BigInteger n) {
144.789 + if (p == 0)
144.790 + return 0;
144.791 +
144.792 + // Algorithm and comments adapted from Colin Plumb's C library.
144.793 + int j = 1;
144.794 + int u = n.mag[n.mag.length-1];
144.795 +
144.796 + // Make p positive
144.797 + if (p < 0) {
144.798 + p = -p;
144.799 + int n8 = u & 7;
144.800 + if ((n8 == 3) || (n8 == 7))
144.801 + j = -j; // 3 (011) or 7 (111) mod 8
144.802 + }
144.803 +
144.804 + // Get rid of factors of 2 in p
144.805 + while ((p & 3) == 0)
144.806 + p >>= 2;
144.807 + if ((p & 1) == 0) {
144.808 + p >>= 1;
144.809 + if (((u ^ (u>>1)) & 2) != 0)
144.810 + j = -j; // 3 (011) or 5 (101) mod 8
144.811 + }
144.812 + if (p == 1)
144.813 + return j;
144.814 + // Then, apply quadratic reciprocity
144.815 + if ((p & u & 2) != 0) // p = u = 3 (mod 4)?
144.816 + j = -j;
144.817 + // And reduce u mod p
144.818 + u = n.mod(BigInteger.valueOf(p)).intValue();
144.819 +
144.820 + // Now compute Jacobi(u,p), u < p
144.821 + while (u != 0) {
144.822 + while ((u & 3) == 0)
144.823 + u >>= 2;
144.824 + if ((u & 1) == 0) {
144.825 + u >>= 1;
144.826 + if (((p ^ (p>>1)) & 2) != 0)
144.827 + j = -j; // 3 (011) or 5 (101) mod 8
144.828 + }
144.829 + if (u == 1)
144.830 + return j;
144.831 + // Now both u and p are odd, so use quadratic reciprocity
144.832 + assert (u < p);
144.833 + int t = u; u = p; p = t;
144.834 + if ((u & p & 2) != 0) // u = p = 3 (mod 4)?
144.835 + j = -j;
144.836 + // Now u >= p, so it can be reduced
144.837 + u %= p;
144.838 + }
144.839 + return 0;
144.840 + }
144.841 +
144.842 + private static BigInteger lucasLehmerSequence(int z, BigInteger k, BigInteger n) {
144.843 + BigInteger d = BigInteger.valueOf(z);
144.844 + BigInteger u = ONE; BigInteger u2;
144.845 + BigInteger v = ONE; BigInteger v2;
144.846 +
144.847 + for (int i=k.bitLength()-2; i>=0; i--) {
144.848 + u2 = u.multiply(v).mod(n);
144.849 +
144.850 + v2 = v.square().add(d.multiply(u.square())).mod(n);
144.851 + if (v2.testBit(0))
144.852 + v2 = v2.subtract(n);
144.853 +
144.854 + v2 = v2.shiftRight(1);
144.855 +
144.856 + u = u2; v = v2;
144.857 + if (k.testBit(i)) {
144.858 + u2 = u.add(v).mod(n);
144.859 + if (u2.testBit(0))
144.860 + u2 = u2.subtract(n);
144.861 +
144.862 + u2 = u2.shiftRight(1);
144.863 + v2 = v.add(d.multiply(u)).mod(n);
144.864 + if (v2.testBit(0))
144.865 + v2 = v2.subtract(n);
144.866 + v2 = v2.shiftRight(1);
144.867 +
144.868 + u = u2; v = v2;
144.869 + }
144.870 + }
144.871 + return u;
144.872 + }
144.873 +
144.874 + private static volatile Random staticRandom;
144.875 +
144.876 + private static Random getSecureRandom() {
144.877 + if (staticRandom == null) {
144.878 + staticRandom = new Random();
144.879 + }
144.880 + return staticRandom;
144.881 + }
144.882 +
144.883 + /**
144.884 + * Returns true iff this BigInteger passes the specified number of
144.885 + * Miller-Rabin tests. This test is taken from the DSA spec (NIST FIPS
144.886 + * 186-2).
144.887 + *
144.888 + * The following assumptions are made:
144.889 + * This BigInteger is a positive, odd number greater than 2.
144.890 + * iterations<=50.
144.891 + */
144.892 + private boolean passesMillerRabin(int iterations, Random rnd) {
144.893 + // Find a and m such that m is odd and this == 1 + 2**a * m
144.894 + BigInteger thisMinusOne = this.subtract(ONE);
144.895 + BigInteger m = thisMinusOne;
144.896 + int a = m.getLowestSetBit();
144.897 + m = m.shiftRight(a);
144.898 +
144.899 + // Do the tests
144.900 + if (rnd == null) {
144.901 + rnd = getSecureRandom();
144.902 + }
144.903 + for (int i=0; i<iterations; i++) {
144.904 + // Generate a uniform random on (1, this)
144.905 + BigInteger b;
144.906 + do {
144.907 + b = new BigInteger(this.bitLength(), rnd);
144.908 + } while (b.compareTo(ONE) <= 0 || b.compareTo(this) >= 0);
144.909 +
144.910 + int j = 0;
144.911 + BigInteger z = b.modPow(m, this);
144.912 + while(!((j==0 && z.equals(ONE)) || z.equals(thisMinusOne))) {
144.913 + if (j>0 && z.equals(ONE) || ++j==a)
144.914 + return false;
144.915 + z = z.modPow(TWO, this);
144.916 + }
144.917 + }
144.918 + return true;
144.919 + }
144.920 +
144.921 + /**
144.922 + * This internal constructor differs from its public cousin
144.923 + * with the arguments reversed in two ways: it assumes that its
144.924 + * arguments are correct, and it doesn't copy the magnitude array.
144.925 + */
144.926 + BigInteger(int[] magnitude, int signum) {
144.927 + this.signum = (magnitude.length==0 ? 0 : signum);
144.928 + this.mag = magnitude;
144.929 + }
144.930 +
144.931 + /**
144.932 + * This private constructor is for internal use and assumes that its
144.933 + * arguments are correct.
144.934 + */
144.935 + private BigInteger(byte[] magnitude, int signum) {
144.936 + this.signum = (magnitude.length==0 ? 0 : signum);
144.937 + this.mag = stripLeadingZeroBytes(magnitude);
144.938 + }
144.939 +
144.940 + //Static Factory Methods
144.941 +
144.942 + /**
144.943 + * Returns a BigInteger whose value is equal to that of the
144.944 + * specified {@code long}. This "static factory method" is
144.945 + * provided in preference to a ({@code long}) constructor
144.946 + * because it allows for reuse of frequently used BigIntegers.
144.947 + *
144.948 + * @param val value of the BigInteger to return.
144.949 + * @return a BigInteger with the specified value.
144.950 + */
144.951 + public static BigInteger valueOf(long val) {
144.952 + // If -MAX_CONSTANT < val < MAX_CONSTANT, return stashed constant
144.953 + if (val == 0)
144.954 + return ZERO;
144.955 + if (val > 0 && val <= MAX_CONSTANT)
144.956 + return posConst[(int) val];
144.957 + else if (val < 0 && val >= -MAX_CONSTANT)
144.958 + return negConst[(int) -val];
144.959 +
144.960 + return new BigInteger(val);
144.961 + }
144.962 +
144.963 + /**
144.964 + * Constructs a BigInteger with the specified value, which may not be zero.
144.965 + */
144.966 + private BigInteger(long val) {
144.967 + if (val < 0) {
144.968 + val = -val;
144.969 + signum = -1;
144.970 + } else {
144.971 + signum = 1;
144.972 + }
144.973 +
144.974 + int highWord = (int)(val >>> 32);
144.975 + if (highWord==0) {
144.976 + mag = new int[1];
144.977 + mag[0] = (int)val;
144.978 + } else {
144.979 + mag = new int[2];
144.980 + mag[0] = highWord;
144.981 + mag[1] = (int)val;
144.982 + }
144.983 + }
144.984 +
144.985 + /**
144.986 + * Returns a BigInteger with the given two's complement representation.
144.987 + * Assumes that the input array will not be modified (the returned
144.988 + * BigInteger will reference the input array if feasible).
144.989 + */
144.990 + private static BigInteger valueOf(int val[]) {
144.991 + return (val[0]>0 ? new BigInteger(val, 1) : new BigInteger(val));
144.992 + }
144.993 +
144.994 + // Constants
144.995 +
144.996 + /**
144.997 + * Initialize static constant array when class is loaded.
144.998 + */
144.999 + private final static int MAX_CONSTANT = 16;
144.1000 + private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
144.1001 + private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
144.1002 + static {
144.1003 + for (int i = 1; i <= MAX_CONSTANT; i++) {
144.1004 + int[] magnitude = new int[1];
144.1005 + magnitude[0] = i;
144.1006 + posConst[i] = new BigInteger(magnitude, 1);
144.1007 + negConst[i] = new BigInteger(magnitude, -1);
144.1008 + }
144.1009 + }
144.1010 +
144.1011 + /**
144.1012 + * The BigInteger constant zero.
144.1013 + *
144.1014 + * @since 1.2
144.1015 + */
144.1016 + public static final BigInteger ZERO = new BigInteger(new int[0], 0);
144.1017 +
144.1018 + /**
144.1019 + * The BigInteger constant one.
144.1020 + *
144.1021 + * @since 1.2
144.1022 + */
144.1023 + public static final BigInteger ONE = valueOf(1);
144.1024 +
144.1025 + /**
144.1026 + * The BigInteger constant two. (Not exported.)
144.1027 + */
144.1028 + private static final BigInteger TWO = valueOf(2);
144.1029 +
144.1030 + /**
144.1031 + * The BigInteger constant ten.
144.1032 + *
144.1033 + * @since 1.5
144.1034 + */
144.1035 + public static final BigInteger TEN = valueOf(10);
144.1036 +
144.1037 + // Arithmetic Operations
144.1038 +
144.1039 + /**
144.1040 + * Returns a BigInteger whose value is {@code (this + val)}.
144.1041 + *
144.1042 + * @param val value to be added to this BigInteger.
144.1043 + * @return {@code this + val}
144.1044 + */
144.1045 + public BigInteger add(BigInteger val) {
144.1046 + if (val.signum == 0)
144.1047 + return this;
144.1048 + if (signum == 0)
144.1049 + return val;
144.1050 + if (val.signum == signum)
144.1051 + return new BigInteger(add(mag, val.mag), signum);
144.1052 +
144.1053 + int cmp = compareMagnitude(val);
144.1054 + if (cmp == 0)
144.1055 + return ZERO;
144.1056 + int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
144.1057 + : subtract(val.mag, mag));
144.1058 + resultMag = trustedStripLeadingZeroInts(resultMag);
144.1059 +
144.1060 + return new BigInteger(resultMag, cmp == signum ? 1 : -1);
144.1061 + }
144.1062 +
144.1063 + /**
144.1064 + * Adds the contents of the int arrays x and y. This method allocates
144.1065 + * a new int array to hold the answer and returns a reference to that
144.1066 + * array.
144.1067 + */
144.1068 + private static int[] add(int[] x, int[] y) {
144.1069 + // If x is shorter, swap the two arrays
144.1070 + if (x.length < y.length) {
144.1071 + int[] tmp = x;
144.1072 + x = y;
144.1073 + y = tmp;
144.1074 + }
144.1075 +
144.1076 + int xIndex = x.length;
144.1077 + int yIndex = y.length;
144.1078 + int result[] = new int[xIndex];
144.1079 + long sum = 0;
144.1080 +
144.1081 + // Add common parts of both numbers
144.1082 + while(yIndex > 0) {
144.1083 + sum = (x[--xIndex] & LONG_MASK) +
144.1084 + (y[--yIndex] & LONG_MASK) + (sum >>> 32);
144.1085 + result[xIndex] = (int)sum;
144.1086 + }
144.1087 +
144.1088 + // Copy remainder of longer number while carry propagation is required
144.1089 + boolean carry = (sum >>> 32 != 0);
144.1090 + while (xIndex > 0 && carry)
144.1091 + carry = ((result[--xIndex] = x[xIndex] + 1) == 0);
144.1092 +
144.1093 + // Copy remainder of longer number
144.1094 + while (xIndex > 0)
144.1095 + result[--xIndex] = x[xIndex];
144.1096 +
144.1097 + // Grow result if necessary
144.1098 + if (carry) {
144.1099 + int bigger[] = new int[result.length + 1];
144.1100 + System.arraycopy(result, 0, bigger, 1, result.length);
144.1101 + bigger[0] = 0x01;
144.1102 + return bigger;
144.1103 + }
144.1104 + return result;
144.1105 + }
144.1106 +
144.1107 + /**
144.1108 + * Returns a BigInteger whose value is {@code (this - val)}.
144.1109 + *
144.1110 + * @param val value to be subtracted from this BigInteger.
144.1111 + * @return {@code this - val}
144.1112 + */
144.1113 + public BigInteger subtract(BigInteger val) {
144.1114 + if (val.signum == 0)
144.1115 + return this;
144.1116 + if (signum == 0)
144.1117 + return val.negate();
144.1118 + if (val.signum != signum)
144.1119 + return new BigInteger(add(mag, val.mag), signum);
144.1120 +
144.1121 + int cmp = compareMagnitude(val);
144.1122 + if (cmp == 0)
144.1123 + return ZERO;
144.1124 + int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
144.1125 + : subtract(val.mag, mag));
144.1126 + resultMag = trustedStripLeadingZeroInts(resultMag);
144.1127 + return new BigInteger(resultMag, cmp == signum ? 1 : -1);
144.1128 + }
144.1129 +
144.1130 + /**
144.1131 + * Subtracts the contents of the second int arrays (little) from the
144.1132 + * first (big). The first int array (big) must represent a larger number
144.1133 + * than the second. This method allocates the space necessary to hold the
144.1134 + * answer.
144.1135 + */
144.1136 + private static int[] subtract(int[] big, int[] little) {
144.1137 + int bigIndex = big.length;
144.1138 + int result[] = new int[bigIndex];
144.1139 + int littleIndex = little.length;
144.1140 + long difference = 0;
144.1141 +
144.1142 + // Subtract common parts of both numbers
144.1143 + while(littleIndex > 0) {
144.1144 + difference = (big[--bigIndex] & LONG_MASK) -
144.1145 + (little[--littleIndex] & LONG_MASK) +
144.1146 + (difference >> 32);
144.1147 + result[bigIndex] = (int)difference;
144.1148 + }
144.1149 +
144.1150 + // Subtract remainder of longer number while borrow propagates
144.1151 + boolean borrow = (difference >> 32 != 0);
144.1152 + while (bigIndex > 0 && borrow)
144.1153 + borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
144.1154 +
144.1155 + // Copy remainder of longer number
144.1156 + while (bigIndex > 0)
144.1157 + result[--bigIndex] = big[bigIndex];
144.1158 +
144.1159 + return result;
144.1160 + }
144.1161 +
144.1162 + /**
144.1163 + * Returns a BigInteger whose value is {@code (this * val)}.
144.1164 + *
144.1165 + * @param val value to be multiplied by this BigInteger.
144.1166 + * @return {@code this * val}
144.1167 + */
144.1168 + public BigInteger multiply(BigInteger val) {
144.1169 + if (val.signum == 0 || signum == 0)
144.1170 + return ZERO;
144.1171 +
144.1172 + int[] result = multiplyToLen(mag, mag.length,
144.1173 + val.mag, val.mag.length, null);
144.1174 + result = trustedStripLeadingZeroInts(result);
144.1175 + return new BigInteger(result, signum == val.signum ? 1 : -1);
144.1176 + }
144.1177 +
144.1178 + /**
144.1179 + * Package private methods used by BigDecimal code to multiply a BigInteger
144.1180 + * with a long. Assumes v is not equal to INFLATED.
144.1181 + */
144.1182 + BigInteger multiply(long v) {
144.1183 + if (v == 0 || signum == 0)
144.1184 + return ZERO;
144.1185 + if (v == BigDecimal.INFLATED)
144.1186 + return multiply(BigInteger.valueOf(v));
144.1187 + int rsign = (v > 0 ? signum : -signum);
144.1188 + if (v < 0)
144.1189 + v = -v;
144.1190 + long dh = v >>> 32; // higher order bits
144.1191 + long dl = v & LONG_MASK; // lower order bits
144.1192 +
144.1193 + int xlen = mag.length;
144.1194 + int[] value = mag;
144.1195 + int[] rmag = (dh == 0L) ? (new int[xlen + 1]) : (new int[xlen + 2]);
144.1196 + long carry = 0;
144.1197 + int rstart = rmag.length - 1;
144.1198 + for (int i = xlen - 1; i >= 0; i--) {
144.1199 + long product = (value[i] & LONG_MASK) * dl + carry;
144.1200 + rmag[rstart--] = (int)product;
144.1201 + carry = product >>> 32;
144.1202 + }
144.1203 + rmag[rstart] = (int)carry;
144.1204 + if (dh != 0L) {
144.1205 + carry = 0;
144.1206 + rstart = rmag.length - 2;
144.1207 + for (int i = xlen - 1; i >= 0; i--) {
144.1208 + long product = (value[i] & LONG_MASK) * dh +
144.1209 + (rmag[rstart] & LONG_MASK) + carry;
144.1210 + rmag[rstart--] = (int)product;
144.1211 + carry = product >>> 32;
144.1212 + }
144.1213 + rmag[0] = (int)carry;
144.1214 + }
144.1215 + if (carry == 0L)
144.1216 + rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
144.1217 + return new BigInteger(rmag, rsign);
144.1218 + }
144.1219 +
144.1220 + /**
144.1221 + * Multiplies int arrays x and y to the specified lengths and places
144.1222 + * the result into z. There will be no leading zeros in the resultant array.
144.1223 + */
144.1224 + private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
144.1225 + int xstart = xlen - 1;
144.1226 + int ystart = ylen - 1;
144.1227 +
144.1228 + if (z == null || z.length < (xlen+ ylen))
144.1229 + z = new int[xlen+ylen];
144.1230 +
144.1231 + long carry = 0;
144.1232 + for (int j=ystart, k=ystart+1+xstart; j>=0; j--, k--) {
144.1233 + long product = (y[j] & LONG_MASK) *
144.1234 + (x[xstart] & LONG_MASK) + carry;
144.1235 + z[k] = (int)product;
144.1236 + carry = product >>> 32;
144.1237 + }
144.1238 + z[xstart] = (int)carry;
144.1239 +
144.1240 + for (int i = xstart-1; i >= 0; i--) {
144.1241 + carry = 0;
144.1242 + for (int j=ystart, k=ystart+1+i; j>=0; j--, k--) {
144.1243 + long product = (y[j] & LONG_MASK) *
144.1244 + (x[i] & LONG_MASK) +
144.1245 + (z[k] & LONG_MASK) + carry;
144.1246 + z[k] = (int)product;
144.1247 + carry = product >>> 32;
144.1248 + }
144.1249 + z[i] = (int)carry;
144.1250 + }
144.1251 + return z;
144.1252 + }
144.1253 +
144.1254 + /**
144.1255 + * Returns a BigInteger whose value is {@code (this<sup>2</sup>)}.
144.1256 + *
144.1257 + * @return {@code this<sup>2</sup>}
144.1258 + */
144.1259 + private BigInteger square() {
144.1260 + if (signum == 0)
144.1261 + return ZERO;
144.1262 + int[] z = squareToLen(mag, mag.length, null);
144.1263 + return new BigInteger(trustedStripLeadingZeroInts(z), 1);
144.1264 + }
144.1265 +
144.1266 + /**
144.1267 + * Squares the contents of the int array x. The result is placed into the
144.1268 + * int array z. The contents of x are not changed.
144.1269 + */
144.1270 + private static final int[] squareToLen(int[] x, int len, int[] z) {
144.1271 + /*
144.1272 + * The algorithm used here is adapted from Colin Plumb's C library.
144.1273 + * Technique: Consider the partial products in the multiplication
144.1274 + * of "abcde" by itself:
144.1275 + *
144.1276 + * a b c d e
144.1277 + * * a b c d e
144.1278 + * ==================
144.1279 + * ae be ce de ee
144.1280 + * ad bd cd dd de
144.1281 + * ac bc cc cd ce
144.1282 + * ab bb bc bd be
144.1283 + * aa ab ac ad ae
144.1284 + *
144.1285 + * Note that everything above the main diagonal:
144.1286 + * ae be ce de = (abcd) * e
144.1287 + * ad bd cd = (abc) * d
144.1288 + * ac bc = (ab) * c
144.1289 + * ab = (a) * b
144.1290 + *
144.1291 + * is a copy of everything below the main diagonal:
144.1292 + * de
144.1293 + * cd ce
144.1294 + * bc bd be
144.1295 + * ab ac ad ae
144.1296 + *
144.1297 + * Thus, the sum is 2 * (off the diagonal) + diagonal.
144.1298 + *
144.1299 + * This is accumulated beginning with the diagonal (which
144.1300 + * consist of the squares of the digits of the input), which is then
144.1301 + * divided by two, the off-diagonal added, and multiplied by two
144.1302 + * again. The low bit is simply a copy of the low bit of the
144.1303 + * input, so it doesn't need special care.
144.1304 + */
144.1305 + int zlen = len << 1;
144.1306 + if (z == null || z.length < zlen)
144.1307 + z = new int[zlen];
144.1308 +
144.1309 + // Store the squares, right shifted one bit (i.e., divided by 2)
144.1310 + int lastProductLowWord = 0;
144.1311 + for (int j=0, i=0; j<len; j++) {
144.1312 + long piece = (x[j] & LONG_MASK);
144.1313 + long product = piece * piece;
144.1314 + z[i++] = (lastProductLowWord << 31) | (int)(product >>> 33);
144.1315 + z[i++] = (int)(product >>> 1);
144.1316 + lastProductLowWord = (int)product;
144.1317 + }
144.1318 +
144.1319 + // Add in off-diagonal sums
144.1320 + for (int i=len, offset=1; i>0; i--, offset+=2) {
144.1321 + int t = x[i-1];
144.1322 + t = mulAdd(z, x, offset, i-1, t);
144.1323 + addOne(z, offset-1, i, t);
144.1324 + }
144.1325 +
144.1326 + // Shift back up and set low bit
144.1327 + primitiveLeftShift(z, zlen, 1);
144.1328 + z[zlen-1] |= x[len-1] & 1;
144.1329 +
144.1330 + return z;
144.1331 + }
144.1332 +
144.1333 + /**
144.1334 + * Returns a BigInteger whose value is {@code (this / val)}.
144.1335 + *
144.1336 + * @param val value by which this BigInteger is to be divided.
144.1337 + * @return {@code this / val}
144.1338 + * @throws ArithmeticException if {@code val} is zero.
144.1339 + */
144.1340 + public BigInteger divide(BigInteger val) {
144.1341 + MutableBigInteger q = new MutableBigInteger(),
144.1342 + a = new MutableBigInteger(this.mag),
144.1343 + b = new MutableBigInteger(val.mag);
144.1344 +
144.1345 + a.divide(b, q);
144.1346 + return q.toBigInteger(this.signum == val.signum ? 1 : -1);
144.1347 + }
144.1348 +
144.1349 + /**
144.1350 + * Returns an array of two BigIntegers containing {@code (this / val)}
144.1351 + * followed by {@code (this % val)}.
144.1352 + *
144.1353 + * @param val value by which this BigInteger is to be divided, and the
144.1354 + * remainder computed.
144.1355 + * @return an array of two BigIntegers: the quotient {@code (this / val)}
144.1356 + * is the initial element, and the remainder {@code (this % val)}
144.1357 + * is the final element.
144.1358 + * @throws ArithmeticException if {@code val} is zero.
144.1359 + */
144.1360 + public BigInteger[] divideAndRemainder(BigInteger val) {
144.1361 + BigInteger[] result = new BigInteger[2];
144.1362 + MutableBigInteger q = new MutableBigInteger(),
144.1363 + a = new MutableBigInteger(this.mag),
144.1364 + b = new MutableBigInteger(val.mag);
144.1365 + MutableBigInteger r = a.divide(b, q);
144.1366 + result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
144.1367 + result[1] = r.toBigInteger(this.signum);
144.1368 + return result;
144.1369 + }
144.1370 +
144.1371 + /**
144.1372 + * Returns a BigInteger whose value is {@code (this % val)}.
144.1373 + *
144.1374 + * @param val value by which this BigInteger is to be divided, and the
144.1375 + * remainder computed.
144.1376 + * @return {@code this % val}
144.1377 + * @throws ArithmeticException if {@code val} is zero.
144.1378 + */
144.1379 + public BigInteger remainder(BigInteger val) {
144.1380 + MutableBigInteger q = new MutableBigInteger(),
144.1381 + a = new MutableBigInteger(this.mag),
144.1382 + b = new MutableBigInteger(val.mag);
144.1383 +
144.1384 + return a.divide(b, q).toBigInteger(this.signum);
144.1385 + }
144.1386 +
144.1387 + /**
144.1388 + * Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
144.1389 + * Note that {@code exponent} is an integer rather than a BigInteger.
144.1390 + *
144.1391 + * @param exponent exponent to which this BigInteger is to be raised.
144.1392 + * @return <tt>this<sup>exponent</sup></tt>
144.1393 + * @throws ArithmeticException {@code exponent} is negative. (This would
144.1394 + * cause the operation to yield a non-integer value.)
144.1395 + */
144.1396 + public BigInteger pow(int exponent) {
144.1397 + if (exponent < 0)
144.1398 + throw new ArithmeticException("Negative exponent");
144.1399 + if (signum==0)
144.1400 + return (exponent==0 ? ONE : this);
144.1401 +
144.1402 + // Perform exponentiation using repeated squaring trick
144.1403 + int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
144.1404 + int[] baseToPow2 = this.mag;
144.1405 + int[] result = {1};
144.1406 +
144.1407 + while (exponent != 0) {
144.1408 + if ((exponent & 1)==1) {
144.1409 + result = multiplyToLen(result, result.length,
144.1410 + baseToPow2, baseToPow2.length, null);
144.1411 + result = trustedStripLeadingZeroInts(result);
144.1412 + }
144.1413 + if ((exponent >>>= 1) != 0) {
144.1414 + baseToPow2 = squareToLen(baseToPow2, baseToPow2.length, null);
144.1415 + baseToPow2 = trustedStripLeadingZeroInts(baseToPow2);
144.1416 + }
144.1417 + }
144.1418 + return new BigInteger(result, newSign);
144.1419 + }
144.1420 +
144.1421 + /**
144.1422 + * Returns a BigInteger whose value is the greatest common divisor of
144.1423 + * {@code abs(this)} and {@code abs(val)}. Returns 0 if
144.1424 + * {@code this==0 && val==0}.
144.1425 + *
144.1426 + * @param val value with which the GCD is to be computed.
144.1427 + * @return {@code GCD(abs(this), abs(val))}
144.1428 + */
144.1429 + public BigInteger gcd(BigInteger val) {
144.1430 + if (val.signum == 0)
144.1431 + return this.abs();
144.1432 + else if (this.signum == 0)
144.1433 + return val.abs();
144.1434 +
144.1435 + MutableBigInteger a = new MutableBigInteger(this);
144.1436 + MutableBigInteger b = new MutableBigInteger(val);
144.1437 +
144.1438 + MutableBigInteger result = a.hybridGCD(b);
144.1439 +
144.1440 + return result.toBigInteger(1);
144.1441 + }
144.1442 +
144.1443 + /**
144.1444 + * Package private method to return bit length for an integer.
144.1445 + */
144.1446 + static int bitLengthForInt(int n) {
144.1447 + return 32 - Integer.numberOfLeadingZeros(n);
144.1448 + }
144.1449 +
144.1450 + /**
144.1451 + * Left shift int array a up to len by n bits. Returns the array that
144.1452 + * results from the shift since space may have to be reallocated.
144.1453 + */
144.1454 + private static int[] leftShift(int[] a, int len, int n) {
144.1455 + int nInts = n >>> 5;
144.1456 + int nBits = n&0x1F;
144.1457 + int bitsInHighWord = bitLengthForInt(a[0]);
144.1458 +
144.1459 + // If shift can be done without recopy, do so
144.1460 + if (n <= (32-bitsInHighWord)) {
144.1461 + primitiveLeftShift(a, len, nBits);
144.1462 + return a;
144.1463 + } else { // Array must be resized
144.1464 + if (nBits <= (32-bitsInHighWord)) {
144.1465 + int result[] = new int[nInts+len];
144.1466 + for (int i=0; i<len; i++)
144.1467 + result[i] = a[i];
144.1468 + primitiveLeftShift(result, result.length, nBits);
144.1469 + return result;
144.1470 + } else {
144.1471 + int result[] = new int[nInts+len+1];
144.1472 + for (int i=0; i<len; i++)
144.1473 + result[i] = a[i];
144.1474 + primitiveRightShift(result, result.length, 32 - nBits);
144.1475 + return result;
144.1476 + }
144.1477 + }
144.1478 + }
144.1479 +
144.1480 + // shifts a up to len right n bits assumes no leading zeros, 0<n<32
144.1481 + static void primitiveRightShift(int[] a, int len, int n) {
144.1482 + int n2 = 32 - n;
144.1483 + for (int i=len-1, c=a[i]; i>0; i--) {
144.1484 + int b = c;
144.1485 + c = a[i-1];
144.1486 + a[i] = (c << n2) | (b >>> n);
144.1487 + }
144.1488 + a[0] >>>= n;
144.1489 + }
144.1490 +
144.1491 + // shifts a up to len left n bits assumes no leading zeros, 0<=n<32
144.1492 + static void primitiveLeftShift(int[] a, int len, int n) {
144.1493 + if (len == 0 || n == 0)
144.1494 + return;
144.1495 +
144.1496 + int n2 = 32 - n;
144.1497 + for (int i=0, c=a[i], m=i+len-1; i<m; i++) {
144.1498 + int b = c;
144.1499 + c = a[i+1];
144.1500 + a[i] = (b << n) | (c >>> n2);
144.1501 + }
144.1502 + a[len-1] <<= n;
144.1503 + }
144.1504 +
144.1505 + /**
144.1506 + * Calculate bitlength of contents of the first len elements an int array,
144.1507 + * assuming there are no leading zero ints.
144.1508 + */
144.1509 + private static int bitLength(int[] val, int len) {
144.1510 + if (len == 0)
144.1511 + return 0;
144.1512 + return ((len - 1) << 5) + bitLengthForInt(val[0]);
144.1513 + }
144.1514 +
144.1515 + /**
144.1516 + * Returns a BigInteger whose value is the absolute value of this
144.1517 + * BigInteger.
144.1518 + *
144.1519 + * @return {@code abs(this)}
144.1520 + */
144.1521 + public BigInteger abs() {
144.1522 + return (signum >= 0 ? this : this.negate());
144.1523 + }
144.1524 +
144.1525 + /**
144.1526 + * Returns a BigInteger whose value is {@code (-this)}.
144.1527 + *
144.1528 + * @return {@code -this}
144.1529 + */
144.1530 + public BigInteger negate() {
144.1531 + return new BigInteger(this.mag, -this.signum);
144.1532 + }
144.1533 +
144.1534 + /**
144.1535 + * Returns the signum function of this BigInteger.
144.1536 + *
144.1537 + * @return -1, 0 or 1 as the value of this BigInteger is negative, zero or
144.1538 + * positive.
144.1539 + */
144.1540 + public int signum() {
144.1541 + return this.signum;
144.1542 + }
144.1543 +
144.1544 + // Modular Arithmetic Operations
144.1545 +
144.1546 + /**
144.1547 + * Returns a BigInteger whose value is {@code (this mod m}). This method
144.1548 + * differs from {@code remainder} in that it always returns a
144.1549 + * <i>non-negative</i> BigInteger.
144.1550 + *
144.1551 + * @param m the modulus.
144.1552 + * @return {@code this mod m}
144.1553 + * @throws ArithmeticException {@code m} ≤ 0
144.1554 + * @see #remainder
144.1555 + */
144.1556 + public BigInteger mod(BigInteger m) {
144.1557 + if (m.signum <= 0)
144.1558 + throw new ArithmeticException("BigInteger: modulus not positive");
144.1559 +
144.1560 + BigInteger result = this.remainder(m);
144.1561 + return (result.signum >= 0 ? result : result.add(m));
144.1562 + }
144.1563 +
144.1564 + /**
144.1565 + * Returns a BigInteger whose value is
144.1566 + * <tt>(this<sup>exponent</sup> mod m)</tt>. (Unlike {@code pow}, this
144.1567 + * method permits negative exponents.)
144.1568 + *
144.1569 + * @param exponent the exponent.
144.1570 + * @param m the modulus.
144.1571 + * @return <tt>this<sup>exponent</sup> mod m</tt>
144.1572 + * @throws ArithmeticException {@code m} ≤ 0 or the exponent is
144.1573 + * negative and this BigInteger is not <i>relatively
144.1574 + * prime</i> to {@code m}.
144.1575 + * @see #modInverse
144.1576 + */
144.1577 + public BigInteger modPow(BigInteger exponent, BigInteger m) {
144.1578 + if (m.signum <= 0)
144.1579 + throw new ArithmeticException("BigInteger: modulus not positive");
144.1580 +
144.1581 + // Trivial cases
144.1582 + if (exponent.signum == 0)
144.1583 + return (m.equals(ONE) ? ZERO : ONE);
144.1584 +
144.1585 + if (this.equals(ONE))
144.1586 + return (m.equals(ONE) ? ZERO : ONE);
144.1587 +
144.1588 + if (this.equals(ZERO) && exponent.signum >= 0)
144.1589 + return ZERO;
144.1590 +
144.1591 + if (this.equals(negConst[1]) && (!exponent.testBit(0)))
144.1592 + return (m.equals(ONE) ? ZERO : ONE);
144.1593 +
144.1594 + boolean invertResult;
144.1595 + if ((invertResult = (exponent.signum < 0)))
144.1596 + exponent = exponent.negate();
144.1597 +
144.1598 + BigInteger base = (this.signum < 0 || this.compareTo(m) >= 0
144.1599 + ? this.mod(m) : this);
144.1600 + BigInteger result;
144.1601 + if (m.testBit(0)) { // odd modulus
144.1602 + result = base.oddModPow(exponent, m);
144.1603 + } else {
144.1604 + /*
144.1605 + * Even modulus. Tear it into an "odd part" (m1) and power of two
144.1606 + * (m2), exponentiate mod m1, manually exponentiate mod m2, and
144.1607 + * use Chinese Remainder Theorem to combine results.
144.1608 + */
144.1609 +
144.1610 + // Tear m apart into odd part (m1) and power of 2 (m2)
144.1611 + int p = m.getLowestSetBit(); // Max pow of 2 that divides m
144.1612 +
144.1613 + BigInteger m1 = m.shiftRight(p); // m/2**p
144.1614 + BigInteger m2 = ONE.shiftLeft(p); // 2**p
144.1615 +
144.1616 + // Calculate new base from m1
144.1617 + BigInteger base2 = (this.signum < 0 || this.compareTo(m1) >= 0
144.1618 + ? this.mod(m1) : this);
144.1619 +
144.1620 + // Caculate (base ** exponent) mod m1.
144.1621 + BigInteger a1 = (m1.equals(ONE) ? ZERO :
144.1622 + base2.oddModPow(exponent, m1));
144.1623 +
144.1624 + // Calculate (this ** exponent) mod m2
144.1625 + BigInteger a2 = base.modPow2(exponent, p);
144.1626 +
144.1627 + // Combine results using Chinese Remainder Theorem
144.1628 + BigInteger y1 = m2.modInverse(m1);
144.1629 + BigInteger y2 = m1.modInverse(m2);
144.1630 +
144.1631 + result = a1.multiply(m2).multiply(y1).add
144.1632 + (a2.multiply(m1).multiply(y2)).mod(m);
144.1633 + }
144.1634 +
144.1635 + return (invertResult ? result.modInverse(m) : result);
144.1636 + }
144.1637 +
144.1638 + static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793,
144.1639 + Integer.MAX_VALUE}; // Sentinel
144.1640 +
144.1641 + /**
144.1642 + * Returns a BigInteger whose value is x to the power of y mod z.
144.1643 + * Assumes: z is odd && x < z.
144.1644 + */
144.1645 + private BigInteger oddModPow(BigInteger y, BigInteger z) {
144.1646 + /*
144.1647 + * The algorithm is adapted from Colin Plumb's C library.
144.1648 + *
144.1649 + * The window algorithm:
144.1650 + * The idea is to keep a running product of b1 = n^(high-order bits of exp)
144.1651 + * and then keep appending exponent bits to it. The following patterns
144.1652 + * apply to a 3-bit window (k = 3):
144.1653 + * To append 0: square
144.1654 + * To append 1: square, multiply by n^1
144.1655 + * To append 10: square, multiply by n^1, square
144.1656 + * To append 11: square, square, multiply by n^3
144.1657 + * To append 100: square, multiply by n^1, square, square
144.1658 + * To append 101: square, square, square, multiply by n^5
144.1659 + * To append 110: square, square, multiply by n^3, square
144.1660 + * To append 111: square, square, square, multiply by n^7
144.1661 + *
144.1662 + * Since each pattern involves only one multiply, the longer the pattern
144.1663 + * the better, except that a 0 (no multiplies) can be appended directly.
144.1664 + * We precompute a table of odd powers of n, up to 2^k, and can then
144.1665 + * multiply k bits of exponent at a time. Actually, assuming random
144.1666 + * exponents, there is on average one zero bit between needs to
144.1667 + * multiply (1/2 of the time there's none, 1/4 of the time there's 1,
144.1668 + * 1/8 of the time, there's 2, 1/32 of the time, there's 3, etc.), so
144.1669 + * you have to do one multiply per k+1 bits of exponent.
144.1670 + *
144.1671 + * The loop walks down the exponent, squaring the result buffer as
144.1672 + * it goes. There is a wbits+1 bit lookahead buffer, buf, that is
144.1673 + * filled with the upcoming exponent bits. (What is read after the
144.1674 + * end of the exponent is unimportant, but it is filled with zero here.)
144.1675 + * When the most-significant bit of this buffer becomes set, i.e.
144.1676 + * (buf & tblmask) != 0, we have to decide what pattern to multiply
144.1677 + * by, and when to do it. We decide, remember to do it in future
144.1678 + * after a suitable number of squarings have passed (e.g. a pattern
144.1679 + * of "100" in the buffer requires that we multiply by n^1 immediately;
144.1680 + * a pattern of "110" calls for multiplying by n^3 after one more
144.1681 + * squaring), clear the buffer, and continue.
144.1682 + *
144.1683 + * When we start, there is one more optimization: the result buffer
144.1684 + * is implcitly one, so squaring it or multiplying by it can be
144.1685 + * optimized away. Further, if we start with a pattern like "100"
144.1686 + * in the lookahead window, rather than placing n into the buffer
144.1687 + * and then starting to square it, we have already computed n^2
144.1688 + * to compute the odd-powers table, so we can place that into
144.1689 + * the buffer and save a squaring.
144.1690 + *
144.1691 + * This means that if you have a k-bit window, to compute n^z,
144.1692 + * where z is the high k bits of the exponent, 1/2 of the time
144.1693 + * it requires no squarings. 1/4 of the time, it requires 1
144.1694 + * squaring, ... 1/2^(k-1) of the time, it reqires k-2 squarings.
144.1695 + * And the remaining 1/2^(k-1) of the time, the top k bits are a
144.1696 + * 1 followed by k-1 0 bits, so it again only requires k-2
144.1697 + * squarings, not k-1. The average of these is 1. Add that
144.1698 + * to the one squaring we have to do to compute the table,
144.1699 + * and you'll see that a k-bit window saves k-2 squarings
144.1700 + * as well as reducing the multiplies. (It actually doesn't
144.1701 + * hurt in the case k = 1, either.)
144.1702 + */
144.1703 + // Special case for exponent of one
144.1704 + if (y.equals(ONE))
144.1705 + return this;
144.1706 +
144.1707 + // Special case for base of zero
144.1708 + if (signum==0)
144.1709 + return ZERO;
144.1710 +
144.1711 + int[] base = mag.clone();
144.1712 + int[] exp = y.mag;
144.1713 + int[] mod = z.mag;
144.1714 + int modLen = mod.length;
144.1715 +
144.1716 + // Select an appropriate window size
144.1717 + int wbits = 0;
144.1718 + int ebits = bitLength(exp, exp.length);
144.1719 + // if exponent is 65537 (0x10001), use minimum window size
144.1720 + if ((ebits != 17) || (exp[0] != 65537)) {
144.1721 + while (ebits > bnExpModThreshTable[wbits]) {
144.1722 + wbits++;
144.1723 + }
144.1724 + }
144.1725 +
144.1726 + // Calculate appropriate table size
144.1727 + int tblmask = 1 << wbits;
144.1728 +
144.1729 + // Allocate table for precomputed odd powers of base in Montgomery form
144.1730 + int[][] table = new int[tblmask][];
144.1731 + for (int i=0; i<tblmask; i++)
144.1732 + table[i] = new int[modLen];
144.1733 +
144.1734 + // Compute the modular inverse
144.1735 + int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]);
144.1736 +
144.1737 + // Convert base to Montgomery form
144.1738 + int[] a = leftShift(base, base.length, modLen << 5);
144.1739 +
144.1740 + MutableBigInteger q = new MutableBigInteger(),
144.1741 + a2 = new MutableBigInteger(a),
144.1742 + b2 = new MutableBigInteger(mod);
144.1743 +
144.1744 + MutableBigInteger r= a2.divide(b2, q);
144.1745 + table[0] = r.toIntArray();
144.1746 +
144.1747 + // Pad table[0] with leading zeros so its length is at least modLen
144.1748 + if (table[0].length < modLen) {
144.1749 + int offset = modLen - table[0].length;
144.1750 + int[] t2 = new int[modLen];
144.1751 + for (int i=0; i<table[0].length; i++)
144.1752 + t2[i+offset] = table[0][i];
144.1753 + table[0] = t2;
144.1754 + }
144.1755 +
144.1756 + // Set b to the square of the base
144.1757 + int[] b = squareToLen(table[0], modLen, null);
144.1758 + b = montReduce(b, mod, modLen, inv);
144.1759 +
144.1760 + // Set t to high half of b
144.1761 + int[] t = new int[modLen];
144.1762 + for(int i=0; i<modLen; i++)
144.1763 + t[i] = b[i];
144.1764 +
144.1765 + // Fill in the table with odd powers of the base
144.1766 + for (int i=1; i<tblmask; i++) {
144.1767 + int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null);
144.1768 + table[i] = montReduce(prod, mod, modLen, inv);
144.1769 + }
144.1770 +
144.1771 + // Pre load the window that slides over the exponent
144.1772 + int bitpos = 1 << ((ebits-1) & (32-1));
144.1773 +
144.1774 + int buf = 0;
144.1775 + int elen = exp.length;
144.1776 + int eIndex = 0;
144.1777 + for (int i = 0; i <= wbits; i++) {
144.1778 + buf = (buf << 1) | (((exp[eIndex] & bitpos) != 0)?1:0);
144.1779 + bitpos >>>= 1;
144.1780 + if (bitpos == 0) {
144.1781 + eIndex++;
144.1782 + bitpos = 1 << (32-1);
144.1783 + elen--;
144.1784 + }
144.1785 + }
144.1786 +
144.1787 + int multpos = ebits;
144.1788 +
144.1789 + // The first iteration, which is hoisted out of the main loop
144.1790 + ebits--;
144.1791 + boolean isone = true;
144.1792 +
144.1793 + multpos = ebits - wbits;
144.1794 + while ((buf & 1) == 0) {
144.1795 + buf >>>= 1;
144.1796 + multpos++;
144.1797 + }
144.1798 +
144.1799 + int[] mult = table[buf >>> 1];
144.1800 +
144.1801 + buf = 0;
144.1802 + if (multpos == ebits)
144.1803 + isone = false;
144.1804 +
144.1805 + // The main loop
144.1806 + while(true) {
144.1807 + ebits--;
144.1808 + // Advance the window
144.1809 + buf <<= 1;
144.1810 +
144.1811 + if (elen != 0) {
144.1812 + buf |= ((exp[eIndex] & bitpos) != 0) ? 1 : 0;
144.1813 + bitpos >>>= 1;
144.1814 + if (bitpos == 0) {
144.1815 + eIndex++;
144.1816 + bitpos = 1 << (32-1);
144.1817 + elen--;
144.1818 + }
144.1819 + }
144.1820 +
144.1821 + // Examine the window for pending multiplies
144.1822 + if ((buf & tblmask) != 0) {
144.1823 + multpos = ebits - wbits;
144.1824 + while ((buf & 1) == 0) {
144.1825 + buf >>>= 1;
144.1826 + multpos++;
144.1827 + }
144.1828 + mult = table[buf >>> 1];
144.1829 + buf = 0;
144.1830 + }
144.1831 +
144.1832 + // Perform multiply
144.1833 + if (ebits == multpos) {
144.1834 + if (isone) {
144.1835 + b = mult.clone();
144.1836 + isone = false;
144.1837 + } else {
144.1838 + t = b;
144.1839 + a = multiplyToLen(t, modLen, mult, modLen, a);
144.1840 + a = montReduce(a, mod, modLen, inv);
144.1841 + t = a; a = b; b = t;
144.1842 + }
144.1843 + }
144.1844 +
144.1845 + // Check if done
144.1846 + if (ebits == 0)
144.1847 + break;
144.1848 +
144.1849 + // Square the input
144.1850 + if (!isone) {
144.1851 + t = b;
144.1852 + a = squareToLen(t, modLen, a);
144.1853 + a = montReduce(a, mod, modLen, inv);
144.1854 + t = a; a = b; b = t;
144.1855 + }
144.1856 + }
144.1857 +
144.1858 + // Convert result out of Montgomery form and return
144.1859 + int[] t2 = new int[2*modLen];
144.1860 + for(int i=0; i<modLen; i++)
144.1861 + t2[i+modLen] = b[i];
144.1862 +
144.1863 + b = montReduce(t2, mod, modLen, inv);
144.1864 +
144.1865 + t2 = new int[modLen];
144.1866 + for(int i=0; i<modLen; i++)
144.1867 + t2[i] = b[i];
144.1868 +
144.1869 + return new BigInteger(1, t2);
144.1870 + }
144.1871 +
144.1872 + /**
144.1873 + * Montgomery reduce n, modulo mod. This reduces modulo mod and divides
144.1874 + * by 2^(32*mlen). Adapted from Colin Plumb's C library.
144.1875 + */
144.1876 + private static int[] montReduce(int[] n, int[] mod, int mlen, int inv) {
144.1877 + int c=0;
144.1878 + int len = mlen;
144.1879 + int offset=0;
144.1880 +
144.1881 + do {
144.1882 + int nEnd = n[n.length-1-offset];
144.1883 + int carry = mulAdd(n, mod, offset, mlen, inv * nEnd);
144.1884 + c += addOne(n, offset, mlen, carry);
144.1885 + offset++;
144.1886 + } while(--len > 0);
144.1887 +
144.1888 + while(c>0)
144.1889 + c += subN(n, mod, mlen);
144.1890 +
144.1891 + while (intArrayCmpToLen(n, mod, mlen) >= 0)
144.1892 + subN(n, mod, mlen);
144.1893 +
144.1894 + return n;
144.1895 + }
144.1896 +
144.1897 +
144.1898 + /*
144.1899 + * Returns -1, 0 or +1 as big-endian unsigned int array arg1 is less than,
144.1900 + * equal to, or greater than arg2 up to length len.
144.1901 + */
144.1902 + private static int intArrayCmpToLen(int[] arg1, int[] arg2, int len) {
144.1903 + for (int i=0; i<len; i++) {
144.1904 + long b1 = arg1[i] & LONG_MASK;
144.1905 + long b2 = arg2[i] & LONG_MASK;
144.1906 + if (b1 < b2)
144.1907 + return -1;
144.1908 + if (b1 > b2)
144.1909 + return 1;
144.1910 + }
144.1911 + return 0;
144.1912 + }
144.1913 +
144.1914 + /**
144.1915 + * Subtracts two numbers of same length, returning borrow.
144.1916 + */
144.1917 + private static int subN(int[] a, int[] b, int len) {
144.1918 + long sum = 0;
144.1919 +
144.1920 + while(--len >= 0) {
144.1921 + sum = (a[len] & LONG_MASK) -
144.1922 + (b[len] & LONG_MASK) + (sum >> 32);
144.1923 + a[len] = (int)sum;
144.1924 + }
144.1925 +
144.1926 + return (int)(sum >> 32);
144.1927 + }
144.1928 +
144.1929 + /**
144.1930 + * Multiply an array by one word k and add to result, return the carry
144.1931 + */
144.1932 + static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
144.1933 + long kLong = k & LONG_MASK;
144.1934 + long carry = 0;
144.1935 +
144.1936 + offset = out.length-offset - 1;
144.1937 + for (int j=len-1; j >= 0; j--) {
144.1938 + long product = (in[j] & LONG_MASK) * kLong +
144.1939 + (out[offset] & LONG_MASK) + carry;
144.1940 + out[offset--] = (int)product;
144.1941 + carry = product >>> 32;
144.1942 + }
144.1943 + return (int)carry;
144.1944 + }
144.1945 +
144.1946 + /**
144.1947 + * Add one word to the number a mlen words into a. Return the resulting
144.1948 + * carry.
144.1949 + */
144.1950 + static int addOne(int[] a, int offset, int mlen, int carry) {
144.1951 + offset = a.length-1-mlen-offset;
144.1952 + long t = (a[offset] & LONG_MASK) + (carry & LONG_MASK);
144.1953 +
144.1954 + a[offset] = (int)t;
144.1955 + if ((t >>> 32) == 0)
144.1956 + return 0;
144.1957 + while (--mlen >= 0) {
144.1958 + if (--offset < 0) { // Carry out of number
144.1959 + return 1;
144.1960 + } else {
144.1961 + a[offset]++;
144.1962 + if (a[offset] != 0)
144.1963 + return 0;
144.1964 + }
144.1965 + }
144.1966 + return 1;
144.1967 + }
144.1968 +
144.1969 + /**
144.1970 + * Returns a BigInteger whose value is (this ** exponent) mod (2**p)
144.1971 + */
144.1972 + private BigInteger modPow2(BigInteger exponent, int p) {
144.1973 + /*
144.1974 + * Perform exponentiation using repeated squaring trick, chopping off
144.1975 + * high order bits as indicated by modulus.
144.1976 + */
144.1977 + BigInteger result = valueOf(1);
144.1978 + BigInteger baseToPow2 = this.mod2(p);
144.1979 + int expOffset = 0;
144.1980 +
144.1981 + int limit = exponent.bitLength();
144.1982 +
144.1983 + if (this.testBit(0))
144.1984 + limit = (p-1) < limit ? (p-1) : limit;
144.1985 +
144.1986 + while (expOffset < limit) {
144.1987 + if (exponent.testBit(expOffset))
144.1988 + result = result.multiply(baseToPow2).mod2(p);
144.1989 + expOffset++;
144.1990 + if (expOffset < limit)
144.1991 + baseToPow2 = baseToPow2.square().mod2(p);
144.1992 + }
144.1993 +
144.1994 + return result;
144.1995 + }
144.1996 +
144.1997 + /**
144.1998 + * Returns a BigInteger whose value is this mod(2**p).
144.1999 + * Assumes that this {@code BigInteger >= 0} and {@code p > 0}.
144.2000 + */
144.2001 + private BigInteger mod2(int p) {
144.2002 + if (bitLength() <= p)
144.2003 + return this;
144.2004 +
144.2005 + // Copy remaining ints of mag
144.2006 + int numInts = (p + 31) >>> 5;
144.2007 + int[] mag = new int[numInts];
144.2008 + for (int i=0; i<numInts; i++)
144.2009 + mag[i] = this.mag[i + (this.mag.length - numInts)];
144.2010 +
144.2011 + // Mask out any excess bits
144.2012 + int excessBits = (numInts << 5) - p;
144.2013 + mag[0] &= (1L << (32-excessBits)) - 1;
144.2014 +
144.2015 + return (mag[0]==0 ? new BigInteger(1, mag) : new BigInteger(mag, 1));
144.2016 + }
144.2017 +
144.2018 + /**
144.2019 + * Returns a BigInteger whose value is {@code (this}<sup>-1</sup> {@code mod m)}.
144.2020 + *
144.2021 + * @param m the modulus.
144.2022 + * @return {@code this}<sup>-1</sup> {@code mod m}.
144.2023 + * @throws ArithmeticException {@code m} ≤ 0, or this BigInteger
144.2024 + * has no multiplicative inverse mod m (that is, this BigInteger
144.2025 + * is not <i>relatively prime</i> to m).
144.2026 + */
144.2027 + public BigInteger modInverse(BigInteger m) {
144.2028 + if (m.signum != 1)
144.2029 + throw new ArithmeticException("BigInteger: modulus not positive");
144.2030 +
144.2031 + if (m.equals(ONE))
144.2032 + return ZERO;
144.2033 +
144.2034 + // Calculate (this mod m)
144.2035 + BigInteger modVal = this;
144.2036 + if (signum < 0 || (this.compareMagnitude(m) >= 0))
144.2037 + modVal = this.mod(m);
144.2038 +
144.2039 + if (modVal.equals(ONE))
144.2040 + return ONE;
144.2041 +
144.2042 + MutableBigInteger a = new MutableBigInteger(modVal);
144.2043 + MutableBigInteger b = new MutableBigInteger(m);
144.2044 +
144.2045 + MutableBigInteger result = a.mutableModInverse(b);
144.2046 + return result.toBigInteger(1);
144.2047 + }
144.2048 +
144.2049 + // Shift Operations
144.2050 +
144.2051 + /**
144.2052 + * Returns a BigInteger whose value is {@code (this << n)}.
144.2053 + * The shift distance, {@code n}, may be negative, in which case
144.2054 + * this method performs a right shift.
144.2055 + * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.)
144.2056 + *
144.2057 + * @param n shift distance, in bits.
144.2058 + * @return {@code this << n}
144.2059 + * @throws ArithmeticException if the shift distance is {@code
144.2060 + * Integer.MIN_VALUE}.
144.2061 + * @see #shiftRight
144.2062 + */
144.2063 + public BigInteger shiftLeft(int n) {
144.2064 + if (signum == 0)
144.2065 + return ZERO;
144.2066 + if (n==0)
144.2067 + return this;
144.2068 + if (n<0) {
144.2069 + if (n == Integer.MIN_VALUE) {
144.2070 + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
144.2071 + } else {
144.2072 + return shiftRight(-n);
144.2073 + }
144.2074 + }
144.2075 +
144.2076 + int nInts = n >>> 5;
144.2077 + int nBits = n & 0x1f;
144.2078 + int magLen = mag.length;
144.2079 + int newMag[] = null;
144.2080 +
144.2081 + if (nBits == 0) {
144.2082 + newMag = new int[magLen + nInts];
144.2083 + for (int i=0; i<magLen; i++)
144.2084 + newMag[i] = mag[i];
144.2085 + } else {
144.2086 + int i = 0;
144.2087 + int nBits2 = 32 - nBits;
144.2088 + int highBits = mag[0] >>> nBits2;
144.2089 + if (highBits != 0) {
144.2090 + newMag = new int[magLen + nInts + 1];
144.2091 + newMag[i++] = highBits;
144.2092 + } else {
144.2093 + newMag = new int[magLen + nInts];
144.2094 + }
144.2095 + int j=0;
144.2096 + while (j < magLen-1)
144.2097 + newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2;
144.2098 + newMag[i] = mag[j] << nBits;
144.2099 + }
144.2100 +
144.2101 + return new BigInteger(newMag, signum);
144.2102 + }
144.2103 +
144.2104 + /**
144.2105 + * Returns a BigInteger whose value is {@code (this >> n)}. Sign
144.2106 + * extension is performed. The shift distance, {@code n}, may be
144.2107 + * negative, in which case this method performs a left shift.
144.2108 + * (Computes <tt>floor(this / 2<sup>n</sup>)</tt>.)
144.2109 + *
144.2110 + * @param n shift distance, in bits.
144.2111 + * @return {@code this >> n}
144.2112 + * @throws ArithmeticException if the shift distance is {@code
144.2113 + * Integer.MIN_VALUE}.
144.2114 + * @see #shiftLeft
144.2115 + */
144.2116 + public BigInteger shiftRight(int n) {
144.2117 + if (n==0)
144.2118 + return this;
144.2119 + if (n<0) {
144.2120 + if (n == Integer.MIN_VALUE) {
144.2121 + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
144.2122 + } else {
144.2123 + return shiftLeft(-n);
144.2124 + }
144.2125 + }
144.2126 +
144.2127 + int nInts = n >>> 5;
144.2128 + int nBits = n & 0x1f;
144.2129 + int magLen = mag.length;
144.2130 + int newMag[] = null;
144.2131 +
144.2132 + // Special case: entire contents shifted off the end
144.2133 + if (nInts >= magLen)
144.2134 + return (signum >= 0 ? ZERO : negConst[1]);
144.2135 +
144.2136 + if (nBits == 0) {
144.2137 + int newMagLen = magLen - nInts;
144.2138 + newMag = new int[newMagLen];
144.2139 + for (int i=0; i<newMagLen; i++)
144.2140 + newMag[i] = mag[i];
144.2141 + } else {
144.2142 + int i = 0;
144.2143 + int highBits = mag[0] >>> nBits;
144.2144 + if (highBits != 0) {
144.2145 + newMag = new int[magLen - nInts];
144.2146 + newMag[i++] = highBits;
144.2147 + } else {
144.2148 + newMag = new int[magLen - nInts -1];
144.2149 + }
144.2150 +
144.2151 + int nBits2 = 32 - nBits;
144.2152 + int j=0;
144.2153 + while (j < magLen - nInts - 1)
144.2154 + newMag[i++] = (mag[j++] << nBits2) | (mag[j] >>> nBits);
144.2155 + }
144.2156 +
144.2157 + if (signum < 0) {
144.2158 + // Find out whether any one-bits were shifted off the end.
144.2159 + boolean onesLost = false;
144.2160 + for (int i=magLen-1, j=magLen-nInts; i>=j && !onesLost; i--)
144.2161 + onesLost = (mag[i] != 0);
144.2162 + if (!onesLost && nBits != 0)
144.2163 + onesLost = (mag[magLen - nInts - 1] << (32 - nBits) != 0);
144.2164 +
144.2165 + if (onesLost)
144.2166 + newMag = javaIncrement(newMag);
144.2167 + }
144.2168 +
144.2169 + return new BigInteger(newMag, signum);
144.2170 + }
144.2171 +
144.2172 + int[] javaIncrement(int[] val) {
144.2173 + int lastSum = 0;
144.2174 + for (int i=val.length-1; i >= 0 && lastSum == 0; i--)
144.2175 + lastSum = (val[i] += 1);
144.2176 + if (lastSum == 0) {
144.2177 + val = new int[val.length+1];
144.2178 + val[0] = 1;
144.2179 + }
144.2180 + return val;
144.2181 + }
144.2182 +
144.2183 + // Bitwise Operations
144.2184 +
144.2185 + /**
144.2186 + * Returns a BigInteger whose value is {@code (this & val)}. (This
144.2187 + * method returns a negative BigInteger if and only if this and val are
144.2188 + * both negative.)
144.2189 + *
144.2190 + * @param val value to be AND'ed with this BigInteger.
144.2191 + * @return {@code this & val}
144.2192 + */
144.2193 + public BigInteger and(BigInteger val) {
144.2194 + int[] result = new int[Math.max(intLength(), val.intLength())];
144.2195 + for (int i=0; i<result.length; i++)
144.2196 + result[i] = (getInt(result.length-i-1)
144.2197 + & val.getInt(result.length-i-1));
144.2198 +
144.2199 + return valueOf(result);
144.2200 + }
144.2201 +
144.2202 + /**
144.2203 + * Returns a BigInteger whose value is {@code (this | val)}. (This method
144.2204 + * returns a negative BigInteger if and only if either this or val is
144.2205 + * negative.)
144.2206 + *
144.2207 + * @param val value to be OR'ed with this BigInteger.
144.2208 + * @return {@code this | val}
144.2209 + */
144.2210 + public BigInteger or(BigInteger val) {
144.2211 + int[] result = new int[Math.max(intLength(), val.intLength())];
144.2212 + for (int i=0; i<result.length; i++)
144.2213 + result[i] = (getInt(result.length-i-1)
144.2214 + | val.getInt(result.length-i-1));
144.2215 +
144.2216 + return valueOf(result);
144.2217 + }
144.2218 +
144.2219 + /**
144.2220 + * Returns a BigInteger whose value is {@code (this ^ val)}. (This method
144.2221 + * returns a negative BigInteger if and only if exactly one of this and
144.2222 + * val are negative.)
144.2223 + *
144.2224 + * @param val value to be XOR'ed with this BigInteger.
144.2225 + * @return {@code this ^ val}
144.2226 + */
144.2227 + public BigInteger xor(BigInteger val) {
144.2228 + int[] result = new int[Math.max(intLength(), val.intLength())];
144.2229 + for (int i=0; i<result.length; i++)
144.2230 + result[i] = (getInt(result.length-i-1)
144.2231 + ^ val.getInt(result.length-i-1));
144.2232 +
144.2233 + return valueOf(result);
144.2234 + }
144.2235 +
144.2236 + /**
144.2237 + * Returns a BigInteger whose value is {@code (~this)}. (This method
144.2238 + * returns a negative value if and only if this BigInteger is
144.2239 + * non-negative.)
144.2240 + *
144.2241 + * @return {@code ~this}
144.2242 + */
144.2243 + public BigInteger not() {
144.2244 + int[] result = new int[intLength()];
144.2245 + for (int i=0; i<result.length; i++)
144.2246 + result[i] = ~getInt(result.length-i-1);
144.2247 +
144.2248 + return valueOf(result);
144.2249 + }
144.2250 +
144.2251 + /**
144.2252 + * Returns a BigInteger whose value is {@code (this & ~val)}. This
144.2253 + * method, which is equivalent to {@code and(val.not())}, is provided as
144.2254 + * a convenience for masking operations. (This method returns a negative
144.2255 + * BigInteger if and only if {@code this} is negative and {@code val} is
144.2256 + * positive.)
144.2257 + *
144.2258 + * @param val value to be complemented and AND'ed with this BigInteger.
144.2259 + * @return {@code this & ~val}
144.2260 + */
144.2261 + public BigInteger andNot(BigInteger val) {
144.2262 + int[] result = new int[Math.max(intLength(), val.intLength())];
144.2263 + for (int i=0; i<result.length; i++)
144.2264 + result[i] = (getInt(result.length-i-1)
144.2265 + & ~val.getInt(result.length-i-1));
144.2266 +
144.2267 + return valueOf(result);
144.2268 + }
144.2269 +
144.2270 +
144.2271 + // Single Bit Operations
144.2272 +
144.2273 + /**
144.2274 + * Returns {@code true} if and only if the designated bit is set.
144.2275 + * (Computes {@code ((this & (1<<n)) != 0)}.)
144.2276 + *
144.2277 + * @param n index of bit to test.
144.2278 + * @return {@code true} if and only if the designated bit is set.
144.2279 + * @throws ArithmeticException {@code n} is negative.
144.2280 + */
144.2281 + public boolean testBit(int n) {
144.2282 + if (n<0)
144.2283 + throw new ArithmeticException("Negative bit address");
144.2284 +
144.2285 + return (getInt(n >>> 5) & (1 << (n & 31))) != 0;
144.2286 + }
144.2287 +
144.2288 + /**
144.2289 + * Returns a BigInteger whose value is equivalent to this BigInteger
144.2290 + * with the designated bit set. (Computes {@code (this | (1<<n))}.)
144.2291 + *
144.2292 + * @param n index of bit to set.
144.2293 + * @return {@code this | (1<<n)}
144.2294 + * @throws ArithmeticException {@code n} is negative.
144.2295 + */
144.2296 + public BigInteger setBit(int n) {
144.2297 + if (n<0)
144.2298 + throw new ArithmeticException("Negative bit address");
144.2299 +
144.2300 + int intNum = n >>> 5;
144.2301 + int[] result = new int[Math.max(intLength(), intNum+2)];
144.2302 +
144.2303 + for (int i=0; i<result.length; i++)
144.2304 + result[result.length-i-1] = getInt(i);
144.2305 +
144.2306 + result[result.length-intNum-1] |= (1 << (n & 31));
144.2307 +
144.2308 + return valueOf(result);
144.2309 + }
144.2310 +
144.2311 + /**
144.2312 + * Returns a BigInteger whose value is equivalent to this BigInteger
144.2313 + * with the designated bit cleared.
144.2314 + * (Computes {@code (this & ~(1<<n))}.)
144.2315 + *
144.2316 + * @param n index of bit to clear.
144.2317 + * @return {@code this & ~(1<<n)}
144.2318 + * @throws ArithmeticException {@code n} is negative.
144.2319 + */
144.2320 + public BigInteger clearBit(int n) {
144.2321 + if (n<0)
144.2322 + throw new ArithmeticException("Negative bit address");
144.2323 +
144.2324 + int intNum = n >>> 5;
144.2325 + int[] result = new int[Math.max(intLength(), ((n + 1) >>> 5) + 1)];
144.2326 +
144.2327 + for (int i=0; i<result.length; i++)
144.2328 + result[result.length-i-1] = getInt(i);
144.2329 +
144.2330 + result[result.length-intNum-1] &= ~(1 << (n & 31));
144.2331 +
144.2332 + return valueOf(result);
144.2333 + }
144.2334 +
144.2335 + /**
144.2336 + * Returns a BigInteger whose value is equivalent to this BigInteger
144.2337 + * with the designated bit flipped.
144.2338 + * (Computes {@code (this ^ (1<<n))}.)
144.2339 + *
144.2340 + * @param n index of bit to flip.
144.2341 + * @return {@code this ^ (1<<n)}
144.2342 + * @throws ArithmeticException {@code n} is negative.
144.2343 + */
144.2344 + public BigInteger flipBit(int n) {
144.2345 + if (n<0)
144.2346 + throw new ArithmeticException("Negative bit address");
144.2347 +
144.2348 + int intNum = n >>> 5;
144.2349 + int[] result = new int[Math.max(intLength(), intNum+2)];
144.2350 +
144.2351 + for (int i=0; i<result.length; i++)
144.2352 + result[result.length-i-1] = getInt(i);
144.2353 +
144.2354 + result[result.length-intNum-1] ^= (1 << (n & 31));
144.2355 +
144.2356 + return valueOf(result);
144.2357 + }
144.2358 +
144.2359 + /**
144.2360 + * Returns the index of the rightmost (lowest-order) one bit in this
144.2361 + * BigInteger (the number of zero bits to the right of the rightmost
144.2362 + * one bit). Returns -1 if this BigInteger contains no one bits.
144.2363 + * (Computes {@code (this==0? -1 : log2(this & -this))}.)
144.2364 + *
144.2365 + * @return index of the rightmost one bit in this BigInteger.
144.2366 + */
144.2367 + public int getLowestSetBit() {
144.2368 + @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
144.2369 + if (lsb == -2) { // lowestSetBit not initialized yet
144.2370 + lsb = 0;
144.2371 + if (signum == 0) {
144.2372 + lsb -= 1;
144.2373 + } else {
144.2374 + // Search for lowest order nonzero int
144.2375 + int i,b;
144.2376 + for (i=0; (b = getInt(i))==0; i++)
144.2377 + ;
144.2378 + lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
144.2379 + }
144.2380 + lowestSetBit = lsb + 2;
144.2381 + }
144.2382 + return lsb;
144.2383 + }
144.2384 +
144.2385 +
144.2386 + // Miscellaneous Bit Operations
144.2387 +
144.2388 + /**
144.2389 + * Returns the number of bits in the minimal two's-complement
144.2390 + * representation of this BigInteger, <i>excluding</i> a sign bit.
144.2391 + * For positive BigIntegers, this is equivalent to the number of bits in
144.2392 + * the ordinary binary representation. (Computes
144.2393 + * {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
144.2394 + *
144.2395 + * @return number of bits in the minimal two's-complement
144.2396 + * representation of this BigInteger, <i>excluding</i> a sign bit.
144.2397 + */
144.2398 + public int bitLength() {
144.2399 + @SuppressWarnings("deprecation") int n = bitLength - 1;
144.2400 + if (n == -1) { // bitLength not initialized yet
144.2401 + int[] m = mag;
144.2402 + int len = m.length;
144.2403 + if (len == 0) {
144.2404 + n = 0; // offset by one to initialize
144.2405 + } else {
144.2406 + // Calculate the bit length of the magnitude
144.2407 + int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]);
144.2408 + if (signum < 0) {
144.2409 + // Check if magnitude is a power of two
144.2410 + boolean pow2 = (Integer.bitCount(mag[0]) == 1);
144.2411 + for(int i=1; i< len && pow2; i++)
144.2412 + pow2 = (mag[i] == 0);
144.2413 +
144.2414 + n = (pow2 ? magBitLength -1 : magBitLength);
144.2415 + } else {
144.2416 + n = magBitLength;
144.2417 + }
144.2418 + }
144.2419 + bitLength = n + 1;
144.2420 + }
144.2421 + return n;
144.2422 + }
144.2423 +
144.2424 + /**
144.2425 + * Returns the number of bits in the two's complement representation
144.2426 + * of this BigInteger that differ from its sign bit. This method is
144.2427 + * useful when implementing bit-vector style sets atop BigIntegers.
144.2428 + *
144.2429 + * @return number of bits in the two's complement representation
144.2430 + * of this BigInteger that differ from its sign bit.
144.2431 + */
144.2432 + public int bitCount() {
144.2433 + @SuppressWarnings("deprecation") int bc = bitCount - 1;
144.2434 + if (bc == -1) { // bitCount not initialized yet
144.2435 + bc = 0; // offset by one to initialize
144.2436 + // Count the bits in the magnitude
144.2437 + for (int i=0; i<mag.length; i++)
144.2438 + bc += Integer.bitCount(mag[i]);
144.2439 + if (signum < 0) {
144.2440 + // Count the trailing zeros in the magnitude
144.2441 + int magTrailingZeroCount = 0, j;
144.2442 + for (j=mag.length-1; mag[j]==0; j--)
144.2443 + magTrailingZeroCount += 32;
144.2444 + magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
144.2445 + bc += magTrailingZeroCount - 1;
144.2446 + }
144.2447 + bitCount = bc + 1;
144.2448 + }
144.2449 + return bc;
144.2450 + }
144.2451 +
144.2452 + // Primality Testing
144.2453 +
144.2454 + /**
144.2455 + * Returns {@code true} if this BigInteger is probably prime,
144.2456 + * {@code false} if it's definitely composite. If
144.2457 + * {@code certainty} is ≤ 0, {@code true} is
144.2458 + * returned.
144.2459 + *
144.2460 + * @param certainty a measure of the uncertainty that the caller is
144.2461 + * willing to tolerate: if the call returns {@code true}
144.2462 + * the probability that this BigInteger is prime exceeds
144.2463 + * (1 - 1/2<sup>{@code certainty}</sup>). The execution time of
144.2464 + * this method is proportional to the value of this parameter.
144.2465 + * @return {@code true} if this BigInteger is probably prime,
144.2466 + * {@code false} if it's definitely composite.
144.2467 + */
144.2468 + public boolean isProbablePrime(int certainty) {
144.2469 + if (certainty <= 0)
144.2470 + return true;
144.2471 + BigInteger w = this.abs();
144.2472 + if (w.equals(TWO))
144.2473 + return true;
144.2474 + if (!w.testBit(0) || w.equals(ONE))
144.2475 + return false;
144.2476 +
144.2477 + return w.primeToCertainty(certainty, null);
144.2478 + }
144.2479 +
144.2480 + // Comparison Operations
144.2481 +
144.2482 + /**
144.2483 + * Compares this BigInteger with the specified BigInteger. This
144.2484 + * method is provided in preference to individual methods for each
144.2485 + * of the six boolean comparison operators ({@literal <}, ==,
144.2486 + * {@literal >}, {@literal >=}, !=, {@literal <=}). The suggested
144.2487 + * idiom for performing these comparisons is: {@code
144.2488 + * (x.compareTo(y)} <<i>op</i>> {@code 0)}, where
144.2489 + * <<i>op</i>> is one of the six comparison operators.
144.2490 + *
144.2491 + * @param val BigInteger to which this BigInteger is to be compared.
144.2492 + * @return -1, 0 or 1 as this BigInteger is numerically less than, equal
144.2493 + * to, or greater than {@code val}.
144.2494 + */
144.2495 + public int compareTo(BigInteger val) {
144.2496 + if (signum == val.signum) {
144.2497 + switch (signum) {
144.2498 + case 1:
144.2499 + return compareMagnitude(val);
144.2500 + case -1:
144.2501 + return val.compareMagnitude(this);
144.2502 + default:
144.2503 + return 0;
144.2504 + }
144.2505 + }
144.2506 + return signum > val.signum ? 1 : -1;
144.2507 + }
144.2508 +
144.2509 + /**
144.2510 + * Compares the magnitude array of this BigInteger with the specified
144.2511 + * BigInteger's. This is the version of compareTo ignoring sign.
144.2512 + *
144.2513 + * @param val BigInteger whose magnitude array to be compared.
144.2514 + * @return -1, 0 or 1 as this magnitude array is less than, equal to or
144.2515 + * greater than the magnitude aray for the specified BigInteger's.
144.2516 + */
144.2517 + final int compareMagnitude(BigInteger val) {
144.2518 + int[] m1 = mag;
144.2519 + int len1 = m1.length;
144.2520 + int[] m2 = val.mag;
144.2521 + int len2 = m2.length;
144.2522 + if (len1 < len2)
144.2523 + return -1;
144.2524 + if (len1 > len2)
144.2525 + return 1;
144.2526 + for (int i = 0; i < len1; i++) {
144.2527 + int a = m1[i];
144.2528 + int b = m2[i];
144.2529 + if (a != b)
144.2530 + return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
144.2531 + }
144.2532 + return 0;
144.2533 + }
144.2534 +
144.2535 + /**
144.2536 + * Compares this BigInteger with the specified Object for equality.
144.2537 + *
144.2538 + * @param x Object to which this BigInteger is to be compared.
144.2539 + * @return {@code true} if and only if the specified Object is a
144.2540 + * BigInteger whose value is numerically equal to this BigInteger.
144.2541 + */
144.2542 + public boolean equals(Object x) {
144.2543 + // This test is just an optimization, which may or may not help
144.2544 + if (x == this)
144.2545 + return true;
144.2546 +
144.2547 + if (!(x instanceof BigInteger))
144.2548 + return false;
144.2549 +
144.2550 + BigInteger xInt = (BigInteger) x;
144.2551 + if (xInt.signum != signum)
144.2552 + return false;
144.2553 +
144.2554 + int[] m = mag;
144.2555 + int len = m.length;
144.2556 + int[] xm = xInt.mag;
144.2557 + if (len != xm.length)
144.2558 + return false;
144.2559 +
144.2560 + for (int i = 0; i < len; i++)
144.2561 + if (xm[i] != m[i])
144.2562 + return false;
144.2563 +
144.2564 + return true;
144.2565 + }
144.2566 +
144.2567 + /**
144.2568 + * Returns the minimum of this BigInteger and {@code val}.
144.2569 + *
144.2570 + * @param val value with which the minimum is to be computed.
144.2571 + * @return the BigInteger whose value is the lesser of this BigInteger and
144.2572 + * {@code val}. If they are equal, either may be returned.
144.2573 + */
144.2574 + public BigInteger min(BigInteger val) {
144.2575 + return (compareTo(val)<0 ? this : val);
144.2576 + }
144.2577 +
144.2578 + /**
144.2579 + * Returns the maximum of this BigInteger and {@code val}.
144.2580 + *
144.2581 + * @param val value with which the maximum is to be computed.
144.2582 + * @return the BigInteger whose value is the greater of this and
144.2583 + * {@code val}. If they are equal, either may be returned.
144.2584 + */
144.2585 + public BigInteger max(BigInteger val) {
144.2586 + return (compareTo(val)>0 ? this : val);
144.2587 + }
144.2588 +
144.2589 +
144.2590 + // Hash Function
144.2591 +
144.2592 + /**
144.2593 + * Returns the hash code for this BigInteger.
144.2594 + *
144.2595 + * @return hash code for this BigInteger.
144.2596 + */
144.2597 + public int hashCode() {
144.2598 + int hashCode = 0;
144.2599 +
144.2600 + for (int i=0; i<mag.length; i++)
144.2601 + hashCode = (int)(31*hashCode + (mag[i] & LONG_MASK));
144.2602 +
144.2603 + return hashCode * signum;
144.2604 + }
144.2605 +
144.2606 + /**
144.2607 + * Returns the String representation of this BigInteger in the
144.2608 + * given radix. If the radix is outside the range from {@link
144.2609 + * Character#MIN_RADIX} to {@link Character#MAX_RADIX} inclusive,
144.2610 + * it will default to 10 (as is the case for
144.2611 + * {@code Integer.toString}). The digit-to-character mapping
144.2612 + * provided by {@code Character.forDigit} is used, and a minus
144.2613 + * sign is prepended if appropriate. (This representation is
144.2614 + * compatible with the {@link #BigInteger(String, int) (String,
144.2615 + * int)} constructor.)
144.2616 + *
144.2617 + * @param radix radix of the String representation.
144.2618 + * @return String representation of this BigInteger in the given radix.
144.2619 + * @see Integer#toString
144.2620 + * @see Character#forDigit
144.2621 + * @see #BigInteger(java.lang.String, int)
144.2622 + */
144.2623 + public String toString(int radix) {
144.2624 + if (signum == 0)
144.2625 + return "0";
144.2626 + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
144.2627 + radix = 10;
144.2628 +
144.2629 + // Compute upper bound on number of digit groups and allocate space
144.2630 + int maxNumDigitGroups = (4*mag.length + 6)/7;
144.2631 + String digitGroup[] = new String[maxNumDigitGroups];
144.2632 +
144.2633 + // Translate number to string, a digit group at a time
144.2634 + BigInteger tmp = this.abs();
144.2635 + int numGroups = 0;
144.2636 + while (tmp.signum != 0) {
144.2637 + BigInteger d = longRadix[radix];
144.2638 +
144.2639 + MutableBigInteger q = new MutableBigInteger(),
144.2640 + a = new MutableBigInteger(tmp.mag),
144.2641 + b = new MutableBigInteger(d.mag);
144.2642 + MutableBigInteger r = a.divide(b, q);
144.2643 + BigInteger q2 = q.toBigInteger(tmp.signum * d.signum);
144.2644 + BigInteger r2 = r.toBigInteger(tmp.signum * d.signum);
144.2645 +
144.2646 + digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);
144.2647 + tmp = q2;
144.2648 + }
144.2649 +
144.2650 + // Put sign (if any) and first digit group into result buffer
144.2651 + StringBuilder buf = new StringBuilder(numGroups*digitsPerLong[radix]+1);
144.2652 + if (signum<0)
144.2653 + buf.append('-');
144.2654 + buf.append(digitGroup[numGroups-1]);
144.2655 +
144.2656 + // Append remaining digit groups padded with leading zeros
144.2657 + for (int i=numGroups-2; i>=0; i--) {
144.2658 + // Prepend (any) leading zeros for this digit group
144.2659 + int numLeadingZeros = digitsPerLong[radix]-digitGroup[i].length();
144.2660 + if (numLeadingZeros != 0)
144.2661 + buf.append(zeros[numLeadingZeros]);
144.2662 + buf.append(digitGroup[i]);
144.2663 + }
144.2664 + return buf.toString();
144.2665 + }
144.2666 +
144.2667 + /* zero[i] is a string of i consecutive zeros. */
144.2668 + private static String zeros[] = new String[64];
144.2669 + static {
144.2670 + zeros[63] =
144.2671 + "000000000000000000000000000000000000000000000000000000000000000";
144.2672 + for (int i=0; i<63; i++)
144.2673 + zeros[i] = zeros[63].substring(0, i);
144.2674 + }
144.2675 +
144.2676 + /**
144.2677 + * Returns the decimal String representation of this BigInteger.
144.2678 + * The digit-to-character mapping provided by
144.2679 + * {@code Character.forDigit} is used, and a minus sign is
144.2680 + * prepended if appropriate. (This representation is compatible
144.2681 + * with the {@link #BigInteger(String) (String)} constructor, and
144.2682 + * allows for String concatenation with Java's + operator.)
144.2683 + *
144.2684 + * @return decimal String representation of this BigInteger.
144.2685 + * @see Character#forDigit
144.2686 + * @see #BigInteger(java.lang.String)
144.2687 + */
144.2688 + public String toString() {
144.2689 + return toString(10);
144.2690 + }
144.2691 +
144.2692 + /**
144.2693 + * Returns a byte array containing the two's-complement
144.2694 + * representation of this BigInteger. The byte array will be in
144.2695 + * <i>big-endian</i> byte-order: the most significant byte is in
144.2696 + * the zeroth element. The array will contain the minimum number
144.2697 + * of bytes required to represent this BigInteger, including at
144.2698 + * least one sign bit, which is {@code (ceil((this.bitLength() +
144.2699 + * 1)/8))}. (This representation is compatible with the
144.2700 + * {@link #BigInteger(byte[]) (byte[])} constructor.)
144.2701 + *
144.2702 + * @return a byte array containing the two's-complement representation of
144.2703 + * this BigInteger.
144.2704 + * @see #BigInteger(byte[])
144.2705 + */
144.2706 + public byte[] toByteArray() {
144.2707 + int byteLen = bitLength()/8 + 1;
144.2708 + byte[] byteArray = new byte[byteLen];
144.2709 +
144.2710 + for (int i=byteLen-1, bytesCopied=4, nextInt=0, intIndex=0; i>=0; i--) {
144.2711 + if (bytesCopied == 4) {
144.2712 + nextInt = getInt(intIndex++);
144.2713 + bytesCopied = 1;
144.2714 + } else {
144.2715 + nextInt >>>= 8;
144.2716 + bytesCopied++;
144.2717 + }
144.2718 + byteArray[i] = (byte)nextInt;
144.2719 + }
144.2720 + return byteArray;
144.2721 + }
144.2722 +
144.2723 + /**
144.2724 + * Converts this BigInteger to an {@code int}. This
144.2725 + * conversion is analogous to a
144.2726 + * <i>narrowing primitive conversion</i> from {@code long} to
144.2727 + * {@code int} as defined in section 5.1.3 of
144.2728 + * <cite>The Java™ Language Specification</cite>:
144.2729 + * if this BigInteger is too big to fit in an
144.2730 + * {@code int}, only the low-order 32 bits are returned.
144.2731 + * Note that this conversion can lose information about the
144.2732 + * overall magnitude of the BigInteger value as well as return a
144.2733 + * result with the opposite sign.
144.2734 + *
144.2735 + * @return this BigInteger converted to an {@code int}.
144.2736 + */
144.2737 + public int intValue() {
144.2738 + int result = 0;
144.2739 + result = getInt(0);
144.2740 + return result;
144.2741 + }
144.2742 +
144.2743 + /**
144.2744 + * Converts this BigInteger to a {@code long}. This
144.2745 + * conversion is analogous to a
144.2746 + * <i>narrowing primitive conversion</i> from {@code long} to
144.2747 + * {@code int} as defined in section 5.1.3 of
144.2748 + * <cite>The Java™ Language Specification</cite>:
144.2749 + * if this BigInteger is too big to fit in a
144.2750 + * {@code long}, only the low-order 64 bits are returned.
144.2751 + * Note that this conversion can lose information about the
144.2752 + * overall magnitude of the BigInteger value as well as return a
144.2753 + * result with the opposite sign.
144.2754 + *
144.2755 + * @return this BigInteger converted to a {@code long}.
144.2756 + */
144.2757 + public long longValue() {
144.2758 + long result = 0;
144.2759 +
144.2760 + for (int i=1; i>=0; i--)
144.2761 + result = (result << 32) + (getInt(i) & LONG_MASK);
144.2762 + return result;
144.2763 + }
144.2764 +
144.2765 + /**
144.2766 + * Converts this BigInteger to a {@code float}. This
144.2767 + * conversion is similar to the
144.2768 + * <i>narrowing primitive conversion</i> from {@code double} to
144.2769 + * {@code float} as defined in section 5.1.3 of
144.2770 + * <cite>The Java™ Language Specification</cite>:
144.2771 + * if this BigInteger has too great a magnitude
144.2772 + * to represent as a {@code float}, it will be converted to
144.2773 + * {@link Float#NEGATIVE_INFINITY} or {@link
144.2774 + * Float#POSITIVE_INFINITY} as appropriate. Note that even when
144.2775 + * the return value is finite, this conversion can lose
144.2776 + * information about the precision of the BigInteger value.
144.2777 + *
144.2778 + * @return this BigInteger converted to a {@code float}.
144.2779 + */
144.2780 + public float floatValue() {
144.2781 + // Somewhat inefficient, but guaranteed to work.
144.2782 + return Float.parseFloat(this.toString());
144.2783 + }
144.2784 +
144.2785 + /**
144.2786 + * Converts this BigInteger to a {@code double}. This
144.2787 + * conversion is similar to the
144.2788 + * <i>narrowing primitive conversion</i> from {@code double} to
144.2789 + * {@code float} as defined in section 5.1.3 of
144.2790 + * <cite>The Java™ Language Specification</cite>:
144.2791 + * if this BigInteger has too great a magnitude
144.2792 + * to represent as a {@code double}, it will be converted to
144.2793 + * {@link Double#NEGATIVE_INFINITY} or {@link
144.2794 + * Double#POSITIVE_INFINITY} as appropriate. Note that even when
144.2795 + * the return value is finite, this conversion can lose
144.2796 + * information about the precision of the BigInteger value.
144.2797 + *
144.2798 + * @return this BigInteger converted to a {@code double}.
144.2799 + */
144.2800 + public double doubleValue() {
144.2801 + // Somewhat inefficient, but guaranteed to work.
144.2802 + return Double.parseDouble(this.toString());
144.2803 + }
144.2804 +
144.2805 + /**
144.2806 + * Returns a copy of the input array stripped of any leading zero bytes.
144.2807 + */
144.2808 + private static int[] stripLeadingZeroInts(int val[]) {
144.2809 + int vlen = val.length;
144.2810 + int keep;
144.2811 +
144.2812 + // Find first nonzero byte
144.2813 + for (keep = 0; keep < vlen && val[keep] == 0; keep++)
144.2814 + ;
144.2815 + return java.util.Arrays.copyOfRange(val, keep, vlen);
144.2816 + }
144.2817 +
144.2818 + /**
144.2819 + * Returns the input array stripped of any leading zero bytes.
144.2820 + * Since the source is trusted the copying may be skipped.
144.2821 + */
144.2822 + private static int[] trustedStripLeadingZeroInts(int val[]) {
144.2823 + int vlen = val.length;
144.2824 + int keep;
144.2825 +
144.2826 + // Find first nonzero byte
144.2827 + for (keep = 0; keep < vlen && val[keep] == 0; keep++)
144.2828 + ;
144.2829 + return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen);
144.2830 + }
144.2831 +
144.2832 + /**
144.2833 + * Returns a copy of the input array stripped of any leading zero bytes.
144.2834 + */
144.2835 + private static int[] stripLeadingZeroBytes(byte a[]) {
144.2836 + int byteLength = a.length;
144.2837 + int keep;
144.2838 +
144.2839 + // Find first nonzero byte
144.2840 + for (keep = 0; keep < byteLength && a[keep]==0; keep++)
144.2841 + ;
144.2842 +
144.2843 + // Allocate new array and copy relevant part of input array
144.2844 + int intLength = ((byteLength - keep) + 3) >>> 2;
144.2845 + int[] result = new int[intLength];
144.2846 + int b = byteLength - 1;
144.2847 + for (int i = intLength-1; i >= 0; i--) {
144.2848 + result[i] = a[b--] & 0xff;
144.2849 + int bytesRemaining = b - keep + 1;
144.2850 + int bytesToTransfer = Math.min(3, bytesRemaining);
144.2851 + for (int j=8; j <= (bytesToTransfer << 3); j += 8)
144.2852 + result[i] |= ((a[b--] & 0xff) << j);
144.2853 + }
144.2854 + return result;
144.2855 + }
144.2856 +
144.2857 + /**
144.2858 + * Takes an array a representing a negative 2's-complement number and
144.2859 + * returns the minimal (no leading zero bytes) unsigned whose value is -a.
144.2860 + */
144.2861 + private static int[] makePositive(byte a[]) {
144.2862 + int keep, k;
144.2863 + int byteLength = a.length;
144.2864 +
144.2865 + // Find first non-sign (0xff) byte of input
144.2866 + for (keep=0; keep<byteLength && a[keep]==-1; keep++)
144.2867 + ;
144.2868 +
144.2869 +
144.2870 + /* Allocate output array. If all non-sign bytes are 0x00, we must
144.2871 + * allocate space for one extra output byte. */
144.2872 + for (k=keep; k<byteLength && a[k]==0; k++)
144.2873 + ;
144.2874 +
144.2875 + int extraByte = (k==byteLength) ? 1 : 0;
144.2876 + int intLength = ((byteLength - keep + extraByte) + 3)/4;
144.2877 + int result[] = new int[intLength];
144.2878 +
144.2879 + /* Copy one's complement of input into output, leaving extra
144.2880 + * byte (if it exists) == 0x00 */
144.2881 + int b = byteLength - 1;
144.2882 + for (int i = intLength-1; i >= 0; i--) {
144.2883 + result[i] = a[b--] & 0xff;
144.2884 + int numBytesToTransfer = Math.min(3, b-keep+1);
144.2885 + if (numBytesToTransfer < 0)
144.2886 + numBytesToTransfer = 0;
144.2887 + for (int j=8; j <= 8*numBytesToTransfer; j += 8)
144.2888 + result[i] |= ((a[b--] & 0xff) << j);
144.2889 +
144.2890 + // Mask indicates which bits must be complemented
144.2891 + int mask = -1 >>> (8*(3-numBytesToTransfer));
144.2892 + result[i] = ~result[i] & mask;
144.2893 + }
144.2894 +
144.2895 + // Add one to one's complement to generate two's complement
144.2896 + for (int i=result.length-1; i>=0; i--) {
144.2897 + result[i] = (int)((result[i] & LONG_MASK) + 1);
144.2898 + if (result[i] != 0)
144.2899 + break;
144.2900 + }
144.2901 +
144.2902 + return result;
144.2903 + }
144.2904 +
144.2905 + /**
144.2906 + * Takes an array a representing a negative 2's-complement number and
144.2907 + * returns the minimal (no leading zero ints) unsigned whose value is -a.
144.2908 + */
144.2909 + private static int[] makePositive(int a[]) {
144.2910 + int keep, j;
144.2911 +
144.2912 + // Find first non-sign (0xffffffff) int of input
144.2913 + for (keep=0; keep<a.length && a[keep]==-1; keep++)
144.2914 + ;
144.2915 +
144.2916 + /* Allocate output array. If all non-sign ints are 0x00, we must
144.2917 + * allocate space for one extra output int. */
144.2918 + for (j=keep; j<a.length && a[j]==0; j++)
144.2919 + ;
144.2920 + int extraInt = (j==a.length ? 1 : 0);
144.2921 + int result[] = new int[a.length - keep + extraInt];
144.2922 +
144.2923 + /* Copy one's complement of input into output, leaving extra
144.2924 + * int (if it exists) == 0x00 */
144.2925 + for (int i = keep; i<a.length; i++)
144.2926 + result[i - keep + extraInt] = ~a[i];
144.2927 +
144.2928 + // Add one to one's complement to generate two's complement
144.2929 + for (int i=result.length-1; ++result[i]==0; i--)
144.2930 + ;
144.2931 +
144.2932 + return result;
144.2933 + }
144.2934 +
144.2935 + /*
144.2936 + * The following two arrays are used for fast String conversions. Both
144.2937 + * are indexed by radix. The first is the number of digits of the given
144.2938 + * radix that can fit in a Java long without "going negative", i.e., the
144.2939 + * highest integer n such that radix**n < 2**63. The second is the
144.2940 + * "long radix" that tears each number into "long digits", each of which
144.2941 + * consists of the number of digits in the corresponding element in
144.2942 + * digitsPerLong (longRadix[i] = i**digitPerLong[i]). Both arrays have
144.2943 + * nonsense values in their 0 and 1 elements, as radixes 0 and 1 are not
144.2944 + * used.
144.2945 + */
144.2946 + private static int digitsPerLong[] = {0, 0,
144.2947 + 62, 39, 31, 27, 24, 22, 20, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14,
144.2948 + 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12};
144.2949 +
144.2950 + private static BigInteger longRadix[] = {null, null,
144.2951 + valueOf(0x4000000000000000L), valueOf(0x383d9170b85ff80bL),
144.2952 + valueOf(0x4000000000000000L), valueOf(0x6765c793fa10079dL),
144.2953 + valueOf(0x41c21cb8e1000000L), valueOf(0x3642798750226111L),
144.2954 + valueOf(0x1000000000000000L), valueOf(0x12bf307ae81ffd59L),
144.2955 + valueOf( 0xde0b6b3a7640000L), valueOf(0x4d28cb56c33fa539L),
144.2956 + valueOf(0x1eca170c00000000L), valueOf(0x780c7372621bd74dL),
144.2957 + valueOf(0x1e39a5057d810000L), valueOf(0x5b27ac993df97701L),
144.2958 + valueOf(0x1000000000000000L), valueOf(0x27b95e997e21d9f1L),
144.2959 + valueOf(0x5da0e1e53c5c8000L), valueOf( 0xb16a458ef403f19L),
144.2960 + valueOf(0x16bcc41e90000000L), valueOf(0x2d04b7fdd9c0ef49L),
144.2961 + valueOf(0x5658597bcaa24000L), valueOf( 0x6feb266931a75b7L),
144.2962 + valueOf( 0xc29e98000000000L), valueOf(0x14adf4b7320334b9L),
144.2963 + valueOf(0x226ed36478bfa000L), valueOf(0x383d9170b85ff80bL),
144.2964 + valueOf(0x5a3c23e39c000000L), valueOf( 0x4e900abb53e6b71L),
144.2965 + valueOf( 0x7600ec618141000L), valueOf( 0xaee5720ee830681L),
144.2966 + valueOf(0x1000000000000000L), valueOf(0x172588ad4f5f0981L),
144.2967 + valueOf(0x211e44f7d02c1000L), valueOf(0x2ee56725f06e5c71L),
144.2968 + valueOf(0x41c21cb8e1000000L)};
144.2969 +
144.2970 + /*
144.2971 + * These two arrays are the integer analogue of above.
144.2972 + */
144.2973 + private static int digitsPerInt[] = {0, 0, 30, 19, 15, 13, 11,
144.2974 + 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
144.2975 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5};
144.2976 +
144.2977 + private static int intRadix[] = {0, 0,
144.2978 + 0x40000000, 0x4546b3db, 0x40000000, 0x48c27395, 0x159fd800,
144.2979 + 0x75db9c97, 0x40000000, 0x17179149, 0x3b9aca00, 0xcc6db61,
144.2980 + 0x19a10000, 0x309f1021, 0x57f6c100, 0xa2f1b6f, 0x10000000,
144.2981 + 0x18754571, 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
144.2982 + 0x6c20a40, 0x8d2d931, 0xb640000, 0xe8d4a51, 0x1269ae40,
144.2983 + 0x17179149, 0x1cb91000, 0x23744899, 0x2b73a840, 0x34e63b41,
144.2984 + 0x40000000, 0x4cfa3cc1, 0x5c13d840, 0x6d91b519, 0x39aa400
144.2985 + };
144.2986 +
144.2987 + /**
144.2988 + * These routines provide access to the two's complement representation
144.2989 + * of BigIntegers.
144.2990 + */
144.2991 +
144.2992 + /**
144.2993 + * Returns the length of the two's complement representation in ints,
144.2994 + * including space for at least one sign bit.
144.2995 + */
144.2996 + private int intLength() {
144.2997 + return (bitLength() >>> 5) + 1;
144.2998 + }
144.2999 +
144.3000 + /* Returns sign bit */
144.3001 + private int signBit() {
144.3002 + return signum < 0 ? 1 : 0;
144.3003 + }
144.3004 +
144.3005 + /* Returns an int of sign bits */
144.3006 + private int signInt() {
144.3007 + return signum < 0 ? -1 : 0;
144.3008 + }
144.3009 +
144.3010 + /**
144.3011 + * Returns the specified int of the little-endian two's complement
144.3012 + * representation (int 0 is the least significant). The int number can
144.3013 + * be arbitrarily high (values are logically preceded by infinitely many
144.3014 + * sign ints).
144.3015 + */
144.3016 + private int getInt(int n) {
144.3017 + if (n < 0)
144.3018 + return 0;
144.3019 + if (n >= mag.length)
144.3020 + return signInt();
144.3021 +
144.3022 + int magInt = mag[mag.length-n-1];
144.3023 +
144.3024 + return (signum >= 0 ? magInt :
144.3025 + (n <= firstNonzeroIntNum() ? -magInt : ~magInt));
144.3026 + }
144.3027 +
144.3028 + /**
144.3029 + * Returns the index of the int that contains the first nonzero int in the
144.3030 + * little-endian binary representation of the magnitude (int 0 is the
144.3031 + * least significant). If the magnitude is zero, return value is undefined.
144.3032 + */
144.3033 + private int firstNonzeroIntNum() {
144.3034 + int fn = firstNonzeroIntNum - 2;
144.3035 + if (fn == -2) { // firstNonzeroIntNum not initialized yet
144.3036 + fn = 0;
144.3037 +
144.3038 + // Search for the first nonzero int
144.3039 + int i;
144.3040 + int mlen = mag.length;
144.3041 + for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
144.3042 + ;
144.3043 + fn = mlen - i - 1;
144.3044 + firstNonzeroIntNum = fn + 2; // offset by two to initialize
144.3045 + }
144.3046 + return fn;
144.3047 + }
144.3048 +
144.3049 + /** use serialVersionUID from JDK 1.1. for interoperability */
144.3050 + private static final long serialVersionUID = -8287574255936472291L;
144.3051 +
144.3052 + /**
144.3053 + * Serializable fields for BigInteger.
144.3054 + *
144.3055 + * @serialField signum int
144.3056 + * signum of this BigInteger.
144.3057 + * @serialField magnitude int[]
144.3058 + * magnitude array of this BigInteger.
144.3059 + * @serialField bitCount int
144.3060 + * number of bits in this BigInteger
144.3061 + * @serialField bitLength int
144.3062 + * the number of bits in the minimal two's-complement
144.3063 + * representation of this BigInteger
144.3064 + * @serialField lowestSetBit int
144.3065 + * lowest set bit in the twos complement representation
144.3066 + */
144.3067 + private static final ObjectStreamField[] serialPersistentFields = {
144.3068 + new ObjectStreamField("signum", Integer.TYPE),
144.3069 + new ObjectStreamField("magnitude", byte[].class),
144.3070 + new ObjectStreamField("bitCount", Integer.TYPE),
144.3071 + new ObjectStreamField("bitLength", Integer.TYPE),
144.3072 + new ObjectStreamField("firstNonzeroByteNum", Integer.TYPE),
144.3073 + new ObjectStreamField("lowestSetBit", Integer.TYPE)
144.3074 + };
144.3075 +
144.3076 +
144.3077 +
144.3078 + /**
144.3079 + * Save the {@code BigInteger} instance to a stream.
144.3080 + * The magnitude of a BigInteger is serialized as a byte array for
144.3081 + * historical reasons.
144.3082 + *
144.3083 + * @serialData two necessary fields are written as well as obsolete
144.3084 + * fields for compatibility with older versions.
144.3085 + */
144.3086 + private void writeObject(ObjectOutputStream s) throws IOException {
144.3087 + // set the values of the Serializable fields
144.3088 + ObjectOutputStream.PutField fields = s.putFields();
144.3089 + fields.put("signum", signum);
144.3090 + fields.put("magnitude", magSerializedForm());
144.3091 + // The values written for cached fields are compatible with older
144.3092 + // versions, but are ignored in readObject so don't otherwise matter.
144.3093 + fields.put("bitCount", -1);
144.3094 + fields.put("bitLength", -1);
144.3095 + fields.put("lowestSetBit", -2);
144.3096 + fields.put("firstNonzeroByteNum", -2);
144.3097 +
144.3098 + // save them
144.3099 + s.writeFields();
144.3100 +}
144.3101 +
144.3102 + /**
144.3103 + * Returns the mag array as an array of bytes.
144.3104 + */
144.3105 + private byte[] magSerializedForm() {
144.3106 + int len = mag.length;
144.3107 +
144.3108 + int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0]));
144.3109 + int byteLen = (bitLen + 7) >>> 3;
144.3110 + byte[] result = new byte[byteLen];
144.3111 +
144.3112 + for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0;
144.3113 + i>=0; i--) {
144.3114 + if (bytesCopied == 4) {
144.3115 + nextInt = mag[intIndex--];
144.3116 + bytesCopied = 1;
144.3117 + } else {
144.3118 + nextInt >>>= 8;
144.3119 + bytesCopied++;
144.3120 + }
144.3121 + result[i] = (byte)nextInt;
144.3122 + }
144.3123 + return result;
144.3124 + }
144.3125 +}
145.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
145.2 +++ b/rt/emul/compact/src/main/java/java/math/BitSieve.java Mon Oct 07 14:20:58 2013 +0200
145.3 @@ -0,0 +1,212 @@
145.4 +/*
145.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
145.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
145.7 + *
145.8 + * This code is free software; you can redistribute it and/or modify it
145.9 + * under the terms of the GNU General Public License version 2 only, as
145.10 + * published by the Free Software Foundation. Oracle designates this
145.11 + * particular file as subject to the "Classpath" exception as provided
145.12 + * by Oracle in the LICENSE file that accompanied this code.
145.13 + *
145.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
145.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
145.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
145.17 + * version 2 for more details (a copy is included in the LICENSE file that
145.18 + * accompanied this code).
145.19 + *
145.20 + * You should have received a copy of the GNU General Public License version
145.21 + * 2 along with this work; if not, write to the Free Software Foundation,
145.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
145.23 + *
145.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
145.25 + * or visit www.oracle.com if you need additional information or have any
145.26 + * questions.
145.27 + */
145.28 +
145.29 +package java.math;
145.30 +
145.31 +/**
145.32 + * A simple bit sieve used for finding prime number candidates. Allows setting
145.33 + * and clearing of bits in a storage array. The size of the sieve is assumed to
145.34 + * be constant to reduce overhead. All the bits of a new bitSieve are zero, and
145.35 + * bits are removed from it by setting them.
145.36 + *
145.37 + * To reduce storage space and increase efficiency, no even numbers are
145.38 + * represented in the sieve (each bit in the sieve represents an odd number).
145.39 + * The relationship between the index of a bit and the number it represents is
145.40 + * given by
145.41 + * N = offset + (2*index + 1);
145.42 + * Where N is the integer represented by a bit in the sieve, offset is some
145.43 + * even integer offset indicating where the sieve begins, and index is the
145.44 + * index of a bit in the sieve array.
145.45 + *
145.46 + * @see BigInteger
145.47 + * @author Michael McCloskey
145.48 + * @since 1.3
145.49 + */
145.50 +class BitSieve {
145.51 + /**
145.52 + * Stores the bits in this bitSieve.
145.53 + */
145.54 + private long bits[];
145.55 +
145.56 + /**
145.57 + * Length is how many bits this sieve holds.
145.58 + */
145.59 + private int length;
145.60 +
145.61 + /**
145.62 + * A small sieve used to filter out multiples of small primes in a search
145.63 + * sieve.
145.64 + */
145.65 + private static BitSieve smallSieve = new BitSieve();
145.66 +
145.67 + /**
145.68 + * Construct a "small sieve" with a base of 0. This constructor is
145.69 + * used internally to generate the set of "small primes" whose multiples
145.70 + * are excluded from sieves generated by the main (package private)
145.71 + * constructor, BitSieve(BigInteger base, int searchLen). The length
145.72 + * of the sieve generated by this constructor was chosen for performance;
145.73 + * it controls a tradeoff between how much time is spent constructing
145.74 + * other sieves, and how much time is wasted testing composite candidates
145.75 + * for primality. The length was chosen experimentally to yield good
145.76 + * performance.
145.77 + */
145.78 + private BitSieve() {
145.79 + length = 150 * 64;
145.80 + bits = new long[(unitIndex(length - 1) + 1)];
145.81 +
145.82 + // Mark 1 as composite
145.83 + set(0);
145.84 + int nextIndex = 1;
145.85 + int nextPrime = 3;
145.86 +
145.87 + // Find primes and remove their multiples from sieve
145.88 + do {
145.89 + sieveSingle(length, nextIndex + nextPrime, nextPrime);
145.90 + nextIndex = sieveSearch(length, nextIndex + 1);
145.91 + nextPrime = 2*nextIndex + 1;
145.92 + } while((nextIndex > 0) && (nextPrime < length));
145.93 + }
145.94 +
145.95 + /**
145.96 + * Construct a bit sieve of searchLen bits used for finding prime number
145.97 + * candidates. The new sieve begins at the specified base, which must
145.98 + * be even.
145.99 + */
145.100 + BitSieve(BigInteger base, int searchLen) {
145.101 + /*
145.102 + * Candidates are indicated by clear bits in the sieve. As a candidates
145.103 + * nonprimality is calculated, a bit is set in the sieve to eliminate
145.104 + * it. To reduce storage space and increase efficiency, no even numbers
145.105 + * are represented in the sieve (each bit in the sieve represents an
145.106 + * odd number).
145.107 + */
145.108 + bits = new long[(unitIndex(searchLen-1) + 1)];
145.109 + length = searchLen;
145.110 + int start = 0;
145.111 +
145.112 + int step = smallSieve.sieveSearch(smallSieve.length, start);
145.113 + int convertedStep = (step *2) + 1;
145.114 +
145.115 + // Construct the large sieve at an even offset specified by base
145.116 + MutableBigInteger b = new MutableBigInteger(base);
145.117 + MutableBigInteger q = new MutableBigInteger();
145.118 + do {
145.119 + // Calculate base mod convertedStep
145.120 + start = b.divideOneWord(convertedStep, q);
145.121 +
145.122 + // Take each multiple of step out of sieve
145.123 + start = convertedStep - start;
145.124 + if (start%2 == 0)
145.125 + start += convertedStep;
145.126 + sieveSingle(searchLen, (start-1)/2, convertedStep);
145.127 +
145.128 + // Find next prime from small sieve
145.129 + step = smallSieve.sieveSearch(smallSieve.length, step+1);
145.130 + convertedStep = (step *2) + 1;
145.131 + } while (step > 0);
145.132 + }
145.133 +
145.134 + /**
145.135 + * Given a bit index return unit index containing it.
145.136 + */
145.137 + private static int unitIndex(int bitIndex) {
145.138 + return bitIndex >>> 6;
145.139 + }
145.140 +
145.141 + /**
145.142 + * Return a unit that masks the specified bit in its unit.
145.143 + */
145.144 + private static long bit(int bitIndex) {
145.145 + return 1L << (bitIndex & ((1<<6) - 1));
145.146 + }
145.147 +
145.148 + /**
145.149 + * Get the value of the bit at the specified index.
145.150 + */
145.151 + private boolean get(int bitIndex) {
145.152 + int unitIndex = unitIndex(bitIndex);
145.153 + return ((bits[unitIndex] & bit(bitIndex)) != 0);
145.154 + }
145.155 +
145.156 + /**
145.157 + * Set the bit at the specified index.
145.158 + */
145.159 + private void set(int bitIndex) {
145.160 + int unitIndex = unitIndex(bitIndex);
145.161 + bits[unitIndex] |= bit(bitIndex);
145.162 + }
145.163 +
145.164 + /**
145.165 + * This method returns the index of the first clear bit in the search
145.166 + * array that occurs at or after start. It will not search past the
145.167 + * specified limit. It returns -1 if there is no such clear bit.
145.168 + */
145.169 + private int sieveSearch(int limit, int start) {
145.170 + if (start >= limit)
145.171 + return -1;
145.172 +
145.173 + int index = start;
145.174 + do {
145.175 + if (!get(index))
145.176 + return index;
145.177 + index++;
145.178 + } while(index < limit-1);
145.179 + return -1;
145.180 + }
145.181 +
145.182 + /**
145.183 + * Sieve a single set of multiples out of the sieve. Begin to remove
145.184 + * multiples of the specified step starting at the specified start index,
145.185 + * up to the specified limit.
145.186 + */
145.187 + private void sieveSingle(int limit, int start, int step) {
145.188 + while(start < limit) {
145.189 + set(start);
145.190 + start += step;
145.191 + }
145.192 + }
145.193 +
145.194 + /**
145.195 + * Test probable primes in the sieve and return successful candidates.
145.196 + */
145.197 + BigInteger retrieve(BigInteger initValue, int certainty, java.util.Random random) {
145.198 + // Examine the sieve one long at a time to find possible primes
145.199 + int offset = 1;
145.200 + for (int i=0; i<bits.length; i++) {
145.201 + long nextLong = ~bits[i];
145.202 + for (int j=0; j<64; j++) {
145.203 + if ((nextLong & 1) == 1) {
145.204 + BigInteger candidate = initValue.add(
145.205 + BigInteger.valueOf(offset));
145.206 + if (candidate.primeToCertainty(certainty, random))
145.207 + return candidate;
145.208 + }
145.209 + nextLong >>>= 1;
145.210 + offset+=2;
145.211 + }
145.212 + }
145.213 + return null;
145.214 + }
145.215 +}
146.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
146.2 +++ b/rt/emul/compact/src/main/java/java/math/MathContext.java Mon Oct 07 14:20:58 2013 +0200
146.3 @@ -0,0 +1,326 @@
146.4 +/*
146.5 + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
146.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
146.7 + *
146.8 + * This code is free software; you can redistribute it and/or modify it
146.9 + * under the terms of the GNU General Public License version 2 only, as
146.10 + * published by the Free Software Foundation. Oracle designates this
146.11 + * particular file as subject to the "Classpath" exception as provided
146.12 + * by Oracle in the LICENSE file that accompanied this code.
146.13 + *
146.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
146.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
146.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
146.17 + * version 2 for more details (a copy is included in the LICENSE file that
146.18 + * accompanied this code).
146.19 + *
146.20 + * You should have received a copy of the GNU General Public License version
146.21 + * 2 along with this work; if not, write to the Free Software Foundation,
146.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
146.23 + *
146.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
146.25 + * or visit www.oracle.com if you need additional information or have any
146.26 + * questions.
146.27 + */
146.28 +
146.29 +/*
146.30 + * Portions Copyright IBM Corporation, 1997, 2001. All Rights Reserved.
146.31 + */
146.32 +
146.33 +package java.math;
146.34 +import java.io.*;
146.35 +
146.36 +/**
146.37 + * Immutable objects which encapsulate the context settings which
146.38 + * describe certain rules for numerical operators, such as those
146.39 + * implemented by the {@link BigDecimal} class.
146.40 + *
146.41 + * <p>The base-independent settings are:
146.42 + * <ol>
146.43 + * <li>{@code precision}:
146.44 + * the number of digits to be used for an operation; results are
146.45 + * rounded to this precision
146.46 + *
146.47 + * <li>{@code roundingMode}:
146.48 + * a {@link RoundingMode} object which specifies the algorithm to be
146.49 + * used for rounding.
146.50 + * </ol>
146.51 + *
146.52 + * @see BigDecimal
146.53 + * @see RoundingMode
146.54 + * @author Mike Cowlishaw
146.55 + * @author Joseph D. Darcy
146.56 + * @since 1.5
146.57 + */
146.58 +
146.59 +public final class MathContext implements Serializable {
146.60 +
146.61 + /* ----- Constants ----- */
146.62 +
146.63 + // defaults for constructors
146.64 + private static final int DEFAULT_DIGITS = 9;
146.65 + private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP;
146.66 + // Smallest values for digits (Maximum is Integer.MAX_VALUE)
146.67 + private static final int MIN_DIGITS = 0;
146.68 +
146.69 + // Serialization version
146.70 + private static final long serialVersionUID = 5579720004786848255L;
146.71 +
146.72 + /* ----- Public Properties ----- */
146.73 + /**
146.74 + * A {@code MathContext} object whose settings have the values
146.75 + * required for unlimited precision arithmetic.
146.76 + * The values of the settings are:
146.77 + * <code>
146.78 + * precision=0 roundingMode=HALF_UP
146.79 + * </code>
146.80 + */
146.81 + public static final MathContext UNLIMITED =
146.82 + new MathContext(0, RoundingMode.HALF_UP);
146.83 +
146.84 + /**
146.85 + * A {@code MathContext} object with a precision setting
146.86 + * matching the IEEE 754R Decimal32 format, 7 digits, and a
146.87 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
146.88 + * IEEE 754R default.
146.89 + */
146.90 + public static final MathContext DECIMAL32 =
146.91 + new MathContext(7, RoundingMode.HALF_EVEN);
146.92 +
146.93 + /**
146.94 + * A {@code MathContext} object with a precision setting
146.95 + * matching the IEEE 754R Decimal64 format, 16 digits, and a
146.96 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
146.97 + * IEEE 754R default.
146.98 + */
146.99 + public static final MathContext DECIMAL64 =
146.100 + new MathContext(16, RoundingMode.HALF_EVEN);
146.101 +
146.102 + /**
146.103 + * A {@code MathContext} object with a precision setting
146.104 + * matching the IEEE 754R Decimal128 format, 34 digits, and a
146.105 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
146.106 + * IEEE 754R default.
146.107 + */
146.108 + public static final MathContext DECIMAL128 =
146.109 + new MathContext(34, RoundingMode.HALF_EVEN);
146.110 +
146.111 + /* ----- Shared Properties ----- */
146.112 + /**
146.113 + * The number of digits to be used for an operation. A value of 0
146.114 + * indicates that unlimited precision (as many digits as are
146.115 + * required) will be used. Note that leading zeros (in the
146.116 + * coefficient of a number) are never significant.
146.117 + *
146.118 + * <p>{@code precision} will always be non-negative.
146.119 + *
146.120 + * @serial
146.121 + */
146.122 + final int precision;
146.123 +
146.124 + /**
146.125 + * The rounding algorithm to be used for an operation.
146.126 + *
146.127 + * @see RoundingMode
146.128 + * @serial
146.129 + */
146.130 + final RoundingMode roundingMode;
146.131 +
146.132 + /* ----- Constructors ----- */
146.133 +
146.134 + /**
146.135 + * Constructs a new {@code MathContext} with the specified
146.136 + * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding
146.137 + * mode.
146.138 + *
146.139 + * @param setPrecision The non-negative {@code int} precision setting.
146.140 + * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
146.141 + * than zero.
146.142 + */
146.143 + public MathContext(int setPrecision) {
146.144 + this(setPrecision, DEFAULT_ROUNDINGMODE);
146.145 + return;
146.146 + }
146.147 +
146.148 + /**
146.149 + * Constructs a new {@code MathContext} with a specified
146.150 + * precision and rounding mode.
146.151 + *
146.152 + * @param setPrecision The non-negative {@code int} precision setting.
146.153 + * @param setRoundingMode The rounding mode to use.
146.154 + * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
146.155 + * than zero.
146.156 + * @throws NullPointerException if the rounding mode argument is {@code null}
146.157 + */
146.158 + public MathContext(int setPrecision,
146.159 + RoundingMode setRoundingMode) {
146.160 + if (setPrecision < MIN_DIGITS)
146.161 + throw new IllegalArgumentException("Digits < 0");
146.162 + if (setRoundingMode == null)
146.163 + throw new NullPointerException("null RoundingMode");
146.164 +
146.165 + precision = setPrecision;
146.166 + roundingMode = setRoundingMode;
146.167 + return;
146.168 + }
146.169 +
146.170 + /**
146.171 + * Constructs a new {@code MathContext} from a string.
146.172 + *
146.173 + * The string must be in the same format as that produced by the
146.174 + * {@link #toString} method.
146.175 + *
146.176 + * <p>An {@code IllegalArgumentException} is thrown if the precision
146.177 + * section of the string is out of range ({@code < 0}) or the string is
146.178 + * not in the format created by the {@link #toString} method.
146.179 + *
146.180 + * @param val The string to be parsed
146.181 + * @throws IllegalArgumentException if the precision section is out of range
146.182 + * or of incorrect format
146.183 + * @throws NullPointerException if the argument is {@code null}
146.184 + */
146.185 + public MathContext(String val) {
146.186 + boolean bad = false;
146.187 + int setPrecision;
146.188 + if (val == null)
146.189 + throw new NullPointerException("null String");
146.190 + try { // any error here is a string format problem
146.191 + if (!val.startsWith("precision=")) throw new RuntimeException();
146.192 + int fence = val.indexOf(' '); // could be -1
146.193 + int off = 10; // where value starts
146.194 + setPrecision = Integer.parseInt(val.substring(10, fence));
146.195 +
146.196 + if (!val.startsWith("roundingMode=", fence+1))
146.197 + throw new RuntimeException();
146.198 + off = fence + 1 + 13;
146.199 + String str = val.substring(off, val.length());
146.200 + roundingMode = RoundingMode.valueOf(str);
146.201 + } catch (RuntimeException re) {
146.202 + throw new IllegalArgumentException("bad string format");
146.203 + }
146.204 +
146.205 + if (setPrecision < MIN_DIGITS)
146.206 + throw new IllegalArgumentException("Digits < 0");
146.207 + // the other parameters cannot be invalid if we got here
146.208 + precision = setPrecision;
146.209 + }
146.210 +
146.211 + /**
146.212 + * Returns the {@code precision} setting.
146.213 + * This value is always non-negative.
146.214 + *
146.215 + * @return an {@code int} which is the value of the {@code precision}
146.216 + * setting
146.217 + */
146.218 + public int getPrecision() {
146.219 + return precision;
146.220 + }
146.221 +
146.222 + /**
146.223 + * Returns the roundingMode setting.
146.224 + * This will be one of
146.225 + * {@link RoundingMode#CEILING},
146.226 + * {@link RoundingMode#DOWN},
146.227 + * {@link RoundingMode#FLOOR},
146.228 + * {@link RoundingMode#HALF_DOWN},
146.229 + * {@link RoundingMode#HALF_EVEN},
146.230 + * {@link RoundingMode#HALF_UP},
146.231 + * {@link RoundingMode#UNNECESSARY}, or
146.232 + * {@link RoundingMode#UP}.
146.233 + *
146.234 + * @return a {@code RoundingMode} object which is the value of the
146.235 + * {@code roundingMode} setting
146.236 + */
146.237 +
146.238 + public RoundingMode getRoundingMode() {
146.239 + return roundingMode;
146.240 + }
146.241 +
146.242 + /**
146.243 + * Compares this {@code MathContext} with the specified
146.244 + * {@code Object} for equality.
146.245 + *
146.246 + * @param x {@code Object} to which this {@code MathContext} is to
146.247 + * be compared.
146.248 + * @return {@code true} if and only if the specified {@code Object} is
146.249 + * a {@code MathContext} object which has exactly the same
146.250 + * settings as this object
146.251 + */
146.252 + public boolean equals(Object x){
146.253 + MathContext mc;
146.254 + if (!(x instanceof MathContext))
146.255 + return false;
146.256 + mc = (MathContext) x;
146.257 + return mc.precision == this.precision
146.258 + && mc.roundingMode == this.roundingMode; // no need for .equals()
146.259 + }
146.260 +
146.261 + /**
146.262 + * Returns the hash code for this {@code MathContext}.
146.263 + *
146.264 + * @return hash code for this {@code MathContext}
146.265 + */
146.266 + public int hashCode() {
146.267 + return this.precision + roundingMode.hashCode() * 59;
146.268 + }
146.269 +
146.270 + /**
146.271 + * Returns the string representation of this {@code MathContext}.
146.272 + * The {@code String} returned represents the settings of the
146.273 + * {@code MathContext} object as two space-delimited words
146.274 + * (separated by a single space character, <tt>'\u0020'</tt>,
146.275 + * and with no leading or trailing white space), as follows:
146.276 + * <ol>
146.277 + * <li>
146.278 + * The string {@code "precision="}, immediately followed
146.279 + * by the value of the precision setting as a numeric string as if
146.280 + * generated by the {@link Integer#toString(int) Integer.toString}
146.281 + * method.
146.282 + *
146.283 + * <li>
146.284 + * The string {@code "roundingMode="}, immediately
146.285 + * followed by the value of the {@code roundingMode} setting as a
146.286 + * word. This word will be the same as the name of the
146.287 + * corresponding public constant in the {@link RoundingMode}
146.288 + * enum.
146.289 + * </ol>
146.290 + * <p>
146.291 + * For example:
146.292 + * <pre>
146.293 + * precision=9 roundingMode=HALF_UP
146.294 + * </pre>
146.295 + *
146.296 + * Additional words may be appended to the result of
146.297 + * {@code toString} in the future if more properties are added to
146.298 + * this class.
146.299 + *
146.300 + * @return a {@code String} representing the context settings
146.301 + */
146.302 + public java.lang.String toString() {
146.303 + return "precision=" + precision + " " +
146.304 + "roundingMode=" + roundingMode.toString();
146.305 + }
146.306 +
146.307 + // Private methods
146.308 +
146.309 + /**
146.310 + * Reconstitute the {@code MathContext} instance from a stream (that is,
146.311 + * deserialize it).
146.312 + *
146.313 + * @param s the stream being read.
146.314 + */
146.315 + private void readObject(java.io.ObjectInputStream s)
146.316 + throws java.io.IOException, ClassNotFoundException {
146.317 + s.defaultReadObject(); // read in all fields
146.318 + // validate possibly bad fields
146.319 + if (precision < MIN_DIGITS) {
146.320 + String message = "MathContext: invalid digits in stream";
146.321 + throw new java.io.StreamCorruptedException(message);
146.322 + }
146.323 + if (roundingMode == null) {
146.324 + String message = "MathContext: null roundingMode in stream";
146.325 + throw new java.io.StreamCorruptedException(message);
146.326 + }
146.327 + }
146.328 +
146.329 +}
147.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
147.2 +++ b/rt/emul/compact/src/main/java/java/math/MutableBigInteger.java Mon Oct 07 14:20:58 2013 +0200
147.3 @@ -0,0 +1,1477 @@
147.4 +/*
147.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
147.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
147.7 + *
147.8 + * This code is free software; you can redistribute it and/or modify it
147.9 + * under the terms of the GNU General Public License version 2 only, as
147.10 + * published by the Free Software Foundation. Oracle designates this
147.11 + * particular file as subject to the "Classpath" exception as provided
147.12 + * by Oracle in the LICENSE file that accompanied this code.
147.13 + *
147.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
147.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
147.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
147.17 + * version 2 for more details (a copy is included in the LICENSE file that
147.18 + * accompanied this code).
147.19 + *
147.20 + * You should have received a copy of the GNU General Public License version
147.21 + * 2 along with this work; if not, write to the Free Software Foundation,
147.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
147.23 + *
147.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
147.25 + * or visit www.oracle.com if you need additional information or have any
147.26 + * questions.
147.27 + */
147.28 +
147.29 +package java.math;
147.30 +
147.31 +/**
147.32 + * A class used to represent multiprecision integers that makes efficient
147.33 + * use of allocated space by allowing a number to occupy only part of
147.34 + * an array so that the arrays do not have to be reallocated as often.
147.35 + * When performing an operation with many iterations the array used to
147.36 + * hold a number is only reallocated when necessary and does not have to
147.37 + * be the same size as the number it represents. A mutable number allows
147.38 + * calculations to occur on the same number without having to create
147.39 + * a new number for every step of the calculation as occurs with
147.40 + * BigIntegers.
147.41 + *
147.42 + * @see BigInteger
147.43 + * @author Michael McCloskey
147.44 + * @since 1.3
147.45 + */
147.46 +
147.47 +import java.util.Arrays;
147.48 +
147.49 +import static java.math.BigInteger.LONG_MASK;
147.50 +import static java.math.BigDecimal.INFLATED;
147.51 +
147.52 +class MutableBigInteger {
147.53 + /**
147.54 + * Holds the magnitude of this MutableBigInteger in big endian order.
147.55 + * The magnitude may start at an offset into the value array, and it may
147.56 + * end before the length of the value array.
147.57 + */
147.58 + int[] value;
147.59 +
147.60 + /**
147.61 + * The number of ints of the value array that are currently used
147.62 + * to hold the magnitude of this MutableBigInteger. The magnitude starts
147.63 + * at an offset and offset + intLen may be less than value.length.
147.64 + */
147.65 + int intLen;
147.66 +
147.67 + /**
147.68 + * The offset into the value array where the magnitude of this
147.69 + * MutableBigInteger begins.
147.70 + */
147.71 + int offset = 0;
147.72 +
147.73 + // Constants
147.74 + /**
147.75 + * MutableBigInteger with one element value array with the value 1. Used by
147.76 + * BigDecimal divideAndRound to increment the quotient. Use this constant
147.77 + * only when the method is not going to modify this object.
147.78 + */
147.79 + static final MutableBigInteger ONE = new MutableBigInteger(1);
147.80 +
147.81 + // Constructors
147.82 +
147.83 + /**
147.84 + * The default constructor. An empty MutableBigInteger is created with
147.85 + * a one word capacity.
147.86 + */
147.87 + MutableBigInteger() {
147.88 + value = new int[1];
147.89 + intLen = 0;
147.90 + }
147.91 +
147.92 + /**
147.93 + * Construct a new MutableBigInteger with a magnitude specified by
147.94 + * the int val.
147.95 + */
147.96 + MutableBigInteger(int val) {
147.97 + value = new int[1];
147.98 + intLen = 1;
147.99 + value[0] = val;
147.100 + }
147.101 +
147.102 + /**
147.103 + * Construct a new MutableBigInteger with the specified value array
147.104 + * up to the length of the array supplied.
147.105 + */
147.106 + MutableBigInteger(int[] val) {
147.107 + value = val;
147.108 + intLen = val.length;
147.109 + }
147.110 +
147.111 + /**
147.112 + * Construct a new MutableBigInteger with a magnitude equal to the
147.113 + * specified BigInteger.
147.114 + */
147.115 + MutableBigInteger(BigInteger b) {
147.116 + intLen = b.mag.length;
147.117 + value = Arrays.copyOf(b.mag, intLen);
147.118 + }
147.119 +
147.120 + /**
147.121 + * Construct a new MutableBigInteger with a magnitude equal to the
147.122 + * specified MutableBigInteger.
147.123 + */
147.124 + MutableBigInteger(MutableBigInteger val) {
147.125 + intLen = val.intLen;
147.126 + value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen);
147.127 + }
147.128 +
147.129 + /**
147.130 + * Internal helper method to return the magnitude array. The caller is not
147.131 + * supposed to modify the returned array.
147.132 + */
147.133 + private int[] getMagnitudeArray() {
147.134 + if (offset > 0 || value.length != intLen)
147.135 + return Arrays.copyOfRange(value, offset, offset + intLen);
147.136 + return value;
147.137 + }
147.138 +
147.139 + /**
147.140 + * Convert this MutableBigInteger to a long value. The caller has to make
147.141 + * sure this MutableBigInteger can be fit into long.
147.142 + */
147.143 + private long toLong() {
147.144 + assert (intLen <= 2) : "this MutableBigInteger exceeds the range of long";
147.145 + if (intLen == 0)
147.146 + return 0;
147.147 + long d = value[offset] & LONG_MASK;
147.148 + return (intLen == 2) ? d << 32 | (value[offset + 1] & LONG_MASK) : d;
147.149 + }
147.150 +
147.151 + /**
147.152 + * Convert this MutableBigInteger to a BigInteger object.
147.153 + */
147.154 + BigInteger toBigInteger(int sign) {
147.155 + if (intLen == 0 || sign == 0)
147.156 + return BigInteger.ZERO;
147.157 + return new BigInteger(getMagnitudeArray(), sign);
147.158 + }
147.159 +
147.160 + /**
147.161 + * Convert this MutableBigInteger to BigDecimal object with the specified sign
147.162 + * and scale.
147.163 + */
147.164 + BigDecimal toBigDecimal(int sign, int scale) {
147.165 + if (intLen == 0 || sign == 0)
147.166 + return BigDecimal.valueOf(0, scale);
147.167 + int[] mag = getMagnitudeArray();
147.168 + int len = mag.length;
147.169 + int d = mag[0];
147.170 + // If this MutableBigInteger can't be fit into long, we need to
147.171 + // make a BigInteger object for the resultant BigDecimal object.
147.172 + if (len > 2 || (d < 0 && len == 2))
147.173 + return new BigDecimal(new BigInteger(mag, sign), INFLATED, scale, 0);
147.174 + long v = (len == 2) ?
147.175 + ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
147.176 + d & LONG_MASK;
147.177 + return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
147.178 + }
147.179 +
147.180 + /**
147.181 + * Clear out a MutableBigInteger for reuse.
147.182 + */
147.183 + void clear() {
147.184 + offset = intLen = 0;
147.185 + for (int index=0, n=value.length; index < n; index++)
147.186 + value[index] = 0;
147.187 + }
147.188 +
147.189 + /**
147.190 + * Set a MutableBigInteger to zero, removing its offset.
147.191 + */
147.192 + void reset() {
147.193 + offset = intLen = 0;
147.194 + }
147.195 +
147.196 + /**
147.197 + * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1
147.198 + * as this MutableBigInteger is numerically less than, equal to, or
147.199 + * greater than <tt>b</tt>.
147.200 + */
147.201 + final int compare(MutableBigInteger b) {
147.202 + int blen = b.intLen;
147.203 + if (intLen < blen)
147.204 + return -1;
147.205 + if (intLen > blen)
147.206 + return 1;
147.207 +
147.208 + // Add Integer.MIN_VALUE to make the comparison act as unsigned integer
147.209 + // comparison.
147.210 + int[] bval = b.value;
147.211 + for (int i = offset, j = b.offset; i < intLen + offset; i++, j++) {
147.212 + int b1 = value[i] + 0x80000000;
147.213 + int b2 = bval[j] + 0x80000000;
147.214 + if (b1 < b2)
147.215 + return -1;
147.216 + if (b1 > b2)
147.217 + return 1;
147.218 + }
147.219 + return 0;
147.220 + }
147.221 +
147.222 + /**
147.223 + * Compare this against half of a MutableBigInteger object (Needed for
147.224 + * remainder tests).
147.225 + * Assumes no leading unnecessary zeros, which holds for results
147.226 + * from divide().
147.227 + */
147.228 + final int compareHalf(MutableBigInteger b) {
147.229 + int blen = b.intLen;
147.230 + int len = intLen;
147.231 + if (len <= 0)
147.232 + return blen <=0 ? 0 : -1;
147.233 + if (len > blen)
147.234 + return 1;
147.235 + if (len < blen - 1)
147.236 + return -1;
147.237 + int[] bval = b.value;
147.238 + int bstart = 0;
147.239 + int carry = 0;
147.240 + // Only 2 cases left:len == blen or len == blen - 1
147.241 + if (len != blen) { // len == blen - 1
147.242 + if (bval[bstart] == 1) {
147.243 + ++bstart;
147.244 + carry = 0x80000000;
147.245 + } else
147.246 + return -1;
147.247 + }
147.248 + // compare values with right-shifted values of b,
147.249 + // carrying shifted-out bits across words
147.250 + int[] val = value;
147.251 + for (int i = offset, j = bstart; i < len + offset;) {
147.252 + int bv = bval[j++];
147.253 + long hb = ((bv >>> 1) + carry) & LONG_MASK;
147.254 + long v = val[i++] & LONG_MASK;
147.255 + if (v != hb)
147.256 + return v < hb ? -1 : 1;
147.257 + carry = (bv & 1) << 31; // carray will be either 0x80000000 or 0
147.258 + }
147.259 + return carry == 0? 0 : -1;
147.260 + }
147.261 +
147.262 + /**
147.263 + * Return the index of the lowest set bit in this MutableBigInteger. If the
147.264 + * magnitude of this MutableBigInteger is zero, -1 is returned.
147.265 + */
147.266 + private final int getLowestSetBit() {
147.267 + if (intLen == 0)
147.268 + return -1;
147.269 + int j, b;
147.270 + for (j=intLen-1; (j>0) && (value[j+offset]==0); j--)
147.271 + ;
147.272 + b = value[j+offset];
147.273 + if (b==0)
147.274 + return -1;
147.275 + return ((intLen-1-j)<<5) + Integer.numberOfTrailingZeros(b);
147.276 + }
147.277 +
147.278 + /**
147.279 + * Return the int in use in this MutableBigInteger at the specified
147.280 + * index. This method is not used because it is not inlined on all
147.281 + * platforms.
147.282 + */
147.283 + private final int getInt(int index) {
147.284 + return value[offset+index];
147.285 + }
147.286 +
147.287 + /**
147.288 + * Return a long which is equal to the unsigned value of the int in
147.289 + * use in this MutableBigInteger at the specified index. This method is
147.290 + * not used because it is not inlined on all platforms.
147.291 + */
147.292 + private final long getLong(int index) {
147.293 + return value[offset+index] & LONG_MASK;
147.294 + }
147.295 +
147.296 + /**
147.297 + * Ensure that the MutableBigInteger is in normal form, specifically
147.298 + * making sure that there are no leading zeros, and that if the
147.299 + * magnitude is zero, then intLen is zero.
147.300 + */
147.301 + final void normalize() {
147.302 + if (intLen == 0) {
147.303 + offset = 0;
147.304 + return;
147.305 + }
147.306 +
147.307 + int index = offset;
147.308 + if (value[index] != 0)
147.309 + return;
147.310 +
147.311 + int indexBound = index+intLen;
147.312 + do {
147.313 + index++;
147.314 + } while(index < indexBound && value[index]==0);
147.315 +
147.316 + int numZeros = index - offset;
147.317 + intLen -= numZeros;
147.318 + offset = (intLen==0 ? 0 : offset+numZeros);
147.319 + }
147.320 +
147.321 + /**
147.322 + * If this MutableBigInteger cannot hold len words, increase the size
147.323 + * of the value array to len words.
147.324 + */
147.325 + private final void ensureCapacity(int len) {
147.326 + if (value.length < len) {
147.327 + value = new int[len];
147.328 + offset = 0;
147.329 + intLen = len;
147.330 + }
147.331 + }
147.332 +
147.333 + /**
147.334 + * Convert this MutableBigInteger into an int array with no leading
147.335 + * zeros, of a length that is equal to this MutableBigInteger's intLen.
147.336 + */
147.337 + int[] toIntArray() {
147.338 + int[] result = new int[intLen];
147.339 + for(int i=0; i<intLen; i++)
147.340 + result[i] = value[offset+i];
147.341 + return result;
147.342 + }
147.343 +
147.344 + /**
147.345 + * Sets the int at index+offset in this MutableBigInteger to val.
147.346 + * This does not get inlined on all platforms so it is not used
147.347 + * as often as originally intended.
147.348 + */
147.349 + void setInt(int index, int val) {
147.350 + value[offset + index] = val;
147.351 + }
147.352 +
147.353 + /**
147.354 + * Sets this MutableBigInteger's value array to the specified array.
147.355 + * The intLen is set to the specified length.
147.356 + */
147.357 + void setValue(int[] val, int length) {
147.358 + value = val;
147.359 + intLen = length;
147.360 + offset = 0;
147.361 + }
147.362 +
147.363 + /**
147.364 + * Sets this MutableBigInteger's value array to a copy of the specified
147.365 + * array. The intLen is set to the length of the new array.
147.366 + */
147.367 + void copyValue(MutableBigInteger src) {
147.368 + int len = src.intLen;
147.369 + if (value.length < len)
147.370 + value = new int[len];
147.371 + System.arraycopy(src.value, src.offset, value, 0, len);
147.372 + intLen = len;
147.373 + offset = 0;
147.374 + }
147.375 +
147.376 + /**
147.377 + * Sets this MutableBigInteger's value array to a copy of the specified
147.378 + * array. The intLen is set to the length of the specified array.
147.379 + */
147.380 + void copyValue(int[] val) {
147.381 + int len = val.length;
147.382 + if (value.length < len)
147.383 + value = new int[len];
147.384 + System.arraycopy(val, 0, value, 0, len);
147.385 + intLen = len;
147.386 + offset = 0;
147.387 + }
147.388 +
147.389 + /**
147.390 + * Returns true iff this MutableBigInteger has a value of one.
147.391 + */
147.392 + boolean isOne() {
147.393 + return (intLen == 1) && (value[offset] == 1);
147.394 + }
147.395 +
147.396 + /**
147.397 + * Returns true iff this MutableBigInteger has a value of zero.
147.398 + */
147.399 + boolean isZero() {
147.400 + return (intLen == 0);
147.401 + }
147.402 +
147.403 + /**
147.404 + * Returns true iff this MutableBigInteger is even.
147.405 + */
147.406 + boolean isEven() {
147.407 + return (intLen == 0) || ((value[offset + intLen - 1] & 1) == 0);
147.408 + }
147.409 +
147.410 + /**
147.411 + * Returns true iff this MutableBigInteger is odd.
147.412 + */
147.413 + boolean isOdd() {
147.414 + return isZero() ? false : ((value[offset + intLen - 1] & 1) == 1);
147.415 + }
147.416 +
147.417 + /**
147.418 + * Returns true iff this MutableBigInteger is in normal form. A
147.419 + * MutableBigInteger is in normal form if it has no leading zeros
147.420 + * after the offset, and intLen + offset <= value.length.
147.421 + */
147.422 + boolean isNormal() {
147.423 + if (intLen + offset > value.length)
147.424 + return false;
147.425 + if (intLen ==0)
147.426 + return true;
147.427 + return (value[offset] != 0);
147.428 + }
147.429 +
147.430 + /**
147.431 + * Returns a String representation of this MutableBigInteger in radix 10.
147.432 + */
147.433 + public String toString() {
147.434 + BigInteger b = toBigInteger(1);
147.435 + return b.toString();
147.436 + }
147.437 +
147.438 + /**
147.439 + * Right shift this MutableBigInteger n bits. The MutableBigInteger is left
147.440 + * in normal form.
147.441 + */
147.442 + void rightShift(int n) {
147.443 + if (intLen == 0)
147.444 + return;
147.445 + int nInts = n >>> 5;
147.446 + int nBits = n & 0x1F;
147.447 + this.intLen -= nInts;
147.448 + if (nBits == 0)
147.449 + return;
147.450 + int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
147.451 + if (nBits >= bitsInHighWord) {
147.452 + this.primitiveLeftShift(32 - nBits);
147.453 + this.intLen--;
147.454 + } else {
147.455 + primitiveRightShift(nBits);
147.456 + }
147.457 + }
147.458 +
147.459 + /**
147.460 + * Left shift this MutableBigInteger n bits.
147.461 + */
147.462 + void leftShift(int n) {
147.463 + /*
147.464 + * If there is enough storage space in this MutableBigInteger already
147.465 + * the available space will be used. Space to the right of the used
147.466 + * ints in the value array is faster to utilize, so the extra space
147.467 + * will be taken from the right if possible.
147.468 + */
147.469 + if (intLen == 0)
147.470 + return;
147.471 + int nInts = n >>> 5;
147.472 + int nBits = n&0x1F;
147.473 + int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
147.474 +
147.475 + // If shift can be done without moving words, do so
147.476 + if (n <= (32-bitsInHighWord)) {
147.477 + primitiveLeftShift(nBits);
147.478 + return;
147.479 + }
147.480 +
147.481 + int newLen = intLen + nInts +1;
147.482 + if (nBits <= (32-bitsInHighWord))
147.483 + newLen--;
147.484 + if (value.length < newLen) {
147.485 + // The array must grow
147.486 + int[] result = new int[newLen];
147.487 + for (int i=0; i<intLen; i++)
147.488 + result[i] = value[offset+i];
147.489 + setValue(result, newLen);
147.490 + } else if (value.length - offset >= newLen) {
147.491 + // Use space on right
147.492 + for(int i=0; i<newLen - intLen; i++)
147.493 + value[offset+intLen+i] = 0;
147.494 + } else {
147.495 + // Must use space on left
147.496 + for (int i=0; i<intLen; i++)
147.497 + value[i] = value[offset+i];
147.498 + for (int i=intLen; i<newLen; i++)
147.499 + value[i] = 0;
147.500 + offset = 0;
147.501 + }
147.502 + intLen = newLen;
147.503 + if (nBits == 0)
147.504 + return;
147.505 + if (nBits <= (32-bitsInHighWord))
147.506 + primitiveLeftShift(nBits);
147.507 + else
147.508 + primitiveRightShift(32 -nBits);
147.509 + }
147.510 +
147.511 + /**
147.512 + * A primitive used for division. This method adds in one multiple of the
147.513 + * divisor a back to the dividend result at a specified offset. It is used
147.514 + * when qhat was estimated too large, and must be adjusted.
147.515 + */
147.516 + private int divadd(int[] a, int[] result, int offset) {
147.517 + long carry = 0;
147.518 +
147.519 + for (int j=a.length-1; j >= 0; j--) {
147.520 + long sum = (a[j] & LONG_MASK) +
147.521 + (result[j+offset] & LONG_MASK) + carry;
147.522 + result[j+offset] = (int)sum;
147.523 + carry = sum >>> 32;
147.524 + }
147.525 + return (int)carry;
147.526 + }
147.527 +
147.528 + /**
147.529 + * This method is used for division. It multiplies an n word input a by one
147.530 + * word input x, and subtracts the n word product from q. This is needed
147.531 + * when subtracting qhat*divisor from dividend.
147.532 + */
147.533 + private int mulsub(int[] q, int[] a, int x, int len, int offset) {
147.534 + long xLong = x & LONG_MASK;
147.535 + long carry = 0;
147.536 + offset += len;
147.537 +
147.538 + for (int j=len-1; j >= 0; j--) {
147.539 + long product = (a[j] & LONG_MASK) * xLong + carry;
147.540 + long difference = q[offset] - product;
147.541 + q[offset--] = (int)difference;
147.542 + carry = (product >>> 32)
147.543 + + (((difference & LONG_MASK) >
147.544 + (((~(int)product) & LONG_MASK))) ? 1:0);
147.545 + }
147.546 + return (int)carry;
147.547 + }
147.548 +
147.549 + /**
147.550 + * Right shift this MutableBigInteger n bits, where n is
147.551 + * less than 32.
147.552 + * Assumes that intLen > 0, n > 0 for speed
147.553 + */
147.554 + private final void primitiveRightShift(int n) {
147.555 + int[] val = value;
147.556 + int n2 = 32 - n;
147.557 + for (int i=offset+intLen-1, c=val[i]; i>offset; i--) {
147.558 + int b = c;
147.559 + c = val[i-1];
147.560 + val[i] = (c << n2) | (b >>> n);
147.561 + }
147.562 + val[offset] >>>= n;
147.563 + }
147.564 +
147.565 + /**
147.566 + * Left shift this MutableBigInteger n bits, where n is
147.567 + * less than 32.
147.568 + * Assumes that intLen > 0, n > 0 for speed
147.569 + */
147.570 + private final void primitiveLeftShift(int n) {
147.571 + int[] val = value;
147.572 + int n2 = 32 - n;
147.573 + for (int i=offset, c=val[i], m=i+intLen-1; i<m; i++) {
147.574 + int b = c;
147.575 + c = val[i+1];
147.576 + val[i] = (b << n) | (c >>> n2);
147.577 + }
147.578 + val[offset+intLen-1] <<= n;
147.579 + }
147.580 +
147.581 + /**
147.582 + * Adds the contents of two MutableBigInteger objects.The result
147.583 + * is placed within this MutableBigInteger.
147.584 + * The contents of the addend are not changed.
147.585 + */
147.586 + void add(MutableBigInteger addend) {
147.587 + int x = intLen;
147.588 + int y = addend.intLen;
147.589 + int resultLen = (intLen > addend.intLen ? intLen : addend.intLen);
147.590 + int[] result = (value.length < resultLen ? new int[resultLen] : value);
147.591 +
147.592 + int rstart = result.length-1;
147.593 + long sum;
147.594 + long carry = 0;
147.595 +
147.596 + // Add common parts of both numbers
147.597 + while(x>0 && y>0) {
147.598 + x--; y--;
147.599 + sum = (value[x+offset] & LONG_MASK) +
147.600 + (addend.value[y+addend.offset] & LONG_MASK) + carry;
147.601 + result[rstart--] = (int)sum;
147.602 + carry = sum >>> 32;
147.603 + }
147.604 +
147.605 + // Add remainder of the longer number
147.606 + while(x>0) {
147.607 + x--;
147.608 + if (carry == 0 && result == value && rstart == (x + offset))
147.609 + return;
147.610 + sum = (value[x+offset] & LONG_MASK) + carry;
147.611 + result[rstart--] = (int)sum;
147.612 + carry = sum >>> 32;
147.613 + }
147.614 + while(y>0) {
147.615 + y--;
147.616 + sum = (addend.value[y+addend.offset] & LONG_MASK) + carry;
147.617 + result[rstart--] = (int)sum;
147.618 + carry = sum >>> 32;
147.619 + }
147.620 +
147.621 + if (carry > 0) { // Result must grow in length
147.622 + resultLen++;
147.623 + if (result.length < resultLen) {
147.624 + int temp[] = new int[resultLen];
147.625 + // Result one word longer from carry-out; copy low-order
147.626 + // bits into new result.
147.627 + System.arraycopy(result, 0, temp, 1, result.length);
147.628 + temp[0] = 1;
147.629 + result = temp;
147.630 + } else {
147.631 + result[rstart--] = 1;
147.632 + }
147.633 + }
147.634 +
147.635 + value = result;
147.636 + intLen = resultLen;
147.637 + offset = result.length - resultLen;
147.638 + }
147.639 +
147.640 +
147.641 + /**
147.642 + * Subtracts the smaller of this and b from the larger and places the
147.643 + * result into this MutableBigInteger.
147.644 + */
147.645 + int subtract(MutableBigInteger b) {
147.646 + MutableBigInteger a = this;
147.647 +
147.648 + int[] result = value;
147.649 + int sign = a.compare(b);
147.650 +
147.651 + if (sign == 0) {
147.652 + reset();
147.653 + return 0;
147.654 + }
147.655 + if (sign < 0) {
147.656 + MutableBigInteger tmp = a;
147.657 + a = b;
147.658 + b = tmp;
147.659 + }
147.660 +
147.661 + int resultLen = a.intLen;
147.662 + if (result.length < resultLen)
147.663 + result = new int[resultLen];
147.664 +
147.665 + long diff = 0;
147.666 + int x = a.intLen;
147.667 + int y = b.intLen;
147.668 + int rstart = result.length - 1;
147.669 +
147.670 + // Subtract common parts of both numbers
147.671 + while (y>0) {
147.672 + x--; y--;
147.673 +
147.674 + diff = (a.value[x+a.offset] & LONG_MASK) -
147.675 + (b.value[y+b.offset] & LONG_MASK) - ((int)-(diff>>32));
147.676 + result[rstart--] = (int)diff;
147.677 + }
147.678 + // Subtract remainder of longer number
147.679 + while (x>0) {
147.680 + x--;
147.681 + diff = (a.value[x+a.offset] & LONG_MASK) - ((int)-(diff>>32));
147.682 + result[rstart--] = (int)diff;
147.683 + }
147.684 +
147.685 + value = result;
147.686 + intLen = resultLen;
147.687 + offset = value.length - resultLen;
147.688 + normalize();
147.689 + return sign;
147.690 + }
147.691 +
147.692 + /**
147.693 + * Subtracts the smaller of a and b from the larger and places the result
147.694 + * into the larger. Returns 1 if the answer is in a, -1 if in b, 0 if no
147.695 + * operation was performed.
147.696 + */
147.697 + private int difference(MutableBigInteger b) {
147.698 + MutableBigInteger a = this;
147.699 + int sign = a.compare(b);
147.700 + if (sign ==0)
147.701 + return 0;
147.702 + if (sign < 0) {
147.703 + MutableBigInteger tmp = a;
147.704 + a = b;
147.705 + b = tmp;
147.706 + }
147.707 +
147.708 + long diff = 0;
147.709 + int x = a.intLen;
147.710 + int y = b.intLen;
147.711 +
147.712 + // Subtract common parts of both numbers
147.713 + while (y>0) {
147.714 + x--; y--;
147.715 + diff = (a.value[a.offset+ x] & LONG_MASK) -
147.716 + (b.value[b.offset+ y] & LONG_MASK) - ((int)-(diff>>32));
147.717 + a.value[a.offset+x] = (int)diff;
147.718 + }
147.719 + // Subtract remainder of longer number
147.720 + while (x>0) {
147.721 + x--;
147.722 + diff = (a.value[a.offset+ x] & LONG_MASK) - ((int)-(diff>>32));
147.723 + a.value[a.offset+x] = (int)diff;
147.724 + }
147.725 +
147.726 + a.normalize();
147.727 + return sign;
147.728 + }
147.729 +
147.730 + /**
147.731 + * Multiply the contents of two MutableBigInteger objects. The result is
147.732 + * placed into MutableBigInteger z. The contents of y are not changed.
147.733 + */
147.734 + void multiply(MutableBigInteger y, MutableBigInteger z) {
147.735 + int xLen = intLen;
147.736 + int yLen = y.intLen;
147.737 + int newLen = xLen + yLen;
147.738 +
147.739 + // Put z into an appropriate state to receive product
147.740 + if (z.value.length < newLen)
147.741 + z.value = new int[newLen];
147.742 + z.offset = 0;
147.743 + z.intLen = newLen;
147.744 +
147.745 + // The first iteration is hoisted out of the loop to avoid extra add
147.746 + long carry = 0;
147.747 + for (int j=yLen-1, k=yLen+xLen-1; j >= 0; j--, k--) {
147.748 + long product = (y.value[j+y.offset] & LONG_MASK) *
147.749 + (value[xLen-1+offset] & LONG_MASK) + carry;
147.750 + z.value[k] = (int)product;
147.751 + carry = product >>> 32;
147.752 + }
147.753 + z.value[xLen-1] = (int)carry;
147.754 +
147.755 + // Perform the multiplication word by word
147.756 + for (int i = xLen-2; i >= 0; i--) {
147.757 + carry = 0;
147.758 + for (int j=yLen-1, k=yLen+i; j >= 0; j--, k--) {
147.759 + long product = (y.value[j+y.offset] & LONG_MASK) *
147.760 + (value[i+offset] & LONG_MASK) +
147.761 + (z.value[k] & LONG_MASK) + carry;
147.762 + z.value[k] = (int)product;
147.763 + carry = product >>> 32;
147.764 + }
147.765 + z.value[i] = (int)carry;
147.766 + }
147.767 +
147.768 + // Remove leading zeros from product
147.769 + z.normalize();
147.770 + }
147.771 +
147.772 + /**
147.773 + * Multiply the contents of this MutableBigInteger by the word y. The
147.774 + * result is placed into z.
147.775 + */
147.776 + void mul(int y, MutableBigInteger z) {
147.777 + if (y == 1) {
147.778 + z.copyValue(this);
147.779 + return;
147.780 + }
147.781 +
147.782 + if (y == 0) {
147.783 + z.clear();
147.784 + return;
147.785 + }
147.786 +
147.787 + // Perform the multiplication word by word
147.788 + long ylong = y & LONG_MASK;
147.789 + int[] zval = (z.value.length<intLen+1 ? new int[intLen + 1]
147.790 + : z.value);
147.791 + long carry = 0;
147.792 + for (int i = intLen-1; i >= 0; i--) {
147.793 + long product = ylong * (value[i+offset] & LONG_MASK) + carry;
147.794 + zval[i+1] = (int)product;
147.795 + carry = product >>> 32;
147.796 + }
147.797 +
147.798 + if (carry == 0) {
147.799 + z.offset = 1;
147.800 + z.intLen = intLen;
147.801 + } else {
147.802 + z.offset = 0;
147.803 + z.intLen = intLen + 1;
147.804 + zval[0] = (int)carry;
147.805 + }
147.806 + z.value = zval;
147.807 + }
147.808 +
147.809 + /**
147.810 + * This method is used for division of an n word dividend by a one word
147.811 + * divisor. The quotient is placed into quotient. The one word divisor is
147.812 + * specified by divisor.
147.813 + *
147.814 + * @return the remainder of the division is returned.
147.815 + *
147.816 + */
147.817 + int divideOneWord(int divisor, MutableBigInteger quotient) {
147.818 + long divisorLong = divisor & LONG_MASK;
147.819 +
147.820 + // Special case of one word dividend
147.821 + if (intLen == 1) {
147.822 + long dividendValue = value[offset] & LONG_MASK;
147.823 + int q = (int) (dividendValue / divisorLong);
147.824 + int r = (int) (dividendValue - q * divisorLong);
147.825 + quotient.value[0] = q;
147.826 + quotient.intLen = (q == 0) ? 0 : 1;
147.827 + quotient.offset = 0;
147.828 + return r;
147.829 + }
147.830 +
147.831 + if (quotient.value.length < intLen)
147.832 + quotient.value = new int[intLen];
147.833 + quotient.offset = 0;
147.834 + quotient.intLen = intLen;
147.835 +
147.836 + // Normalize the divisor
147.837 + int shift = Integer.numberOfLeadingZeros(divisor);
147.838 +
147.839 + int rem = value[offset];
147.840 + long remLong = rem & LONG_MASK;
147.841 + if (remLong < divisorLong) {
147.842 + quotient.value[0] = 0;
147.843 + } else {
147.844 + quotient.value[0] = (int)(remLong / divisorLong);
147.845 + rem = (int) (remLong - (quotient.value[0] * divisorLong));
147.846 + remLong = rem & LONG_MASK;
147.847 + }
147.848 +
147.849 + int xlen = intLen;
147.850 + int[] qWord = new int[2];
147.851 + while (--xlen > 0) {
147.852 + long dividendEstimate = (remLong<<32) |
147.853 + (value[offset + intLen - xlen] & LONG_MASK);
147.854 + if (dividendEstimate >= 0) {
147.855 + qWord[0] = (int) (dividendEstimate / divisorLong);
147.856 + qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
147.857 + } else {
147.858 + divWord(qWord, dividendEstimate, divisor);
147.859 + }
147.860 + quotient.value[intLen - xlen] = qWord[0];
147.861 + rem = qWord[1];
147.862 + remLong = rem & LONG_MASK;
147.863 + }
147.864 +
147.865 + quotient.normalize();
147.866 + // Unnormalize
147.867 + if (shift > 0)
147.868 + return rem % divisor;
147.869 + else
147.870 + return rem;
147.871 + }
147.872 +
147.873 + /**
147.874 + * Calculates the quotient of this div b and places the quotient in the
147.875 + * provided MutableBigInteger objects and the remainder object is returned.
147.876 + *
147.877 + * Uses Algorithm D in Knuth section 4.3.1.
147.878 + * Many optimizations to that algorithm have been adapted from the Colin
147.879 + * Plumb C library.
147.880 + * It special cases one word divisors for speed. The content of b is not
147.881 + * changed.
147.882 + *
147.883 + */
147.884 + MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
147.885 + if (b.intLen == 0)
147.886 + throw new ArithmeticException("BigInteger divide by zero");
147.887 +
147.888 + // Dividend is zero
147.889 + if (intLen == 0) {
147.890 + quotient.intLen = quotient.offset;
147.891 + return new MutableBigInteger();
147.892 + }
147.893 +
147.894 + int cmp = compare(b);
147.895 + // Dividend less than divisor
147.896 + if (cmp < 0) {
147.897 + quotient.intLen = quotient.offset = 0;
147.898 + return new MutableBigInteger(this);
147.899 + }
147.900 + // Dividend equal to divisor
147.901 + if (cmp == 0) {
147.902 + quotient.value[0] = quotient.intLen = 1;
147.903 + quotient.offset = 0;
147.904 + return new MutableBigInteger();
147.905 + }
147.906 +
147.907 + quotient.clear();
147.908 + // Special case one word divisor
147.909 + if (b.intLen == 1) {
147.910 + int r = divideOneWord(b.value[b.offset], quotient);
147.911 + if (r == 0)
147.912 + return new MutableBigInteger();
147.913 + return new MutableBigInteger(r);
147.914 + }
147.915 +
147.916 + // Copy divisor value to protect divisor
147.917 + int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
147.918 + return divideMagnitude(div, quotient);
147.919 + }
147.920 +
147.921 + /**
147.922 + * Internally used to calculate the quotient of this div v and places the
147.923 + * quotient in the provided MutableBigInteger object and the remainder is
147.924 + * returned.
147.925 + *
147.926 + * @return the remainder of the division will be returned.
147.927 + */
147.928 + long divide(long v, MutableBigInteger quotient) {
147.929 + if (v == 0)
147.930 + throw new ArithmeticException("BigInteger divide by zero");
147.931 +
147.932 + // Dividend is zero
147.933 + if (intLen == 0) {
147.934 + quotient.intLen = quotient.offset = 0;
147.935 + return 0;
147.936 + }
147.937 + if (v < 0)
147.938 + v = -v;
147.939 +
147.940 + int d = (int)(v >>> 32);
147.941 + quotient.clear();
147.942 + // Special case on word divisor
147.943 + if (d == 0)
147.944 + return divideOneWord((int)v, quotient) & LONG_MASK;
147.945 + else {
147.946 + int[] div = new int[]{ d, (int)(v & LONG_MASK) };
147.947 + return divideMagnitude(div, quotient).toLong();
147.948 + }
147.949 + }
147.950 +
147.951 + /**
147.952 + * Divide this MutableBigInteger by the divisor represented by its magnitude
147.953 + * array. The quotient will be placed into the provided quotient object &
147.954 + * the remainder object is returned.
147.955 + */
147.956 + private MutableBigInteger divideMagnitude(int[] divisor,
147.957 + MutableBigInteger quotient) {
147.958 +
147.959 + // Remainder starts as dividend with space for a leading zero
147.960 + MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
147.961 + System.arraycopy(value, offset, rem.value, 1, intLen);
147.962 + rem.intLen = intLen;
147.963 + rem.offset = 1;
147.964 +
147.965 + int nlen = rem.intLen;
147.966 +
147.967 + // Set the quotient size
147.968 + int dlen = divisor.length;
147.969 + int limit = nlen - dlen + 1;
147.970 + if (quotient.value.length < limit) {
147.971 + quotient.value = new int[limit];
147.972 + quotient.offset = 0;
147.973 + }
147.974 + quotient.intLen = limit;
147.975 + int[] q = quotient.value;
147.976 +
147.977 + // D1 normalize the divisor
147.978 + int shift = Integer.numberOfLeadingZeros(divisor[0]);
147.979 + if (shift > 0) {
147.980 + // First shift will not grow array
147.981 + BigInteger.primitiveLeftShift(divisor, dlen, shift);
147.982 + // But this one might
147.983 + rem.leftShift(shift);
147.984 + }
147.985 +
147.986 + // Must insert leading 0 in rem if its length did not change
147.987 + if (rem.intLen == nlen) {
147.988 + rem.offset = 0;
147.989 + rem.value[0] = 0;
147.990 + rem.intLen++;
147.991 + }
147.992 +
147.993 + int dh = divisor[0];
147.994 + long dhLong = dh & LONG_MASK;
147.995 + int dl = divisor[1];
147.996 + int[] qWord = new int[2];
147.997 +
147.998 + // D2 Initialize j
147.999 + for(int j=0; j<limit; j++) {
147.1000 + // D3 Calculate qhat
147.1001 + // estimate qhat
147.1002 + int qhat = 0;
147.1003 + int qrem = 0;
147.1004 + boolean skipCorrection = false;
147.1005 + int nh = rem.value[j+rem.offset];
147.1006 + int nh2 = nh + 0x80000000;
147.1007 + int nm = rem.value[j+1+rem.offset];
147.1008 +
147.1009 + if (nh == dh) {
147.1010 + qhat = ~0;
147.1011 + qrem = nh + nm;
147.1012 + skipCorrection = qrem + 0x80000000 < nh2;
147.1013 + } else {
147.1014 + long nChunk = (((long)nh) << 32) | (nm & LONG_MASK);
147.1015 + if (nChunk >= 0) {
147.1016 + qhat = (int) (nChunk / dhLong);
147.1017 + qrem = (int) (nChunk - (qhat * dhLong));
147.1018 + } else {
147.1019 + divWord(qWord, nChunk, dh);
147.1020 + qhat = qWord[0];
147.1021 + qrem = qWord[1];
147.1022 + }
147.1023 + }
147.1024 +
147.1025 + if (qhat == 0)
147.1026 + continue;
147.1027 +
147.1028 + if (!skipCorrection) { // Correct qhat
147.1029 + long nl = rem.value[j+2+rem.offset] & LONG_MASK;
147.1030 + long rs = ((qrem & LONG_MASK) << 32) | nl;
147.1031 + long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
147.1032 +
147.1033 + if (unsignedLongCompare(estProduct, rs)) {
147.1034 + qhat--;
147.1035 + qrem = (int)((qrem & LONG_MASK) + dhLong);
147.1036 + if ((qrem & LONG_MASK) >= dhLong) {
147.1037 + estProduct -= (dl & LONG_MASK);
147.1038 + rs = ((qrem & LONG_MASK) << 32) | nl;
147.1039 + if (unsignedLongCompare(estProduct, rs))
147.1040 + qhat--;
147.1041 + }
147.1042 + }
147.1043 + }
147.1044 +
147.1045 + // D4 Multiply and subtract
147.1046 + rem.value[j+rem.offset] = 0;
147.1047 + int borrow = mulsub(rem.value, divisor, qhat, dlen, j+rem.offset);
147.1048 +
147.1049 + // D5 Test remainder
147.1050 + if (borrow + 0x80000000 > nh2) {
147.1051 + // D6 Add back
147.1052 + divadd(divisor, rem.value, j+1+rem.offset);
147.1053 + qhat--;
147.1054 + }
147.1055 +
147.1056 + // Store the quotient digit
147.1057 + q[j] = qhat;
147.1058 + } // D7 loop on j
147.1059 +
147.1060 + // D8 Unnormalize
147.1061 + if (shift > 0)
147.1062 + rem.rightShift(shift);
147.1063 +
147.1064 + quotient.normalize();
147.1065 + rem.normalize();
147.1066 + return rem;
147.1067 + }
147.1068 +
147.1069 + /**
147.1070 + * Compare two longs as if they were unsigned.
147.1071 + * Returns true iff one is bigger than two.
147.1072 + */
147.1073 + private boolean unsignedLongCompare(long one, long two) {
147.1074 + return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
147.1075 + }
147.1076 +
147.1077 + /**
147.1078 + * This method divides a long quantity by an int to estimate
147.1079 + * qhat for two multi precision numbers. It is used when
147.1080 + * the signed value of n is less than zero.
147.1081 + */
147.1082 + private void divWord(int[] result, long n, int d) {
147.1083 + long dLong = d & LONG_MASK;
147.1084 +
147.1085 + if (dLong == 1) {
147.1086 + result[0] = (int)n;
147.1087 + result[1] = 0;
147.1088 + return;
147.1089 + }
147.1090 +
147.1091 + // Approximate the quotient and remainder
147.1092 + long q = (n >>> 1) / (dLong >>> 1);
147.1093 + long r = n - q*dLong;
147.1094 +
147.1095 + // Correct the approximation
147.1096 + while (r < 0) {
147.1097 + r += dLong;
147.1098 + q--;
147.1099 + }
147.1100 + while (r >= dLong) {
147.1101 + r -= dLong;
147.1102 + q++;
147.1103 + }
147.1104 +
147.1105 + // n - q*dlong == r && 0 <= r <dLong, hence we're done.
147.1106 + result[0] = (int)q;
147.1107 + result[1] = (int)r;
147.1108 + }
147.1109 +
147.1110 + /**
147.1111 + * Calculate GCD of this and b. This and b are changed by the computation.
147.1112 + */
147.1113 + MutableBigInteger hybridGCD(MutableBigInteger b) {
147.1114 + // Use Euclid's algorithm until the numbers are approximately the
147.1115 + // same length, then use the binary GCD algorithm to find the GCD.
147.1116 + MutableBigInteger a = this;
147.1117 + MutableBigInteger q = new MutableBigInteger();
147.1118 +
147.1119 + while (b.intLen != 0) {
147.1120 + if (Math.abs(a.intLen - b.intLen) < 2)
147.1121 + return a.binaryGCD(b);
147.1122 +
147.1123 + MutableBigInteger r = a.divide(b, q);
147.1124 + a = b;
147.1125 + b = r;
147.1126 + }
147.1127 + return a;
147.1128 + }
147.1129 +
147.1130 + /**
147.1131 + * Calculate GCD of this and v.
147.1132 + * Assumes that this and v are not zero.
147.1133 + */
147.1134 + private MutableBigInteger binaryGCD(MutableBigInteger v) {
147.1135 + // Algorithm B from Knuth section 4.5.2
147.1136 + MutableBigInteger u = this;
147.1137 + MutableBigInteger r = new MutableBigInteger();
147.1138 +
147.1139 + // step B1
147.1140 + int s1 = u.getLowestSetBit();
147.1141 + int s2 = v.getLowestSetBit();
147.1142 + int k = (s1 < s2) ? s1 : s2;
147.1143 + if (k != 0) {
147.1144 + u.rightShift(k);
147.1145 + v.rightShift(k);
147.1146 + }
147.1147 +
147.1148 + // step B2
147.1149 + boolean uOdd = (k==s1);
147.1150 + MutableBigInteger t = uOdd ? v: u;
147.1151 + int tsign = uOdd ? -1 : 1;
147.1152 +
147.1153 + int lb;
147.1154 + while ((lb = t.getLowestSetBit()) >= 0) {
147.1155 + // steps B3 and B4
147.1156 + t.rightShift(lb);
147.1157 + // step B5
147.1158 + if (tsign > 0)
147.1159 + u = t;
147.1160 + else
147.1161 + v = t;
147.1162 +
147.1163 + // Special case one word numbers
147.1164 + if (u.intLen < 2 && v.intLen < 2) {
147.1165 + int x = u.value[u.offset];
147.1166 + int y = v.value[v.offset];
147.1167 + x = binaryGcd(x, y);
147.1168 + r.value[0] = x;
147.1169 + r.intLen = 1;
147.1170 + r.offset = 0;
147.1171 + if (k > 0)
147.1172 + r.leftShift(k);
147.1173 + return r;
147.1174 + }
147.1175 +
147.1176 + // step B6
147.1177 + if ((tsign = u.difference(v)) == 0)
147.1178 + break;
147.1179 + t = (tsign >= 0) ? u : v;
147.1180 + }
147.1181 +
147.1182 + if (k > 0)
147.1183 + u.leftShift(k);
147.1184 + return u;
147.1185 + }
147.1186 +
147.1187 + /**
147.1188 + * Calculate GCD of a and b interpreted as unsigned integers.
147.1189 + */
147.1190 + static int binaryGcd(int a, int b) {
147.1191 + if (b==0)
147.1192 + return a;
147.1193 + if (a==0)
147.1194 + return b;
147.1195 +
147.1196 + // Right shift a & b till their last bits equal to 1.
147.1197 + int aZeros = Integer.numberOfTrailingZeros(a);
147.1198 + int bZeros = Integer.numberOfTrailingZeros(b);
147.1199 + a >>>= aZeros;
147.1200 + b >>>= bZeros;
147.1201 +
147.1202 + int t = (aZeros < bZeros ? aZeros : bZeros);
147.1203 +
147.1204 + while (a != b) {
147.1205 + if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned
147.1206 + a -= b;
147.1207 + a >>>= Integer.numberOfTrailingZeros(a);
147.1208 + } else {
147.1209 + b -= a;
147.1210 + b >>>= Integer.numberOfTrailingZeros(b);
147.1211 + }
147.1212 + }
147.1213 + return a<<t;
147.1214 + }
147.1215 +
147.1216 + /**
147.1217 + * Returns the modInverse of this mod p. This and p are not affected by
147.1218 + * the operation.
147.1219 + */
147.1220 + MutableBigInteger mutableModInverse(MutableBigInteger p) {
147.1221 + // Modulus is odd, use Schroeppel's algorithm
147.1222 + if (p.isOdd())
147.1223 + return modInverse(p);
147.1224 +
147.1225 + // Base and modulus are even, throw exception
147.1226 + if (isEven())
147.1227 + throw new ArithmeticException("BigInteger not invertible.");
147.1228 +
147.1229 + // Get even part of modulus expressed as a power of 2
147.1230 + int powersOf2 = p.getLowestSetBit();
147.1231 +
147.1232 + // Construct odd part of modulus
147.1233 + MutableBigInteger oddMod = new MutableBigInteger(p);
147.1234 + oddMod.rightShift(powersOf2);
147.1235 +
147.1236 + if (oddMod.isOne())
147.1237 + return modInverseMP2(powersOf2);
147.1238 +
147.1239 + // Calculate 1/a mod oddMod
147.1240 + MutableBigInteger oddPart = modInverse(oddMod);
147.1241 +
147.1242 + // Calculate 1/a mod evenMod
147.1243 + MutableBigInteger evenPart = modInverseMP2(powersOf2);
147.1244 +
147.1245 + // Combine the results using Chinese Remainder Theorem
147.1246 + MutableBigInteger y1 = modInverseBP2(oddMod, powersOf2);
147.1247 + MutableBigInteger y2 = oddMod.modInverseMP2(powersOf2);
147.1248 +
147.1249 + MutableBigInteger temp1 = new MutableBigInteger();
147.1250 + MutableBigInteger temp2 = new MutableBigInteger();
147.1251 + MutableBigInteger result = new MutableBigInteger();
147.1252 +
147.1253 + oddPart.leftShift(powersOf2);
147.1254 + oddPart.multiply(y1, result);
147.1255 +
147.1256 + evenPart.multiply(oddMod, temp1);
147.1257 + temp1.multiply(y2, temp2);
147.1258 +
147.1259 + result.add(temp2);
147.1260 + return result.divide(p, temp1);
147.1261 + }
147.1262 +
147.1263 + /*
147.1264 + * Calculate the multiplicative inverse of this mod 2^k.
147.1265 + */
147.1266 + MutableBigInteger modInverseMP2(int k) {
147.1267 + if (isEven())
147.1268 + throw new ArithmeticException("Non-invertible. (GCD != 1)");
147.1269 +
147.1270 + if (k > 64)
147.1271 + return euclidModInverse(k);
147.1272 +
147.1273 + int t = inverseMod32(value[offset+intLen-1]);
147.1274 +
147.1275 + if (k < 33) {
147.1276 + t = (k == 32 ? t : t & ((1 << k) - 1));
147.1277 + return new MutableBigInteger(t);
147.1278 + }
147.1279 +
147.1280 + long pLong = (value[offset+intLen-1] & LONG_MASK);
147.1281 + if (intLen > 1)
147.1282 + pLong |= ((long)value[offset+intLen-2] << 32);
147.1283 + long tLong = t & LONG_MASK;
147.1284 + tLong = tLong * (2 - pLong * tLong); // 1 more Newton iter step
147.1285 + tLong = (k == 64 ? tLong : tLong & ((1L << k) - 1));
147.1286 +
147.1287 + MutableBigInteger result = new MutableBigInteger(new int[2]);
147.1288 + result.value[0] = (int)(tLong >>> 32);
147.1289 + result.value[1] = (int)tLong;
147.1290 + result.intLen = 2;
147.1291 + result.normalize();
147.1292 + return result;
147.1293 + }
147.1294 +
147.1295 + /*
147.1296 + * Returns the multiplicative inverse of val mod 2^32. Assumes val is odd.
147.1297 + */
147.1298 + static int inverseMod32(int val) {
147.1299 + // Newton's iteration!
147.1300 + int t = val;
147.1301 + t *= 2 - val*t;
147.1302 + t *= 2 - val*t;
147.1303 + t *= 2 - val*t;
147.1304 + t *= 2 - val*t;
147.1305 + return t;
147.1306 + }
147.1307 +
147.1308 + /*
147.1309 + * Calculate the multiplicative inverse of 2^k mod mod, where mod is odd.
147.1310 + */
147.1311 + static MutableBigInteger modInverseBP2(MutableBigInteger mod, int k) {
147.1312 + // Copy the mod to protect original
147.1313 + return fixup(new MutableBigInteger(1), new MutableBigInteger(mod), k);
147.1314 + }
147.1315 +
147.1316 + /**
147.1317 + * Calculate the multiplicative inverse of this mod mod, where mod is odd.
147.1318 + * This and mod are not changed by the calculation.
147.1319 + *
147.1320 + * This method implements an algorithm due to Richard Schroeppel, that uses
147.1321 + * the same intermediate representation as Montgomery Reduction
147.1322 + * ("Montgomery Form"). The algorithm is described in an unpublished
147.1323 + * manuscript entitled "Fast Modular Reciprocals."
147.1324 + */
147.1325 + private MutableBigInteger modInverse(MutableBigInteger mod) {
147.1326 + MutableBigInteger p = new MutableBigInteger(mod);
147.1327 + MutableBigInteger f = new MutableBigInteger(this);
147.1328 + MutableBigInteger g = new MutableBigInteger(p);
147.1329 + SignedMutableBigInteger c = new SignedMutableBigInteger(1);
147.1330 + SignedMutableBigInteger d = new SignedMutableBigInteger();
147.1331 + MutableBigInteger temp = null;
147.1332 + SignedMutableBigInteger sTemp = null;
147.1333 +
147.1334 + int k = 0;
147.1335 + // Right shift f k times until odd, left shift d k times
147.1336 + if (f.isEven()) {
147.1337 + int trailingZeros = f.getLowestSetBit();
147.1338 + f.rightShift(trailingZeros);
147.1339 + d.leftShift(trailingZeros);
147.1340 + k = trailingZeros;
147.1341 + }
147.1342 +
147.1343 + // The Almost Inverse Algorithm
147.1344 + while(!f.isOne()) {
147.1345 + // If gcd(f, g) != 1, number is not invertible modulo mod
147.1346 + if (f.isZero())
147.1347 + throw new ArithmeticException("BigInteger not invertible.");
147.1348 +
147.1349 + // If f < g exchange f, g and c, d
147.1350 + if (f.compare(g) < 0) {
147.1351 + temp = f; f = g; g = temp;
147.1352 + sTemp = d; d = c; c = sTemp;
147.1353 + }
147.1354 +
147.1355 + // If f == g (mod 4)
147.1356 + if (((f.value[f.offset + f.intLen - 1] ^
147.1357 + g.value[g.offset + g.intLen - 1]) & 3) == 0) {
147.1358 + f.subtract(g);
147.1359 + c.signedSubtract(d);
147.1360 + } else { // If f != g (mod 4)
147.1361 + f.add(g);
147.1362 + c.signedAdd(d);
147.1363 + }
147.1364 +
147.1365 + // Right shift f k times until odd, left shift d k times
147.1366 + int trailingZeros = f.getLowestSetBit();
147.1367 + f.rightShift(trailingZeros);
147.1368 + d.leftShift(trailingZeros);
147.1369 + k += trailingZeros;
147.1370 + }
147.1371 +
147.1372 + while (c.sign < 0)
147.1373 + c.signedAdd(p);
147.1374 +
147.1375 + return fixup(c, p, k);
147.1376 + }
147.1377 +
147.1378 + /*
147.1379 + * The Fixup Algorithm
147.1380 + * Calculates X such that X = C * 2^(-k) (mod P)
147.1381 + * Assumes C<P and P is odd.
147.1382 + */
147.1383 + static MutableBigInteger fixup(MutableBigInteger c, MutableBigInteger p,
147.1384 + int k) {
147.1385 + MutableBigInteger temp = new MutableBigInteger();
147.1386 + // Set r to the multiplicative inverse of p mod 2^32
147.1387 + int r = -inverseMod32(p.value[p.offset+p.intLen-1]);
147.1388 +
147.1389 + for(int i=0, numWords = k >> 5; i<numWords; i++) {
147.1390 + // V = R * c (mod 2^j)
147.1391 + int v = r * c.value[c.offset + c.intLen-1];
147.1392 + // c = c + (v * p)
147.1393 + p.mul(v, temp);
147.1394 + c.add(temp);
147.1395 + // c = c / 2^j
147.1396 + c.intLen--;
147.1397 + }
147.1398 + int numBits = k & 0x1f;
147.1399 + if (numBits != 0) {
147.1400 + // V = R * c (mod 2^j)
147.1401 + int v = r * c.value[c.offset + c.intLen-1];
147.1402 + v &= ((1<<numBits) - 1);
147.1403 + // c = c + (v * p)
147.1404 + p.mul(v, temp);
147.1405 + c.add(temp);
147.1406 + // c = c / 2^j
147.1407 + c.rightShift(numBits);
147.1408 + }
147.1409 +
147.1410 + // In theory, c may be greater than p at this point (Very rare!)
147.1411 + while (c.compare(p) >= 0)
147.1412 + c.subtract(p);
147.1413 +
147.1414 + return c;
147.1415 + }
147.1416 +
147.1417 + /**
147.1418 + * Uses the extended Euclidean algorithm to compute the modInverse of base
147.1419 + * mod a modulus that is a power of 2. The modulus is 2^k.
147.1420 + */
147.1421 + MutableBigInteger euclidModInverse(int k) {
147.1422 + MutableBigInteger b = new MutableBigInteger(1);
147.1423 + b.leftShift(k);
147.1424 + MutableBigInteger mod = new MutableBigInteger(b);
147.1425 +
147.1426 + MutableBigInteger a = new MutableBigInteger(this);
147.1427 + MutableBigInteger q = new MutableBigInteger();
147.1428 + MutableBigInteger r = b.divide(a, q);
147.1429 +
147.1430 + MutableBigInteger swapper = b;
147.1431 + // swap b & r
147.1432 + b = r;
147.1433 + r = swapper;
147.1434 +
147.1435 + MutableBigInteger t1 = new MutableBigInteger(q);
147.1436 + MutableBigInteger t0 = new MutableBigInteger(1);
147.1437 + MutableBigInteger temp = new MutableBigInteger();
147.1438 +
147.1439 + while (!b.isOne()) {
147.1440 + r = a.divide(b, q);
147.1441 +
147.1442 + if (r.intLen == 0)
147.1443 + throw new ArithmeticException("BigInteger not invertible.");
147.1444 +
147.1445 + swapper = r;
147.1446 + a = swapper;
147.1447 +
147.1448 + if (q.intLen == 1)
147.1449 + t1.mul(q.value[q.offset], temp);
147.1450 + else
147.1451 + q.multiply(t1, temp);
147.1452 + swapper = q;
147.1453 + q = temp;
147.1454 + temp = swapper;
147.1455 + t0.add(q);
147.1456 +
147.1457 + if (a.isOne())
147.1458 + return t0;
147.1459 +
147.1460 + r = b.divide(a, q);
147.1461 +
147.1462 + if (r.intLen == 0)
147.1463 + throw new ArithmeticException("BigInteger not invertible.");
147.1464 +
147.1465 + swapper = b;
147.1466 + b = r;
147.1467 +
147.1468 + if (q.intLen == 1)
147.1469 + t0.mul(q.value[q.offset], temp);
147.1470 + else
147.1471 + q.multiply(t0, temp);
147.1472 + swapper = q; q = temp; temp = swapper;
147.1473 +
147.1474 + t1.add(q);
147.1475 + }
147.1476 + mod.subtract(t1);
147.1477 + return mod;
147.1478 + }
147.1479 +
147.1480 +}
148.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
148.2 +++ b/rt/emul/compact/src/main/java/java/math/RoundingMode.java Mon Oct 07 14:20:58 2013 +0200
148.3 @@ -0,0 +1,349 @@
148.4 +/*
148.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
148.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
148.7 + *
148.8 + * This code is free software; you can redistribute it and/or modify it
148.9 + * under the terms of the GNU General Public License version 2 only, as
148.10 + * published by the Free Software Foundation. Oracle designates this
148.11 + * particular file as subject to the "Classpath" exception as provided
148.12 + * by Oracle in the LICENSE file that accompanied this code.
148.13 + *
148.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
148.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
148.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
148.17 + * version 2 for more details (a copy is included in the LICENSE file that
148.18 + * accompanied this code).
148.19 + *
148.20 + * You should have received a copy of the GNU General Public License version
148.21 + * 2 along with this work; if not, write to the Free Software Foundation,
148.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
148.23 + *
148.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
148.25 + * or visit www.oracle.com if you need additional information or have any
148.26 + * questions.
148.27 + */
148.28 +
148.29 +/*
148.30 + * Portions Copyright IBM Corporation, 2001. All Rights Reserved.
148.31 + */
148.32 +package java.math;
148.33 +
148.34 +/**
148.35 + * Specifies a <i>rounding behavior</i> for numerical operations
148.36 + * capable of discarding precision. Each rounding mode indicates how
148.37 + * the least significant returned digit of a rounded result is to be
148.38 + * calculated. If fewer digits are returned than the digits needed to
148.39 + * represent the exact numerical result, the discarded digits will be
148.40 + * referred to as the <i>discarded fraction</i> regardless the digits'
148.41 + * contribution to the value of the number. In other words,
148.42 + * considered as a numerical value, the discarded fraction could have
148.43 + * an absolute value greater than one.
148.44 + *
148.45 + * <p>Each rounding mode description includes a table listing how
148.46 + * different two-digit decimal values would round to a one digit
148.47 + * decimal value under the rounding mode in question. The result
148.48 + * column in the tables could be gotten by creating a
148.49 + * {@code BigDecimal} number with the specified value, forming a
148.50 + * {@link MathContext} object with the proper settings
148.51 + * ({@code precision} set to {@code 1}, and the
148.52 + * {@code roundingMode} set to the rounding mode in question), and
148.53 + * calling {@link BigDecimal#round round} on this number with the
148.54 + * proper {@code MathContext}. A summary table showing the results
148.55 + * of these rounding operations for all rounding modes appears below.
148.56 + *
148.57 + *<p>
148.58 + *<table border>
148.59 + * <caption><b>Summary of Rounding Operations Under Different Rounding Modes</b></caption>
148.60 + * <tr><th></th><th colspan=8>Result of rounding input to one digit with the given
148.61 + * rounding mode</th>
148.62 + * <tr valign=top>
148.63 + * <th>Input Number</th> <th>{@code UP}</th>
148.64 + * <th>{@code DOWN}</th>
148.65 + * <th>{@code CEILING}</th>
148.66 + * <th>{@code FLOOR}</th>
148.67 + * <th>{@code HALF_UP}</th>
148.68 + * <th>{@code HALF_DOWN}</th>
148.69 + * <th>{@code HALF_EVEN}</th>
148.70 + * <th>{@code UNNECESSARY}</th>
148.71 + *
148.72 + * <tr align=right><td>5.5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>throw {@code ArithmeticException}</td>
148.73 + * <tr align=right><td>2.5</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
148.74 + * <tr align=right><td>1.6</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>2</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
148.75 + * <tr align=right><td>1.1</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>throw {@code ArithmeticException}</td>
148.76 + * <tr align=right><td>1.0</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td>
148.77 + * <tr align=right><td>-1.0</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td>
148.78 + * <tr align=right><td>-1.1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>throw {@code ArithmeticException}</td>
148.79 + * <tr align=right><td>-1.6</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
148.80 + * <tr align=right><td>-2.5</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>-3</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
148.81 + * <tr align=right><td>-5.5</td> <td>-6</td> <td>-5</td> <td>-5</td> <td>-6</td> <td>-6</td> <td>-5</td> <td>-6</td> <td>throw {@code ArithmeticException}</td>
148.82 + *</table>
148.83 + *
148.84 + *
148.85 + * <p>This {@code enum} is intended to replace the integer-based
148.86 + * enumeration of rounding mode constants in {@link BigDecimal}
148.87 + * ({@link BigDecimal#ROUND_UP}, {@link BigDecimal#ROUND_DOWN},
148.88 + * etc. ).
148.89 + *
148.90 + * @see BigDecimal
148.91 + * @see MathContext
148.92 + * @author Josh Bloch
148.93 + * @author Mike Cowlishaw
148.94 + * @author Joseph D. Darcy
148.95 + * @since 1.5
148.96 + */
148.97 +public enum RoundingMode {
148.98 +
148.99 + /**
148.100 + * Rounding mode to round away from zero. Always increments the
148.101 + * digit prior to a non-zero discarded fraction. Note that this
148.102 + * rounding mode never decreases the magnitude of the calculated
148.103 + * value.
148.104 + *
148.105 + *<p>Example:
148.106 + *<table border>
148.107 + *<tr valign=top><th>Input Number</th>
148.108 + * <th>Input rounded to one digit<br> with {@code UP} rounding
148.109 + *<tr align=right><td>5.5</td> <td>6</td>
148.110 + *<tr align=right><td>2.5</td> <td>3</td>
148.111 + *<tr align=right><td>1.6</td> <td>2</td>
148.112 + *<tr align=right><td>1.1</td> <td>2</td>
148.113 + *<tr align=right><td>1.0</td> <td>1</td>
148.114 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.115 + *<tr align=right><td>-1.1</td> <td>-2</td>
148.116 + *<tr align=right><td>-1.6</td> <td>-2</td>
148.117 + *<tr align=right><td>-2.5</td> <td>-3</td>
148.118 + *<tr align=right><td>-5.5</td> <td>-6</td>
148.119 + *</table>
148.120 + */
148.121 + UP(BigDecimal.ROUND_UP),
148.122 +
148.123 + /**
148.124 + * Rounding mode to round towards zero. Never increments the digit
148.125 + * prior to a discarded fraction (i.e., truncates). Note that this
148.126 + * rounding mode never increases the magnitude of the calculated value.
148.127 + *
148.128 + *<p>Example:
148.129 + *<table border>
148.130 + *<tr valign=top><th>Input Number</th>
148.131 + * <th>Input rounded to one digit<br> with {@code DOWN} rounding
148.132 + *<tr align=right><td>5.5</td> <td>5</td>
148.133 + *<tr align=right><td>2.5</td> <td>2</td>
148.134 + *<tr align=right><td>1.6</td> <td>1</td>
148.135 + *<tr align=right><td>1.1</td> <td>1</td>
148.136 + *<tr align=right><td>1.0</td> <td>1</td>
148.137 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.138 + *<tr align=right><td>-1.1</td> <td>-1</td>
148.139 + *<tr align=right><td>-1.6</td> <td>-1</td>
148.140 + *<tr align=right><td>-2.5</td> <td>-2</td>
148.141 + *<tr align=right><td>-5.5</td> <td>-5</td>
148.142 + *</table>
148.143 + */
148.144 + DOWN(BigDecimal.ROUND_DOWN),
148.145 +
148.146 + /**
148.147 + * Rounding mode to round towards positive infinity. If the
148.148 + * result is positive, behaves as for {@code RoundingMode.UP};
148.149 + * if negative, behaves as for {@code RoundingMode.DOWN}. Note
148.150 + * that this rounding mode never decreases the calculated value.
148.151 + *
148.152 + *<p>Example:
148.153 + *<table border>
148.154 + *<tr valign=top><th>Input Number</th>
148.155 + * <th>Input rounded to one digit<br> with {@code CEILING} rounding
148.156 + *<tr align=right><td>5.5</td> <td>6</td>
148.157 + *<tr align=right><td>2.5</td> <td>3</td>
148.158 + *<tr align=right><td>1.6</td> <td>2</td>
148.159 + *<tr align=right><td>1.1</td> <td>2</td>
148.160 + *<tr align=right><td>1.0</td> <td>1</td>
148.161 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.162 + *<tr align=right><td>-1.1</td> <td>-1</td>
148.163 + *<tr align=right><td>-1.6</td> <td>-1</td>
148.164 + *<tr align=right><td>-2.5</td> <td>-2</td>
148.165 + *<tr align=right><td>-5.5</td> <td>-5</td>
148.166 + *</table>
148.167 + */
148.168 + CEILING(BigDecimal.ROUND_CEILING),
148.169 +
148.170 + /**
148.171 + * Rounding mode to round towards negative infinity. If the
148.172 + * result is positive, behave as for {@code RoundingMode.DOWN};
148.173 + * if negative, behave as for {@code RoundingMode.UP}. Note that
148.174 + * this rounding mode never increases the calculated value.
148.175 + *
148.176 + *<p>Example:
148.177 + *<table border>
148.178 + *<tr valign=top><th>Input Number</th>
148.179 + * <th>Input rounded to one digit<br> with {@code FLOOR} rounding
148.180 + *<tr align=right><td>5.5</td> <td>5</td>
148.181 + *<tr align=right><td>2.5</td> <td>2</td>
148.182 + *<tr align=right><td>1.6</td> <td>1</td>
148.183 + *<tr align=right><td>1.1</td> <td>1</td>
148.184 + *<tr align=right><td>1.0</td> <td>1</td>
148.185 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.186 + *<tr align=right><td>-1.1</td> <td>-2</td>
148.187 + *<tr align=right><td>-1.6</td> <td>-2</td>
148.188 + *<tr align=right><td>-2.5</td> <td>-3</td>
148.189 + *<tr align=right><td>-5.5</td> <td>-6</td>
148.190 + *</table>
148.191 + */
148.192 + FLOOR(BigDecimal.ROUND_FLOOR),
148.193 +
148.194 + /**
148.195 + * Rounding mode to round towards {@literal "nearest neighbor"}
148.196 + * unless both neighbors are equidistant, in which case round up.
148.197 + * Behaves as for {@code RoundingMode.UP} if the discarded
148.198 + * fraction is ≥ 0.5; otherwise, behaves as for
148.199 + * {@code RoundingMode.DOWN}. Note that this is the rounding
148.200 + * mode commonly taught at school.
148.201 + *
148.202 + *<p>Example:
148.203 + *<table border>
148.204 + *<tr valign=top><th>Input Number</th>
148.205 + * <th>Input rounded to one digit<br> with {@code HALF_UP} rounding
148.206 + *<tr align=right><td>5.5</td> <td>6</td>
148.207 + *<tr align=right><td>2.5</td> <td>3</td>
148.208 + *<tr align=right><td>1.6</td> <td>2</td>
148.209 + *<tr align=right><td>1.1</td> <td>1</td>
148.210 + *<tr align=right><td>1.0</td> <td>1</td>
148.211 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.212 + *<tr align=right><td>-1.1</td> <td>-1</td>
148.213 + *<tr align=right><td>-1.6</td> <td>-2</td>
148.214 + *<tr align=right><td>-2.5</td> <td>-3</td>
148.215 + *<tr align=right><td>-5.5</td> <td>-6</td>
148.216 + *</table>
148.217 + */
148.218 + HALF_UP(BigDecimal.ROUND_HALF_UP),
148.219 +
148.220 + /**
148.221 + * Rounding mode to round towards {@literal "nearest neighbor"}
148.222 + * unless both neighbors are equidistant, in which case round
148.223 + * down. Behaves as for {@code RoundingMode.UP} if the discarded
148.224 + * fraction is > 0.5; otherwise, behaves as for
148.225 + * {@code RoundingMode.DOWN}.
148.226 + *
148.227 + *<p>Example:
148.228 + *<table border>
148.229 + *<tr valign=top><th>Input Number</th>
148.230 + * <th>Input rounded to one digit<br> with {@code HALF_DOWN} rounding
148.231 + *<tr align=right><td>5.5</td> <td>5</td>
148.232 + *<tr align=right><td>2.5</td> <td>2</td>
148.233 + *<tr align=right><td>1.6</td> <td>2</td>
148.234 + *<tr align=right><td>1.1</td> <td>1</td>
148.235 + *<tr align=right><td>1.0</td> <td>1</td>
148.236 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.237 + *<tr align=right><td>-1.1</td> <td>-1</td>
148.238 + *<tr align=right><td>-1.6</td> <td>-2</td>
148.239 + *<tr align=right><td>-2.5</td> <td>-2</td>
148.240 + *<tr align=right><td>-5.5</td> <td>-5</td>
148.241 + *</table>
148.242 + */
148.243 + HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
148.244 +
148.245 + /**
148.246 + * Rounding mode to round towards the {@literal "nearest neighbor"}
148.247 + * unless both neighbors are equidistant, in which case, round
148.248 + * towards the even neighbor. Behaves as for
148.249 + * {@code RoundingMode.HALF_UP} if the digit to the left of the
148.250 + * discarded fraction is odd; behaves as for
148.251 + * {@code RoundingMode.HALF_DOWN} if it's even. Note that this
148.252 + * is the rounding mode that statistically minimizes cumulative
148.253 + * error when applied repeatedly over a sequence of calculations.
148.254 + * It is sometimes known as {@literal "Banker's rounding,"} and is
148.255 + * chiefly used in the USA. This rounding mode is analogous to
148.256 + * the rounding policy used for {@code float} and {@code double}
148.257 + * arithmetic in Java.
148.258 + *
148.259 + *<p>Example:
148.260 + *<table border>
148.261 + *<tr valign=top><th>Input Number</th>
148.262 + * <th>Input rounded to one digit<br> with {@code HALF_EVEN} rounding
148.263 + *<tr align=right><td>5.5</td> <td>6</td>
148.264 + *<tr align=right><td>2.5</td> <td>2</td>
148.265 + *<tr align=right><td>1.6</td> <td>2</td>
148.266 + *<tr align=right><td>1.1</td> <td>1</td>
148.267 + *<tr align=right><td>1.0</td> <td>1</td>
148.268 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.269 + *<tr align=right><td>-1.1</td> <td>-1</td>
148.270 + *<tr align=right><td>-1.6</td> <td>-2</td>
148.271 + *<tr align=right><td>-2.5</td> <td>-2</td>
148.272 + *<tr align=right><td>-5.5</td> <td>-6</td>
148.273 + *</table>
148.274 + */
148.275 + HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
148.276 +
148.277 + /**
148.278 + * Rounding mode to assert that the requested operation has an exact
148.279 + * result, hence no rounding is necessary. If this rounding mode is
148.280 + * specified on an operation that yields an inexact result, an
148.281 + * {@code ArithmeticException} is thrown.
148.282 + *<p>Example:
148.283 + *<table border>
148.284 + *<tr valign=top><th>Input Number</th>
148.285 + * <th>Input rounded to one digit<br> with {@code UNNECESSARY} rounding
148.286 + *<tr align=right><td>5.5</td> <td>throw {@code ArithmeticException}</td>
148.287 + *<tr align=right><td>2.5</td> <td>throw {@code ArithmeticException}</td>
148.288 + *<tr align=right><td>1.6</td> <td>throw {@code ArithmeticException}</td>
148.289 + *<tr align=right><td>1.1</td> <td>throw {@code ArithmeticException}</td>
148.290 + *<tr align=right><td>1.0</td> <td>1</td>
148.291 + *<tr align=right><td>-1.0</td> <td>-1</td>
148.292 + *<tr align=right><td>-1.1</td> <td>throw {@code ArithmeticException}</td>
148.293 + *<tr align=right><td>-1.6</td> <td>throw {@code ArithmeticException}</td>
148.294 + *<tr align=right><td>-2.5</td> <td>throw {@code ArithmeticException}</td>
148.295 + *<tr align=right><td>-5.5</td> <td>throw {@code ArithmeticException}</td>
148.296 + *</table>
148.297 + */
148.298 + UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
148.299 +
148.300 + // Corresponding BigDecimal rounding constant
148.301 + final int oldMode;
148.302 +
148.303 + /**
148.304 + * Constructor
148.305 + *
148.306 + * @param oldMode The {@code BigDecimal} constant corresponding to
148.307 + * this mode
148.308 + */
148.309 + private RoundingMode(int oldMode) {
148.310 + this.oldMode = oldMode;
148.311 + }
148.312 +
148.313 + /**
148.314 + * Returns the {@code RoundingMode} object corresponding to a
148.315 + * legacy integer rounding mode constant in {@link BigDecimal}.
148.316 + *
148.317 + * @param rm legacy integer rounding mode to convert
148.318 + * @return {@code RoundingMode} corresponding to the given integer.
148.319 + * @throws IllegalArgumentException integer is out of range
148.320 + */
148.321 + public static RoundingMode valueOf(int rm) {
148.322 + switch(rm) {
148.323 +
148.324 + case BigDecimal.ROUND_UP:
148.325 + return UP;
148.326 +
148.327 + case BigDecimal.ROUND_DOWN:
148.328 + return DOWN;
148.329 +
148.330 + case BigDecimal.ROUND_CEILING:
148.331 + return CEILING;
148.332 +
148.333 + case BigDecimal.ROUND_FLOOR:
148.334 + return FLOOR;
148.335 +
148.336 + case BigDecimal.ROUND_HALF_UP:
148.337 + return HALF_UP;
148.338 +
148.339 + case BigDecimal.ROUND_HALF_DOWN:
148.340 + return HALF_DOWN;
148.341 +
148.342 + case BigDecimal.ROUND_HALF_EVEN:
148.343 + return HALF_EVEN;
148.344 +
148.345 + case BigDecimal.ROUND_UNNECESSARY:
148.346 + return UNNECESSARY;
148.347 +
148.348 + default:
148.349 + throw new IllegalArgumentException("argument out of range");
148.350 + }
148.351 + }
148.352 +}
149.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
149.2 +++ b/rt/emul/compact/src/main/java/java/math/SignedMutableBigInteger.java Mon Oct 07 14:20:58 2013 +0200
149.3 @@ -0,0 +1,135 @@
149.4 +/*
149.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
149.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
149.7 + *
149.8 + * This code is free software; you can redistribute it and/or modify it
149.9 + * under the terms of the GNU General Public License version 2 only, as
149.10 + * published by the Free Software Foundation. Oracle designates this
149.11 + * particular file as subject to the "Classpath" exception as provided
149.12 + * by Oracle in the LICENSE file that accompanied this code.
149.13 + *
149.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
149.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
149.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
149.17 + * version 2 for more details (a copy is included in the LICENSE file that
149.18 + * accompanied this code).
149.19 + *
149.20 + * You should have received a copy of the GNU General Public License version
149.21 + * 2 along with this work; if not, write to the Free Software Foundation,
149.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
149.23 + *
149.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
149.25 + * or visit www.oracle.com if you need additional information or have any
149.26 + * questions.
149.27 + */
149.28 +
149.29 +package java.math;
149.30 +
149.31 +/**
149.32 + * A class used to represent multiprecision integers that makes efficient
149.33 + * use of allocated space by allowing a number to occupy only part of
149.34 + * an array so that the arrays do not have to be reallocated as often.
149.35 + * When performing an operation with many iterations the array used to
149.36 + * hold a number is only increased when necessary and does not have to
149.37 + * be the same size as the number it represents. A mutable number allows
149.38 + * calculations to occur on the same number without having to create
149.39 + * a new number for every step of the calculation as occurs with
149.40 + * BigIntegers.
149.41 + *
149.42 + * Note that SignedMutableBigIntegers only support signed addition and
149.43 + * subtraction. All other operations occur as with MutableBigIntegers.
149.44 + *
149.45 + * @see BigInteger
149.46 + * @author Michael McCloskey
149.47 + * @since 1.3
149.48 + */
149.49 +
149.50 +class SignedMutableBigInteger extends MutableBigInteger {
149.51 +
149.52 + /**
149.53 + * The sign of this MutableBigInteger.
149.54 + */
149.55 + int sign = 1;
149.56 +
149.57 + // Constructors
149.58 +
149.59 + /**
149.60 + * The default constructor. An empty MutableBigInteger is created with
149.61 + * a one word capacity.
149.62 + */
149.63 + SignedMutableBigInteger() {
149.64 + super();
149.65 + }
149.66 +
149.67 + /**
149.68 + * Construct a new MutableBigInteger with a magnitude specified by
149.69 + * the int val.
149.70 + */
149.71 + SignedMutableBigInteger(int val) {
149.72 + super(val);
149.73 + }
149.74 +
149.75 + /**
149.76 + * Construct a new MutableBigInteger with a magnitude equal to the
149.77 + * specified MutableBigInteger.
149.78 + */
149.79 + SignedMutableBigInteger(MutableBigInteger val) {
149.80 + super(val);
149.81 + }
149.82 +
149.83 + // Arithmetic Operations
149.84 +
149.85 + /**
149.86 + * Signed addition built upon unsigned add and subtract.
149.87 + */
149.88 + void signedAdd(SignedMutableBigInteger addend) {
149.89 + if (sign == addend.sign)
149.90 + add(addend);
149.91 + else
149.92 + sign = sign * subtract(addend);
149.93 +
149.94 + }
149.95 +
149.96 + /**
149.97 + * Signed addition built upon unsigned add and subtract.
149.98 + */
149.99 + void signedAdd(MutableBigInteger addend) {
149.100 + if (sign == 1)
149.101 + add(addend);
149.102 + else
149.103 + sign = sign * subtract(addend);
149.104 +
149.105 + }
149.106 +
149.107 + /**
149.108 + * Signed subtraction built upon unsigned add and subtract.
149.109 + */
149.110 + void signedSubtract(SignedMutableBigInteger addend) {
149.111 + if (sign == addend.sign)
149.112 + sign = sign * subtract(addend);
149.113 + else
149.114 + add(addend);
149.115 +
149.116 + }
149.117 +
149.118 + /**
149.119 + * Signed subtraction built upon unsigned add and subtract.
149.120 + */
149.121 + void signedSubtract(MutableBigInteger addend) {
149.122 + if (sign == 1)
149.123 + sign = sign * subtract(addend);
149.124 + else
149.125 + add(addend);
149.126 + if (intLen == 0)
149.127 + sign = 1;
149.128 + }
149.129 +
149.130 + /**
149.131 + * Print out the first intLen ints of this MutableBigInteger's value
149.132 + * array starting at offset.
149.133 + */
149.134 + public String toString() {
149.135 + return this.toBigInteger(sign).toString();
149.136 + }
149.137 +
149.138 +}
150.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
150.2 +++ b/rt/emul/compact/src/main/java/java/math/package-info.java Mon Oct 07 14:20:58 2013 +0200
150.3 @@ -0,0 +1,45 @@
150.4 +/*
150.5 + * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
150.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
150.7 + *
150.8 + * This code is free software; you can redistribute it and/or modify it
150.9 + * under the terms of the GNU General Public License version 2 only, as
150.10 + * published by the Free Software Foundation. Oracle designates this
150.11 + * particular file as subject to the "Classpath" exception as provided
150.12 + * by Oracle in the LICENSE file that accompanied this code.
150.13 + *
150.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
150.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
150.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
150.17 + * version 2 for more details (a copy is included in the LICENSE file that
150.18 + * accompanied this code).
150.19 + *
150.20 + * You should have received a copy of the GNU General Public License version
150.21 + * 2 along with this work; if not, write to the Free Software Foundation,
150.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
150.23 + *
150.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
150.25 + * or visit www.oracle.com if you need additional information or have any
150.26 + * questions.
150.27 + */
150.28 +
150.29 +/**
150.30 + * Provides classes for performing arbitrary-precision integer
150.31 + * arithmetic ({@code BigInteger}) and arbitrary-precision decimal
150.32 + * arithmetic ({@code BigDecimal}). {@code BigInteger} is analogous
150.33 + * to the primitive integer types except that it provides arbitrary
150.34 + * precision, hence operations on {@code BigInteger}s do not overflow
150.35 + * or lose precision. In addition to standard arithmetic operations,
150.36 + * {@code BigInteger} provides modular arithmetic, GCD calculation,
150.37 + * primality testing, prime generation, bit manipulation, and a few
150.38 + * other miscellaneous operations.
150.39 + *
150.40 + * {@code BigDecimal} provides arbitrary-precision signed decimal
150.41 + * numbers suitable for currency calculations and the like. {@code
150.42 + * BigDecimal} gives the user complete control over rounding behavior,
150.43 + * allowing the user to choose from a comprehensive set of eight
150.44 + * rounding modes.
150.45 + *
150.46 + * @since JDK1.1
150.47 + */
150.48 +package java.math;
151.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
151.2 +++ b/rt/emul/compact/src/main/java/java/net/URI.java Mon Oct 07 14:20:58 2013 +0200
151.3 @@ -0,0 +1,3520 @@
151.4 +/*
151.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
151.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
151.7 + *
151.8 + * This code is free software; you can redistribute it and/or modify it
151.9 + * under the terms of the GNU General Public License version 2 only, as
151.10 + * published by the Free Software Foundation. Oracle designates this
151.11 + * particular file as subject to the "Classpath" exception as provided
151.12 + * by Oracle in the LICENSE file that accompanied this code.
151.13 + *
151.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
151.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
151.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151.17 + * version 2 for more details (a copy is included in the LICENSE file that
151.18 + * accompanied this code).
151.19 + *
151.20 + * You should have received a copy of the GNU General Public License version
151.21 + * 2 along with this work; if not, write to the Free Software Foundation,
151.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
151.23 + *
151.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
151.25 + * or visit www.oracle.com if you need additional information or have any
151.26 + * questions.
151.27 + */
151.28 +
151.29 +package java.net;
151.30 +
151.31 +import java.io.IOException;
151.32 +import java.io.InvalidObjectException;
151.33 +import java.io.ObjectInputStream;
151.34 +import java.io.ObjectOutputStream;
151.35 +import java.io.Serializable;
151.36 +
151.37 +import java.lang.Character; // for javadoc
151.38 +import java.lang.NullPointerException; // for javadoc
151.39 +
151.40 +
151.41 +/**
151.42 + * Represents a Uniform Resource Identifier (URI) reference.
151.43 + *
151.44 + * <p> Aside from some minor deviations noted below, an instance of this
151.45 + * class represents a URI reference as defined by
151.46 + * <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC 2396: Uniform
151.47 + * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
151.48 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format for
151.49 + * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
151.50 + * also supports scope_ids. The syntax and usage of scope_ids is described
151.51 + * <a href="Inet6Address.html#scoped">here</a>.
151.52 + * This class provides constructors for creating URI instances from
151.53 + * their components or by parsing their string forms, methods for accessing the
151.54 + * various components of an instance, and methods for normalizing, resolving,
151.55 + * and relativizing URI instances. Instances of this class are immutable.
151.56 + *
151.57 + *
151.58 + * <h4> URI syntax and components </h4>
151.59 + *
151.60 + * At the highest level a URI reference (hereinafter simply "URI") in string
151.61 + * form has the syntax
151.62 + *
151.63 + * <blockquote>
151.64 + * [<i>scheme</i><tt><b>:</b></tt><i></i>]<i>scheme-specific-part</i>[<tt><b>#</b></tt><i>fragment</i>]
151.65 + * </blockquote>
151.66 + *
151.67 + * where square brackets [...] delineate optional components and the characters
151.68 + * <tt><b>:</b></tt> and <tt><b>#</b></tt> stand for themselves.
151.69 + *
151.70 + * <p> An <i>absolute</i> URI specifies a scheme; a URI that is not absolute is
151.71 + * said to be <i>relative</i>. URIs are also classified according to whether
151.72 + * they are <i>opaque</i> or <i>hierarchical</i>.
151.73 + *
151.74 + * <p> An <i>opaque</i> URI is an absolute URI whose scheme-specific part does
151.75 + * not begin with a slash character (<tt>'/'</tt>). Opaque URIs are not
151.76 + * subject to further parsing. Some examples of opaque URIs are:
151.77 + *
151.78 + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
151.79 + * <tr><td><tt>mailto:java-net@java.sun.com</tt><td></tr>
151.80 + * <tr><td><tt>news:comp.lang.java</tt><td></tr>
151.81 + * <tr><td><tt>urn:isbn:096139210x</tt></td></tr>
151.82 + * </table></blockquote>
151.83 + *
151.84 + * <p> A <i>hierarchical</i> URI is either an absolute URI whose
151.85 + * scheme-specific part begins with a slash character, or a relative URI, that
151.86 + * is, a URI that does not specify a scheme. Some examples of hierarchical
151.87 + * URIs are:
151.88 + *
151.89 + * <blockquote>
151.90 + * <tt>http://java.sun.com/j2se/1.3/</tt><br>
151.91 + * <tt>docs/guide/collections/designfaq.html#28</tt><br>
151.92 + * <tt>../../../demo/jfc/SwingSet2/src/SwingSet2.java</tt><br>
151.93 + * <tt>file:///~/calendar</tt>
151.94 + * </blockquote>
151.95 + *
151.96 + * <p> A hierarchical URI is subject to further parsing according to the syntax
151.97 + *
151.98 + * <blockquote>
151.99 + * [<i>scheme</i><tt><b>:</b></tt>][<tt><b>//</b></tt><i>authority</i>][<i>path</i>][<tt><b>?</b></tt><i>query</i>][<tt><b>#</b></tt><i>fragment</i>]
151.100 + * </blockquote>
151.101 + *
151.102 + * where the characters <tt><b>:</b></tt>, <tt><b>/</b></tt>,
151.103 + * <tt><b>?</b></tt>, and <tt><b>#</b></tt> stand for themselves. The
151.104 + * scheme-specific part of a hierarchical URI consists of the characters
151.105 + * between the scheme and fragment components.
151.106 + *
151.107 + * <p> The authority component of a hierarchical URI is, if specified, either
151.108 + * <i>server-based</i> or <i>registry-based</i>. A server-based authority
151.109 + * parses according to the familiar syntax
151.110 + *
151.111 + * <blockquote>
151.112 + * [<i>user-info</i><tt><b>@</b></tt>]<i>host</i>[<tt><b>:</b></tt><i>port</i>]
151.113 + * </blockquote>
151.114 + *
151.115 + * where the characters <tt><b>@</b></tt> and <tt><b>:</b></tt> stand for
151.116 + * themselves. Nearly all URI schemes currently in use are server-based. An
151.117 + * authority component that does not parse in this way is considered to be
151.118 + * registry-based.
151.119 + *
151.120 + * <p> The path component of a hierarchical URI is itself said to be absolute
151.121 + * if it begins with a slash character (<tt>'/'</tt>); otherwise it is
151.122 + * relative. The path of a hierarchical URI that is either absolute or
151.123 + * specifies an authority is always absolute.
151.124 + *
151.125 + * <p> All told, then, a URI instance has the following nine components:
151.126 + *
151.127 + * <blockquote><table summary="Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment">
151.128 + * <tr><th><i>Component</i></th><th><i>Type</i></th></tr>
151.129 + * <tr><td>scheme</td><td><tt>String</tt></td></tr>
151.130 + * <tr><td>scheme-specific-part </td><td><tt>String</tt></td></tr>
151.131 + * <tr><td>authority</td><td><tt>String</tt></td></tr>
151.132 + * <tr><td>user-info</td><td><tt>String</tt></td></tr>
151.133 + * <tr><td>host</td><td><tt>String</tt></td></tr>
151.134 + * <tr><td>port</td><td><tt>int</tt></td></tr>
151.135 + * <tr><td>path</td><td><tt>String</tt></td></tr>
151.136 + * <tr><td>query</td><td><tt>String</tt></td></tr>
151.137 + * <tr><td>fragment</td><td><tt>String</tt></td></tr>
151.138 + * </table></blockquote>
151.139 + *
151.140 + * In a given instance any particular component is either <i>undefined</i> or
151.141 + * <i>defined</i> with a distinct value. Undefined string components are
151.142 + * represented by <tt>null</tt>, while undefined integer components are
151.143 + * represented by <tt>-1</tt>. A string component may be defined to have the
151.144 + * empty string as its value; this is not equivalent to that component being
151.145 + * undefined.
151.146 + *
151.147 + * <p> Whether a particular component is or is not defined in an instance
151.148 + * depends upon the type of the URI being represented. An absolute URI has a
151.149 + * scheme component. An opaque URI has a scheme, a scheme-specific part, and
151.150 + * possibly a fragment, but has no other components. A hierarchical URI always
151.151 + * has a path (though it may be empty) and a scheme-specific-part (which at
151.152 + * least contains the path), and may have any of the other components. If the
151.153 + * authority component is present and is server-based then the host component
151.154 + * will be defined and the user-information and port components may be defined.
151.155 + *
151.156 + *
151.157 + * <h4> Operations on URI instances </h4>
151.158 + *
151.159 + * The key operations supported by this class are those of
151.160 + * <i>normalization</i>, <i>resolution</i>, and <i>relativization</i>.
151.161 + *
151.162 + * <p> <i>Normalization</i> is the process of removing unnecessary <tt>"."</tt>
151.163 + * and <tt>".."</tt> segments from the path component of a hierarchical URI.
151.164 + * Each <tt>"."</tt> segment is simply removed. A <tt>".."</tt> segment is
151.165 + * removed only if it is preceded by a non-<tt>".."</tt> segment.
151.166 + * Normalization has no effect upon opaque URIs.
151.167 + *
151.168 + * <p> <i>Resolution</i> is the process of resolving one URI against another,
151.169 + * <i>base</i> URI. The resulting URI is constructed from components of both
151.170 + * URIs in the manner specified by RFC 2396, taking components from the
151.171 + * base URI for those not specified in the original. For hierarchical URIs,
151.172 + * the path of the original is resolved against the path of the base and then
151.173 + * normalized. The result, for example, of resolving
151.174 + *
151.175 + * <blockquote>
151.176 + * <tt>docs/guide/collections/designfaq.html#28 </tt>(1)
151.177 + * </blockquote>
151.178 + *
151.179 + * against the base URI <tt>http://java.sun.com/j2se/1.3/</tt> is the result
151.180 + * URI
151.181 + *
151.182 + * <blockquote>
151.183 + * <tt>http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28</tt>
151.184 + * </blockquote>
151.185 + *
151.186 + * Resolving the relative URI
151.187 + *
151.188 + * <blockquote>
151.189 + * <tt>../../../demo/jfc/SwingSet2/src/SwingSet2.java </tt>(2)
151.190 + * </blockquote>
151.191 + *
151.192 + * against this result yields, in turn,
151.193 + *
151.194 + * <blockquote>
151.195 + * <tt>http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java</tt>
151.196 + * </blockquote>
151.197 + *
151.198 + * Resolution of both absolute and relative URIs, and of both absolute and
151.199 + * relative paths in the case of hierarchical URIs, is supported. Resolving
151.200 + * the URI <tt>file:///~calendar</tt> against any other URI simply yields the
151.201 + * original URI, since it is absolute. Resolving the relative URI (2) above
151.202 + * against the relative base URI (1) yields the normalized, but still relative,
151.203 + * URI
151.204 + *
151.205 + * <blockquote>
151.206 + * <tt>demo/jfc/SwingSet2/src/SwingSet2.java</tt>
151.207 + * </blockquote>
151.208 + *
151.209 + * <p> <i>Relativization</i>, finally, is the inverse of resolution: For any
151.210 + * two normalized URIs <i>u</i> and <i>v</i>,
151.211 + *
151.212 + * <blockquote>
151.213 + * <i>u</i><tt>.relativize(</tt><i>u</i><tt>.resolve(</tt><i>v</i><tt>)).equals(</tt><i>v</i><tt>)</tt> and<br>
151.214 + * <i>u</i><tt>.resolve(</tt><i>u</i><tt>.relativize(</tt><i>v</i><tt>)).equals(</tt><i>v</i><tt>)</tt> .<br>
151.215 + * </blockquote>
151.216 + *
151.217 + * This operation is often useful when constructing a document containing URIs
151.218 + * that must be made relative to the base URI of the document wherever
151.219 + * possible. For example, relativizing the URI
151.220 + *
151.221 + * <blockquote>
151.222 + * <tt>http://java.sun.com/j2se/1.3/docs/guide/index.html</tt>
151.223 + * </blockquote>
151.224 + *
151.225 + * against the base URI
151.226 + *
151.227 + * <blockquote>
151.228 + * <tt>http://java.sun.com/j2se/1.3</tt>
151.229 + * </blockquote>
151.230 + *
151.231 + * yields the relative URI <tt>docs/guide/index.html</tt>.
151.232 + *
151.233 + *
151.234 + * <h4> Character categories </h4>
151.235 + *
151.236 + * RFC 2396 specifies precisely which characters are permitted in the
151.237 + * various components of a URI reference. The following categories, most of
151.238 + * which are taken from that specification, are used below to describe these
151.239 + * constraints:
151.240 + *
151.241 + * <blockquote><table cellspacing=2 summary="Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other">
151.242 + * <tr><th valign=top><i>alpha</i></th>
151.243 + * <td>The US-ASCII alphabetic characters,
151.244 + * <tt>'A'</tt> through <tt>'Z'</tt>
151.245 + * and <tt>'a'</tt> through <tt>'z'</tt></td></tr>
151.246 + * <tr><th valign=top><i>digit</i></th>
151.247 + * <td>The US-ASCII decimal digit characters,
151.248 + * <tt>'0'</tt> through <tt>'9'</tt></td></tr>
151.249 + * <tr><th valign=top><i>alphanum</i></th>
151.250 + * <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
151.251 + * <tr><th valign=top><i>unreserved</i> </th>
151.252 + * <td>All <i>alphanum</i> characters together with those in the string
151.253 + * <tt>"_-!.~'()*"</tt></td></tr>
151.254 + * <tr><th valign=top><i>punct</i></th>
151.255 + * <td>The characters in the string <tt>",;:$&+="</tt></td></tr>
151.256 + * <tr><th valign=top><i>reserved</i></th>
151.257 + * <td>All <i>punct</i> characters together with those in the string
151.258 + * <tt>"?/[]@"</tt></td></tr>
151.259 + * <tr><th valign=top><i>escaped</i></th>
151.260 + * <td>Escaped octets, that is, triplets consisting of the percent
151.261 + * character (<tt>'%'</tt>) followed by two hexadecimal digits
151.262 + * (<tt>'0'</tt>-<tt>'9'</tt>, <tt>'A'</tt>-<tt>'F'</tt>, and
151.263 + * <tt>'a'</tt>-<tt>'f'</tt>)</td></tr>
151.264 + * <tr><th valign=top><i>other</i></th>
151.265 + * <td>The Unicode characters that are not in the US-ASCII character set,
151.266 + * are not control characters (according to the {@link
151.267 + * java.lang.Character#isISOControl(char) Character.isISOControl}
151.268 + * method), and are not space characters (according to the {@link
151.269 + * java.lang.Character#isSpaceChar(char) Character.isSpaceChar}
151.270 + * method) <i>(<b>Deviation from RFC 2396</b>, which is
151.271 + * limited to US-ASCII)</i></td></tr>
151.272 + * </table></blockquote>
151.273 + *
151.274 + * <p><a name="legal-chars"></a> The set of all legal URI characters consists of
151.275 + * the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>
151.276 + * characters.
151.277 + *
151.278 + *
151.279 + * <h4> Escaped octets, quotation, encoding, and decoding </h4>
151.280 + *
151.281 + * RFC 2396 allows escaped octets to appear in the user-info, path, query, and
151.282 + * fragment components. Escaping serves two purposes in URIs:
151.283 + *
151.284 + * <ul>
151.285 + *
151.286 + * <li><p> To <i>encode</i> non-US-ASCII characters when a URI is required to
151.287 + * conform strictly to RFC 2396 by not containing any <i>other</i>
151.288 + * characters. </p></li>
151.289 + *
151.290 + * <li><p> To <i>quote</i> characters that are otherwise illegal in a
151.291 + * component. The user-info, path, query, and fragment components differ
151.292 + * slightly in terms of which characters are considered legal and illegal.
151.293 + * </p></li>
151.294 + *
151.295 + * </ul>
151.296 + *
151.297 + * These purposes are served in this class by three related operations:
151.298 + *
151.299 + * <ul>
151.300 + *
151.301 + * <li><p><a name="encode"></a> A character is <i>encoded</i> by replacing it
151.302 + * with the sequence of escaped octets that represent that character in the
151.303 + * UTF-8 character set. The Euro currency symbol (<tt>'\u20AC'</tt>),
151.304 + * for example, is encoded as <tt>"%E2%82%AC"</tt>. <i>(<b>Deviation from
151.305 + * RFC 2396</b>, which does not specify any particular character
151.306 + * set.)</i> </p></li>
151.307 + *
151.308 + * <li><p><a name="quote"></a> An illegal character is <i>quoted</i> simply by
151.309 + * encoding it. The space character, for example, is quoted by replacing it
151.310 + * with <tt>"%20"</tt>. UTF-8 contains US-ASCII, hence for US-ASCII
151.311 + * characters this transformation has exactly the effect required by
151.312 + * RFC 2396. </p></li>
151.313 + *
151.314 + * <li><p><a name="decode"></a>
151.315 + * A sequence of escaped octets is <i>decoded</i> by
151.316 + * replacing it with the sequence of characters that it represents in the
151.317 + * UTF-8 character set. UTF-8 contains US-ASCII, hence decoding has the
151.318 + * effect of de-quoting any quoted US-ASCII characters as well as that of
151.319 + * decoding any encoded non-US-ASCII characters. If a <a
151.320 + * href="../nio/charset/CharsetDecoder.html#ce">decoding error</a> occurs
151.321 + * when decoding the escaped octets then the erroneous octets are replaced by
151.322 + * <tt>'\uFFFD'</tt>, the Unicode replacement character. </p></li>
151.323 + *
151.324 + * </ul>
151.325 + *
151.326 + * These operations are exposed in the constructors and methods of this class
151.327 + * as follows:
151.328 + *
151.329 + * <ul>
151.330 + *
151.331 + * <li><p> The {@link #URI(java.lang.String) <code>single-argument
151.332 + * constructor</code>} requires any illegal characters in its argument to be
151.333 + * quoted and preserves any escaped octets and <i>other</i> characters that
151.334 + * are present. </p></li>
151.335 + *
151.336 + * <li><p> The {@link
151.337 + * #URI(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
151.338 + * <code>multi-argument constructors</code>} quote illegal characters as
151.339 + * required by the components in which they appear. The percent character
151.340 + * (<tt>'%'</tt>) is always quoted by these constructors. Any <i>other</i>
151.341 + * characters are preserved. </p></li>
151.342 + *
151.343 + * <li><p> The {@link #getRawUserInfo() getRawUserInfo}, {@link #getRawPath()
151.344 + * getRawPath}, {@link #getRawQuery() getRawQuery}, {@link #getRawFragment()
151.345 + * getRawFragment}, {@link #getRawAuthority() getRawAuthority}, and {@link
151.346 + * #getRawSchemeSpecificPart() getRawSchemeSpecificPart} methods return the
151.347 + * values of their corresponding components in raw form, without interpreting
151.348 + * any escaped octets. The strings returned by these methods may contain
151.349 + * both escaped octets and <i>other</i> characters, and will not contain any
151.350 + * illegal characters. </p></li>
151.351 + *
151.352 + * <li><p> The {@link #getUserInfo() getUserInfo}, {@link #getPath()
151.353 + * getPath}, {@link #getQuery() getQuery}, {@link #getFragment()
151.354 + * getFragment}, {@link #getAuthority() getAuthority}, and {@link
151.355 + * #getSchemeSpecificPart() getSchemeSpecificPart} methods decode any escaped
151.356 + * octets in their corresponding components. The strings returned by these
151.357 + * methods may contain both <i>other</i> characters and illegal characters,
151.358 + * and will not contain any escaped octets. </p></li>
151.359 + *
151.360 + * <li><p> The {@link #toString() toString} method returns a URI string with
151.361 + * all necessary quotation but which may contain <i>other</i> characters.
151.362 + * </p></li>
151.363 + *
151.364 + * <li><p> The {@link #toASCIIString() toASCIIString} method returns a fully
151.365 + * quoted and encoded URI string that does not contain any <i>other</i>
151.366 + * characters. </p></li>
151.367 + *
151.368 + * </ul>
151.369 + *
151.370 + *
151.371 + * <h4> Identities </h4>
151.372 + *
151.373 + * For any URI <i>u</i>, it is always the case that
151.374 + *
151.375 + * <blockquote>
151.376 + * <tt>new URI(</tt><i>u</i><tt>.toString()).equals(</tt><i>u</i><tt>)</tt> .
151.377 + * </blockquote>
151.378 + *
151.379 + * For any URI <i>u</i> that does not contain redundant syntax such as two
151.380 + * slashes before an empty authority (as in <tt>file:///tmp/</tt> ) or a
151.381 + * colon following a host name but no port (as in
151.382 + * <tt>http://java.sun.com:</tt> ), and that does not encode characters
151.383 + * except those that must be quoted, the following identities also hold:
151.384 + *
151.385 + * <blockquote>
151.386 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
151.387 + * </tt><i>u</i><tt>.getSchemeSpecificPart(),<br>
151.388 + * </tt><i>u</i><tt>.getFragment())<br>
151.389 + * .equals(</tt><i>u</i><tt>)</tt>
151.390 + * </blockquote>
151.391 + *
151.392 + * in all cases,
151.393 + *
151.394 + * <blockquote>
151.395 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
151.396 + * </tt><i>u</i><tt>.getUserInfo(), </tt><i>u</i><tt>.getAuthority(),<br>
151.397 + * </tt><i>u</i><tt>.getPath(), </tt><i>u</i><tt>.getQuery(),<br>
151.398 + * </tt><i>u</i><tt>.getFragment())<br>
151.399 + * .equals(</tt><i>u</i><tt>)</tt>
151.400 + * </blockquote>
151.401 + *
151.402 + * if <i>u</i> is hierarchical, and
151.403 + *
151.404 + * <blockquote>
151.405 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
151.406 + * </tt><i>u</i><tt>.getUserInfo(), </tt><i>u</i><tt>.getHost(), </tt><i>u</i><tt>.getPort(),<br>
151.407 + * </tt><i>u</i><tt>.getPath(), </tt><i>u</i><tt>.getQuery(),<br>
151.408 + * </tt><i>u</i><tt>.getFragment())<br>
151.409 + * .equals(</tt><i>u</i><tt>)</tt>
151.410 + * </blockquote>
151.411 + *
151.412 + * if <i>u</i> is hierarchical and has either no authority or a server-based
151.413 + * authority.
151.414 + *
151.415 + *
151.416 + * <h4> URIs, URLs, and URNs </h4>
151.417 + *
151.418 + * A URI is a uniform resource <i>identifier</i> while a URL is a uniform
151.419 + * resource <i>locator</i>. Hence every URL is a URI, abstractly speaking, but
151.420 + * not every URI is a URL. This is because there is another subcategory of
151.421 + * URIs, uniform resource <i>names</i> (URNs), which name resources but do not
151.422 + * specify how to locate them. The <tt>mailto</tt>, <tt>news</tt>, and
151.423 + * <tt>isbn</tt> URIs shown above are examples of URNs.
151.424 + *
151.425 + * <p> The conceptual distinction between URIs and URLs is reflected in the
151.426 + * differences between this class and the {@link URL} class.
151.427 + *
151.428 + * <p> An instance of this class represents a URI reference in the syntactic
151.429 + * sense defined by RFC 2396. A URI may be either absolute or relative.
151.430 + * A URI string is parsed according to the generic syntax without regard to the
151.431 + * scheme, if any, that it specifies. No lookup of the host, if any, is
151.432 + * performed, and no scheme-dependent stream handler is constructed. Equality,
151.433 + * hashing, and comparison are defined strictly in terms of the character
151.434 + * content of the instance. In other words, a URI instance is little more than
151.435 + * a structured string that supports the syntactic, scheme-independent
151.436 + * operations of comparison, normalization, resolution, and relativization.
151.437 + *
151.438 + * <p> An instance of the {@link URL} class, by contrast, represents the
151.439 + * syntactic components of a URL together with some of the information required
151.440 + * to access the resource that it describes. A URL must be absolute, that is,
151.441 + * it must always specify a scheme. A URL string is parsed according to its
151.442 + * scheme. A stream handler is always established for a URL, and in fact it is
151.443 + * impossible to create a URL instance for a scheme for which no handler is
151.444 + * available. Equality and hashing depend upon both the scheme and the
151.445 + * Internet address of the host, if any; comparison is not defined. In other
151.446 + * words, a URL is a structured string that supports the syntactic operation of
151.447 + * resolution as well as the network I/O operations of looking up the host and
151.448 + * opening a connection to the specified resource.
151.449 + *
151.450 + *
151.451 + * @author Mark Reinhold
151.452 + * @since 1.4
151.453 + *
151.454 + * @see <a href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC 2279: UTF-8, a
151.455 + * transformation format of ISO 10646</i></a>, <br><a
151.456 + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IPv6 Addressing
151.457 + * Architecture</i></a>, <br><a
151.458 + * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC 2396: Uniform
151.459 + * Resource Identifiers (URI): Generic Syntax</i></a>, <br><a
151.460 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format for
151.461 + * Literal IPv6 Addresses in URLs</i></a>, <br><a
151.462 + * href="URISyntaxException.html">URISyntaxException</a>
151.463 + */
151.464 +
151.465 +public final class URI
151.466 + implements Comparable<URI>, Serializable
151.467 +{
151.468 +
151.469 + // Note: Comments containing the word "ASSERT" indicate places where a
151.470 + // throw of an InternalError should be replaced by an appropriate assertion
151.471 + // statement once asserts are enabled in the build.
151.472 +
151.473 + static final long serialVersionUID = -6052424284110960213L;
151.474 +
151.475 +
151.476 + // -- Properties and components of this instance --
151.477 +
151.478 + // Components of all URIs: [<scheme>:]<scheme-specific-part>[#<fragment>]
151.479 + private transient String scheme; // null ==> relative URI
151.480 + private transient String fragment;
151.481 +
151.482 + // Hierarchical URI components: [//<authority>]<path>[?<query>]
151.483 + private transient String authority; // Registry or server
151.484 +
151.485 + // Server-based authority: [<userInfo>@]<host>[:<port>]
151.486 + private transient String userInfo;
151.487 + private transient String host; // null ==> registry-based
151.488 + private transient int port = -1; // -1 ==> undefined
151.489 +
151.490 + // Remaining components of hierarchical URIs
151.491 + private transient String path; // null ==> opaque
151.492 + private transient String query;
151.493 +
151.494 + // The remaining fields may be computed on demand
151.495 +
151.496 + private volatile transient String schemeSpecificPart;
151.497 + private volatile transient int hash; // Zero ==> undefined
151.498 +
151.499 + private volatile transient String decodedUserInfo = null;
151.500 + private volatile transient String decodedAuthority = null;
151.501 + private volatile transient String decodedPath = null;
151.502 + private volatile transient String decodedQuery = null;
151.503 + private volatile transient String decodedFragment = null;
151.504 + private volatile transient String decodedSchemeSpecificPart = null;
151.505 +
151.506 + /**
151.507 + * The string form of this URI.
151.508 + *
151.509 + * @serial
151.510 + */
151.511 + private volatile String string; // The only serializable field
151.512 +
151.513 +
151.514 +
151.515 + // -- Constructors and factories --
151.516 +
151.517 + private URI() { } // Used internally
151.518 +
151.519 + /**
151.520 + * Constructs a URI by parsing the given string.
151.521 + *
151.522 + * <p> This constructor parses the given string exactly as specified by the
151.523 + * grammar in <a
151.524 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.525 + * Appendix A, <b><i>except for the following deviations:</i></b> </p>
151.526 + *
151.527 + * <ul type=disc>
151.528 + *
151.529 + * <li><p> An empty authority component is permitted as long as it is
151.530 + * followed by a non-empty path, a query component, or a fragment
151.531 + * component. This allows the parsing of URIs such as
151.532 + * <tt>"file:///foo/bar"</tt>, which seems to be the intent of
151.533 + * RFC 2396 although the grammar does not permit it. If the
151.534 + * authority component is empty then the user-information, host, and port
151.535 + * components are undefined. </p></li>
151.536 + *
151.537 + * <li><p> Empty relative paths are permitted; this seems to be the
151.538 + * intent of RFC 2396 although the grammar does not permit it. The
151.539 + * primary consequence of this deviation is that a standalone fragment
151.540 + * such as <tt>"#foo"</tt> parses as a relative URI with an empty path
151.541 + * and the given fragment, and can be usefully <a
151.542 + * href="#resolve-frag">resolved</a> against a base URI.
151.543 + *
151.544 + * <li><p> IPv4 addresses in host components are parsed rigorously, as
151.545 + * specified by <a
151.546 + * href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>: Each
151.547 + * element of a dotted-quad address must contain no more than three
151.548 + * decimal digits. Each element is further constrained to have a value
151.549 + * no greater than 255. </p></li>
151.550 + *
151.551 + * <li> <p> Hostnames in host components that comprise only a single
151.552 + * domain label are permitted to start with an <i>alphanum</i>
151.553 + * character. This seems to be the intent of <a
151.554 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
151.555 + * section 3.2.2 although the grammar does not permit it. The
151.556 + * consequence of this deviation is that the authority component of a
151.557 + * hierarchical URI such as <tt>s://123</tt>, will parse as a server-based
151.558 + * authority. </p></li>
151.559 + *
151.560 + * <li><p> IPv6 addresses are permitted for the host component. An IPv6
151.561 + * address must be enclosed in square brackets (<tt>'['</tt> and
151.562 + * <tt>']'</tt>) as specified by <a
151.563 + * href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>. The
151.564 + * IPv6 address itself must parse according to <a
151.565 + * href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a>. IPv6
151.566 + * addresses are further constrained to describe no more than sixteen
151.567 + * bytes of address information, a constraint implicit in RFC 2373
151.568 + * but not expressible in the grammar. </p></li>
151.569 + *
151.570 + * <li><p> Characters in the <i>other</i> category are permitted wherever
151.571 + * RFC 2396 permits <i>escaped</i> octets, that is, in the
151.572 + * user-information, path, query, and fragment components, as well as in
151.573 + * the authority component if the authority is registry-based. This
151.574 + * allows URIs to contain Unicode characters beyond those in the US-ASCII
151.575 + * character set. </p></li>
151.576 + *
151.577 + * </ul>
151.578 + *
151.579 + * @param str The string to be parsed into a URI
151.580 + *
151.581 + * @throws NullPointerException
151.582 + * If <tt>str</tt> is <tt>null</tt>
151.583 + *
151.584 + * @throws URISyntaxException
151.585 + * If the given string violates RFC 2396, as augmented
151.586 + * by the above deviations
151.587 + */
151.588 + public URI(String str) throws URISyntaxException {
151.589 + new Parser(str).parse(false);
151.590 + }
151.591 +
151.592 + /**
151.593 + * Constructs a hierarchical URI from the given components.
151.594 + *
151.595 + * <p> If a scheme is given then the path, if also given, must either be
151.596 + * empty or begin with a slash character (<tt>'/'</tt>). Otherwise a
151.597 + * component of the new URI may be left undefined by passing <tt>null</tt>
151.598 + * for the corresponding parameter or, in the case of the <tt>port</tt>
151.599 + * parameter, by passing <tt>-1</tt>.
151.600 + *
151.601 + * <p> This constructor first builds a URI string from the given components
151.602 + * according to the rules specified in <a
151.603 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.604 + * section 5.2, step 7: </p>
151.605 + *
151.606 + * <ol>
151.607 + *
151.608 + * <li><p> Initially, the result string is empty. </p></li>
151.609 + *
151.610 + * <li><p> If a scheme is given then it is appended to the result,
151.611 + * followed by a colon character (<tt>':'</tt>). </p></li>
151.612 + *
151.613 + * <li><p> If user information, a host, or a port are given then the
151.614 + * string <tt>"//"</tt> is appended. </p></li>
151.615 + *
151.616 + * <li><p> If user information is given then it is appended, followed by
151.617 + * a commercial-at character (<tt>'@'</tt>). Any character not in the
151.618 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
151.619 + * categories is <a href="#quote">quoted</a>. </p></li>
151.620 + *
151.621 + * <li><p> If a host is given then it is appended. If the host is a
151.622 + * literal IPv6 address but is not enclosed in square brackets
151.623 + * (<tt>'['</tt> and <tt>']'</tt>) then the square brackets are added.
151.624 + * </p></li>
151.625 + *
151.626 + * <li><p> If a port number is given then a colon character
151.627 + * (<tt>':'</tt>) is appended, followed by the port number in decimal.
151.628 + * </p></li>
151.629 + *
151.630 + * <li><p> If a path is given then it is appended. Any character not in
151.631 + * the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
151.632 + * categories, and not equal to the slash character (<tt>'/'</tt>) or the
151.633 + * commercial-at character (<tt>'@'</tt>), is quoted. </p></li>
151.634 + *
151.635 + * <li><p> If a query is given then a question-mark character
151.636 + * (<tt>'?'</tt>) is appended, followed by the query. Any character that
151.637 + * is not a <a href="#legal-chars">legal URI character</a> is quoted.
151.638 + * </p></li>
151.639 + *
151.640 + * <li><p> Finally, if a fragment is given then a hash character
151.641 + * (<tt>'#'</tt>) is appended, followed by the fragment. Any character
151.642 + * that is not a legal URI character is quoted. </p></li>
151.643 + *
151.644 + * </ol>
151.645 + *
151.646 + * <p> The resulting URI string is then parsed as if by invoking the {@link
151.647 + * #URI(String)} constructor and then invoking the {@link
151.648 + * #parseServerAuthority()} method upon the result; this may cause a {@link
151.649 + * URISyntaxException} to be thrown. </p>
151.650 + *
151.651 + * @param scheme Scheme name
151.652 + * @param userInfo User name and authorization information
151.653 + * @param host Host name
151.654 + * @param port Port number
151.655 + * @param path Path
151.656 + * @param query Query
151.657 + * @param fragment Fragment
151.658 + *
151.659 + * @throws URISyntaxException
151.660 + * If both a scheme and a path are given but the path is relative,
151.661 + * if the URI string constructed from the given components violates
151.662 + * RFC 2396, or if the authority component of the string is
151.663 + * present but cannot be parsed as a server-based authority
151.664 + */
151.665 + public URI(String scheme,
151.666 + String userInfo, String host, int port,
151.667 + String path, String query, String fragment)
151.668 + throws URISyntaxException
151.669 + {
151.670 + String s = toString(scheme, null,
151.671 + null, userInfo, host, port,
151.672 + path, query, fragment);
151.673 + checkPath(s, scheme, path);
151.674 + new Parser(s).parse(true);
151.675 + }
151.676 +
151.677 + /**
151.678 + * Constructs a hierarchical URI from the given components.
151.679 + *
151.680 + * <p> If a scheme is given then the path, if also given, must either be
151.681 + * empty or begin with a slash character (<tt>'/'</tt>). Otherwise a
151.682 + * component of the new URI may be left undefined by passing <tt>null</tt>
151.683 + * for the corresponding parameter.
151.684 + *
151.685 + * <p> This constructor first builds a URI string from the given components
151.686 + * according to the rules specified in <a
151.687 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.688 + * section 5.2, step 7: </p>
151.689 + *
151.690 + * <ol>
151.691 + *
151.692 + * <li><p> Initially, the result string is empty. </p></li>
151.693 + *
151.694 + * <li><p> If a scheme is given then it is appended to the result,
151.695 + * followed by a colon character (<tt>':'</tt>). </p></li>
151.696 + *
151.697 + * <li><p> If an authority is given then the string <tt>"//"</tt> is
151.698 + * appended, followed by the authority. If the authority contains a
151.699 + * literal IPv6 address then the address must be enclosed in square
151.700 + * brackets (<tt>'['</tt> and <tt>']'</tt>). Any character not in the
151.701 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
151.702 + * categories, and not equal to the commercial-at character
151.703 + * (<tt>'@'</tt>), is <a href="#quote">quoted</a>. </p></li>
151.704 + *
151.705 + * <li><p> If a path is given then it is appended. Any character not in
151.706 + * the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
151.707 + * categories, and not equal to the slash character (<tt>'/'</tt>) or the
151.708 + * commercial-at character (<tt>'@'</tt>), is quoted. </p></li>
151.709 + *
151.710 + * <li><p> If a query is given then a question-mark character
151.711 + * (<tt>'?'</tt>) is appended, followed by the query. Any character that
151.712 + * is not a <a href="#legal-chars">legal URI character</a> is quoted.
151.713 + * </p></li>
151.714 + *
151.715 + * <li><p> Finally, if a fragment is given then a hash character
151.716 + * (<tt>'#'</tt>) is appended, followed by the fragment. Any character
151.717 + * that is not a legal URI character is quoted. </p></li>
151.718 + *
151.719 + * </ol>
151.720 + *
151.721 + * <p> The resulting URI string is then parsed as if by invoking the {@link
151.722 + * #URI(String)} constructor and then invoking the {@link
151.723 + * #parseServerAuthority()} method upon the result; this may cause a {@link
151.724 + * URISyntaxException} to be thrown. </p>
151.725 + *
151.726 + * @param scheme Scheme name
151.727 + * @param authority Authority
151.728 + * @param path Path
151.729 + * @param query Query
151.730 + * @param fragment Fragment
151.731 + *
151.732 + * @throws URISyntaxException
151.733 + * If both a scheme and a path are given but the path is relative,
151.734 + * if the URI string constructed from the given components violates
151.735 + * RFC 2396, or if the authority component of the string is
151.736 + * present but cannot be parsed as a server-based authority
151.737 + */
151.738 + public URI(String scheme,
151.739 + String authority,
151.740 + String path, String query, String fragment)
151.741 + throws URISyntaxException
151.742 + {
151.743 + String s = toString(scheme, null,
151.744 + authority, null, null, -1,
151.745 + path, query, fragment);
151.746 + checkPath(s, scheme, path);
151.747 + new Parser(s).parse(false);
151.748 + }
151.749 +
151.750 + /**
151.751 + * Constructs a hierarchical URI from the given components.
151.752 + *
151.753 + * <p> A component may be left undefined by passing <tt>null</tt>.
151.754 + *
151.755 + * <p> This convenience constructor works as if by invoking the
151.756 + * seven-argument constructor as follows:
151.757 + *
151.758 + * <blockquote><tt>
151.759 + * new {@link #URI(String, String, String, int, String, String, String)
151.760 + * URI}(scheme, null, host, -1, path, null, fragment);
151.761 + * </tt></blockquote>
151.762 + *
151.763 + * @param scheme Scheme name
151.764 + * @param host Host name
151.765 + * @param path Path
151.766 + * @param fragment Fragment
151.767 + *
151.768 + * @throws URISyntaxException
151.769 + * If the URI string constructed from the given components
151.770 + * violates RFC 2396
151.771 + */
151.772 + public URI(String scheme, String host, String path, String fragment)
151.773 + throws URISyntaxException
151.774 + {
151.775 + this(scheme, null, host, -1, path, null, fragment);
151.776 + }
151.777 +
151.778 + /**
151.779 + * Constructs a URI from the given components.
151.780 + *
151.781 + * <p> A component may be left undefined by passing <tt>null</tt>.
151.782 + *
151.783 + * <p> This constructor first builds a URI in string form using the given
151.784 + * components as follows: </p>
151.785 + *
151.786 + * <ol>
151.787 + *
151.788 + * <li><p> Initially, the result string is empty. </p></li>
151.789 + *
151.790 + * <li><p> If a scheme is given then it is appended to the result,
151.791 + * followed by a colon character (<tt>':'</tt>). </p></li>
151.792 + *
151.793 + * <li><p> If a scheme-specific part is given then it is appended. Any
151.794 + * character that is not a <a href="#legal-chars">legal URI character</a>
151.795 + * is <a href="#quote">quoted</a>. </p></li>
151.796 + *
151.797 + * <li><p> Finally, if a fragment is given then a hash character
151.798 + * (<tt>'#'</tt>) is appended to the string, followed by the fragment.
151.799 + * Any character that is not a legal URI character is quoted. </p></li>
151.800 + *
151.801 + * </ol>
151.802 + *
151.803 + * <p> The resulting URI string is then parsed in order to create the new
151.804 + * URI instance as if by invoking the {@link #URI(String)} constructor;
151.805 + * this may cause a {@link URISyntaxException} to be thrown. </p>
151.806 + *
151.807 + * @param scheme Scheme name
151.808 + * @param ssp Scheme-specific part
151.809 + * @param fragment Fragment
151.810 + *
151.811 + * @throws URISyntaxException
151.812 + * If the URI string constructed from the given components
151.813 + * violates RFC 2396
151.814 + */
151.815 + public URI(String scheme, String ssp, String fragment)
151.816 + throws URISyntaxException
151.817 + {
151.818 + new Parser(toString(scheme, ssp,
151.819 + null, null, null, -1,
151.820 + null, null, fragment))
151.821 + .parse(false);
151.822 + }
151.823 +
151.824 + /**
151.825 + * Creates a URI by parsing the given string.
151.826 + *
151.827 + * <p> This convenience factory method works as if by invoking the {@link
151.828 + * #URI(String)} constructor; any {@link URISyntaxException} thrown by the
151.829 + * constructor is caught and wrapped in a new {@link
151.830 + * IllegalArgumentException} object, which is then thrown.
151.831 + *
151.832 + * <p> This method is provided for use in situations where it is known that
151.833 + * the given string is a legal URI, for example for URI constants declared
151.834 + * within in a program, and so it would be considered a programming error
151.835 + * for the string not to parse as such. The constructors, which throw
151.836 + * {@link URISyntaxException} directly, should be used situations where a
151.837 + * URI is being constructed from user input or from some other source that
151.838 + * may be prone to errors. </p>
151.839 + *
151.840 + * @param str The string to be parsed into a URI
151.841 + * @return The new URI
151.842 + *
151.843 + * @throws NullPointerException
151.844 + * If <tt>str</tt> is <tt>null</tt>
151.845 + *
151.846 + * @throws IllegalArgumentException
151.847 + * If the given string violates RFC 2396
151.848 + */
151.849 + public static URI create(String str) {
151.850 + try {
151.851 + return new URI(str);
151.852 + } catch (URISyntaxException x) {
151.853 + throw new IllegalArgumentException(x.getMessage(), x);
151.854 + }
151.855 + }
151.856 +
151.857 +
151.858 + // -- Operations --
151.859 +
151.860 + /**
151.861 + * Attempts to parse this URI's authority component, if defined, into
151.862 + * user-information, host, and port components.
151.863 + *
151.864 + * <p> If this URI's authority component has already been recognized as
151.865 + * being server-based then it will already have been parsed into
151.866 + * user-information, host, and port components. In this case, or if this
151.867 + * URI has no authority component, this method simply returns this URI.
151.868 + *
151.869 + * <p> Otherwise this method attempts once more to parse the authority
151.870 + * component into user-information, host, and port components, and throws
151.871 + * an exception describing why the authority component could not be parsed
151.872 + * in that way.
151.873 + *
151.874 + * <p> This method is provided because the generic URI syntax specified in
151.875 + * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
151.876 + * cannot always distinguish a malformed server-based authority from a
151.877 + * legitimate registry-based authority. It must therefore treat some
151.878 + * instances of the former as instances of the latter. The authority
151.879 + * component in the URI string <tt>"//foo:bar"</tt>, for example, is not a
151.880 + * legal server-based authority but it is legal as a registry-based
151.881 + * authority.
151.882 + *
151.883 + * <p> In many common situations, for example when working URIs that are
151.884 + * known to be either URNs or URLs, the hierarchical URIs being used will
151.885 + * always be server-based. They therefore must either be parsed as such or
151.886 + * treated as an error. In these cases a statement such as
151.887 + *
151.888 + * <blockquote>
151.889 + * <tt>URI </tt><i>u</i><tt> = new URI(str).parseServerAuthority();</tt>
151.890 + * </blockquote>
151.891 + *
151.892 + * <p> can be used to ensure that <i>u</i> always refers to a URI that, if
151.893 + * it has an authority component, has a server-based authority with proper
151.894 + * user-information, host, and port components. Invoking this method also
151.895 + * ensures that if the authority could not be parsed in that way then an
151.896 + * appropriate diagnostic message can be issued based upon the exception
151.897 + * that is thrown. </p>
151.898 + *
151.899 + * @return A URI whose authority field has been parsed
151.900 + * as a server-based authority
151.901 + *
151.902 + * @throws URISyntaxException
151.903 + * If the authority component of this URI is defined
151.904 + * but cannot be parsed as a server-based authority
151.905 + * according to RFC 2396
151.906 + */
151.907 + public URI parseServerAuthority()
151.908 + throws URISyntaxException
151.909 + {
151.910 + // We could be clever and cache the error message and index from the
151.911 + // exception thrown during the original parse, but that would require
151.912 + // either more fields or a more-obscure representation.
151.913 + if ((host != null) || (authority == null))
151.914 + return this;
151.915 + defineString();
151.916 + new Parser(string).parse(true);
151.917 + return this;
151.918 + }
151.919 +
151.920 + /**
151.921 + * Normalizes this URI's path.
151.922 + *
151.923 + * <p> If this URI is opaque, or if its path is already in normal form,
151.924 + * then this URI is returned. Otherwise a new URI is constructed that is
151.925 + * identical to this URI except that its path is computed by normalizing
151.926 + * this URI's path in a manner consistent with <a
151.927 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.928 + * section 5.2, step 6, sub-steps c through f; that is:
151.929 + * </p>
151.930 + *
151.931 + * <ol>
151.932 + *
151.933 + * <li><p> All <tt>"."</tt> segments are removed. </p></li>
151.934 + *
151.935 + * <li><p> If a <tt>".."</tt> segment is preceded by a non-<tt>".."</tt>
151.936 + * segment then both of these segments are removed. This step is
151.937 + * repeated until it is no longer applicable. </p></li>
151.938 + *
151.939 + * <li><p> If the path is relative, and if its first segment contains a
151.940 + * colon character (<tt>':'</tt>), then a <tt>"."</tt> segment is
151.941 + * prepended. This prevents a relative URI with a path such as
151.942 + * <tt>"a:b/c/d"</tt> from later being re-parsed as an opaque URI with a
151.943 + * scheme of <tt>"a"</tt> and a scheme-specific part of <tt>"b/c/d"</tt>.
151.944 + * <b><i>(Deviation from RFC 2396)</i></b> </p></li>
151.945 + *
151.946 + * </ol>
151.947 + *
151.948 + * <p> A normalized path will begin with one or more <tt>".."</tt> segments
151.949 + * if there were insufficient non-<tt>".."</tt> segments preceding them to
151.950 + * allow their removal. A normalized path will begin with a <tt>"."</tt>
151.951 + * segment if one was inserted by step 3 above. Otherwise, a normalized
151.952 + * path will not contain any <tt>"."</tt> or <tt>".."</tt> segments. </p>
151.953 + *
151.954 + * @return A URI equivalent to this URI,
151.955 + * but whose path is in normal form
151.956 + */
151.957 + public URI normalize() {
151.958 + return normalize(this);
151.959 + }
151.960 +
151.961 + /**
151.962 + * Resolves the given URI against this URI.
151.963 + *
151.964 + * <p> If the given URI is already absolute, or if this URI is opaque, then
151.965 + * the given URI is returned.
151.966 + *
151.967 + * <p><a name="resolve-frag"></a> If the given URI's fragment component is
151.968 + * defined, its path component is empty, and its scheme, authority, and
151.969 + * query components are undefined, then a URI with the given fragment but
151.970 + * with all other components equal to those of this URI is returned. This
151.971 + * allows a URI representing a standalone fragment reference, such as
151.972 + * <tt>"#foo"</tt>, to be usefully resolved against a base URI.
151.973 + *
151.974 + * <p> Otherwise this method constructs a new hierarchical URI in a manner
151.975 + * consistent with <a
151.976 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.977 + * section 5.2; that is: </p>
151.978 + *
151.979 + * <ol>
151.980 + *
151.981 + * <li><p> A new URI is constructed with this URI's scheme and the given
151.982 + * URI's query and fragment components. </p></li>
151.983 + *
151.984 + * <li><p> If the given URI has an authority component then the new URI's
151.985 + * authority and path are taken from the given URI. </p></li>
151.986 + *
151.987 + * <li><p> Otherwise the new URI's authority component is copied from
151.988 + * this URI, and its path is computed as follows: </p>
151.989 + *
151.990 + * <ol type=a>
151.991 + *
151.992 + * <li><p> If the given URI's path is absolute then the new URI's path
151.993 + * is taken from the given URI. </p></li>
151.994 + *
151.995 + * <li><p> Otherwise the given URI's path is relative, and so the new
151.996 + * URI's path is computed by resolving the path of the given URI
151.997 + * against the path of this URI. This is done by concatenating all but
151.998 + * the last segment of this URI's path, if any, with the given URI's
151.999 + * path and then normalizing the result as if by invoking the {@link
151.1000 + * #normalize() normalize} method. </p></li>
151.1001 + *
151.1002 + * </ol></li>
151.1003 + *
151.1004 + * </ol>
151.1005 + *
151.1006 + * <p> The result of this method is absolute if, and only if, either this
151.1007 + * URI is absolute or the given URI is absolute. </p>
151.1008 + *
151.1009 + * @param uri The URI to be resolved against this URI
151.1010 + * @return The resulting URI
151.1011 + *
151.1012 + * @throws NullPointerException
151.1013 + * If <tt>uri</tt> is <tt>null</tt>
151.1014 + */
151.1015 + public URI resolve(URI uri) {
151.1016 + return resolve(this, uri);
151.1017 + }
151.1018 +
151.1019 + /**
151.1020 + * Constructs a new URI by parsing the given string and then resolving it
151.1021 + * against this URI.
151.1022 + *
151.1023 + * <p> This convenience method works as if invoking it were equivalent to
151.1024 + * evaluating the expression <tt>{@link #resolve(java.net.URI)
151.1025 + * resolve}(URI.{@link #create(String) create}(str))</tt>. </p>
151.1026 + *
151.1027 + * @param str The string to be parsed into a URI
151.1028 + * @return The resulting URI
151.1029 + *
151.1030 + * @throws NullPointerException
151.1031 + * If <tt>str</tt> is <tt>null</tt>
151.1032 + *
151.1033 + * @throws IllegalArgumentException
151.1034 + * If the given string violates RFC 2396
151.1035 + */
151.1036 + public URI resolve(String str) {
151.1037 + return resolve(URI.create(str));
151.1038 + }
151.1039 +
151.1040 + /**
151.1041 + * Relativizes the given URI against this URI.
151.1042 + *
151.1043 + * <p> The relativization of the given URI against this URI is computed as
151.1044 + * follows: </p>
151.1045 + *
151.1046 + * <ol>
151.1047 + *
151.1048 + * <li><p> If either this URI or the given URI are opaque, or if the
151.1049 + * scheme and authority components of the two URIs are not identical, or
151.1050 + * if the path of this URI is not a prefix of the path of the given URI,
151.1051 + * then the given URI is returned. </p></li>
151.1052 + *
151.1053 + * <li><p> Otherwise a new relative hierarchical URI is constructed with
151.1054 + * query and fragment components taken from the given URI and with a path
151.1055 + * component computed by removing this URI's path from the beginning of
151.1056 + * the given URI's path. </p></li>
151.1057 + *
151.1058 + * </ol>
151.1059 + *
151.1060 + * @param uri The URI to be relativized against this URI
151.1061 + * @return The resulting URI
151.1062 + *
151.1063 + * @throws NullPointerException
151.1064 + * If <tt>uri</tt> is <tt>null</tt>
151.1065 + */
151.1066 + public URI relativize(URI uri) {
151.1067 + return relativize(this, uri);
151.1068 + }
151.1069 +
151.1070 + /**
151.1071 + * Constructs a URL from this URI.
151.1072 + *
151.1073 + * <p> This convenience method works as if invoking it were equivalent to
151.1074 + * evaluating the expression <tt>new URL(this.toString())</tt> after
151.1075 + * first checking that this URI is absolute. </p>
151.1076 + *
151.1077 + * @return A URL constructed from this URI
151.1078 + *
151.1079 + * @throws IllegalArgumentException
151.1080 + * If this URL is not absolute
151.1081 + *
151.1082 + * @throws MalformedURLException
151.1083 + * If a protocol handler for the URL could not be found,
151.1084 + * or if some other error occurred while constructing the URL
151.1085 + */
151.1086 + public URL toURL()
151.1087 + throws MalformedURLException {
151.1088 + if (!isAbsolute())
151.1089 + throw new IllegalArgumentException("URI is not absolute");
151.1090 + return new URL(toString());
151.1091 + }
151.1092 +
151.1093 + // -- Component access methods --
151.1094 +
151.1095 + /**
151.1096 + * Returns the scheme component of this URI.
151.1097 + *
151.1098 + * <p> The scheme component of a URI, if defined, only contains characters
151.1099 + * in the <i>alphanum</i> category and in the string <tt>"-.+"</tt>. A
151.1100 + * scheme always starts with an <i>alpha</i> character. <p>
151.1101 + *
151.1102 + * The scheme component of a URI cannot contain escaped octets, hence this
151.1103 + * method does not perform any decoding.
151.1104 + *
151.1105 + * @return The scheme component of this URI,
151.1106 + * or <tt>null</tt> if the scheme is undefined
151.1107 + */
151.1108 + public String getScheme() {
151.1109 + return scheme;
151.1110 + }
151.1111 +
151.1112 + /**
151.1113 + * Tells whether or not this URI is absolute.
151.1114 + *
151.1115 + * <p> A URI is absolute if, and only if, it has a scheme component. </p>
151.1116 + *
151.1117 + * @return <tt>true</tt> if, and only if, this URI is absolute
151.1118 + */
151.1119 + public boolean isAbsolute() {
151.1120 + return scheme != null;
151.1121 + }
151.1122 +
151.1123 + /**
151.1124 + * Tells whether or not this URI is opaque.
151.1125 + *
151.1126 + * <p> A URI is opaque if, and only if, it is absolute and its
151.1127 + * scheme-specific part does not begin with a slash character ('/').
151.1128 + * An opaque URI has a scheme, a scheme-specific part, and possibly
151.1129 + * a fragment; all other components are undefined. </p>
151.1130 + *
151.1131 + * @return <tt>true</tt> if, and only if, this URI is opaque
151.1132 + */
151.1133 + public boolean isOpaque() {
151.1134 + return path == null;
151.1135 + }
151.1136 +
151.1137 + /**
151.1138 + * Returns the raw scheme-specific part of this URI. The scheme-specific
151.1139 + * part is never undefined, though it may be empty.
151.1140 + *
151.1141 + * <p> The scheme-specific part of a URI only contains legal URI
151.1142 + * characters. </p>
151.1143 + *
151.1144 + * @return The raw scheme-specific part of this URI
151.1145 + * (never <tt>null</tt>)
151.1146 + */
151.1147 + public String getRawSchemeSpecificPart() {
151.1148 + defineSchemeSpecificPart();
151.1149 + return schemeSpecificPart;
151.1150 + }
151.1151 +
151.1152 + /**
151.1153 + * Returns the decoded scheme-specific part of this URI.
151.1154 + *
151.1155 + * <p> The string returned by this method is equal to that returned by the
151.1156 + * {@link #getRawSchemeSpecificPart() getRawSchemeSpecificPart} method
151.1157 + * except that all sequences of escaped octets are <a
151.1158 + * href="#decode">decoded</a>. </p>
151.1159 + *
151.1160 + * @return The decoded scheme-specific part of this URI
151.1161 + * (never <tt>null</tt>)
151.1162 + */
151.1163 + public String getSchemeSpecificPart() {
151.1164 + if (decodedSchemeSpecificPart == null)
151.1165 + decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
151.1166 + return decodedSchemeSpecificPart;
151.1167 + }
151.1168 +
151.1169 + /**
151.1170 + * Returns the raw authority component of this URI.
151.1171 + *
151.1172 + * <p> The authority component of a URI, if defined, only contains the
151.1173 + * commercial-at character (<tt>'@'</tt>) and characters in the
151.1174 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and <i>other</i>
151.1175 + * categories. If the authority is server-based then it is further
151.1176 + * constrained to have valid user-information, host, and port
151.1177 + * components. </p>
151.1178 + *
151.1179 + * @return The raw authority component of this URI,
151.1180 + * or <tt>null</tt> if the authority is undefined
151.1181 + */
151.1182 + public String getRawAuthority() {
151.1183 + return authority;
151.1184 + }
151.1185 +
151.1186 + /**
151.1187 + * Returns the decoded authority component of this URI.
151.1188 + *
151.1189 + * <p> The string returned by this method is equal to that returned by the
151.1190 + * {@link #getRawAuthority() getRawAuthority} method except that all
151.1191 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
151.1192 + *
151.1193 + * @return The decoded authority component of this URI,
151.1194 + * or <tt>null</tt> if the authority is undefined
151.1195 + */
151.1196 + public String getAuthority() {
151.1197 + if (decodedAuthority == null)
151.1198 + decodedAuthority = decode(authority);
151.1199 + return decodedAuthority;
151.1200 + }
151.1201 +
151.1202 + /**
151.1203 + * Returns the raw user-information component of this URI.
151.1204 + *
151.1205 + * <p> The user-information component of a URI, if defined, only contains
151.1206 + * characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and
151.1207 + * <i>other</i> categories. </p>
151.1208 + *
151.1209 + * @return The raw user-information component of this URI,
151.1210 + * or <tt>null</tt> if the user information is undefined
151.1211 + */
151.1212 + public String getRawUserInfo() {
151.1213 + return userInfo;
151.1214 + }
151.1215 +
151.1216 + /**
151.1217 + * Returns the decoded user-information component of this URI.
151.1218 + *
151.1219 + * <p> The string returned by this method is equal to that returned by the
151.1220 + * {@link #getRawUserInfo() getRawUserInfo} method except that all
151.1221 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
151.1222 + *
151.1223 + * @return The decoded user-information component of this URI,
151.1224 + * or <tt>null</tt> if the user information is undefined
151.1225 + */
151.1226 + public String getUserInfo() {
151.1227 + if ((decodedUserInfo == null) && (userInfo != null))
151.1228 + decodedUserInfo = decode(userInfo);
151.1229 + return decodedUserInfo;
151.1230 + }
151.1231 +
151.1232 + /**
151.1233 + * Returns the host component of this URI.
151.1234 + *
151.1235 + * <p> The host component of a URI, if defined, will have one of the
151.1236 + * following forms: </p>
151.1237 + *
151.1238 + * <ul type=disc>
151.1239 + *
151.1240 + * <li><p> A domain name consisting of one or more <i>labels</i>
151.1241 + * separated by period characters (<tt>'.'</tt>), optionally followed by
151.1242 + * a period character. Each label consists of <i>alphanum</i> characters
151.1243 + * as well as hyphen characters (<tt>'-'</tt>), though hyphens never
151.1244 + * occur as the first or last characters in a label. The rightmost
151.1245 + * label of a domain name consisting of two or more labels, begins
151.1246 + * with an <i>alpha</i> character. </li>
151.1247 + *
151.1248 + * <li><p> A dotted-quad IPv4 address of the form
151.1249 + * <i>digit</i><tt>+.</tt><i>digit</i><tt>+.</tt><i>digit</i><tt>+.</tt><i>digit</i><tt>+</tt>,
151.1250 + * where no <i>digit</i> sequence is longer than three characters and no
151.1251 + * sequence has a value larger than 255. </p></li>
151.1252 + *
151.1253 + * <li><p> An IPv6 address enclosed in square brackets (<tt>'['</tt> and
151.1254 + * <tt>']'</tt>) and consisting of hexadecimal digits, colon characters
151.1255 + * (<tt>':'</tt>), and possibly an embedded IPv4 address. The full
151.1256 + * syntax of IPv6 addresses is specified in <a
151.1257 + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IPv6
151.1258 + * Addressing Architecture</i></a>. </p></li>
151.1259 + *
151.1260 + * </ul>
151.1261 + *
151.1262 + * The host component of a URI cannot contain escaped octets, hence this
151.1263 + * method does not perform any decoding.
151.1264 + *
151.1265 + * @return The host component of this URI,
151.1266 + * or <tt>null</tt> if the host is undefined
151.1267 + */
151.1268 + public String getHost() {
151.1269 + return host;
151.1270 + }
151.1271 +
151.1272 + /**
151.1273 + * Returns the port number of this URI.
151.1274 + *
151.1275 + * <p> The port component of a URI, if defined, is a non-negative
151.1276 + * integer. </p>
151.1277 + *
151.1278 + * @return The port component of this URI,
151.1279 + * or <tt>-1</tt> if the port is undefined
151.1280 + */
151.1281 + public int getPort() {
151.1282 + return port;
151.1283 + }
151.1284 +
151.1285 + /**
151.1286 + * Returns the raw path component of this URI.
151.1287 + *
151.1288 + * <p> The path component of a URI, if defined, only contains the slash
151.1289 + * character (<tt>'/'</tt>), the commercial-at character (<tt>'@'</tt>),
151.1290 + * and characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>,
151.1291 + * and <i>other</i> categories. </p>
151.1292 + *
151.1293 + * @return The path component of this URI,
151.1294 + * or <tt>null</tt> if the path is undefined
151.1295 + */
151.1296 + public String getRawPath() {
151.1297 + return path;
151.1298 + }
151.1299 +
151.1300 + /**
151.1301 + * Returns the decoded path component of this URI.
151.1302 + *
151.1303 + * <p> The string returned by this method is equal to that returned by the
151.1304 + * {@link #getRawPath() getRawPath} method except that all sequences of
151.1305 + * escaped octets are <a href="#decode">decoded</a>. </p>
151.1306 + *
151.1307 + * @return The decoded path component of this URI,
151.1308 + * or <tt>null</tt> if the path is undefined
151.1309 + */
151.1310 + public String getPath() {
151.1311 + if ((decodedPath == null) && (path != null))
151.1312 + decodedPath = decode(path);
151.1313 + return decodedPath;
151.1314 + }
151.1315 +
151.1316 + /**
151.1317 + * Returns the raw query component of this URI.
151.1318 + *
151.1319 + * <p> The query component of a URI, if defined, only contains legal URI
151.1320 + * characters. </p>
151.1321 + *
151.1322 + * @return The raw query component of this URI,
151.1323 + * or <tt>null</tt> if the query is undefined
151.1324 + */
151.1325 + public String getRawQuery() {
151.1326 + return query;
151.1327 + }
151.1328 +
151.1329 + /**
151.1330 + * Returns the decoded query component of this URI.
151.1331 + *
151.1332 + * <p> The string returned by this method is equal to that returned by the
151.1333 + * {@link #getRawQuery() getRawQuery} method except that all sequences of
151.1334 + * escaped octets are <a href="#decode">decoded</a>. </p>
151.1335 + *
151.1336 + * @return The decoded query component of this URI,
151.1337 + * or <tt>null</tt> if the query is undefined
151.1338 + */
151.1339 + public String getQuery() {
151.1340 + if ((decodedQuery == null) && (query != null))
151.1341 + decodedQuery = decode(query);
151.1342 + return decodedQuery;
151.1343 + }
151.1344 +
151.1345 + /**
151.1346 + * Returns the raw fragment component of this URI.
151.1347 + *
151.1348 + * <p> The fragment component of a URI, if defined, only contains legal URI
151.1349 + * characters. </p>
151.1350 + *
151.1351 + * @return The raw fragment component of this URI,
151.1352 + * or <tt>null</tt> if the fragment is undefined
151.1353 + */
151.1354 + public String getRawFragment() {
151.1355 + return fragment;
151.1356 + }
151.1357 +
151.1358 + /**
151.1359 + * Returns the decoded fragment component of this URI.
151.1360 + *
151.1361 + * <p> The string returned by this method is equal to that returned by the
151.1362 + * {@link #getRawFragment() getRawFragment} method except that all
151.1363 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
151.1364 + *
151.1365 + * @return The decoded fragment component of this URI,
151.1366 + * or <tt>null</tt> if the fragment is undefined
151.1367 + */
151.1368 + public String getFragment() {
151.1369 + if ((decodedFragment == null) && (fragment != null))
151.1370 + decodedFragment = decode(fragment);
151.1371 + return decodedFragment;
151.1372 + }
151.1373 +
151.1374 +
151.1375 + // -- Equality, comparison, hash code, toString, and serialization --
151.1376 +
151.1377 + /**
151.1378 + * Tests this URI for equality with another object.
151.1379 + *
151.1380 + * <p> If the given object is not a URI then this method immediately
151.1381 + * returns <tt>false</tt>.
151.1382 + *
151.1383 + * <p> For two URIs to be considered equal requires that either both are
151.1384 + * opaque or both are hierarchical. Their schemes must either both be
151.1385 + * undefined or else be equal without regard to case. Their fragments
151.1386 + * must either both be undefined or else be equal.
151.1387 + *
151.1388 + * <p> For two opaque URIs to be considered equal, their scheme-specific
151.1389 + * parts must be equal.
151.1390 + *
151.1391 + * <p> For two hierarchical URIs to be considered equal, their paths must
151.1392 + * be equal and their queries must either both be undefined or else be
151.1393 + * equal. Their authorities must either both be undefined, or both be
151.1394 + * registry-based, or both be server-based. If their authorities are
151.1395 + * defined and are registry-based, then they must be equal. If their
151.1396 + * authorities are defined and are server-based, then their hosts must be
151.1397 + * equal without regard to case, their port numbers must be equal, and
151.1398 + * their user-information components must be equal.
151.1399 + *
151.1400 + * <p> When testing the user-information, path, query, fragment, authority,
151.1401 + * or scheme-specific parts of two URIs for equality, the raw forms rather
151.1402 + * than the encoded forms of these components are compared and the
151.1403 + * hexadecimal digits of escaped octets are compared without regard to
151.1404 + * case.
151.1405 + *
151.1406 + * <p> This method satisfies the general contract of the {@link
151.1407 + * java.lang.Object#equals(Object) Object.equals} method. </p>
151.1408 + *
151.1409 + * @param ob The object to which this object is to be compared
151.1410 + *
151.1411 + * @return <tt>true</tt> if, and only if, the given object is a URI that
151.1412 + * is identical to this URI
151.1413 + */
151.1414 + public boolean equals(Object ob) {
151.1415 + if (ob == this)
151.1416 + return true;
151.1417 + if (!(ob instanceof URI))
151.1418 + return false;
151.1419 + URI that = (URI)ob;
151.1420 + if (this.isOpaque() != that.isOpaque()) return false;
151.1421 + if (!equalIgnoringCase(this.scheme, that.scheme)) return false;
151.1422 + if (!equal(this.fragment, that.fragment)) return false;
151.1423 +
151.1424 + // Opaque
151.1425 + if (this.isOpaque())
151.1426 + return equal(this.schemeSpecificPart, that.schemeSpecificPart);
151.1427 +
151.1428 + // Hierarchical
151.1429 + if (!equal(this.path, that.path)) return false;
151.1430 + if (!equal(this.query, that.query)) return false;
151.1431 +
151.1432 + // Authorities
151.1433 + if (this.authority == that.authority) return true;
151.1434 + if (this.host != null) {
151.1435 + // Server-based
151.1436 + if (!equal(this.userInfo, that.userInfo)) return false;
151.1437 + if (!equalIgnoringCase(this.host, that.host)) return false;
151.1438 + if (this.port != that.port) return false;
151.1439 + } else if (this.authority != null) {
151.1440 + // Registry-based
151.1441 + if (!equal(this.authority, that.authority)) return false;
151.1442 + } else if (this.authority != that.authority) {
151.1443 + return false;
151.1444 + }
151.1445 +
151.1446 + return true;
151.1447 + }
151.1448 +
151.1449 + /**
151.1450 + * Returns a hash-code value for this URI. The hash code is based upon all
151.1451 + * of the URI's components, and satisfies the general contract of the
151.1452 + * {@link java.lang.Object#hashCode() Object.hashCode} method.
151.1453 + *
151.1454 + * @return A hash-code value for this URI
151.1455 + */
151.1456 + public int hashCode() {
151.1457 + if (hash != 0)
151.1458 + return hash;
151.1459 + int h = hashIgnoringCase(0, scheme);
151.1460 + h = hash(h, fragment);
151.1461 + if (isOpaque()) {
151.1462 + h = hash(h, schemeSpecificPart);
151.1463 + } else {
151.1464 + h = hash(h, path);
151.1465 + h = hash(h, query);
151.1466 + if (host != null) {
151.1467 + h = hash(h, userInfo);
151.1468 + h = hashIgnoringCase(h, host);
151.1469 + h += 1949 * port;
151.1470 + } else {
151.1471 + h = hash(h, authority);
151.1472 + }
151.1473 + }
151.1474 + hash = h;
151.1475 + return h;
151.1476 + }
151.1477 +
151.1478 + /**
151.1479 + * Compares this URI to another object, which must be a URI.
151.1480 + *
151.1481 + * <p> When comparing corresponding components of two URIs, if one
151.1482 + * component is undefined but the other is defined then the first is
151.1483 + * considered to be less than the second. Unless otherwise noted, string
151.1484 + * components are ordered according to their natural, case-sensitive
151.1485 + * ordering as defined by the {@link java.lang.String#compareTo(Object)
151.1486 + * String.compareTo} method. String components that are subject to
151.1487 + * encoding are compared by comparing their raw forms rather than their
151.1488 + * encoded forms.
151.1489 + *
151.1490 + * <p> The ordering of URIs is defined as follows: </p>
151.1491 + *
151.1492 + * <ul type=disc>
151.1493 + *
151.1494 + * <li><p> Two URIs with different schemes are ordered according the
151.1495 + * ordering of their schemes, without regard to case. </p></li>
151.1496 + *
151.1497 + * <li><p> A hierarchical URI is considered to be less than an opaque URI
151.1498 + * with an identical scheme. </p></li>
151.1499 + *
151.1500 + * <li><p> Two opaque URIs with identical schemes are ordered according
151.1501 + * to the ordering of their scheme-specific parts. </p></li>
151.1502 + *
151.1503 + * <li><p> Two opaque URIs with identical schemes and scheme-specific
151.1504 + * parts are ordered according to the ordering of their
151.1505 + * fragments. </p></li>
151.1506 + *
151.1507 + * <li><p> Two hierarchical URIs with identical schemes are ordered
151.1508 + * according to the ordering of their authority components: </p>
151.1509 + *
151.1510 + * <ul type=disc>
151.1511 + *
151.1512 + * <li><p> If both authority components are server-based then the URIs
151.1513 + * are ordered according to their user-information components; if these
151.1514 + * components are identical then the URIs are ordered according to the
151.1515 + * ordering of their hosts, without regard to case; if the hosts are
151.1516 + * identical then the URIs are ordered according to the ordering of
151.1517 + * their ports. </p></li>
151.1518 + *
151.1519 + * <li><p> If one or both authority components are registry-based then
151.1520 + * the URIs are ordered according to the ordering of their authority
151.1521 + * components. </p></li>
151.1522 + *
151.1523 + * </ul></li>
151.1524 + *
151.1525 + * <li><p> Finally, two hierarchical URIs with identical schemes and
151.1526 + * authority components are ordered according to the ordering of their
151.1527 + * paths; if their paths are identical then they are ordered according to
151.1528 + * the ordering of their queries; if the queries are identical then they
151.1529 + * are ordered according to the order of their fragments. </p></li>
151.1530 + *
151.1531 + * </ul>
151.1532 + *
151.1533 + * <p> This method satisfies the general contract of the {@link
151.1534 + * java.lang.Comparable#compareTo(Object) Comparable.compareTo}
151.1535 + * method. </p>
151.1536 + *
151.1537 + * @param that
151.1538 + * The object to which this URI is to be compared
151.1539 + *
151.1540 + * @return A negative integer, zero, or a positive integer as this URI is
151.1541 + * less than, equal to, or greater than the given URI
151.1542 + *
151.1543 + * @throws ClassCastException
151.1544 + * If the given object is not a URI
151.1545 + */
151.1546 + public int compareTo(URI that) {
151.1547 + int c;
151.1548 +
151.1549 + if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0)
151.1550 + return c;
151.1551 +
151.1552 + if (this.isOpaque()) {
151.1553 + if (that.isOpaque()) {
151.1554 + // Both opaque
151.1555 + if ((c = compare(this.schemeSpecificPart,
151.1556 + that.schemeSpecificPart)) != 0)
151.1557 + return c;
151.1558 + return compare(this.fragment, that.fragment);
151.1559 + }
151.1560 + return +1; // Opaque > hierarchical
151.1561 + } else if (that.isOpaque()) {
151.1562 + return -1; // Hierarchical < opaque
151.1563 + }
151.1564 +
151.1565 + // Hierarchical
151.1566 + if ((this.host != null) && (that.host != null)) {
151.1567 + // Both server-based
151.1568 + if ((c = compare(this.userInfo, that.userInfo)) != 0)
151.1569 + return c;
151.1570 + if ((c = compareIgnoringCase(this.host, that.host)) != 0)
151.1571 + return c;
151.1572 + if ((c = this.port - that.port) != 0)
151.1573 + return c;
151.1574 + } else {
151.1575 + // If one or both authorities are registry-based then we simply
151.1576 + // compare them in the usual, case-sensitive way. If one is
151.1577 + // registry-based and one is server-based then the strings are
151.1578 + // guaranteed to be unequal, hence the comparison will never return
151.1579 + // zero and the compareTo and equals methods will remain
151.1580 + // consistent.
151.1581 + if ((c = compare(this.authority, that.authority)) != 0) return c;
151.1582 + }
151.1583 +
151.1584 + if ((c = compare(this.path, that.path)) != 0) return c;
151.1585 + if ((c = compare(this.query, that.query)) != 0) return c;
151.1586 + return compare(this.fragment, that.fragment);
151.1587 + }
151.1588 +
151.1589 + /**
151.1590 + * Returns the content of this URI as a string.
151.1591 + *
151.1592 + * <p> If this URI was created by invoking one of the constructors in this
151.1593 + * class then a string equivalent to the original input string, or to the
151.1594 + * string computed from the originally-given components, as appropriate, is
151.1595 + * returned. Otherwise this URI was created by normalization, resolution,
151.1596 + * or relativization, and so a string is constructed from this URI's
151.1597 + * components according to the rules specified in <a
151.1598 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
151.1599 + * section 5.2, step 7. </p>
151.1600 + *
151.1601 + * @return The string form of this URI
151.1602 + */
151.1603 + public String toString() {
151.1604 + defineString();
151.1605 + return string;
151.1606 + }
151.1607 +
151.1608 + /**
151.1609 + * Returns the content of this URI as a US-ASCII string.
151.1610 + *
151.1611 + * <p> If this URI does not contain any characters in the <i>other</i>
151.1612 + * category then an invocation of this method will return the same value as
151.1613 + * an invocation of the {@link #toString() toString} method. Otherwise
151.1614 + * this method works as if by invoking that method and then <a
151.1615 + * href="#encode">encoding</a> the result. </p>
151.1616 + *
151.1617 + * @return The string form of this URI, encoded as needed
151.1618 + * so that it only contains characters in the US-ASCII
151.1619 + * charset
151.1620 + */
151.1621 + public String toASCIIString() {
151.1622 + defineString();
151.1623 + return encode(string);
151.1624 + }
151.1625 +
151.1626 +
151.1627 + // -- Serialization support --
151.1628 +
151.1629 + /**
151.1630 + * Saves the content of this URI to the given serial stream.
151.1631 + *
151.1632 + * <p> The only serializable field of a URI instance is its <tt>string</tt>
151.1633 + * field. That field is given a value, if it does not have one already,
151.1634 + * and then the {@link java.io.ObjectOutputStream#defaultWriteObject()}
151.1635 + * method of the given object-output stream is invoked. </p>
151.1636 + *
151.1637 + * @param os The object-output stream to which this object
151.1638 + * is to be written
151.1639 + */
151.1640 + private void writeObject(ObjectOutputStream os)
151.1641 + throws IOException
151.1642 + {
151.1643 + defineString();
151.1644 + os.defaultWriteObject(); // Writes the string field only
151.1645 + }
151.1646 +
151.1647 + /**
151.1648 + * Reconstitutes a URI from the given serial stream.
151.1649 + *
151.1650 + * <p> The {@link java.io.ObjectInputStream#defaultReadObject()} method is
151.1651 + * invoked to read the value of the <tt>string</tt> field. The result is
151.1652 + * then parsed in the usual way.
151.1653 + *
151.1654 + * @param is The object-input stream from which this object
151.1655 + * is being read
151.1656 + */
151.1657 + private void readObject(ObjectInputStream is)
151.1658 + throws ClassNotFoundException, IOException
151.1659 + {
151.1660 + port = -1; // Argh
151.1661 + is.defaultReadObject();
151.1662 + try {
151.1663 + new Parser(string).parse(false);
151.1664 + } catch (URISyntaxException x) {
151.1665 + IOException y = new InvalidObjectException("Invalid URI");
151.1666 + y.initCause(x);
151.1667 + throw y;
151.1668 + }
151.1669 + }
151.1670 +
151.1671 +
151.1672 + // -- End of public methods --
151.1673 +
151.1674 +
151.1675 + // -- Utility methods for string-field comparison and hashing --
151.1676 +
151.1677 + // These methods return appropriate values for null string arguments,
151.1678 + // thereby simplifying the equals, hashCode, and compareTo methods.
151.1679 + //
151.1680 + // The case-ignoring methods should only be applied to strings whose
151.1681 + // characters are all known to be US-ASCII. Because of this restriction,
151.1682 + // these methods are faster than the similar methods in the String class.
151.1683 +
151.1684 + // US-ASCII only
151.1685 + private static int toLower(char c) {
151.1686 + if ((c >= 'A') && (c <= 'Z'))
151.1687 + return c + ('a' - 'A');
151.1688 + return c;
151.1689 + }
151.1690 +
151.1691 + private static boolean equal(String s, String t) {
151.1692 + if (s == t) return true;
151.1693 + if ((s != null) && (t != null)) {
151.1694 + if (s.length() != t.length())
151.1695 + return false;
151.1696 + if (s.indexOf('%') < 0)
151.1697 + return s.equals(t);
151.1698 + int n = s.length();
151.1699 + for (int i = 0; i < n;) {
151.1700 + char c = s.charAt(i);
151.1701 + char d = t.charAt(i);
151.1702 + if (c != '%') {
151.1703 + if (c != d)
151.1704 + return false;
151.1705 + i++;
151.1706 + continue;
151.1707 + }
151.1708 + i++;
151.1709 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
151.1710 + return false;
151.1711 + i++;
151.1712 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
151.1713 + return false;
151.1714 + i++;
151.1715 + }
151.1716 + return true;
151.1717 + }
151.1718 + return false;
151.1719 + }
151.1720 +
151.1721 + // US-ASCII only
151.1722 + private static boolean equalIgnoringCase(String s, String t) {
151.1723 + if (s == t) return true;
151.1724 + if ((s != null) && (t != null)) {
151.1725 + int n = s.length();
151.1726 + if (t.length() != n)
151.1727 + return false;
151.1728 + for (int i = 0; i < n; i++) {
151.1729 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
151.1730 + return false;
151.1731 + }
151.1732 + return true;
151.1733 + }
151.1734 + return false;
151.1735 + }
151.1736 +
151.1737 + private static int hash(int hash, String s) {
151.1738 + if (s == null) return hash;
151.1739 + return hash * 127 + s.hashCode();
151.1740 + }
151.1741 +
151.1742 + // US-ASCII only
151.1743 + private static int hashIgnoringCase(int hash, String s) {
151.1744 + if (s == null) return hash;
151.1745 + int h = hash;
151.1746 + int n = s.length();
151.1747 + for (int i = 0; i < n; i++)
151.1748 + h = 31 * h + toLower(s.charAt(i));
151.1749 + return h;
151.1750 + }
151.1751 +
151.1752 + private static int compare(String s, String t) {
151.1753 + if (s == t) return 0;
151.1754 + if (s != null) {
151.1755 + if (t != null)
151.1756 + return s.compareTo(t);
151.1757 + else
151.1758 + return +1;
151.1759 + } else {
151.1760 + return -1;
151.1761 + }
151.1762 + }
151.1763 +
151.1764 + // US-ASCII only
151.1765 + private static int compareIgnoringCase(String s, String t) {
151.1766 + if (s == t) return 0;
151.1767 + if (s != null) {
151.1768 + if (t != null) {
151.1769 + int sn = s.length();
151.1770 + int tn = t.length();
151.1771 + int n = sn < tn ? sn : tn;
151.1772 + for (int i = 0; i < n; i++) {
151.1773 + int c = toLower(s.charAt(i)) - toLower(t.charAt(i));
151.1774 + if (c != 0)
151.1775 + return c;
151.1776 + }
151.1777 + return sn - tn;
151.1778 + }
151.1779 + return +1;
151.1780 + } else {
151.1781 + return -1;
151.1782 + }
151.1783 + }
151.1784 +
151.1785 +
151.1786 + // -- String construction --
151.1787 +
151.1788 + // If a scheme is given then the path, if given, must be absolute
151.1789 + //
151.1790 + private static void checkPath(String s, String scheme, String path)
151.1791 + throws URISyntaxException
151.1792 + {
151.1793 + if (scheme != null) {
151.1794 + if ((path != null)
151.1795 + && ((path.length() > 0) && (path.charAt(0) != '/')))
151.1796 + throw new URISyntaxException(s,
151.1797 + "Relative path in absolute URI");
151.1798 + }
151.1799 + }
151.1800 +
151.1801 + private void appendAuthority(StringBuffer sb,
151.1802 + String authority,
151.1803 + String userInfo,
151.1804 + String host,
151.1805 + int port)
151.1806 + {
151.1807 + if (host != null) {
151.1808 + sb.append("//");
151.1809 + if (userInfo != null) {
151.1810 + sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
151.1811 + sb.append('@');
151.1812 + }
151.1813 + boolean needBrackets = ((host.indexOf(':') >= 0)
151.1814 + && !host.startsWith("[")
151.1815 + && !host.endsWith("]"));
151.1816 + if (needBrackets) sb.append('[');
151.1817 + sb.append(host);
151.1818 + if (needBrackets) sb.append(']');
151.1819 + if (port != -1) {
151.1820 + sb.append(':');
151.1821 + sb.append(port);
151.1822 + }
151.1823 + } else if (authority != null) {
151.1824 + sb.append("//");
151.1825 + if (authority.startsWith("[")) {
151.1826 + // authority should (but may not) contain an embedded IPv6 address
151.1827 + int end = authority.indexOf("]");
151.1828 + String doquote = authority, dontquote = "";
151.1829 + if (end != -1 && authority.indexOf(":") != -1) {
151.1830 + // the authority contains an IPv6 address
151.1831 + if (end == authority.length()) {
151.1832 + dontquote = authority;
151.1833 + doquote = "";
151.1834 + } else {
151.1835 + dontquote = authority.substring(0 , end + 1);
151.1836 + doquote = authority.substring(end + 1);
151.1837 + }
151.1838 + }
151.1839 + sb.append(dontquote);
151.1840 + sb.append(quote(doquote,
151.1841 + L_REG_NAME | L_SERVER,
151.1842 + H_REG_NAME | H_SERVER));
151.1843 + } else {
151.1844 + sb.append(quote(authority,
151.1845 + L_REG_NAME | L_SERVER,
151.1846 + H_REG_NAME | H_SERVER));
151.1847 + }
151.1848 + }
151.1849 + }
151.1850 +
151.1851 + private void appendSchemeSpecificPart(StringBuffer sb,
151.1852 + String opaquePart,
151.1853 + String authority,
151.1854 + String userInfo,
151.1855 + String host,
151.1856 + int port,
151.1857 + String path,
151.1858 + String query)
151.1859 + {
151.1860 + if (opaquePart != null) {
151.1861 + /* check if SSP begins with an IPv6 address
151.1862 + * because we must not quote a literal IPv6 address
151.1863 + */
151.1864 + if (opaquePart.startsWith("//[")) {
151.1865 + int end = opaquePart.indexOf("]");
151.1866 + if (end != -1 && opaquePart.indexOf(":")!=-1) {
151.1867 + String doquote, dontquote;
151.1868 + if (end == opaquePart.length()) {
151.1869 + dontquote = opaquePart;
151.1870 + doquote = "";
151.1871 + } else {
151.1872 + dontquote = opaquePart.substring(0,end+1);
151.1873 + doquote = opaquePart.substring(end+1);
151.1874 + }
151.1875 + sb.append (dontquote);
151.1876 + sb.append(quote(doquote, L_URIC, H_URIC));
151.1877 + }
151.1878 + } else {
151.1879 + sb.append(quote(opaquePart, L_URIC, H_URIC));
151.1880 + }
151.1881 + } else {
151.1882 + appendAuthority(sb, authority, userInfo, host, port);
151.1883 + if (path != null)
151.1884 + sb.append(quote(path, L_PATH, H_PATH));
151.1885 + if (query != null) {
151.1886 + sb.append('?');
151.1887 + sb.append(quote(query, L_URIC, H_URIC));
151.1888 + }
151.1889 + }
151.1890 + }
151.1891 +
151.1892 + private void appendFragment(StringBuffer sb, String fragment) {
151.1893 + if (fragment != null) {
151.1894 + sb.append('#');
151.1895 + sb.append(quote(fragment, L_URIC, H_URIC));
151.1896 + }
151.1897 + }
151.1898 +
151.1899 + private String toString(String scheme,
151.1900 + String opaquePart,
151.1901 + String authority,
151.1902 + String userInfo,
151.1903 + String host,
151.1904 + int port,
151.1905 + String path,
151.1906 + String query,
151.1907 + String fragment)
151.1908 + {
151.1909 + StringBuffer sb = new StringBuffer();
151.1910 + if (scheme != null) {
151.1911 + sb.append(scheme);
151.1912 + sb.append(':');
151.1913 + }
151.1914 + appendSchemeSpecificPart(sb, opaquePart,
151.1915 + authority, userInfo, host, port,
151.1916 + path, query);
151.1917 + appendFragment(sb, fragment);
151.1918 + return sb.toString();
151.1919 + }
151.1920 +
151.1921 + private void defineSchemeSpecificPart() {
151.1922 + if (schemeSpecificPart != null) return;
151.1923 + StringBuffer sb = new StringBuffer();
151.1924 + appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
151.1925 + host, port, getPath(), getQuery());
151.1926 + if (sb.length() == 0) return;
151.1927 + schemeSpecificPart = sb.toString();
151.1928 + }
151.1929 +
151.1930 + private void defineString() {
151.1931 + if (string != null) return;
151.1932 +
151.1933 + StringBuffer sb = new StringBuffer();
151.1934 + if (scheme != null) {
151.1935 + sb.append(scheme);
151.1936 + sb.append(':');
151.1937 + }
151.1938 + if (isOpaque()) {
151.1939 + sb.append(schemeSpecificPart);
151.1940 + } else {
151.1941 + if (host != null) {
151.1942 + sb.append("//");
151.1943 + if (userInfo != null) {
151.1944 + sb.append(userInfo);
151.1945 + sb.append('@');
151.1946 + }
151.1947 + boolean needBrackets = ((host.indexOf(':') >= 0)
151.1948 + && !host.startsWith("[")
151.1949 + && !host.endsWith("]"));
151.1950 + if (needBrackets) sb.append('[');
151.1951 + sb.append(host);
151.1952 + if (needBrackets) sb.append(']');
151.1953 + if (port != -1) {
151.1954 + sb.append(':');
151.1955 + sb.append(port);
151.1956 + }
151.1957 + } else if (authority != null) {
151.1958 + sb.append("//");
151.1959 + sb.append(authority);
151.1960 + }
151.1961 + if (path != null)
151.1962 + sb.append(path);
151.1963 + if (query != null) {
151.1964 + sb.append('?');
151.1965 + sb.append(query);
151.1966 + }
151.1967 + }
151.1968 + if (fragment != null) {
151.1969 + sb.append('#');
151.1970 + sb.append(fragment);
151.1971 + }
151.1972 + string = sb.toString();
151.1973 + }
151.1974 +
151.1975 +
151.1976 + // -- Normalization, resolution, and relativization --
151.1977 +
151.1978 + // RFC2396 5.2 (6)
151.1979 + private static String resolvePath(String base, String child,
151.1980 + boolean absolute)
151.1981 + {
151.1982 + int i = base.lastIndexOf('/');
151.1983 + int cn = child.length();
151.1984 + String path = "";
151.1985 +
151.1986 + if (cn == 0) {
151.1987 + // 5.2 (6a)
151.1988 + if (i >= 0)
151.1989 + path = base.substring(0, i + 1);
151.1990 + } else {
151.1991 + StringBuffer sb = new StringBuffer(base.length() + cn);
151.1992 + // 5.2 (6a)
151.1993 + if (i >= 0)
151.1994 + sb.append(base.substring(0, i + 1));
151.1995 + // 5.2 (6b)
151.1996 + sb.append(child);
151.1997 + path = sb.toString();
151.1998 + }
151.1999 +
151.2000 + // 5.2 (6c-f)
151.2001 + String np = normalize(path);
151.2002 +
151.2003 + // 5.2 (6g): If the result is absolute but the path begins with "../",
151.2004 + // then we simply leave the path as-is
151.2005 +
151.2006 + return np;
151.2007 + }
151.2008 +
151.2009 + // RFC2396 5.2
151.2010 + private static URI resolve(URI base, URI child) {
151.2011 + // check if child if opaque first so that NPE is thrown
151.2012 + // if child is null.
151.2013 + if (child.isOpaque() || base.isOpaque())
151.2014 + return child;
151.2015 +
151.2016 + // 5.2 (2): Reference to current document (lone fragment)
151.2017 + if ((child.scheme == null) && (child.authority == null)
151.2018 + && child.path.equals("") && (child.fragment != null)
151.2019 + && (child.query == null)) {
151.2020 + if ((base.fragment != null)
151.2021 + && child.fragment.equals(base.fragment)) {
151.2022 + return base;
151.2023 + }
151.2024 + URI ru = new URI();
151.2025 + ru.scheme = base.scheme;
151.2026 + ru.authority = base.authority;
151.2027 + ru.userInfo = base.userInfo;
151.2028 + ru.host = base.host;
151.2029 + ru.port = base.port;
151.2030 + ru.path = base.path;
151.2031 + ru.fragment = child.fragment;
151.2032 + ru.query = base.query;
151.2033 + return ru;
151.2034 + }
151.2035 +
151.2036 + // 5.2 (3): Child is absolute
151.2037 + if (child.scheme != null)
151.2038 + return child;
151.2039 +
151.2040 + URI ru = new URI(); // Resolved URI
151.2041 + ru.scheme = base.scheme;
151.2042 + ru.query = child.query;
151.2043 + ru.fragment = child.fragment;
151.2044 +
151.2045 + // 5.2 (4): Authority
151.2046 + if (child.authority == null) {
151.2047 + ru.authority = base.authority;
151.2048 + ru.host = base.host;
151.2049 + ru.userInfo = base.userInfo;
151.2050 + ru.port = base.port;
151.2051 +
151.2052 + String cp = (child.path == null) ? "" : child.path;
151.2053 + if ((cp.length() > 0) && (cp.charAt(0) == '/')) {
151.2054 + // 5.2 (5): Child path is absolute
151.2055 + ru.path = child.path;
151.2056 + } else {
151.2057 + // 5.2 (6): Resolve relative path
151.2058 + ru.path = resolvePath(base.path, cp, base.isAbsolute());
151.2059 + }
151.2060 + } else {
151.2061 + ru.authority = child.authority;
151.2062 + ru.host = child.host;
151.2063 + ru.userInfo = child.userInfo;
151.2064 + ru.host = child.host;
151.2065 + ru.port = child.port;
151.2066 + ru.path = child.path;
151.2067 + }
151.2068 +
151.2069 + // 5.2 (7): Recombine (nothing to do here)
151.2070 + return ru;
151.2071 + }
151.2072 +
151.2073 + // If the given URI's path is normal then return the URI;
151.2074 + // o.w., return a new URI containing the normalized path.
151.2075 + //
151.2076 + private static URI normalize(URI u) {
151.2077 + if (u.isOpaque() || (u.path == null) || (u.path.length() == 0))
151.2078 + return u;
151.2079 +
151.2080 + String np = normalize(u.path);
151.2081 + if (np == u.path)
151.2082 + return u;
151.2083 +
151.2084 + URI v = new URI();
151.2085 + v.scheme = u.scheme;
151.2086 + v.fragment = u.fragment;
151.2087 + v.authority = u.authority;
151.2088 + v.userInfo = u.userInfo;
151.2089 + v.host = u.host;
151.2090 + v.port = u.port;
151.2091 + v.path = np;
151.2092 + v.query = u.query;
151.2093 + return v;
151.2094 + }
151.2095 +
151.2096 + // If both URIs are hierarchical, their scheme and authority components are
151.2097 + // identical, and the base path is a prefix of the child's path, then
151.2098 + // return a relative URI that, when resolved against the base, yields the
151.2099 + // child; otherwise, return the child.
151.2100 + //
151.2101 + private static URI relativize(URI base, URI child) {
151.2102 + // check if child if opaque first so that NPE is thrown
151.2103 + // if child is null.
151.2104 + if (child.isOpaque() || base.isOpaque())
151.2105 + return child;
151.2106 + if (!equalIgnoringCase(base.scheme, child.scheme)
151.2107 + || !equal(base.authority, child.authority))
151.2108 + return child;
151.2109 +
151.2110 + String bp = normalize(base.path);
151.2111 + String cp = normalize(child.path);
151.2112 + if (!bp.equals(cp)) {
151.2113 + if (!bp.endsWith("/"))
151.2114 + bp = bp + "/";
151.2115 + if (!cp.startsWith(bp))
151.2116 + return child;
151.2117 + }
151.2118 +
151.2119 + URI v = new URI();
151.2120 + v.path = cp.substring(bp.length());
151.2121 + v.query = child.query;
151.2122 + v.fragment = child.fragment;
151.2123 + return v;
151.2124 + }
151.2125 +
151.2126 +
151.2127 +
151.2128 + // -- Path normalization --
151.2129 +
151.2130 + // The following algorithm for path normalization avoids the creation of a
151.2131 + // string object for each segment, as well as the use of a string buffer to
151.2132 + // compute the final result, by using a single char array and editing it in
151.2133 + // place. The array is first split into segments, replacing each slash
151.2134 + // with '\0' and creating a segment-index array, each element of which is
151.2135 + // the index of the first char in the corresponding segment. We then walk
151.2136 + // through both arrays, removing ".", "..", and other segments as necessary
151.2137 + // by setting their entries in the index array to -1. Finally, the two
151.2138 + // arrays are used to rejoin the segments and compute the final result.
151.2139 + //
151.2140 + // This code is based upon src/solaris/native/java/io/canonicalize_md.c
151.2141 +
151.2142 +
151.2143 + // Check the given path to see if it might need normalization. A path
151.2144 + // might need normalization if it contains duplicate slashes, a "."
151.2145 + // segment, or a ".." segment. Return -1 if no further normalization is
151.2146 + // possible, otherwise return the number of segments found.
151.2147 + //
151.2148 + // This method takes a string argument rather than a char array so that
151.2149 + // this test can be performed without invoking path.toCharArray().
151.2150 + //
151.2151 + static private int needsNormalization(String path) {
151.2152 + boolean normal = true;
151.2153 + int ns = 0; // Number of segments
151.2154 + int end = path.length() - 1; // Index of last char in path
151.2155 + int p = 0; // Index of next char in path
151.2156 +
151.2157 + // Skip initial slashes
151.2158 + while (p <= end) {
151.2159 + if (path.charAt(p) != '/') break;
151.2160 + p++;
151.2161 + }
151.2162 + if (p > 1) normal = false;
151.2163 +
151.2164 + // Scan segments
151.2165 + while (p <= end) {
151.2166 +
151.2167 + // Looking at "." or ".." ?
151.2168 + if ((path.charAt(p) == '.')
151.2169 + && ((p == end)
151.2170 + || ((path.charAt(p + 1) == '/')
151.2171 + || ((path.charAt(p + 1) == '.')
151.2172 + && ((p + 1 == end)
151.2173 + || (path.charAt(p + 2) == '/')))))) {
151.2174 + normal = false;
151.2175 + }
151.2176 + ns++;
151.2177 +
151.2178 + // Find beginning of next segment
151.2179 + while (p <= end) {
151.2180 + if (path.charAt(p++) != '/')
151.2181 + continue;
151.2182 +
151.2183 + // Skip redundant slashes
151.2184 + while (p <= end) {
151.2185 + if (path.charAt(p) != '/') break;
151.2186 + normal = false;
151.2187 + p++;
151.2188 + }
151.2189 +
151.2190 + break;
151.2191 + }
151.2192 + }
151.2193 +
151.2194 + return normal ? -1 : ns;
151.2195 + }
151.2196 +
151.2197 +
151.2198 + // Split the given path into segments, replacing slashes with nulls and
151.2199 + // filling in the given segment-index array.
151.2200 + //
151.2201 + // Preconditions:
151.2202 + // segs.length == Number of segments in path
151.2203 + //
151.2204 + // Postconditions:
151.2205 + // All slashes in path replaced by '\0'
151.2206 + // segs[i] == Index of first char in segment i (0 <= i < segs.length)
151.2207 + //
151.2208 + static private void split(char[] path, int[] segs) {
151.2209 + int end = path.length - 1; // Index of last char in path
151.2210 + int p = 0; // Index of next char in path
151.2211 + int i = 0; // Index of current segment
151.2212 +
151.2213 + // Skip initial slashes
151.2214 + while (p <= end) {
151.2215 + if (path[p] != '/') break;
151.2216 + path[p] = '\0';
151.2217 + p++;
151.2218 + }
151.2219 +
151.2220 + while (p <= end) {
151.2221 +
151.2222 + // Note start of segment
151.2223 + segs[i++] = p++;
151.2224 +
151.2225 + // Find beginning of next segment
151.2226 + while (p <= end) {
151.2227 + if (path[p++] != '/')
151.2228 + continue;
151.2229 + path[p - 1] = '\0';
151.2230 +
151.2231 + // Skip redundant slashes
151.2232 + while (p <= end) {
151.2233 + if (path[p] != '/') break;
151.2234 + path[p++] = '\0';
151.2235 + }
151.2236 + break;
151.2237 + }
151.2238 + }
151.2239 +
151.2240 + if (i != segs.length)
151.2241 + throw new InternalError(); // ASSERT
151.2242 + }
151.2243 +
151.2244 +
151.2245 + // Join the segments in the given path according to the given segment-index
151.2246 + // array, ignoring those segments whose index entries have been set to -1,
151.2247 + // and inserting slashes as needed. Return the length of the resulting
151.2248 + // path.
151.2249 + //
151.2250 + // Preconditions:
151.2251 + // segs[i] == -1 implies segment i is to be ignored
151.2252 + // path computed by split, as above, with '\0' having replaced '/'
151.2253 + //
151.2254 + // Postconditions:
151.2255 + // path[0] .. path[return value] == Resulting path
151.2256 + //
151.2257 + static private int join(char[] path, int[] segs) {
151.2258 + int ns = segs.length; // Number of segments
151.2259 + int end = path.length - 1; // Index of last char in path
151.2260 + int p = 0; // Index of next path char to write
151.2261 +
151.2262 + if (path[p] == '\0') {
151.2263 + // Restore initial slash for absolute paths
151.2264 + path[p++] = '/';
151.2265 + }
151.2266 +
151.2267 + for (int i = 0; i < ns; i++) {
151.2268 + int q = segs[i]; // Current segment
151.2269 + if (q == -1)
151.2270 + // Ignore this segment
151.2271 + continue;
151.2272 +
151.2273 + if (p == q) {
151.2274 + // We're already at this segment, so just skip to its end
151.2275 + while ((p <= end) && (path[p] != '\0'))
151.2276 + p++;
151.2277 + if (p <= end) {
151.2278 + // Preserve trailing slash
151.2279 + path[p++] = '/';
151.2280 + }
151.2281 + } else if (p < q) {
151.2282 + // Copy q down to p
151.2283 + while ((q <= end) && (path[q] != '\0'))
151.2284 + path[p++] = path[q++];
151.2285 + if (q <= end) {
151.2286 + // Preserve trailing slash
151.2287 + path[p++] = '/';
151.2288 + }
151.2289 + } else
151.2290 + throw new InternalError(); // ASSERT false
151.2291 + }
151.2292 +
151.2293 + return p;
151.2294 + }
151.2295 +
151.2296 +
151.2297 + // Remove "." segments from the given path, and remove segment pairs
151.2298 + // consisting of a non-".." segment followed by a ".." segment.
151.2299 + //
151.2300 + private static void removeDots(char[] path, int[] segs) {
151.2301 + int ns = segs.length;
151.2302 + int end = path.length - 1;
151.2303 +
151.2304 + for (int i = 0; i < ns; i++) {
151.2305 + int dots = 0; // Number of dots found (0, 1, or 2)
151.2306 +
151.2307 + // Find next occurrence of "." or ".."
151.2308 + do {
151.2309 + int p = segs[i];
151.2310 + if (path[p] == '.') {
151.2311 + if (p == end) {
151.2312 + dots = 1;
151.2313 + break;
151.2314 + } else if (path[p + 1] == '\0') {
151.2315 + dots = 1;
151.2316 + break;
151.2317 + } else if ((path[p + 1] == '.')
151.2318 + && ((p + 1 == end)
151.2319 + || (path[p + 2] == '\0'))) {
151.2320 + dots = 2;
151.2321 + break;
151.2322 + }
151.2323 + }
151.2324 + i++;
151.2325 + } while (i < ns);
151.2326 + if ((i > ns) || (dots == 0))
151.2327 + break;
151.2328 +
151.2329 + if (dots == 1) {
151.2330 + // Remove this occurrence of "."
151.2331 + segs[i] = -1;
151.2332 + } else {
151.2333 + // If there is a preceding non-".." segment, remove both that
151.2334 + // segment and this occurrence of ".."; otherwise, leave this
151.2335 + // ".." segment as-is.
151.2336 + int j;
151.2337 + for (j = i - 1; j >= 0; j--) {
151.2338 + if (segs[j] != -1) break;
151.2339 + }
151.2340 + if (j >= 0) {
151.2341 + int q = segs[j];
151.2342 + if (!((path[q] == '.')
151.2343 + && (path[q + 1] == '.')
151.2344 + && (path[q + 2] == '\0'))) {
151.2345 + segs[i] = -1;
151.2346 + segs[j] = -1;
151.2347 + }
151.2348 + }
151.2349 + }
151.2350 + }
151.2351 + }
151.2352 +
151.2353 +
151.2354 + // DEVIATION: If the normalized path is relative, and if the first
151.2355 + // segment could be parsed as a scheme name, then prepend a "." segment
151.2356 + //
151.2357 + private static void maybeAddLeadingDot(char[] path, int[] segs) {
151.2358 +
151.2359 + if (path[0] == '\0')
151.2360 + // The path is absolute
151.2361 + return;
151.2362 +
151.2363 + int ns = segs.length;
151.2364 + int f = 0; // Index of first segment
151.2365 + while (f < ns) {
151.2366 + if (segs[f] >= 0)
151.2367 + break;
151.2368 + f++;
151.2369 + }
151.2370 + if ((f >= ns) || (f == 0))
151.2371 + // The path is empty, or else the original first segment survived,
151.2372 + // in which case we already know that no leading "." is needed
151.2373 + return;
151.2374 +
151.2375 + int p = segs[f];
151.2376 + while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++;
151.2377 + if (p >= path.length || path[p] == '\0')
151.2378 + // No colon in first segment, so no "." needed
151.2379 + return;
151.2380 +
151.2381 + // At this point we know that the first segment is unused,
151.2382 + // hence we can insert a "." segment at that position
151.2383 + path[0] = '.';
151.2384 + path[1] = '\0';
151.2385 + segs[0] = 0;
151.2386 + }
151.2387 +
151.2388 +
151.2389 + // Normalize the given path string. A normal path string has no empty
151.2390 + // segments (i.e., occurrences of "//"), no segments equal to ".", and no
151.2391 + // segments equal to ".." that are preceded by a segment not equal to "..".
151.2392 + // In contrast to Unix-style pathname normalization, for URI paths we
151.2393 + // always retain trailing slashes.
151.2394 + //
151.2395 + private static String normalize(String ps) {
151.2396 +
151.2397 + // Does this path need normalization?
151.2398 + int ns = needsNormalization(ps); // Number of segments
151.2399 + if (ns < 0)
151.2400 + // Nope -- just return it
151.2401 + return ps;
151.2402 +
151.2403 + char[] path = ps.toCharArray(); // Path in char-array form
151.2404 +
151.2405 + // Split path into segments
151.2406 + int[] segs = new int[ns]; // Segment-index array
151.2407 + split(path, segs);
151.2408 +
151.2409 + // Remove dots
151.2410 + removeDots(path, segs);
151.2411 +
151.2412 + // Prevent scheme-name confusion
151.2413 + maybeAddLeadingDot(path, segs);
151.2414 +
151.2415 + // Join the remaining segments and return the result
151.2416 + String s = new String(path, 0, join(path, segs));
151.2417 + if (s.equals(ps)) {
151.2418 + // string was already normalized
151.2419 + return ps;
151.2420 + }
151.2421 + return s;
151.2422 + }
151.2423 +
151.2424 +
151.2425 +
151.2426 + // -- Character classes for parsing --
151.2427 +
151.2428 + // RFC2396 precisely specifies which characters in the US-ASCII charset are
151.2429 + // permissible in the various components of a URI reference. We here
151.2430 + // define a set of mask pairs to aid in enforcing these restrictions. Each
151.2431 + // mask pair consists of two longs, a low mask and a high mask. Taken
151.2432 + // together they represent a 128-bit mask, where bit i is set iff the
151.2433 + // character with value i is permitted.
151.2434 + //
151.2435 + // This approach is more efficient than sequentially searching arrays of
151.2436 + // permitted characters. It could be made still more efficient by
151.2437 + // precompiling the mask information so that a character's presence in a
151.2438 + // given mask could be determined by a single table lookup.
151.2439 +
151.2440 + // Compute the low-order mask for the characters in the given string
151.2441 + private static long lowMask(String chars) {
151.2442 + int n = chars.length();
151.2443 + long m = 0;
151.2444 + for (int i = 0; i < n; i++) {
151.2445 + char c = chars.charAt(i);
151.2446 + if (c < 64)
151.2447 + m |= (1L << c);
151.2448 + }
151.2449 + return m;
151.2450 + }
151.2451 +
151.2452 + // Compute the high-order mask for the characters in the given string
151.2453 + private static long highMask(String chars) {
151.2454 + int n = chars.length();
151.2455 + long m = 0;
151.2456 + for (int i = 0; i < n; i++) {
151.2457 + char c = chars.charAt(i);
151.2458 + if ((c >= 64) && (c < 128))
151.2459 + m |= (1L << (c - 64));
151.2460 + }
151.2461 + return m;
151.2462 + }
151.2463 +
151.2464 + // Compute a low-order mask for the characters
151.2465 + // between first and last, inclusive
151.2466 + private static long lowMask(char first, char last) {
151.2467 + long m = 0;
151.2468 + int f = Math.max(Math.min(first, 63), 0);
151.2469 + int l = Math.max(Math.min(last, 63), 0);
151.2470 + for (int i = f; i <= l; i++)
151.2471 + m |= 1L << i;
151.2472 + return m;
151.2473 + }
151.2474 +
151.2475 + // Compute a high-order mask for the characters
151.2476 + // between first and last, inclusive
151.2477 + private static long highMask(char first, char last) {
151.2478 + long m = 0;
151.2479 + int f = Math.max(Math.min(first, 127), 64) - 64;
151.2480 + int l = Math.max(Math.min(last, 127), 64) - 64;
151.2481 + for (int i = f; i <= l; i++)
151.2482 + m |= 1L << i;
151.2483 + return m;
151.2484 + }
151.2485 +
151.2486 + // Tell whether the given character is permitted by the given mask pair
151.2487 + private static boolean match(char c, long lowMask, long highMask) {
151.2488 + if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
151.2489 + return false;
151.2490 + if (c < 64)
151.2491 + return ((1L << c) & lowMask) != 0;
151.2492 + if (c < 128)
151.2493 + return ((1L << (c - 64)) & highMask) != 0;
151.2494 + return false;
151.2495 + }
151.2496 +
151.2497 + // Character-class masks, in reverse order from RFC2396 because
151.2498 + // initializers for static fields cannot make forward references.
151.2499 +
151.2500 + // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
151.2501 + // "8" | "9"
151.2502 + private static final long L_DIGIT = lowMask('0', '9');
151.2503 + private static final long H_DIGIT = 0L;
151.2504 +
151.2505 + // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
151.2506 + // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
151.2507 + // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
151.2508 + private static final long L_UPALPHA = 0L;
151.2509 + private static final long H_UPALPHA = highMask('A', 'Z');
151.2510 +
151.2511 + // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
151.2512 + // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
151.2513 + // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
151.2514 + private static final long L_LOWALPHA = 0L;
151.2515 + private static final long H_LOWALPHA = highMask('a', 'z');
151.2516 +
151.2517 + // alpha = lowalpha | upalpha
151.2518 + private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
151.2519 + private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
151.2520 +
151.2521 + // alphanum = alpha | digit
151.2522 + private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
151.2523 + private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
151.2524 +
151.2525 + // hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
151.2526 + // "a" | "b" | "c" | "d" | "e" | "f"
151.2527 + private static final long L_HEX = L_DIGIT;
151.2528 + private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f');
151.2529 +
151.2530 + // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
151.2531 + // "(" | ")"
151.2532 + private static final long L_MARK = lowMask("-_.!~*'()");
151.2533 + private static final long H_MARK = highMask("-_.!~*'()");
151.2534 +
151.2535 + // unreserved = alphanum | mark
151.2536 + private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
151.2537 + private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
151.2538 +
151.2539 + // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
151.2540 + // "$" | "," | "[" | "]"
151.2541 + // Added per RFC2732: "[", "]"
151.2542 + private static final long L_RESERVED = lowMask(";/?:@&=+$,[]");
151.2543 + private static final long H_RESERVED = highMask(";/?:@&=+$,[]");
151.2544 +
151.2545 + // The zero'th bit is used to indicate that escape pairs and non-US-ASCII
151.2546 + // characters are allowed; this is handled by the scanEscape method below.
151.2547 + private static final long L_ESCAPED = 1L;
151.2548 + private static final long H_ESCAPED = 0L;
151.2549 +
151.2550 + // uric = reserved | unreserved | escaped
151.2551 + private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
151.2552 + private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
151.2553 +
151.2554 + // pchar = unreserved | escaped |
151.2555 + // ":" | "@" | "&" | "=" | "+" | "$" | ","
151.2556 + private static final long L_PCHAR
151.2557 + = L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,");
151.2558 + private static final long H_PCHAR
151.2559 + = H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,");
151.2560 +
151.2561 + // All valid path characters
151.2562 + private static final long L_PATH = L_PCHAR | lowMask(";/");
151.2563 + private static final long H_PATH = H_PCHAR | highMask(";/");
151.2564 +
151.2565 + // Dash, for use in domainlabel and toplabel
151.2566 + private static final long L_DASH = lowMask("-");
151.2567 + private static final long H_DASH = highMask("-");
151.2568 +
151.2569 + // Dot, for use in hostnames
151.2570 + private static final long L_DOT = lowMask(".");
151.2571 + private static final long H_DOT = highMask(".");
151.2572 +
151.2573 + // userinfo = *( unreserved | escaped |
151.2574 + // ";" | ":" | "&" | "=" | "+" | "$" | "," )
151.2575 + private static final long L_USERINFO
151.2576 + = L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,");
151.2577 + private static final long H_USERINFO
151.2578 + = H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,");
151.2579 +
151.2580 + // reg_name = 1*( unreserved | escaped | "$" | "," |
151.2581 + // ";" | ":" | "@" | "&" | "=" | "+" )
151.2582 + private static final long L_REG_NAME
151.2583 + = L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+");
151.2584 + private static final long H_REG_NAME
151.2585 + = H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+");
151.2586 +
151.2587 + // All valid characters for server-based authorities
151.2588 + private static final long L_SERVER
151.2589 + = L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]");
151.2590 + private static final long H_SERVER
151.2591 + = H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]");
151.2592 +
151.2593 + // Special case of server authority that represents an IPv6 address
151.2594 + // In this case, a % does not signify an escape sequence
151.2595 + private static final long L_SERVER_PERCENT
151.2596 + = L_SERVER | lowMask("%");
151.2597 + private static final long H_SERVER_PERCENT
151.2598 + = H_SERVER | highMask("%");
151.2599 + private static final long L_LEFT_BRACKET = lowMask("[");
151.2600 + private static final long H_LEFT_BRACKET = highMask("[");
151.2601 +
151.2602 + // scheme = alpha *( alpha | digit | "+" | "-" | "." )
151.2603 + private static final long L_SCHEME = L_ALPHA | L_DIGIT | lowMask("+-.");
151.2604 + private static final long H_SCHEME = H_ALPHA | H_DIGIT | highMask("+-.");
151.2605 +
151.2606 + // uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
151.2607 + // "&" | "=" | "+" | "$" | ","
151.2608 + private static final long L_URIC_NO_SLASH
151.2609 + = L_UNRESERVED | L_ESCAPED | lowMask(";?:@&=+$,");
151.2610 + private static final long H_URIC_NO_SLASH
151.2611 + = H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,");
151.2612 +
151.2613 +
151.2614 + // -- Escaping and encoding --
151.2615 +
151.2616 + private final static char[] hexDigits = {
151.2617 + '0', '1', '2', '3', '4', '5', '6', '7',
151.2618 + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
151.2619 + };
151.2620 +
151.2621 + private static void appendEscape(StringBuffer sb, byte b) {
151.2622 + sb.append('%');
151.2623 + sb.append(hexDigits[(b >> 4) & 0x0f]);
151.2624 + sb.append(hexDigits[(b >> 0) & 0x0f]);
151.2625 + }
151.2626 +
151.2627 + private static void appendEncoded(StringBuffer sb, char c) {
151.2628 + /*
151.2629 + ByteBuffer bb = null;
151.2630 + try {
151.2631 + bb = ThreadLocalCoders.encoderFor("UTF-8")
151.2632 + .encode(CharBuffer.wrap("" + c));
151.2633 + } catch (CharacterCodingException x) {
151.2634 + assert false;
151.2635 + }
151.2636 + while (bb.hasRemaining()) {
151.2637 + int b = bb.get() & 0xff;
151.2638 + if (b >= 0x80)
151.2639 + appendEscape(sb, (byte)b);
151.2640 + else
151.2641 + sb.append((char)b);
151.2642 + }
151.2643 + */
151.2644 + }
151.2645 +
151.2646 + // Quote any characters in s that are not permitted
151.2647 + // by the given mask pair
151.2648 + //
151.2649 + private static String quote(String s, long lowMask, long highMask) {
151.2650 + int n = s.length();
151.2651 + StringBuffer sb = null;
151.2652 + boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
151.2653 + for (int i = 0; i < s.length(); i++) {
151.2654 + char c = s.charAt(i);
151.2655 + if (c < '\u0080') {
151.2656 + if (!match(c, lowMask, highMask)) {
151.2657 + if (sb == null) {
151.2658 + sb = new StringBuffer();
151.2659 + sb.append(s.substring(0, i));
151.2660 + }
151.2661 + appendEscape(sb, (byte)c);
151.2662 + } else {
151.2663 + if (sb != null)
151.2664 + sb.append(c);
151.2665 + }
151.2666 + } else if (allowNonASCII
151.2667 + && (Character.isSpaceChar(c)
151.2668 + || Character.isISOControl(c))) {
151.2669 + if (sb == null) {
151.2670 + sb = new StringBuffer();
151.2671 + sb.append(s.substring(0, i));
151.2672 + }
151.2673 + appendEncoded(sb, c);
151.2674 + } else {
151.2675 + if (sb != null)
151.2676 + sb.append(c);
151.2677 + }
151.2678 + }
151.2679 + return (sb == null) ? s : sb.toString();
151.2680 + }
151.2681 +
151.2682 + // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
151.2683 + // assuming that s is otherwise legal
151.2684 + //
151.2685 + private static String encode(String s) {
151.2686 + int n = s.length();
151.2687 + if (n == 0)
151.2688 + return s;
151.2689 +
151.2690 + // First check whether we actually need to encode
151.2691 + for (int i = 0;;) {
151.2692 + if (s.charAt(i) >= '\u0080')
151.2693 + break;
151.2694 + if (++i >= n)
151.2695 + return s;
151.2696 + }
151.2697 +/*
151.2698 + String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
151.2699 + ByteBuffer bb = null;
151.2700 + try {
151.2701 + bb = ThreadLocalCoders.encoderFor("UTF-8")
151.2702 + .encode(CharBuffer.wrap(ns));
151.2703 + } catch (CharacterCodingException x) {
151.2704 + assert false;
151.2705 + }
151.2706 +*/
151.2707 + StringBuffer sb = new StringBuffer();
151.2708 + /*
151.2709 + while (bb.hasRemaining()) {
151.2710 + int b = bb.get() & 0xff;
151.2711 + if (b >= 0x80)
151.2712 + appendEscape(sb, (byte)b);
151.2713 + else
151.2714 + sb.append((char)b);
151.2715 + }
151.2716 + */
151.2717 + return sb.toString();
151.2718 + }
151.2719 +
151.2720 + private static int decode(char c) {
151.2721 + if ((c >= '0') && (c <= '9'))
151.2722 + return c - '0';
151.2723 + if ((c >= 'a') && (c <= 'f'))
151.2724 + return c - 'a' + 10;
151.2725 + if ((c >= 'A') && (c <= 'F'))
151.2726 + return c - 'A' + 10;
151.2727 + assert false;
151.2728 + return -1;
151.2729 + }
151.2730 +
151.2731 + private static byte decode(char c1, char c2) {
151.2732 + return (byte)( ((decode(c1) & 0xf) << 4)
151.2733 + | ((decode(c2) & 0xf) << 0));
151.2734 + }
151.2735 +
151.2736 + // Evaluates all escapes in s, applying UTF-8 decoding if needed. Assumes
151.2737 + // that escapes are well-formed syntactically, i.e., of the form %XX. If a
151.2738 + // sequence of escaped octets is not valid UTF-8 then the erroneous octets
151.2739 + // are replaced with '\uFFFD'.
151.2740 + // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal
151.2741 + // with a scope_id
151.2742 + //
151.2743 + private static String decode(String s) {
151.2744 + if (s == null)
151.2745 + return s;
151.2746 + int n = s.length();
151.2747 + if (n == 0)
151.2748 + return s;
151.2749 + if (s.indexOf('%') < 0)
151.2750 + return s;
151.2751 +
151.2752 + StringBuffer sb = new StringBuffer(n);
151.2753 + /*
151.2754 + ByteBuffer bb = ByteBuffer.allocate(n);
151.2755 + CharBuffer cb = CharBuffer.allocate(n);
151.2756 + CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
151.2757 + .onMalformedInput(CodingErrorAction.REPLACE)
151.2758 + .onUnmappableCharacter(CodingErrorAction.REPLACE);
151.2759 +
151.2760 + // This is not horribly efficient, but it will do for now
151.2761 + char c = s.charAt(0);
151.2762 + boolean betweenBrackets = false;
151.2763 +
151.2764 + for (int i = 0; i < n;) {
151.2765 + assert c == s.charAt(i); // Loop invariant
151.2766 + if (c == '[') {
151.2767 + betweenBrackets = true;
151.2768 + } else if (betweenBrackets && c == ']') {
151.2769 + betweenBrackets = false;
151.2770 + }
151.2771 + if (c != '%' || betweenBrackets) {
151.2772 + sb.append(c);
151.2773 + if (++i >= n)
151.2774 + break;
151.2775 + c = s.charAt(i);
151.2776 + continue;
151.2777 + }
151.2778 + bb.clear();
151.2779 + int ui = i;
151.2780 + for (;;) {
151.2781 + assert (n - i >= 2);
151.2782 + bb.put(decode(s.charAt(++i), s.charAt(++i)));
151.2783 + if (++i >= n)
151.2784 + break;
151.2785 + c = s.charAt(i);
151.2786 + if (c != '%')
151.2787 + break;
151.2788 + }
151.2789 + bb.flip();
151.2790 + cb.clear();
151.2791 + dec.reset();
151.2792 + CoderResult cr = dec.decode(bb, cb, true);
151.2793 + assert cr.isUnderflow();
151.2794 + cr = dec.flush(cb);
151.2795 + assert cr.isUnderflow();
151.2796 + sb.append(cb.flip().toString());
151.2797 + }
151.2798 +*/
151.2799 + return sb.toString();
151.2800 + }
151.2801 +
151.2802 +
151.2803 + // -- Parsing --
151.2804 +
151.2805 + // For convenience we wrap the input URI string in a new instance of the
151.2806 + // following internal class. This saves always having to pass the input
151.2807 + // string as an argument to each internal scan/parse method.
151.2808 +
151.2809 + private class Parser {
151.2810 +
151.2811 + private String input; // URI input string
151.2812 + private boolean requireServerAuthority = false;
151.2813 +
151.2814 + Parser(String s) {
151.2815 + input = s;
151.2816 + string = s;
151.2817 + }
151.2818 +
151.2819 + // -- Methods for throwing URISyntaxException in various ways --
151.2820 +
151.2821 + private void fail(String reason) throws URISyntaxException {
151.2822 + throw new URISyntaxException(input, reason);
151.2823 + }
151.2824 +
151.2825 + private void fail(String reason, int p) throws URISyntaxException {
151.2826 + throw new URISyntaxException(input, reason, p);
151.2827 + }
151.2828 +
151.2829 + private void failExpecting(String expected, int p)
151.2830 + throws URISyntaxException
151.2831 + {
151.2832 + fail("Expected " + expected, p);
151.2833 + }
151.2834 +
151.2835 + private void failExpecting(String expected, String prior, int p)
151.2836 + throws URISyntaxException
151.2837 + {
151.2838 + fail("Expected " + expected + " following " + prior, p);
151.2839 + }
151.2840 +
151.2841 +
151.2842 + // -- Simple access to the input string --
151.2843 +
151.2844 + // Return a substring of the input string
151.2845 + //
151.2846 + private String substring(int start, int end) {
151.2847 + return input.substring(start, end);
151.2848 + }
151.2849 +
151.2850 + // Return the char at position p,
151.2851 + // assuming that p < input.length()
151.2852 + //
151.2853 + private char charAt(int p) {
151.2854 + return input.charAt(p);
151.2855 + }
151.2856 +
151.2857 + // Tells whether start < end and, if so, whether charAt(start) == c
151.2858 + //
151.2859 + private boolean at(int start, int end, char c) {
151.2860 + return (start < end) && (charAt(start) == c);
151.2861 + }
151.2862 +
151.2863 + // Tells whether start + s.length() < end and, if so,
151.2864 + // whether the chars at the start position match s exactly
151.2865 + //
151.2866 + private boolean at(int start, int end, String s) {
151.2867 + int p = start;
151.2868 + int sn = s.length();
151.2869 + if (sn > end - p)
151.2870 + return false;
151.2871 + int i = 0;
151.2872 + while (i < sn) {
151.2873 + if (charAt(p++) != s.charAt(i)) {
151.2874 + break;
151.2875 + }
151.2876 + i++;
151.2877 + }
151.2878 + return (i == sn);
151.2879 + }
151.2880 +
151.2881 +
151.2882 + // -- Scanning --
151.2883 +
151.2884 + // The various scan and parse methods that follow use a uniform
151.2885 + // convention of taking the current start position and end index as
151.2886 + // their first two arguments. The start is inclusive while the end is
151.2887 + // exclusive, just as in the String class, i.e., a start/end pair
151.2888 + // denotes the left-open interval [start, end) of the input string.
151.2889 + //
151.2890 + // These methods never proceed past the end position. They may return
151.2891 + // -1 to indicate outright failure, but more often they simply return
151.2892 + // the position of the first char after the last char scanned. Thus
151.2893 + // a typical idiom is
151.2894 + //
151.2895 + // int p = start;
151.2896 + // int q = scan(p, end, ...);
151.2897 + // if (q > p)
151.2898 + // // We scanned something
151.2899 + // ...;
151.2900 + // else if (q == p)
151.2901 + // // We scanned nothing
151.2902 + // ...;
151.2903 + // else if (q == -1)
151.2904 + // // Something went wrong
151.2905 + // ...;
151.2906 +
151.2907 +
151.2908 + // Scan a specific char: If the char at the given start position is
151.2909 + // equal to c, return the index of the next char; otherwise, return the
151.2910 + // start position.
151.2911 + //
151.2912 + private int scan(int start, int end, char c) {
151.2913 + if ((start < end) && (charAt(start) == c))
151.2914 + return start + 1;
151.2915 + return start;
151.2916 + }
151.2917 +
151.2918 + // Scan forward from the given start position. Stop at the first char
151.2919 + // in the err string (in which case -1 is returned), or the first char
151.2920 + // in the stop string (in which case the index of the preceding char is
151.2921 + // returned), or the end of the input string (in which case the length
151.2922 + // of the input string is returned). May return the start position if
151.2923 + // nothing matches.
151.2924 + //
151.2925 + private int scan(int start, int end, String err, String stop) {
151.2926 + int p = start;
151.2927 + while (p < end) {
151.2928 + char c = charAt(p);
151.2929 + if (err.indexOf(c) >= 0)
151.2930 + return -1;
151.2931 + if (stop.indexOf(c) >= 0)
151.2932 + break;
151.2933 + p++;
151.2934 + }
151.2935 + return p;
151.2936 + }
151.2937 +
151.2938 + // Scan a potential escape sequence, starting at the given position,
151.2939 + // with the given first char (i.e., charAt(start) == c).
151.2940 + //
151.2941 + // This method assumes that if escapes are allowed then visible
151.2942 + // non-US-ASCII chars are also allowed.
151.2943 + //
151.2944 + private int scanEscape(int start, int n, char first)
151.2945 + throws URISyntaxException
151.2946 + {
151.2947 + int p = start;
151.2948 + char c = first;
151.2949 + if (c == '%') {
151.2950 + // Process escape pair
151.2951 + if ((p + 3 <= n)
151.2952 + && match(charAt(p + 1), L_HEX, H_HEX)
151.2953 + && match(charAt(p + 2), L_HEX, H_HEX)) {
151.2954 + return p + 3;
151.2955 + }
151.2956 + fail("Malformed escape pair", p);
151.2957 + } else if ((c > 128)
151.2958 + && !Character.isSpaceChar(c)
151.2959 + && !Character.isISOControl(c)) {
151.2960 + // Allow unescaped but visible non-US-ASCII chars
151.2961 + return p + 1;
151.2962 + }
151.2963 + return p;
151.2964 + }
151.2965 +
151.2966 + // Scan chars that match the given mask pair
151.2967 + //
151.2968 + private int scan(int start, int n, long lowMask, long highMask)
151.2969 + throws URISyntaxException
151.2970 + {
151.2971 + int p = start;
151.2972 + while (p < n) {
151.2973 + char c = charAt(p);
151.2974 + if (match(c, lowMask, highMask)) {
151.2975 + p++;
151.2976 + continue;
151.2977 + }
151.2978 + if ((lowMask & L_ESCAPED) != 0) {
151.2979 + int q = scanEscape(p, n, c);
151.2980 + if (q > p) {
151.2981 + p = q;
151.2982 + continue;
151.2983 + }
151.2984 + }
151.2985 + break;
151.2986 + }
151.2987 + return p;
151.2988 + }
151.2989 +
151.2990 + // Check that each of the chars in [start, end) matches the given mask
151.2991 + //
151.2992 + private void checkChars(int start, int end,
151.2993 + long lowMask, long highMask,
151.2994 + String what)
151.2995 + throws URISyntaxException
151.2996 + {
151.2997 + int p = scan(start, end, lowMask, highMask);
151.2998 + if (p < end)
151.2999 + fail("Illegal character in " + what, p);
151.3000 + }
151.3001 +
151.3002 + // Check that the char at position p matches the given mask
151.3003 + //
151.3004 + private void checkChar(int p,
151.3005 + long lowMask, long highMask,
151.3006 + String what)
151.3007 + throws URISyntaxException
151.3008 + {
151.3009 + checkChars(p, p + 1, lowMask, highMask, what);
151.3010 + }
151.3011 +
151.3012 +
151.3013 + // -- Parsing --
151.3014 +
151.3015 + // [<scheme>:]<scheme-specific-part>[#<fragment>]
151.3016 + //
151.3017 + void parse(boolean rsa) throws URISyntaxException {
151.3018 + requireServerAuthority = rsa;
151.3019 + int ssp; // Start of scheme-specific part
151.3020 + int n = input.length();
151.3021 + int p = scan(0, n, "/?#", ":");
151.3022 + if ((p >= 0) && at(p, n, ':')) {
151.3023 + if (p == 0)
151.3024 + failExpecting("scheme name", 0);
151.3025 + checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
151.3026 + checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
151.3027 + scheme = substring(0, p);
151.3028 + p++; // Skip ':'
151.3029 + ssp = p;
151.3030 + if (at(p, n, '/')) {
151.3031 + p = parseHierarchical(p, n);
151.3032 + } else {
151.3033 + int q = scan(p, n, "", "#");
151.3034 + if (q <= p)
151.3035 + failExpecting("scheme-specific part", p);
151.3036 + checkChars(p, q, L_URIC, H_URIC, "opaque part");
151.3037 + p = q;
151.3038 + }
151.3039 + } else {
151.3040 + ssp = 0;
151.3041 + p = parseHierarchical(0, n);
151.3042 + }
151.3043 + schemeSpecificPart = substring(ssp, p);
151.3044 + if (at(p, n, '#')) {
151.3045 + checkChars(p + 1, n, L_URIC, H_URIC, "fragment");
151.3046 + fragment = substring(p + 1, n);
151.3047 + p = n;
151.3048 + }
151.3049 + if (p < n)
151.3050 + fail("end of URI", p);
151.3051 + }
151.3052 +
151.3053 + // [//authority]<path>[?<query>]
151.3054 + //
151.3055 + // DEVIATION from RFC2396: We allow an empty authority component as
151.3056 + // long as it's followed by a non-empty path, query component, or
151.3057 + // fragment component. This is so that URIs such as "file:///foo/bar"
151.3058 + // will parse. This seems to be the intent of RFC2396, though the
151.3059 + // grammar does not permit it. If the authority is empty then the
151.3060 + // userInfo, host, and port components are undefined.
151.3061 + //
151.3062 + // DEVIATION from RFC2396: We allow empty relative paths. This seems
151.3063 + // to be the intent of RFC2396, but the grammar does not permit it.
151.3064 + // The primary consequence of this deviation is that "#f" parses as a
151.3065 + // relative URI with an empty path.
151.3066 + //
151.3067 + private int parseHierarchical(int start, int n)
151.3068 + throws URISyntaxException
151.3069 + {
151.3070 + int p = start;
151.3071 + if (at(p, n, '/') && at(p + 1, n, '/')) {
151.3072 + p += 2;
151.3073 + int q = scan(p, n, "", "/?#");
151.3074 + if (q > p) {
151.3075 + p = parseAuthority(p, q);
151.3076 + } else if (q < n) {
151.3077 + // DEVIATION: Allow empty authority prior to non-empty
151.3078 + // path, query component or fragment identifier
151.3079 + } else
151.3080 + failExpecting("authority", p);
151.3081 + }
151.3082 + int q = scan(p, n, "", "?#"); // DEVIATION: May be empty
151.3083 + checkChars(p, q, L_PATH, H_PATH, "path");
151.3084 + path = substring(p, q);
151.3085 + p = q;
151.3086 + if (at(p, n, '?')) {
151.3087 + p++;
151.3088 + q = scan(p, n, "", "#");
151.3089 + checkChars(p, q, L_URIC, H_URIC, "query");
151.3090 + query = substring(p, q);
151.3091 + p = q;
151.3092 + }
151.3093 + return p;
151.3094 + }
151.3095 +
151.3096 + // authority = server | reg_name
151.3097 + //
151.3098 + // Ambiguity: An authority that is a registry name rather than a server
151.3099 + // might have a prefix that parses as a server. We use the fact that
151.3100 + // the authority component is always followed by '/' or the end of the
151.3101 + // input string to resolve this: If the complete authority did not
151.3102 + // parse as a server then we try to parse it as a registry name.
151.3103 + //
151.3104 + private int parseAuthority(int start, int n)
151.3105 + throws URISyntaxException
151.3106 + {
151.3107 + int p = start;
151.3108 + int q = p;
151.3109 + URISyntaxException ex = null;
151.3110 +
151.3111 + boolean serverChars;
151.3112 + boolean regChars;
151.3113 +
151.3114 + if (scan(p, n, "", "]") > p) {
151.3115 + // contains a literal IPv6 address, therefore % is allowed
151.3116 + serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n);
151.3117 + } else {
151.3118 + serverChars = (scan(p, n, L_SERVER, H_SERVER) == n);
151.3119 + }
151.3120 + regChars = (scan(p, n, L_REG_NAME, H_REG_NAME) == n);
151.3121 +
151.3122 + if (regChars && !serverChars) {
151.3123 + // Must be a registry-based authority
151.3124 + authority = substring(p, n);
151.3125 + return n;
151.3126 + }
151.3127 +
151.3128 + if (serverChars) {
151.3129 + // Might be (probably is) a server-based authority, so attempt
151.3130 + // to parse it as such. If the attempt fails, try to treat it
151.3131 + // as a registry-based authority.
151.3132 + try {
151.3133 + q = parseServer(p, n);
151.3134 + if (q < n)
151.3135 + failExpecting("end of authority", q);
151.3136 + authority = substring(p, n);
151.3137 + } catch (URISyntaxException x) {
151.3138 + // Undo results of failed parse
151.3139 + userInfo = null;
151.3140 + host = null;
151.3141 + port = -1;
151.3142 + if (requireServerAuthority) {
151.3143 + // If we're insisting upon a server-based authority,
151.3144 + // then just re-throw the exception
151.3145 + throw x;
151.3146 + } else {
151.3147 + // Save the exception in case it doesn't parse as a
151.3148 + // registry either
151.3149 + ex = x;
151.3150 + q = p;
151.3151 + }
151.3152 + }
151.3153 + }
151.3154 +
151.3155 + if (q < n) {
151.3156 + if (regChars) {
151.3157 + // Registry-based authority
151.3158 + authority = substring(p, n);
151.3159 + } else if (ex != null) {
151.3160 + // Re-throw exception; it was probably due to
151.3161 + // a malformed IPv6 address
151.3162 + throw ex;
151.3163 + } else {
151.3164 + fail("Illegal character in authority", q);
151.3165 + }
151.3166 + }
151.3167 +
151.3168 + return n;
151.3169 + }
151.3170 +
151.3171 +
151.3172 + // [<userinfo>@]<host>[:<port>]
151.3173 + //
151.3174 + private int parseServer(int start, int n)
151.3175 + throws URISyntaxException
151.3176 + {
151.3177 + int p = start;
151.3178 + int q;
151.3179 +
151.3180 + // userinfo
151.3181 + q = scan(p, n, "/?#", "@");
151.3182 + if ((q >= p) && at(q, n, '@')) {
151.3183 + checkChars(p, q, L_USERINFO, H_USERINFO, "user info");
151.3184 + userInfo = substring(p, q);
151.3185 + p = q + 1; // Skip '@'
151.3186 + }
151.3187 +
151.3188 + // hostname, IPv4 address, or IPv6 address
151.3189 + if (at(p, n, '[')) {
151.3190 + // DEVIATION from RFC2396: Support IPv6 addresses, per RFC2732
151.3191 + p++;
151.3192 + q = scan(p, n, "/?#", "]");
151.3193 + if ((q > p) && at(q, n, ']')) {
151.3194 + // look for a "%" scope id
151.3195 + int r = scan (p, q, "", "%");
151.3196 + if (r > p) {
151.3197 + parseIPv6Reference(p, r);
151.3198 + if (r+1 == q) {
151.3199 + fail ("scope id expected");
151.3200 + }
151.3201 + checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
151.3202 + "scope id");
151.3203 + } else {
151.3204 + parseIPv6Reference(p, q);
151.3205 + }
151.3206 + host = substring(p-1, q+1);
151.3207 + p = q + 1;
151.3208 + } else {
151.3209 + failExpecting("closing bracket for IPv6 address", q);
151.3210 + }
151.3211 + } else {
151.3212 + q = parseIPv4Address(p, n);
151.3213 + if (q <= p)
151.3214 + q = parseHostname(p, n);
151.3215 + p = q;
151.3216 + }
151.3217 +
151.3218 + // port
151.3219 + if (at(p, n, ':')) {
151.3220 + p++;
151.3221 + q = scan(p, n, "", "/");
151.3222 + if (q > p) {
151.3223 + checkChars(p, q, L_DIGIT, H_DIGIT, "port number");
151.3224 + try {
151.3225 + port = Integer.parseInt(substring(p, q));
151.3226 + } catch (NumberFormatException x) {
151.3227 + fail("Malformed port number", p);
151.3228 + }
151.3229 + p = q;
151.3230 + }
151.3231 + }
151.3232 + if (p < n)
151.3233 + failExpecting("port number", p);
151.3234 +
151.3235 + return p;
151.3236 + }
151.3237 +
151.3238 + // Scan a string of decimal digits whose value fits in a byte
151.3239 + //
151.3240 + private int scanByte(int start, int n)
151.3241 + throws URISyntaxException
151.3242 + {
151.3243 + int p = start;
151.3244 + int q = scan(p, n, L_DIGIT, H_DIGIT);
151.3245 + if (q <= p) return q;
151.3246 + if (Integer.parseInt(substring(p, q)) > 255) return p;
151.3247 + return q;
151.3248 + }
151.3249 +
151.3250 + // Scan an IPv4 address.
151.3251 + //
151.3252 + // If the strict argument is true then we require that the given
151.3253 + // interval contain nothing besides an IPv4 address; if it is false
151.3254 + // then we only require that it start with an IPv4 address.
151.3255 + //
151.3256 + // If the interval does not contain or start with (depending upon the
151.3257 + // strict argument) a legal IPv4 address characters then we return -1
151.3258 + // immediately; otherwise we insist that these characters parse as a
151.3259 + // legal IPv4 address and throw an exception on failure.
151.3260 + //
151.3261 + // We assume that any string of decimal digits and dots must be an IPv4
151.3262 + // address. It won't parse as a hostname anyway, so making that
151.3263 + // assumption here allows more meaningful exceptions to be thrown.
151.3264 + //
151.3265 + private int scanIPv4Address(int start, int n, boolean strict)
151.3266 + throws URISyntaxException
151.3267 + {
151.3268 + int p = start;
151.3269 + int q;
151.3270 + int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT);
151.3271 + if ((m <= p) || (strict && (m != n)))
151.3272 + return -1;
151.3273 + for (;;) {
151.3274 + // Per RFC2732: At most three digits per byte
151.3275 + // Further constraint: Each element fits in a byte
151.3276 + if ((q = scanByte(p, m)) <= p) break; p = q;
151.3277 + if ((q = scan(p, m, '.')) <= p) break; p = q;
151.3278 + if ((q = scanByte(p, m)) <= p) break; p = q;
151.3279 + if ((q = scan(p, m, '.')) <= p) break; p = q;
151.3280 + if ((q = scanByte(p, m)) <= p) break; p = q;
151.3281 + if ((q = scan(p, m, '.')) <= p) break; p = q;
151.3282 + if ((q = scanByte(p, m)) <= p) break; p = q;
151.3283 + if (q < m) break;
151.3284 + return q;
151.3285 + }
151.3286 + fail("Malformed IPv4 address", q);
151.3287 + return -1;
151.3288 + }
151.3289 +
151.3290 + // Take an IPv4 address: Throw an exception if the given interval
151.3291 + // contains anything except an IPv4 address
151.3292 + //
151.3293 + private int takeIPv4Address(int start, int n, String expected)
151.3294 + throws URISyntaxException
151.3295 + {
151.3296 + int p = scanIPv4Address(start, n, true);
151.3297 + if (p <= start)
151.3298 + failExpecting(expected, start);
151.3299 + return p;
151.3300 + }
151.3301 +
151.3302 + // Attempt to parse an IPv4 address, returning -1 on failure but
151.3303 + // allowing the given interval to contain [:<characters>] after
151.3304 + // the IPv4 address.
151.3305 + //
151.3306 + private int parseIPv4Address(int start, int n) {
151.3307 + int p;
151.3308 +
151.3309 + try {
151.3310 + p = scanIPv4Address(start, n, false);
151.3311 + } catch (URISyntaxException x) {
151.3312 + return -1;
151.3313 + } catch (NumberFormatException nfe) {
151.3314 + return -1;
151.3315 + }
151.3316 +
151.3317 + if (p > start && p < n) {
151.3318 + // IPv4 address is followed by something - check that
151.3319 + // it's a ":" as this is the only valid character to
151.3320 + // follow an address.
151.3321 + if (charAt(p) != ':') {
151.3322 + p = -1;
151.3323 + }
151.3324 + }
151.3325 +
151.3326 + if (p > start)
151.3327 + host = substring(start, p);
151.3328 +
151.3329 + return p;
151.3330 + }
151.3331 +
151.3332 + // hostname = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
151.3333 + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
151.3334 + // toplabel = alpha | alpha *( alphanum | "-" ) alphanum
151.3335 + //
151.3336 + private int parseHostname(int start, int n)
151.3337 + throws URISyntaxException
151.3338 + {
151.3339 + int p = start;
151.3340 + int q;
151.3341 + int l = -1; // Start of last parsed label
151.3342 +
151.3343 + do {
151.3344 + // domainlabel = alphanum [ *( alphanum | "-" ) alphanum ]
151.3345 + q = scan(p, n, L_ALPHANUM, H_ALPHANUM);
151.3346 + if (q <= p)
151.3347 + break;
151.3348 + l = p;
151.3349 + if (q > p) {
151.3350 + p = q;
151.3351 + q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH);
151.3352 + if (q > p) {
151.3353 + if (charAt(q - 1) == '-')
151.3354 + fail("Illegal character in hostname", q - 1);
151.3355 + p = q;
151.3356 + }
151.3357 + }
151.3358 + q = scan(p, n, '.');
151.3359 + if (q <= p)
151.3360 + break;
151.3361 + p = q;
151.3362 + } while (p < n);
151.3363 +
151.3364 + if ((p < n) && !at(p, n, ':'))
151.3365 + fail("Illegal character in hostname", p);
151.3366 +
151.3367 + if (l < 0)
151.3368 + failExpecting("hostname", start);
151.3369 +
151.3370 + // for a fully qualified hostname check that the rightmost
151.3371 + // label starts with an alpha character.
151.3372 + if (l > start && !match(charAt(l), L_ALPHA, H_ALPHA)) {
151.3373 + fail("Illegal character in hostname", l);
151.3374 + }
151.3375 +
151.3376 + host = substring(start, p);
151.3377 + return p;
151.3378 + }
151.3379 +
151.3380 +
151.3381 + // IPv6 address parsing, from RFC2373: IPv6 Addressing Architecture
151.3382 + //
151.3383 + // Bug: The grammar in RFC2373 Appendix B does not allow addresses of
151.3384 + // the form ::12.34.56.78, which are clearly shown in the examples
151.3385 + // earlier in the document. Here is the original grammar:
151.3386 + //
151.3387 + // IPv6address = hexpart [ ":" IPv4address ]
151.3388 + // hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
151.3389 + // hexseq = hex4 *( ":" hex4)
151.3390 + // hex4 = 1*4HEXDIG
151.3391 + //
151.3392 + // We therefore use the following revised grammar:
151.3393 + //
151.3394 + // IPv6address = hexseq [ ":" IPv4address ]
151.3395 + // | hexseq [ "::" [ hexpost ] ]
151.3396 + // | "::" [ hexpost ]
151.3397 + // hexpost = hexseq | hexseq ":" IPv4address | IPv4address
151.3398 + // hexseq = hex4 *( ":" hex4)
151.3399 + // hex4 = 1*4HEXDIG
151.3400 + //
151.3401 + // This covers all and only the following cases:
151.3402 + //
151.3403 + // hexseq
151.3404 + // hexseq : IPv4address
151.3405 + // hexseq ::
151.3406 + // hexseq :: hexseq
151.3407 + // hexseq :: hexseq : IPv4address
151.3408 + // hexseq :: IPv4address
151.3409 + // :: hexseq
151.3410 + // :: hexseq : IPv4address
151.3411 + // :: IPv4address
151.3412 + // ::
151.3413 + //
151.3414 + // Additionally we constrain the IPv6 address as follows :-
151.3415 + //
151.3416 + // i. IPv6 addresses without compressed zeros should contain
151.3417 + // exactly 16 bytes.
151.3418 + //
151.3419 + // ii. IPv6 addresses with compressed zeros should contain
151.3420 + // less than 16 bytes.
151.3421 +
151.3422 + private int ipv6byteCount = 0;
151.3423 +
151.3424 + private int parseIPv6Reference(int start, int n)
151.3425 + throws URISyntaxException
151.3426 + {
151.3427 + int p = start;
151.3428 + int q;
151.3429 + boolean compressedZeros = false;
151.3430 +
151.3431 + q = scanHexSeq(p, n);
151.3432 +
151.3433 + if (q > p) {
151.3434 + p = q;
151.3435 + if (at(p, n, "::")) {
151.3436 + compressedZeros = true;
151.3437 + p = scanHexPost(p + 2, n);
151.3438 + } else if (at(p, n, ':')) {
151.3439 + p = takeIPv4Address(p + 1, n, "IPv4 address");
151.3440 + ipv6byteCount += 4;
151.3441 + }
151.3442 + } else if (at(p, n, "::")) {
151.3443 + compressedZeros = true;
151.3444 + p = scanHexPost(p + 2, n);
151.3445 + }
151.3446 + if (p < n)
151.3447 + fail("Malformed IPv6 address", start);
151.3448 + if (ipv6byteCount > 16)
151.3449 + fail("IPv6 address too long", start);
151.3450 + if (!compressedZeros && ipv6byteCount < 16)
151.3451 + fail("IPv6 address too short", start);
151.3452 + if (compressedZeros && ipv6byteCount == 16)
151.3453 + fail("Malformed IPv6 address", start);
151.3454 +
151.3455 + return p;
151.3456 + }
151.3457 +
151.3458 + private int scanHexPost(int start, int n)
151.3459 + throws URISyntaxException
151.3460 + {
151.3461 + int p = start;
151.3462 + int q;
151.3463 +
151.3464 + if (p == n)
151.3465 + return p;
151.3466 +
151.3467 + q = scanHexSeq(p, n);
151.3468 + if (q > p) {
151.3469 + p = q;
151.3470 + if (at(p, n, ':')) {
151.3471 + p++;
151.3472 + p = takeIPv4Address(p, n, "hex digits or IPv4 address");
151.3473 + ipv6byteCount += 4;
151.3474 + }
151.3475 + } else {
151.3476 + p = takeIPv4Address(p, n, "hex digits or IPv4 address");
151.3477 + ipv6byteCount += 4;
151.3478 + }
151.3479 + return p;
151.3480 + }
151.3481 +
151.3482 + // Scan a hex sequence; return -1 if one could not be scanned
151.3483 + //
151.3484 + private int scanHexSeq(int start, int n)
151.3485 + throws URISyntaxException
151.3486 + {
151.3487 + int p = start;
151.3488 + int q;
151.3489 +
151.3490 + q = scan(p, n, L_HEX, H_HEX);
151.3491 + if (q <= p)
151.3492 + return -1;
151.3493 + if (at(q, n, '.')) // Beginning of IPv4 address
151.3494 + return -1;
151.3495 + if (q > p + 4)
151.3496 + fail("IPv6 hexadecimal digit sequence too long", p);
151.3497 + ipv6byteCount += 2;
151.3498 + p = q;
151.3499 + while (p < n) {
151.3500 + if (!at(p, n, ':'))
151.3501 + break;
151.3502 + if (at(p + 1, n, ':'))
151.3503 + break; // "::"
151.3504 + p++;
151.3505 + q = scan(p, n, L_HEX, H_HEX);
151.3506 + if (q <= p)
151.3507 + failExpecting("digits for an IPv6 address", p);
151.3508 + if (at(q, n, '.')) { // Beginning of IPv4 address
151.3509 + p--;
151.3510 + break;
151.3511 + }
151.3512 + if (q > p + 4)
151.3513 + fail("IPv6 hexadecimal digit sequence too long", p);
151.3514 + ipv6byteCount += 2;
151.3515 + p = q;
151.3516 + }
151.3517 +
151.3518 + return p;
151.3519 + }
151.3520 +
151.3521 + }
151.3522 +
151.3523 +}
152.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
152.2 +++ b/rt/emul/compact/src/main/java/java/net/URISyntaxException.java Mon Oct 07 14:20:58 2013 +0200
152.3 @@ -0,0 +1,135 @@
152.4 +/*
152.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
152.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
152.7 + *
152.8 + * This code is free software; you can redistribute it and/or modify it
152.9 + * under the terms of the GNU General Public License version 2 only, as
152.10 + * published by the Free Software Foundation. Oracle designates this
152.11 + * particular file as subject to the "Classpath" exception as provided
152.12 + * by Oracle in the LICENSE file that accompanied this code.
152.13 + *
152.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
152.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
152.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
152.17 + * version 2 for more details (a copy is included in the LICENSE file that
152.18 + * accompanied this code).
152.19 + *
152.20 + * You should have received a copy of the GNU General Public License version
152.21 + * 2 along with this work; if not, write to the Free Software Foundation,
152.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
152.23 + *
152.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
152.25 + * or visit www.oracle.com if you need additional information or have any
152.26 + * questions.
152.27 + */
152.28 +
152.29 +package java.net;
152.30 +
152.31 +
152.32 +/**
152.33 + * Checked exception thrown to indicate that a string could not be parsed as a
152.34 + * URI reference.
152.35 + *
152.36 + * @author Mark Reinhold
152.37 + * @see URI
152.38 + * @since 1.4
152.39 + */
152.40 +
152.41 +public class URISyntaxException
152.42 + extends Exception
152.43 +{
152.44 + private static final long serialVersionUID = 2137979680897488891L;
152.45 +
152.46 + private String input;
152.47 + private int index;
152.48 +
152.49 + /**
152.50 + * Constructs an instance from the given input string, reason, and error
152.51 + * index.
152.52 + *
152.53 + * @param input The input string
152.54 + * @param reason A string explaining why the input could not be parsed
152.55 + * @param index The index at which the parse error occurred,
152.56 + * or <tt>-1</tt> if the index is not known
152.57 + *
152.58 + * @throws NullPointerException
152.59 + * If either the input or reason strings are <tt>null</tt>
152.60 + *
152.61 + * @throws IllegalArgumentException
152.62 + * If the error index is less than <tt>-1</tt>
152.63 + */
152.64 + public URISyntaxException(String input, String reason, int index) {
152.65 + super(reason);
152.66 + if ((input == null) || (reason == null))
152.67 + throw new NullPointerException();
152.68 + if (index < -1)
152.69 + throw new IllegalArgumentException();
152.70 + this.input = input;
152.71 + this.index = index;
152.72 + }
152.73 +
152.74 + /**
152.75 + * Constructs an instance from the given input string and reason. The
152.76 + * resulting object will have an error index of <tt>-1</tt>.
152.77 + *
152.78 + * @param input The input string
152.79 + * @param reason A string explaining why the input could not be parsed
152.80 + *
152.81 + * @throws NullPointerException
152.82 + * If either the input or reason strings are <tt>null</tt>
152.83 + */
152.84 + public URISyntaxException(String input, String reason) {
152.85 + this(input, reason, -1);
152.86 + }
152.87 +
152.88 + /**
152.89 + * Returns the input string.
152.90 + *
152.91 + * @return The input string
152.92 + */
152.93 + public String getInput() {
152.94 + return input;
152.95 + }
152.96 +
152.97 + /**
152.98 + * Returns a string explaining why the input string could not be parsed.
152.99 + *
152.100 + * @return The reason string
152.101 + */
152.102 + public String getReason() {
152.103 + return super.getMessage();
152.104 + }
152.105 +
152.106 + /**
152.107 + * Returns an index into the input string of the position at which the
152.108 + * parse error occurred, or <tt>-1</tt> if this position is not known.
152.109 + *
152.110 + * @return The error index
152.111 + */
152.112 + public int getIndex() {
152.113 + return index;
152.114 + }
152.115 +
152.116 + /**
152.117 + * Returns a string describing the parse error. The resulting string
152.118 + * consists of the reason string followed by a colon character
152.119 + * (<tt>':'</tt>), a space, and the input string. If the error index is
152.120 + * defined then the string <tt>" at index "</tt> followed by the index, in
152.121 + * decimal, is inserted after the reason string and before the colon
152.122 + * character.
152.123 + *
152.124 + * @return A string describing the parse error
152.125 + */
152.126 + public String getMessage() {
152.127 + StringBuffer sb = new StringBuffer();
152.128 + sb.append(getReason());
152.129 + if (index > -1) {
152.130 + sb.append(" at index ");
152.131 + sb.append(index);
152.132 + }
152.133 + sb.append(": ");
152.134 + sb.append(input);
152.135 + return sb.toString();
152.136 + }
152.137 +
152.138 +}
153.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
153.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumMap.java Mon Oct 07 14:20:58 2013 +0200
153.3 @@ -0,0 +1,797 @@
153.4 +/*
153.5 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
153.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
153.7 + *
153.8 + * This code is free software; you can redistribute it and/or modify it
153.9 + * under the terms of the GNU General Public License version 2 only, as
153.10 + * published by the Free Software Foundation. Oracle designates this
153.11 + * particular file as subject to the "Classpath" exception as provided
153.12 + * by Oracle in the LICENSE file that accompanied this code.
153.13 + *
153.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
153.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
153.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
153.17 + * version 2 for more details (a copy is included in the LICENSE file that
153.18 + * accompanied this code).
153.19 + *
153.20 + * You should have received a copy of the GNU General Public License version
153.21 + * 2 along with this work; if not, write to the Free Software Foundation,
153.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
153.23 + *
153.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
153.25 + * or visit www.oracle.com if you need additional information or have any
153.26 + * questions.
153.27 + */
153.28 +
153.29 +package java.util;
153.30 +
153.31 +import java.util.Map.Entry;
153.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
153.33 +
153.34 +/**
153.35 + * A specialized {@link Map} implementation for use with enum type keys. All
153.36 + * of the keys in an enum map must come from a single enum type that is
153.37 + * specified, explicitly or implicitly, when the map is created. Enum maps
153.38 + * are represented internally as arrays. This representation is extremely
153.39 + * compact and efficient.
153.40 + *
153.41 + * <p>Enum maps are maintained in the <i>natural order</i> of their keys
153.42 + * (the order in which the enum constants are declared). This is reflected
153.43 + * in the iterators returned by the collections views ({@link #keySet()},
153.44 + * {@link #entrySet()}, and {@link #values()}).
153.45 + *
153.46 + * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
153.47 + * they will never throw {@link ConcurrentModificationException} and they may
153.48 + * or may not show the effects of any modifications to the map that occur while
153.49 + * the iteration is in progress.
153.50 + *
153.51 + * <p>Null keys are not permitted. Attempts to insert a null key will
153.52 + * throw {@link NullPointerException}. Attempts to test for the
153.53 + * presence of a null key or to remove one will, however, function properly.
153.54 + * Null values are permitted.
153.55 +
153.56 + * <P>Like most collection implementations <tt>EnumMap</tt> is not
153.57 + * synchronized. If multiple threads access an enum map concurrently, and at
153.58 + * least one of the threads modifies the map, it should be synchronized
153.59 + * externally. This is typically accomplished by synchronizing on some
153.60 + * object that naturally encapsulates the enum map. If no such object exists,
153.61 + * the map should be "wrapped" using the {@link Collections#synchronizedMap}
153.62 + * method. This is best done at creation time, to prevent accidental
153.63 + * unsynchronized access:
153.64 + *
153.65 + * <pre>
153.66 + * Map<EnumKey, V> m
153.67 + * = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
153.68 + * </pre>
153.69 + *
153.70 + * <p>Implementation note: All basic operations execute in constant time.
153.71 + * They are likely (though not guaranteed) to be faster than their
153.72 + * {@link HashMap} counterparts.
153.73 + *
153.74 + * <p>This class is a member of the
153.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
153.76 + * Java Collections Framework</a>.
153.77 + *
153.78 + * @author Josh Bloch
153.79 + * @see EnumSet
153.80 + * @since 1.5
153.81 + */
153.82 +public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
153.83 + implements java.io.Serializable, Cloneable
153.84 +{
153.85 + /**
153.86 + * The <tt>Class</tt> object for the enum type of all the keys of this map.
153.87 + *
153.88 + * @serial
153.89 + */
153.90 + private final Class<K> keyType;
153.91 +
153.92 + /**
153.93 + * All of the values comprising K. (Cached for performance.)
153.94 + */
153.95 + private transient K[] keyUniverse;
153.96 +
153.97 + /**
153.98 + * Array representation of this map. The ith element is the value
153.99 + * to which universe[i] is currently mapped, or null if it isn't
153.100 + * mapped to anything, or NULL if it's mapped to null.
153.101 + */
153.102 + private transient Object[] vals;
153.103 +
153.104 + /**
153.105 + * The number of mappings in this map.
153.106 + */
153.107 + private transient int size = 0;
153.108 +
153.109 + /**
153.110 + * Distinguished non-null value for representing null values.
153.111 + */
153.112 + private static final Object NULL = new Integer(0);
153.113 +
153.114 + private Object maskNull(Object value) {
153.115 + return (value == null ? NULL : value);
153.116 + }
153.117 +
153.118 + private V unmaskNull(Object value) {
153.119 + return (V) (value == NULL ? null : value);
153.120 + }
153.121 +
153.122 + private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
153.123 +
153.124 + /**
153.125 + * Creates an empty enum map with the specified key type.
153.126 + *
153.127 + * @param keyType the class object of the key type for this enum map
153.128 + * @throws NullPointerException if <tt>keyType</tt> is null
153.129 + */
153.130 + public EnumMap(Class<K> keyType) {
153.131 + this.keyType = keyType;
153.132 + keyUniverse = getKeyUniverse(keyType);
153.133 + vals = new Object[keyUniverse.length];
153.134 + }
153.135 +
153.136 + /**
153.137 + * Creates an enum map with the same key type as the specified enum
153.138 + * map, initially containing the same mappings (if any).
153.139 + *
153.140 + * @param m the enum map from which to initialize this enum map
153.141 + * @throws NullPointerException if <tt>m</tt> is null
153.142 + */
153.143 + public EnumMap(EnumMap<K, ? extends V> m) {
153.144 + keyType = m.keyType;
153.145 + keyUniverse = m.keyUniverse;
153.146 + vals = m.vals.clone();
153.147 + size = m.size;
153.148 + }
153.149 +
153.150 + /**
153.151 + * Creates an enum map initialized from the specified map. If the
153.152 + * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
153.153 + * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map
153.154 + * must contain at least one mapping (in order to determine the new
153.155 + * enum map's key type).
153.156 + *
153.157 + * @param m the map from which to initialize this enum map
153.158 + * @throws IllegalArgumentException if <tt>m</tt> is not an
153.159 + * <tt>EnumMap</tt> instance and contains no mappings
153.160 + * @throws NullPointerException if <tt>m</tt> is null
153.161 + */
153.162 + public EnumMap(Map<K, ? extends V> m) {
153.163 + if (m instanceof EnumMap) {
153.164 + EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
153.165 + keyType = em.keyType;
153.166 + keyUniverse = em.keyUniverse;
153.167 + vals = em.vals.clone();
153.168 + size = em.size;
153.169 + } else {
153.170 + if (m.isEmpty())
153.171 + throw new IllegalArgumentException("Specified map is empty");
153.172 + keyType = m.keySet().iterator().next().getDeclaringClass();
153.173 + keyUniverse = getKeyUniverse(keyType);
153.174 + vals = new Object[keyUniverse.length];
153.175 + putAll(m);
153.176 + }
153.177 + }
153.178 +
153.179 + // Query Operations
153.180 +
153.181 + /**
153.182 + * Returns the number of key-value mappings in this map.
153.183 + *
153.184 + * @return the number of key-value mappings in this map
153.185 + */
153.186 + public int size() {
153.187 + return size;
153.188 + }
153.189 +
153.190 + /**
153.191 + * Returns <tt>true</tt> if this map maps one or more keys to the
153.192 + * specified value.
153.193 + *
153.194 + * @param value the value whose presence in this map is to be tested
153.195 + * @return <tt>true</tt> if this map maps one or more keys to this value
153.196 + */
153.197 + public boolean containsValue(Object value) {
153.198 + value = maskNull(value);
153.199 +
153.200 + for (Object val : vals)
153.201 + if (value.equals(val))
153.202 + return true;
153.203 +
153.204 + return false;
153.205 + }
153.206 +
153.207 + /**
153.208 + * Returns <tt>true</tt> if this map contains a mapping for the specified
153.209 + * key.
153.210 + *
153.211 + * @param key the key whose presence in this map is to be tested
153.212 + * @return <tt>true</tt> if this map contains a mapping for the specified
153.213 + * key
153.214 + */
153.215 + public boolean containsKey(Object key) {
153.216 + return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
153.217 + }
153.218 +
153.219 + private boolean containsMapping(Object key, Object value) {
153.220 + return isValidKey(key) &&
153.221 + maskNull(value).equals(vals[((Enum)key).ordinal()]);
153.222 + }
153.223 +
153.224 + /**
153.225 + * Returns the value to which the specified key is mapped,
153.226 + * or {@code null} if this map contains no mapping for the key.
153.227 + *
153.228 + * <p>More formally, if this map contains a mapping from a key
153.229 + * {@code k} to a value {@code v} such that {@code (key == k)},
153.230 + * then this method returns {@code v}; otherwise it returns
153.231 + * {@code null}. (There can be at most one such mapping.)
153.232 + *
153.233 + * <p>A return value of {@code null} does not <i>necessarily</i>
153.234 + * indicate that the map contains no mapping for the key; it's also
153.235 + * possible that the map explicitly maps the key to {@code null}.
153.236 + * The {@link #containsKey containsKey} operation may be used to
153.237 + * distinguish these two cases.
153.238 + */
153.239 + public V get(Object key) {
153.240 + return (isValidKey(key) ?
153.241 + unmaskNull(vals[((Enum)key).ordinal()]) : null);
153.242 + }
153.243 +
153.244 + // Modification Operations
153.245 +
153.246 + /**
153.247 + * Associates the specified value with the specified key in this map.
153.248 + * If the map previously contained a mapping for this key, the old
153.249 + * value is replaced.
153.250 + *
153.251 + * @param key the key with which the specified value is to be associated
153.252 + * @param value the value to be associated with the specified key
153.253 + *
153.254 + * @return the previous value associated with specified key, or
153.255 + * <tt>null</tt> if there was no mapping for key. (A <tt>null</tt>
153.256 + * return can also indicate that the map previously associated
153.257 + * <tt>null</tt> with the specified key.)
153.258 + * @throws NullPointerException if the specified key is null
153.259 + */
153.260 + public V put(K key, V value) {
153.261 + typeCheck(key);
153.262 +
153.263 + int index = key.ordinal();
153.264 + Object oldValue = vals[index];
153.265 + vals[index] = maskNull(value);
153.266 + if (oldValue == null)
153.267 + size++;
153.268 + return unmaskNull(oldValue);
153.269 + }
153.270 +
153.271 + /**
153.272 + * Removes the mapping for this key from this map if present.
153.273 + *
153.274 + * @param key the key whose mapping is to be removed from the map
153.275 + * @return the previous value associated with specified key, or
153.276 + * <tt>null</tt> if there was no entry for key. (A <tt>null</tt>
153.277 + * return can also indicate that the map previously associated
153.278 + * <tt>null</tt> with the specified key.)
153.279 + */
153.280 + public V remove(Object key) {
153.281 + if (!isValidKey(key))
153.282 + return null;
153.283 + int index = ((Enum)key).ordinal();
153.284 + Object oldValue = vals[index];
153.285 + vals[index] = null;
153.286 + if (oldValue != null)
153.287 + size--;
153.288 + return unmaskNull(oldValue);
153.289 + }
153.290 +
153.291 + private boolean removeMapping(Object key, Object value) {
153.292 + if (!isValidKey(key))
153.293 + return false;
153.294 + int index = ((Enum)key).ordinal();
153.295 + if (maskNull(value).equals(vals[index])) {
153.296 + vals[index] = null;
153.297 + size--;
153.298 + return true;
153.299 + }
153.300 + return false;
153.301 + }
153.302 +
153.303 + /**
153.304 + * Returns true if key is of the proper type to be a key in this
153.305 + * enum map.
153.306 + */
153.307 + private boolean isValidKey(Object key) {
153.308 + if (key == null)
153.309 + return false;
153.310 +
153.311 + // Cheaper than instanceof Enum followed by getDeclaringClass
153.312 + Class keyClass = key.getClass();
153.313 + return keyClass == keyType || keyClass.getSuperclass() == keyType;
153.314 + }
153.315 +
153.316 + // Bulk Operations
153.317 +
153.318 + /**
153.319 + * Copies all of the mappings from the specified map to this map.
153.320 + * These mappings will replace any mappings that this map had for
153.321 + * any of the keys currently in the specified map.
153.322 + *
153.323 + * @param m the mappings to be stored in this map
153.324 + * @throws NullPointerException the specified map is null, or if
153.325 + * one or more keys in the specified map are null
153.326 + */
153.327 + public void putAll(Map<? extends K, ? extends V> m) {
153.328 + if (m instanceof EnumMap) {
153.329 + EnumMap<? extends K, ? extends V> em =
153.330 + (EnumMap<? extends K, ? extends V>)m;
153.331 + if (em.keyType != keyType) {
153.332 + if (em.isEmpty())
153.333 + return;
153.334 + throw new ClassCastException(em.keyType + " != " + keyType);
153.335 + }
153.336 +
153.337 + for (int i = 0; i < keyUniverse.length; i++) {
153.338 + Object emValue = em.vals[i];
153.339 + if (emValue != null) {
153.340 + if (vals[i] == null)
153.341 + size++;
153.342 + vals[i] = emValue;
153.343 + }
153.344 + }
153.345 + } else {
153.346 + super.putAll(m);
153.347 + }
153.348 + }
153.349 +
153.350 + /**
153.351 + * Removes all mappings from this map.
153.352 + */
153.353 + public void clear() {
153.354 + Arrays.fill(vals, null);
153.355 + size = 0;
153.356 + }
153.357 +
153.358 + // Views
153.359 +
153.360 + /**
153.361 + * This field is initialized to contain an instance of the entry set
153.362 + * view the first time this view is requested. The view is stateless,
153.363 + * so there's no reason to create more than one.
153.364 + */
153.365 + private transient Set<Map.Entry<K,V>> entrySet = null;
153.366 +
153.367 + /**
153.368 + * Returns a {@link Set} view of the keys contained in this map.
153.369 + * The returned set obeys the general contract outlined in
153.370 + * {@link Map#keySet()}. The set's iterator will return the keys
153.371 + * in their natural order (the order in which the enum constants
153.372 + * are declared).
153.373 + *
153.374 + * @return a set view of the keys contained in this enum map
153.375 + */
153.376 + public Set<K> keySet() {
153.377 + Set<K> ks = keySet;
153.378 + if (ks != null)
153.379 + return ks;
153.380 + else
153.381 + return keySet = new KeySet();
153.382 + }
153.383 +
153.384 + private class KeySet extends AbstractSet<K> {
153.385 + public Iterator<K> iterator() {
153.386 + return new KeyIterator();
153.387 + }
153.388 + public int size() {
153.389 + return size;
153.390 + }
153.391 + public boolean contains(Object o) {
153.392 + return containsKey(o);
153.393 + }
153.394 + public boolean remove(Object o) {
153.395 + int oldSize = size;
153.396 + EnumMap.this.remove(o);
153.397 + return size != oldSize;
153.398 + }
153.399 + public void clear() {
153.400 + EnumMap.this.clear();
153.401 + }
153.402 + }
153.403 +
153.404 + /**
153.405 + * Returns a {@link Collection} view of the values contained in this map.
153.406 + * The returned collection obeys the general contract outlined in
153.407 + * {@link Map#values()}. The collection's iterator will return the
153.408 + * values in the order their corresponding keys appear in map,
153.409 + * which is their natural order (the order in which the enum constants
153.410 + * are declared).
153.411 + *
153.412 + * @return a collection view of the values contained in this map
153.413 + */
153.414 + public Collection<V> values() {
153.415 + Collection<V> vs = values;
153.416 + if (vs != null)
153.417 + return vs;
153.418 + else
153.419 + return values = new Values();
153.420 + }
153.421 +
153.422 + private class Values extends AbstractCollection<V> {
153.423 + public Iterator<V> iterator() {
153.424 + return new ValueIterator();
153.425 + }
153.426 + public int size() {
153.427 + return size;
153.428 + }
153.429 + public boolean contains(Object o) {
153.430 + return containsValue(o);
153.431 + }
153.432 + public boolean remove(Object o) {
153.433 + o = maskNull(o);
153.434 +
153.435 + for (int i = 0; i < vals.length; i++) {
153.436 + if (o.equals(vals[i])) {
153.437 + vals[i] = null;
153.438 + size--;
153.439 + return true;
153.440 + }
153.441 + }
153.442 + return false;
153.443 + }
153.444 + public void clear() {
153.445 + EnumMap.this.clear();
153.446 + }
153.447 + }
153.448 +
153.449 + /**
153.450 + * Returns a {@link Set} view of the mappings contained in this map.
153.451 + * The returned set obeys the general contract outlined in
153.452 + * {@link Map#keySet()}. The set's iterator will return the
153.453 + * mappings in the order their keys appear in map, which is their
153.454 + * natural order (the order in which the enum constants are declared).
153.455 + *
153.456 + * @return a set view of the mappings contained in this enum map
153.457 + */
153.458 + public Set<Map.Entry<K,V>> entrySet() {
153.459 + Set<Map.Entry<K,V>> es = entrySet;
153.460 + if (es != null)
153.461 + return es;
153.462 + else
153.463 + return entrySet = new EntrySet();
153.464 + }
153.465 +
153.466 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
153.467 + public Iterator<Map.Entry<K,V>> iterator() {
153.468 + return new EntryIterator();
153.469 + }
153.470 +
153.471 + public boolean contains(Object o) {
153.472 + if (!(o instanceof Map.Entry))
153.473 + return false;
153.474 + Map.Entry entry = (Map.Entry)o;
153.475 + return containsMapping(entry.getKey(), entry.getValue());
153.476 + }
153.477 + public boolean remove(Object o) {
153.478 + if (!(o instanceof Map.Entry))
153.479 + return false;
153.480 + Map.Entry entry = (Map.Entry)o;
153.481 + return removeMapping(entry.getKey(), entry.getValue());
153.482 + }
153.483 + public int size() {
153.484 + return size;
153.485 + }
153.486 + public void clear() {
153.487 + EnumMap.this.clear();
153.488 + }
153.489 + public Object[] toArray() {
153.490 + return fillEntryArray(new Object[size]);
153.491 + }
153.492 + @SuppressWarnings("unchecked")
153.493 + public <T> T[] toArray(T[] a) {
153.494 + int size = size();
153.495 + if (a.length < size)
153.496 + a = (T[])java.lang.reflect.Array
153.497 + .newInstance(a.getClass().getComponentType(), size);
153.498 + if (a.length > size)
153.499 + a[size] = null;
153.500 + return (T[]) fillEntryArray(a);
153.501 + }
153.502 + private Object[] fillEntryArray(Object[] a) {
153.503 + int j = 0;
153.504 + for (int i = 0; i < vals.length; i++)
153.505 + if (vals[i] != null)
153.506 + a[j++] = new AbstractMap.SimpleEntry<>(
153.507 + keyUniverse[i], unmaskNull(vals[i]));
153.508 + return a;
153.509 + }
153.510 + }
153.511 +
153.512 + private abstract class EnumMapIterator<T> implements Iterator<T> {
153.513 + // Lower bound on index of next element to return
153.514 + int index = 0;
153.515 +
153.516 + // Index of last returned element, or -1 if none
153.517 + int lastReturnedIndex = -1;
153.518 +
153.519 + public boolean hasNext() {
153.520 + while (index < vals.length && vals[index] == null)
153.521 + index++;
153.522 + return index != vals.length;
153.523 + }
153.524 +
153.525 + public void remove() {
153.526 + checkLastReturnedIndex();
153.527 +
153.528 + if (vals[lastReturnedIndex] != null) {
153.529 + vals[lastReturnedIndex] = null;
153.530 + size--;
153.531 + }
153.532 + lastReturnedIndex = -1;
153.533 + }
153.534 +
153.535 + private void checkLastReturnedIndex() {
153.536 + if (lastReturnedIndex < 0)
153.537 + throw new IllegalStateException();
153.538 + }
153.539 + }
153.540 +
153.541 + private class KeyIterator extends EnumMapIterator<K> {
153.542 + public K next() {
153.543 + if (!hasNext())
153.544 + throw new NoSuchElementException();
153.545 + lastReturnedIndex = index++;
153.546 + return keyUniverse[lastReturnedIndex];
153.547 + }
153.548 + }
153.549 +
153.550 + private class ValueIterator extends EnumMapIterator<V> {
153.551 + public V next() {
153.552 + if (!hasNext())
153.553 + throw new NoSuchElementException();
153.554 + lastReturnedIndex = index++;
153.555 + return unmaskNull(vals[lastReturnedIndex]);
153.556 + }
153.557 + }
153.558 +
153.559 + private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
153.560 + private Entry lastReturnedEntry = null;
153.561 +
153.562 + public Map.Entry<K,V> next() {
153.563 + if (!hasNext())
153.564 + throw new NoSuchElementException();
153.565 + lastReturnedEntry = new Entry(index++);
153.566 + return lastReturnedEntry;
153.567 + }
153.568 +
153.569 + public void remove() {
153.570 + lastReturnedIndex =
153.571 + ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
153.572 + super.remove();
153.573 + lastReturnedEntry.index = lastReturnedIndex;
153.574 + lastReturnedEntry = null;
153.575 + }
153.576 +
153.577 + private class Entry implements Map.Entry<K,V> {
153.578 + private int index;
153.579 +
153.580 + private Entry(int index) {
153.581 + this.index = index;
153.582 + }
153.583 +
153.584 + public K getKey() {
153.585 + checkIndexForEntryUse();
153.586 + return keyUniverse[index];
153.587 + }
153.588 +
153.589 + public V getValue() {
153.590 + checkIndexForEntryUse();
153.591 + return unmaskNull(vals[index]);
153.592 + }
153.593 +
153.594 + public V setValue(V value) {
153.595 + checkIndexForEntryUse();
153.596 + V oldValue = unmaskNull(vals[index]);
153.597 + vals[index] = maskNull(value);
153.598 + return oldValue;
153.599 + }
153.600 +
153.601 + public boolean equals(Object o) {
153.602 + if (index < 0)
153.603 + return o == this;
153.604 +
153.605 + if (!(o instanceof Map.Entry))
153.606 + return false;
153.607 +
153.608 + Map.Entry e = (Map.Entry)o;
153.609 + V ourValue = unmaskNull(vals[index]);
153.610 + Object hisValue = e.getValue();
153.611 + return (e.getKey() == keyUniverse[index] &&
153.612 + (ourValue == hisValue ||
153.613 + (ourValue != null && ourValue.equals(hisValue))));
153.614 + }
153.615 +
153.616 + public int hashCode() {
153.617 + if (index < 0)
153.618 + return super.hashCode();
153.619 +
153.620 + return entryHashCode(index);
153.621 + }
153.622 +
153.623 + public String toString() {
153.624 + if (index < 0)
153.625 + return super.toString();
153.626 +
153.627 + return keyUniverse[index] + "="
153.628 + + unmaskNull(vals[index]);
153.629 + }
153.630 +
153.631 + private void checkIndexForEntryUse() {
153.632 + if (index < 0)
153.633 + throw new IllegalStateException("Entry was removed");
153.634 + }
153.635 + }
153.636 + }
153.637 +
153.638 + // Comparison and hashing
153.639 +
153.640 + /**
153.641 + * Compares the specified object with this map for equality. Returns
153.642 + * <tt>true</tt> if the given object is also a map and the two maps
153.643 + * represent the same mappings, as specified in the {@link
153.644 + * Map#equals(Object)} contract.
153.645 + *
153.646 + * @param o the object to be compared for equality with this map
153.647 + * @return <tt>true</tt> if the specified object is equal to this map
153.648 + */
153.649 + public boolean equals(Object o) {
153.650 + if (this == o)
153.651 + return true;
153.652 + if (o instanceof EnumMap)
153.653 + return equals((EnumMap)o);
153.654 + if (!(o instanceof Map))
153.655 + return false;
153.656 +
153.657 + Map<K,V> m = (Map<K,V>)o;
153.658 + if (size != m.size())
153.659 + return false;
153.660 +
153.661 + for (int i = 0; i < keyUniverse.length; i++) {
153.662 + if (null != vals[i]) {
153.663 + K key = keyUniverse[i];
153.664 + V value = unmaskNull(vals[i]);
153.665 + if (null == value) {
153.666 + if (!((null == m.get(key)) && m.containsKey(key)))
153.667 + return false;
153.668 + } else {
153.669 + if (!value.equals(m.get(key)))
153.670 + return false;
153.671 + }
153.672 + }
153.673 + }
153.674 +
153.675 + return true;
153.676 + }
153.677 +
153.678 + private boolean equals(EnumMap em) {
153.679 + if (em.keyType != keyType)
153.680 + return size == 0 && em.size == 0;
153.681 +
153.682 + // Key types match, compare each value
153.683 + for (int i = 0; i < keyUniverse.length; i++) {
153.684 + Object ourValue = vals[i];
153.685 + Object hisValue = em.vals[i];
153.686 + if (hisValue != ourValue &&
153.687 + (hisValue == null || !hisValue.equals(ourValue)))
153.688 + return false;
153.689 + }
153.690 + return true;
153.691 + }
153.692 +
153.693 + /**
153.694 + * Returns the hash code value for this map. The hash code of a map is
153.695 + * defined to be the sum of the hash codes of each entry in the map.
153.696 + */
153.697 + public int hashCode() {
153.698 + int h = 0;
153.699 +
153.700 + for (int i = 0; i < keyUniverse.length; i++) {
153.701 + if (null != vals[i]) {
153.702 + h += entryHashCode(i);
153.703 + }
153.704 + }
153.705 +
153.706 + return h;
153.707 + }
153.708 +
153.709 + private int entryHashCode(int index) {
153.710 + return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
153.711 + }
153.712 +
153.713 + /**
153.714 + * Returns a shallow copy of this enum map. (The values themselves
153.715 + * are not cloned.
153.716 + *
153.717 + * @return a shallow copy of this enum map
153.718 + */
153.719 + public EnumMap<K, V> clone() {
153.720 + EnumMap<K, V> result = null;
153.721 + try {
153.722 + result = (EnumMap<K, V>) super.clone();
153.723 + } catch(CloneNotSupportedException e) {
153.724 + throw new AssertionError();
153.725 + }
153.726 + result.vals = result.vals.clone();
153.727 + return result;
153.728 + }
153.729 +
153.730 + /**
153.731 + * Throws an exception if e is not of the correct type for this enum set.
153.732 + */
153.733 + private void typeCheck(K key) {
153.734 + Class keyClass = key.getClass();
153.735 + if (keyClass != keyType && keyClass.getSuperclass() != keyType)
153.736 + throw new ClassCastException(keyClass + " != " + keyType);
153.737 + }
153.738 +
153.739 + /**
153.740 + * Returns all of the values comprising K.
153.741 + * The result is uncloned, cached, and shared by all callers.
153.742 + */
153.743 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;")
153.744 + private static native <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType);
153.745 +
153.746 + private static final long serialVersionUID = 458661240069192865L;
153.747 +
153.748 + /**
153.749 + * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
153.750 + * serialize it).
153.751 + *
153.752 + * @serialData The <i>size</i> of the enum map (the number of key-value
153.753 + * mappings) is emitted (int), followed by the key (Object)
153.754 + * and value (Object) for each key-value mapping represented
153.755 + * by the enum map.
153.756 + */
153.757 + private void writeObject(java.io.ObjectOutputStream s)
153.758 + throws java.io.IOException
153.759 + {
153.760 + // Write out the key type and any hidden stuff
153.761 + s.defaultWriteObject();
153.762 +
153.763 + // Write out size (number of Mappings)
153.764 + s.writeInt(size);
153.765 +
153.766 + // Write out keys and values (alternating)
153.767 + int entriesToBeWritten = size;
153.768 + for (int i = 0; entriesToBeWritten > 0; i++) {
153.769 + if (null != vals[i]) {
153.770 + s.writeObject(keyUniverse[i]);
153.771 + s.writeObject(unmaskNull(vals[i]));
153.772 + entriesToBeWritten--;
153.773 + }
153.774 + }
153.775 + }
153.776 +
153.777 + /**
153.778 + * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
153.779 + * deserialize it).
153.780 + */
153.781 + private void readObject(java.io.ObjectInputStream s)
153.782 + throws java.io.IOException, ClassNotFoundException
153.783 + {
153.784 + // Read in the key type and any hidden stuff
153.785 + s.defaultReadObject();
153.786 +
153.787 + keyUniverse = getKeyUniverse(keyType);
153.788 + vals = new Object[keyUniverse.length];
153.789 +
153.790 + // Read in size (number of Mappings)
153.791 + int size = s.readInt();
153.792 +
153.793 + // Read the keys and values, and put the mappings in the HashMap
153.794 + for (int i = 0; i < size; i++) {
153.795 + K key = (K) s.readObject();
153.796 + V value = (V) s.readObject();
153.797 + put(key, value);
153.798 + }
153.799 + }
153.800 +}
154.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
154.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumSet.java Mon Oct 07 14:20:58 2013 +0200
154.3 @@ -0,0 +1,441 @@
154.4 +/*
154.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
154.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
154.7 + *
154.8 + * This code is free software; you can redistribute it and/or modify it
154.9 + * under the terms of the GNU General Public License version 2 only, as
154.10 + * published by the Free Software Foundation. Oracle designates this
154.11 + * particular file as subject to the "Classpath" exception as provided
154.12 + * by Oracle in the LICENSE file that accompanied this code.
154.13 + *
154.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
154.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
154.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
154.17 + * version 2 for more details (a copy is included in the LICENSE file that
154.18 + * accompanied this code).
154.19 + *
154.20 + * You should have received a copy of the GNU General Public License version
154.21 + * 2 along with this work; if not, write to the Free Software Foundation,
154.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
154.23 + *
154.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
154.25 + * or visit www.oracle.com if you need additional information or have any
154.26 + * questions.
154.27 + */
154.28 +
154.29 +package java.util;
154.30 +
154.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
154.32 +
154.33 +/**
154.34 + * A specialized {@link Set} implementation for use with enum types. All of
154.35 + * the elements in an enum set must come from a single enum type that is
154.36 + * specified, explicitly or implicitly, when the set is created. Enum sets
154.37 + * are represented internally as bit vectors. This representation is
154.38 + * extremely compact and efficient. The space and time performance of this
154.39 + * class should be good enough to allow its use as a high-quality, typesafe
154.40 + * alternative to traditional <tt>int</tt>-based "bit flags." Even bulk
154.41 + * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
154.42 + * run very quickly if their argument is also an enum set.
154.43 + *
154.44 + * <p>The iterator returned by the <tt>iterator</tt> method traverses the
154.45 + * elements in their <i>natural order</i> (the order in which the enum
154.46 + * constants are declared). The returned iterator is <i>weakly
154.47 + * consistent</i>: it will never throw {@link ConcurrentModificationException}
154.48 + * and it may or may not show the effects of any modifications to the set that
154.49 + * occur while the iteration is in progress.
154.50 + *
154.51 + * <p>Null elements are not permitted. Attempts to insert a null element
154.52 + * will throw {@link NullPointerException}. Attempts to test for the
154.53 + * presence of a null element or to remove one will, however, function
154.54 + * properly.
154.55 + *
154.56 + * <P>Like most collection implementations, <tt>EnumSet</tt> is not
154.57 + * synchronized. If multiple threads access an enum set concurrently, and at
154.58 + * least one of the threads modifies the set, it should be synchronized
154.59 + * externally. This is typically accomplished by synchronizing on some
154.60 + * object that naturally encapsulates the enum set. If no such object exists,
154.61 + * the set should be "wrapped" using the {@link Collections#synchronizedSet}
154.62 + * method. This is best done at creation time, to prevent accidental
154.63 + * unsynchronized access:
154.64 + *
154.65 + * <pre>
154.66 + * Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
154.67 + * </pre>
154.68 + *
154.69 + * <p>Implementation note: All basic operations execute in constant time.
154.70 + * They are likely (though not guaranteed) to be much faster than their
154.71 + * {@link HashSet} counterparts. Even bulk operations execute in
154.72 + * constant time if their argument is also an enum set.
154.73 + *
154.74 + * <p>This class is a member of the
154.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
154.76 + * Java Collections Framework</a>.
154.77 + *
154.78 + * @author Josh Bloch
154.79 + * @since 1.5
154.80 + * @see EnumMap
154.81 + * @serial exclude
154.82 + */
154.83 +public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
154.84 + implements Cloneable, java.io.Serializable
154.85 +{
154.86 + /**
154.87 + * The class of all the elements of this set.
154.88 + */
154.89 + final Class<E> elementType;
154.90 +
154.91 + /**
154.92 + * All of the values comprising T. (Cached for performance.)
154.93 + */
154.94 + final Enum[] universe;
154.95 +
154.96 + private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
154.97 +
154.98 + EnumSet(Class<E>elementType, Enum[] universe) {
154.99 + this.elementType = elementType;
154.100 + this.universe = universe;
154.101 + }
154.102 +
154.103 + /**
154.104 + * Creates an empty enum set with the specified element type.
154.105 + *
154.106 + * @param elementType the class object of the element type for this enum
154.107 + * set
154.108 + * @throws NullPointerException if <tt>elementType</tt> is null
154.109 + */
154.110 + public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
154.111 + Enum[] universe = getUniverse(elementType);
154.112 + if (universe == null)
154.113 + throw new ClassCastException(elementType + " not an enum");
154.114 +
154.115 + if (universe.length <= 64)
154.116 + return new RegularEnumSet<>(elementType, universe);
154.117 + else
154.118 + return new JumboEnumSet<>(elementType, universe);
154.119 + }
154.120 +
154.121 + /**
154.122 + * Creates an enum set containing all of the elements in the specified
154.123 + * element type.
154.124 + *
154.125 + * @param elementType the class object of the element type for this enum
154.126 + * set
154.127 + * @throws NullPointerException if <tt>elementType</tt> is null
154.128 + */
154.129 + public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
154.130 + EnumSet<E> result = noneOf(elementType);
154.131 + result.addAll();
154.132 + return result;
154.133 + }
154.134 +
154.135 + /**
154.136 + * Adds all of the elements from the appropriate enum type to this enum
154.137 + * set, which is empty prior to the call.
154.138 + */
154.139 + abstract void addAll();
154.140 +
154.141 + /**
154.142 + * Creates an enum set with the same element type as the specified enum
154.143 + * set, initially containing the same elements (if any).
154.144 + *
154.145 + * @param s the enum set from which to initialize this enum set
154.146 + * @throws NullPointerException if <tt>s</tt> is null
154.147 + */
154.148 + public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
154.149 + return s.clone();
154.150 + }
154.151 +
154.152 + /**
154.153 + * Creates an enum set initialized from the specified collection. If
154.154 + * the specified collection is an <tt>EnumSet</tt> instance, this static
154.155 + * factory method behaves identically to {@link #copyOf(EnumSet)}.
154.156 + * Otherwise, the specified collection must contain at least one element
154.157 + * (in order to determine the new enum set's element type).
154.158 + *
154.159 + * @param c the collection from which to initialize this enum set
154.160 + * @throws IllegalArgumentException if <tt>c</tt> is not an
154.161 + * <tt>EnumSet</tt> instance and contains no elements
154.162 + * @throws NullPointerException if <tt>c</tt> is null
154.163 + */
154.164 + public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
154.165 + if (c instanceof EnumSet) {
154.166 + return ((EnumSet<E>)c).clone();
154.167 + } else {
154.168 + if (c.isEmpty())
154.169 + throw new IllegalArgumentException("Collection is empty");
154.170 + Iterator<E> i = c.iterator();
154.171 + E first = i.next();
154.172 + EnumSet<E> result = EnumSet.of(first);
154.173 + while (i.hasNext())
154.174 + result.add(i.next());
154.175 + return result;
154.176 + }
154.177 + }
154.178 +
154.179 + /**
154.180 + * Creates an enum set with the same element type as the specified enum
154.181 + * set, initially containing all the elements of this type that are
154.182 + * <i>not</i> contained in the specified set.
154.183 + *
154.184 + * @param s the enum set from whose complement to initialize this enum set
154.185 + * @throws NullPointerException if <tt>s</tt> is null
154.186 + */
154.187 + public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
154.188 + EnumSet<E> result = copyOf(s);
154.189 + result.complement();
154.190 + return result;
154.191 + }
154.192 +
154.193 + /**
154.194 + * Creates an enum set initially containing the specified element.
154.195 + *
154.196 + * Overloadings of this method exist to initialize an enum set with
154.197 + * one through five elements. A sixth overloading is provided that
154.198 + * uses the varargs feature. This overloading may be used to create
154.199 + * an enum set initially containing an arbitrary number of elements, but
154.200 + * is likely to run slower than the overloadings that do not use varargs.
154.201 + *
154.202 + * @param e the element that this set is to contain initially
154.203 + * @throws NullPointerException if <tt>e</tt> is null
154.204 + * @return an enum set initially containing the specified element
154.205 + */
154.206 + public static <E extends Enum<E>> EnumSet<E> of(E e) {
154.207 + EnumSet<E> result = noneOf(e.getDeclaringClass());
154.208 + result.add(e);
154.209 + return result;
154.210 + }
154.211 +
154.212 + /**
154.213 + * Creates an enum set initially containing the specified elements.
154.214 + *
154.215 + * Overloadings of this method exist to initialize an enum set with
154.216 + * one through five elements. A sixth overloading is provided that
154.217 + * uses the varargs feature. This overloading may be used to create
154.218 + * an enum set initially containing an arbitrary number of elements, but
154.219 + * is likely to run slower than the overloadings that do not use varargs.
154.220 + *
154.221 + * @param e1 an element that this set is to contain initially
154.222 + * @param e2 another element that this set is to contain initially
154.223 + * @throws NullPointerException if any parameters are null
154.224 + * @return an enum set initially containing the specified elements
154.225 + */
154.226 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
154.227 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
154.228 + result.add(e1);
154.229 + result.add(e2);
154.230 + return result;
154.231 + }
154.232 +
154.233 + /**
154.234 + * Creates an enum set initially containing the specified elements.
154.235 + *
154.236 + * Overloadings of this method exist to initialize an enum set with
154.237 + * one through five elements. A sixth overloading is provided that
154.238 + * uses the varargs feature. This overloading may be used to create
154.239 + * an enum set initially containing an arbitrary number of elements, but
154.240 + * is likely to run slower than the overloadings that do not use varargs.
154.241 + *
154.242 + * @param e1 an element that this set is to contain initially
154.243 + * @param e2 another element that this set is to contain initially
154.244 + * @param e3 another element that this set is to contain initially
154.245 + * @throws NullPointerException if any parameters are null
154.246 + * @return an enum set initially containing the specified elements
154.247 + */
154.248 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
154.249 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
154.250 + result.add(e1);
154.251 + result.add(e2);
154.252 + result.add(e3);
154.253 + return result;
154.254 + }
154.255 +
154.256 + /**
154.257 + * Creates an enum set initially containing the specified elements.
154.258 + *
154.259 + * Overloadings of this method exist to initialize an enum set with
154.260 + * one through five elements. A sixth overloading is provided that
154.261 + * uses the varargs feature. This overloading may be used to create
154.262 + * an enum set initially containing an arbitrary number of elements, but
154.263 + * is likely to run slower than the overloadings that do not use varargs.
154.264 + *
154.265 + * @param e1 an element that this set is to contain initially
154.266 + * @param e2 another element that this set is to contain initially
154.267 + * @param e3 another element that this set is to contain initially
154.268 + * @param e4 another element that this set is to contain initially
154.269 + * @throws NullPointerException if any parameters are null
154.270 + * @return an enum set initially containing the specified elements
154.271 + */
154.272 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
154.273 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
154.274 + result.add(e1);
154.275 + result.add(e2);
154.276 + result.add(e3);
154.277 + result.add(e4);
154.278 + return result;
154.279 + }
154.280 +
154.281 + /**
154.282 + * Creates an enum set initially containing the specified elements.
154.283 + *
154.284 + * Overloadings of this method exist to initialize an enum set with
154.285 + * one through five elements. A sixth overloading is provided that
154.286 + * uses the varargs feature. This overloading may be used to create
154.287 + * an enum set initially containing an arbitrary number of elements, but
154.288 + * is likely to run slower than the overloadings that do not use varargs.
154.289 + *
154.290 + * @param e1 an element that this set is to contain initially
154.291 + * @param e2 another element that this set is to contain initially
154.292 + * @param e3 another element that this set is to contain initially
154.293 + * @param e4 another element that this set is to contain initially
154.294 + * @param e5 another element that this set is to contain initially
154.295 + * @throws NullPointerException if any parameters are null
154.296 + * @return an enum set initially containing the specified elements
154.297 + */
154.298 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
154.299 + E e5)
154.300 + {
154.301 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
154.302 + result.add(e1);
154.303 + result.add(e2);
154.304 + result.add(e3);
154.305 + result.add(e4);
154.306 + result.add(e5);
154.307 + return result;
154.308 + }
154.309 +
154.310 + /**
154.311 + * Creates an enum set initially containing the specified elements.
154.312 + * This factory, whose parameter list uses the varargs feature, may
154.313 + * be used to create an enum set initially containing an arbitrary
154.314 + * number of elements, but it is likely to run slower than the overloadings
154.315 + * that do not use varargs.
154.316 + *
154.317 + * @param first an element that the set is to contain initially
154.318 + * @param rest the remaining elements the set is to contain initially
154.319 + * @throws NullPointerException if any of the specified elements are null,
154.320 + * or if <tt>rest</tt> is null
154.321 + * @return an enum set initially containing the specified elements
154.322 + */
154.323 + @SafeVarargs
154.324 + public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
154.325 + EnumSet<E> result = noneOf(first.getDeclaringClass());
154.326 + result.add(first);
154.327 + for (E e : rest)
154.328 + result.add(e);
154.329 + return result;
154.330 + }
154.331 +
154.332 + /**
154.333 + * Creates an enum set initially containing all of the elements in the
154.334 + * range defined by the two specified endpoints. The returned set will
154.335 + * contain the endpoints themselves, which may be identical but must not
154.336 + * be out of order.
154.337 + *
154.338 + * @param from the first element in the range
154.339 + * @param to the last element in the range
154.340 + * @throws NullPointerException if {@code from} or {@code to} are null
154.341 + * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
154.342 + * @return an enum set initially containing all of the elements in the
154.343 + * range defined by the two specified endpoints
154.344 + */
154.345 + public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
154.346 + if (from.compareTo(to) > 0)
154.347 + throw new IllegalArgumentException(from + " > " + to);
154.348 + EnumSet<E> result = noneOf(from.getDeclaringClass());
154.349 + result.addRange(from, to);
154.350 + return result;
154.351 + }
154.352 +
154.353 + /**
154.354 + * Adds the specified range to this enum set, which is empty prior
154.355 + * to the call.
154.356 + */
154.357 + abstract void addRange(E from, E to);
154.358 +
154.359 + /**
154.360 + * Returns a copy of this set.
154.361 + *
154.362 + * @return a copy of this set
154.363 + */
154.364 + public EnumSet<E> clone() {
154.365 + try {
154.366 + return (EnumSet<E>) super.clone();
154.367 + } catch(CloneNotSupportedException e) {
154.368 + throw new AssertionError(e);
154.369 + }
154.370 + }
154.371 +
154.372 + /**
154.373 + * Complements the contents of this enum set.
154.374 + */
154.375 + abstract void complement();
154.376 +
154.377 + /**
154.378 + * Throws an exception if e is not of the correct type for this enum set.
154.379 + */
154.380 + final void typeCheck(E e) {
154.381 + Class eClass = e.getClass();
154.382 + if (eClass != elementType && eClass.getSuperclass() != elementType)
154.383 + throw new ClassCastException(eClass + " != " + elementType);
154.384 + }
154.385 +
154.386 + /**
154.387 + * Returns all of the values comprising E.
154.388 + * The result is uncloned, cached, and shared by all callers.
154.389 + */
154.390 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;")
154.391 + private static native <E extends Enum<E>> E[] getUniverse(Class<E> elementType);
154.392 +
154.393 + /**
154.394 + * This class is used to serialize all EnumSet instances, regardless of
154.395 + * implementation type. It captures their "logical contents" and they
154.396 + * are reconstructed using public static factories. This is necessary
154.397 + * to ensure that the existence of a particular implementation type is
154.398 + * an implementation detail.
154.399 + *
154.400 + * @serial include
154.401 + */
154.402 + private static class SerializationProxy <E extends Enum<E>>
154.403 + implements java.io.Serializable
154.404 + {
154.405 + /**
154.406 + * The element type of this enum set.
154.407 + *
154.408 + * @serial
154.409 + */
154.410 + private final Class<E> elementType;
154.411 +
154.412 + /**
154.413 + * The elements contained in this enum set.
154.414 + *
154.415 + * @serial
154.416 + */
154.417 + private final Enum[] elements;
154.418 +
154.419 + SerializationProxy(EnumSet<E> set) {
154.420 + elementType = set.elementType;
154.421 + elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
154.422 + }
154.423 +
154.424 + private Object readResolve() {
154.425 + EnumSet<E> result = EnumSet.noneOf(elementType);
154.426 + for (Enum e : elements)
154.427 + result.add((E)e);
154.428 + return result;
154.429 + }
154.430 +
154.431 + private static final long serialVersionUID = 362491234563181265L;
154.432 + }
154.433 +
154.434 + Object writeReplace() {
154.435 + return new SerializationProxy<>(this);
154.436 + }
154.437 +
154.438 + // readObject method for the serialization proxy pattern
154.439 + // See Effective Java, Second Ed., Item 78.
154.440 + private void readObject(java.io.ObjectInputStream stream)
154.441 + throws java.io.InvalidObjectException {
154.442 + throw new java.io.InvalidObjectException("Proxy required");
154.443 + }
154.444 +}
155.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
155.2 +++ b/rt/emul/compact/src/main/java/java/util/IdentityHashMap.java Mon Oct 07 14:20:58 2013 +0200
155.3 @@ -0,0 +1,1243 @@
155.4 +/*
155.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
155.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
155.7 + *
155.8 + * This code is free software; you can redistribute it and/or modify it
155.9 + * under the terms of the GNU General Public License version 2 only, as
155.10 + * published by the Free Software Foundation. Oracle designates this
155.11 + * particular file as subject to the "Classpath" exception as provided
155.12 + * by Oracle in the LICENSE file that accompanied this code.
155.13 + *
155.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
155.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
155.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
155.17 + * version 2 for more details (a copy is included in the LICENSE file that
155.18 + * accompanied this code).
155.19 + *
155.20 + * You should have received a copy of the GNU General Public License version
155.21 + * 2 along with this work; if not, write to the Free Software Foundation,
155.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
155.23 + *
155.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
155.25 + * or visit www.oracle.com if you need additional information or have any
155.26 + * questions.
155.27 + */
155.28 +
155.29 +package java.util;
155.30 +import java.io.*;
155.31 +
155.32 +/**
155.33 + * This class implements the <tt>Map</tt> interface with a hash table, using
155.34 + * reference-equality in place of object-equality when comparing keys (and
155.35 + * values). In other words, in an <tt>IdentityHashMap</tt>, two keys
155.36 + * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
155.37 + * <tt>(k1==k2)</tt>. (In normal <tt>Map</tt> implementations (like
155.38 + * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
155.39 + * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
155.40 + *
155.41 + * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
155.42 + * implementation! While this class implements the <tt>Map</tt> interface, it
155.43 + * intentionally violates <tt>Map's</tt> general contract, which mandates the
155.44 + * use of the <tt>equals</tt> method when comparing objects. This class is
155.45 + * designed for use only in the rare cases wherein reference-equality
155.46 + * semantics are required.</b>
155.47 + *
155.48 + * <p>A typical use of this class is <i>topology-preserving object graph
155.49 + * transformations</i>, such as serialization or deep-copying. To perform such
155.50 + * a transformation, a program must maintain a "node table" that keeps track
155.51 + * of all the object references that have already been processed. The node
155.52 + * table must not equate distinct objects even if they happen to be equal.
155.53 + * Another typical use of this class is to maintain <i>proxy objects</i>. For
155.54 + * example, a debugging facility might wish to maintain a proxy object for
155.55 + * each object in the program being debugged.
155.56 + *
155.57 + * <p>This class provides all of the optional map operations, and permits
155.58 + * <tt>null</tt> values and the <tt>null</tt> key. This class makes no
155.59 + * guarantees as to the order of the map; in particular, it does not guarantee
155.60 + * that the order will remain constant over time.
155.61 + *
155.62 + * <p>This class provides constant-time performance for the basic
155.63 + * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
155.64 + * identity hash function ({@link System#identityHashCode(Object)})
155.65 + * disperses elements properly among the buckets.
155.66 + *
155.67 + * <p>This class has one tuning parameter (which affects performance but not
155.68 + * semantics): <i>expected maximum size</i>. This parameter is the maximum
155.69 + * number of key-value mappings that the map is expected to hold. Internally,
155.70 + * this parameter is used to determine the number of buckets initially
155.71 + * comprising the hash table. The precise relationship between the expected
155.72 + * maximum size and the number of buckets is unspecified.
155.73 + *
155.74 + * <p>If the size of the map (the number of key-value mappings) sufficiently
155.75 + * exceeds the expected maximum size, the number of buckets is increased
155.76 + * Increasing the number of buckets ("rehashing") may be fairly expensive, so
155.77 + * it pays to create identity hash maps with a sufficiently large expected
155.78 + * maximum size. On the other hand, iteration over collection views requires
155.79 + * time proportional to the number of buckets in the hash table, so it
155.80 + * pays not to set the expected maximum size too high if you are especially
155.81 + * concerned with iteration performance or memory usage.
155.82 + *
155.83 + * <p><strong>Note that this implementation is not synchronized.</strong>
155.84 + * If multiple threads access an identity hash map concurrently, and at
155.85 + * least one of the threads modifies the map structurally, it <i>must</i>
155.86 + * be synchronized externally. (A structural modification is any operation
155.87 + * that adds or deletes one or more mappings; merely changing the value
155.88 + * associated with a key that an instance already contains is not a
155.89 + * structural modification.) This is typically accomplished by
155.90 + * synchronizing on some object that naturally encapsulates the map.
155.91 + *
155.92 + * If no such object exists, the map should be "wrapped" using the
155.93 + * {@link Collections#synchronizedMap Collections.synchronizedMap}
155.94 + * method. This is best done at creation time, to prevent accidental
155.95 + * unsynchronized access to the map:<pre>
155.96 + * Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
155.97 + *
155.98 + * <p>The iterators returned by the <tt>iterator</tt> method of the
155.99 + * collections returned by all of this class's "collection view
155.100 + * methods" are <i>fail-fast</i>: if the map is structurally modified
155.101 + * at any time after the iterator is created, in any way except
155.102 + * through the iterator's own <tt>remove</tt> method, the iterator
155.103 + * will throw a {@link ConcurrentModificationException}. Thus, in the
155.104 + * face of concurrent modification, the iterator fails quickly and
155.105 + * cleanly, rather than risking arbitrary, non-deterministic behavior
155.106 + * at an undetermined time in the future.
155.107 + *
155.108 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
155.109 + * as it is, generally speaking, impossible to make any hard guarantees in the
155.110 + * presence of unsynchronized concurrent modification. Fail-fast iterators
155.111 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
155.112 + * Therefore, it would be wrong to write a program that depended on this
155.113 + * exception for its correctness: <i>fail-fast iterators should be used only
155.114 + * to detect bugs.</i>
155.115 + *
155.116 + * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
155.117 + * as described for example in texts by Sedgewick and Knuth. The array
155.118 + * alternates holding keys and values. (This has better locality for large
155.119 + * tables than does using separate arrays.) For many JRE implementations
155.120 + * and operation mixes, this class will yield better performance than
155.121 + * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
155.122 + *
155.123 + * <p>This class is a member of the
155.124 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
155.125 + * Java Collections Framework</a>.
155.126 + *
155.127 + * @see System#identityHashCode(Object)
155.128 + * @see Object#hashCode()
155.129 + * @see Collection
155.130 + * @see Map
155.131 + * @see HashMap
155.132 + * @see TreeMap
155.133 + * @author Doug Lea and Josh Bloch
155.134 + * @since 1.4
155.135 + */
155.136 +
155.137 +public class IdentityHashMap<K,V>
155.138 + extends AbstractMap<K,V>
155.139 + implements Map<K,V>, java.io.Serializable, Cloneable
155.140 +{
155.141 + /**
155.142 + * The initial capacity used by the no-args constructor.
155.143 + * MUST be a power of two. The value 32 corresponds to the
155.144 + * (specified) expected maximum size of 21, given a load factor
155.145 + * of 2/3.
155.146 + */
155.147 + private static final int DEFAULT_CAPACITY = 32;
155.148 +
155.149 + /**
155.150 + * The minimum capacity, used if a lower value is implicitly specified
155.151 + * by either of the constructors with arguments. The value 4 corresponds
155.152 + * to an expected maximum size of 2, given a load factor of 2/3.
155.153 + * MUST be a power of two.
155.154 + */
155.155 + private static final int MINIMUM_CAPACITY = 4;
155.156 +
155.157 + /**
155.158 + * The maximum capacity, used if a higher value is implicitly specified
155.159 + * by either of the constructors with arguments.
155.160 + * MUST be a power of two <= 1<<29.
155.161 + */
155.162 + private static final int MAXIMUM_CAPACITY = 1 << 29;
155.163 +
155.164 + /**
155.165 + * The table, resized as necessary. Length MUST always be a power of two.
155.166 + */
155.167 + private transient Object[] table;
155.168 +
155.169 + /**
155.170 + * The number of key-value mappings contained in this identity hash map.
155.171 + *
155.172 + * @serial
155.173 + */
155.174 + private int size;
155.175 +
155.176 + /**
155.177 + * The number of modifications, to support fast-fail iterators
155.178 + */
155.179 + private transient int modCount;
155.180 +
155.181 + /**
155.182 + * The next size value at which to resize (capacity * load factor).
155.183 + */
155.184 + private transient int threshold;
155.185 +
155.186 + /**
155.187 + * Value representing null keys inside tables.
155.188 + */
155.189 + private static final Object NULL_KEY = new Object();
155.190 +
155.191 + /**
155.192 + * Use NULL_KEY for key if it is null.
155.193 + */
155.194 + private static Object maskNull(Object key) {
155.195 + return (key == null ? NULL_KEY : key);
155.196 + }
155.197 +
155.198 + /**
155.199 + * Returns internal representation of null key back to caller as null.
155.200 + */
155.201 + private static Object unmaskNull(Object key) {
155.202 + return (key == NULL_KEY ? null : key);
155.203 + }
155.204 +
155.205 + /**
155.206 + * Constructs a new, empty identity hash map with a default expected
155.207 + * maximum size (21).
155.208 + */
155.209 + public IdentityHashMap() {
155.210 + init(DEFAULT_CAPACITY);
155.211 + }
155.212 +
155.213 + /**
155.214 + * Constructs a new, empty map with the specified expected maximum size.
155.215 + * Putting more than the expected number of key-value mappings into
155.216 + * the map may cause the internal data structure to grow, which may be
155.217 + * somewhat time-consuming.
155.218 + *
155.219 + * @param expectedMaxSize the expected maximum size of the map
155.220 + * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
155.221 + */
155.222 + public IdentityHashMap(int expectedMaxSize) {
155.223 + if (expectedMaxSize < 0)
155.224 + throw new IllegalArgumentException("expectedMaxSize is negative: "
155.225 + + expectedMaxSize);
155.226 + init(capacity(expectedMaxSize));
155.227 + }
155.228 +
155.229 + /**
155.230 + * Returns the appropriate capacity for the specified expected maximum
155.231 + * size. Returns the smallest power of two between MINIMUM_CAPACITY
155.232 + * and MAXIMUM_CAPACITY, inclusive, that is greater than
155.233 + * (3 * expectedMaxSize)/2, if such a number exists. Otherwise
155.234 + * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it
155.235 + * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
155.236 + */
155.237 + private int capacity(int expectedMaxSize) {
155.238 + // Compute min capacity for expectedMaxSize given a load factor of 2/3
155.239 + int minCapacity = (3 * expectedMaxSize)/2;
155.240 +
155.241 + // Compute the appropriate capacity
155.242 + int result;
155.243 + if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
155.244 + result = MAXIMUM_CAPACITY;
155.245 + } else {
155.246 + result = MINIMUM_CAPACITY;
155.247 + while (result < minCapacity)
155.248 + result <<= 1;
155.249 + }
155.250 + return result;
155.251 + }
155.252 +
155.253 + /**
155.254 + * Initializes object to be an empty map with the specified initial
155.255 + * capacity, which is assumed to be a power of two between
155.256 + * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
155.257 + */
155.258 + private void init(int initCapacity) {
155.259 + // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
155.260 + // assert initCapacity >= MINIMUM_CAPACITY;
155.261 + // assert initCapacity <= MAXIMUM_CAPACITY;
155.262 +
155.263 + threshold = (initCapacity * 2)/3;
155.264 + table = new Object[2 * initCapacity];
155.265 + }
155.266 +
155.267 + /**
155.268 + * Constructs a new identity hash map containing the keys-value mappings
155.269 + * in the specified map.
155.270 + *
155.271 + * @param m the map whose mappings are to be placed into this map
155.272 + * @throws NullPointerException if the specified map is null
155.273 + */
155.274 + public IdentityHashMap(Map<? extends K, ? extends V> m) {
155.275 + // Allow for a bit of growth
155.276 + this((int) ((1 + m.size()) * 1.1));
155.277 + putAll(m);
155.278 + }
155.279 +
155.280 + /**
155.281 + * Returns the number of key-value mappings in this identity hash map.
155.282 + *
155.283 + * @return the number of key-value mappings in this map
155.284 + */
155.285 + public int size() {
155.286 + return size;
155.287 + }
155.288 +
155.289 + /**
155.290 + * Returns <tt>true</tt> if this identity hash map contains no key-value
155.291 + * mappings.
155.292 + *
155.293 + * @return <tt>true</tt> if this identity hash map contains no key-value
155.294 + * mappings
155.295 + */
155.296 + public boolean isEmpty() {
155.297 + return size == 0;
155.298 + }
155.299 +
155.300 + /**
155.301 + * Returns index for Object x.
155.302 + */
155.303 + private static int hash(Object x, int length) {
155.304 + int h = System.identityHashCode(x);
155.305 + // Multiply by -127, and left-shift to use least bit as part of hash
155.306 + return ((h << 1) - (h << 8)) & (length - 1);
155.307 + }
155.308 +
155.309 + /**
155.310 + * Circularly traverses table of size len.
155.311 + */
155.312 + private static int nextKeyIndex(int i, int len) {
155.313 + return (i + 2 < len ? i + 2 : 0);
155.314 + }
155.315 +
155.316 + /**
155.317 + * Returns the value to which the specified key is mapped,
155.318 + * or {@code null} if this map contains no mapping for the key.
155.319 + *
155.320 + * <p>More formally, if this map contains a mapping from a key
155.321 + * {@code k} to a value {@code v} such that {@code (key == k)},
155.322 + * then this method returns {@code v}; otherwise it returns
155.323 + * {@code null}. (There can be at most one such mapping.)
155.324 + *
155.325 + * <p>A return value of {@code null} does not <i>necessarily</i>
155.326 + * indicate that the map contains no mapping for the key; it's also
155.327 + * possible that the map explicitly maps the key to {@code null}.
155.328 + * The {@link #containsKey containsKey} operation may be used to
155.329 + * distinguish these two cases.
155.330 + *
155.331 + * @see #put(Object, Object)
155.332 + */
155.333 + public V get(Object key) {
155.334 + Object k = maskNull(key);
155.335 + Object[] tab = table;
155.336 + int len = tab.length;
155.337 + int i = hash(k, len);
155.338 + while (true) {
155.339 + Object item = tab[i];
155.340 + if (item == k)
155.341 + return (V) tab[i + 1];
155.342 + if (item == null)
155.343 + return null;
155.344 + i = nextKeyIndex(i, len);
155.345 + }
155.346 + }
155.347 +
155.348 + /**
155.349 + * Tests whether the specified object reference is a key in this identity
155.350 + * hash map.
155.351 + *
155.352 + * @param key possible key
155.353 + * @return <code>true</code> if the specified object reference is a key
155.354 + * in this map
155.355 + * @see #containsValue(Object)
155.356 + */
155.357 + public boolean containsKey(Object key) {
155.358 + Object k = maskNull(key);
155.359 + Object[] tab = table;
155.360 + int len = tab.length;
155.361 + int i = hash(k, len);
155.362 + while (true) {
155.363 + Object item = tab[i];
155.364 + if (item == k)
155.365 + return true;
155.366 + if (item == null)
155.367 + return false;
155.368 + i = nextKeyIndex(i, len);
155.369 + }
155.370 + }
155.371 +
155.372 + /**
155.373 + * Tests whether the specified object reference is a value in this identity
155.374 + * hash map.
155.375 + *
155.376 + * @param value value whose presence in this map is to be tested
155.377 + * @return <tt>true</tt> if this map maps one or more keys to the
155.378 + * specified object reference
155.379 + * @see #containsKey(Object)
155.380 + */
155.381 + public boolean containsValue(Object value) {
155.382 + Object[] tab = table;
155.383 + for (int i = 1; i < tab.length; i += 2)
155.384 + if (tab[i] == value && tab[i - 1] != null)
155.385 + return true;
155.386 +
155.387 + return false;
155.388 + }
155.389 +
155.390 + /**
155.391 + * Tests if the specified key-value mapping is in the map.
155.392 + *
155.393 + * @param key possible key
155.394 + * @param value possible value
155.395 + * @return <code>true</code> if and only if the specified key-value
155.396 + * mapping is in the map
155.397 + */
155.398 + private boolean containsMapping(Object key, Object value) {
155.399 + Object k = maskNull(key);
155.400 + Object[] tab = table;
155.401 + int len = tab.length;
155.402 + int i = hash(k, len);
155.403 + while (true) {
155.404 + Object item = tab[i];
155.405 + if (item == k)
155.406 + return tab[i + 1] == value;
155.407 + if (item == null)
155.408 + return false;
155.409 + i = nextKeyIndex(i, len);
155.410 + }
155.411 + }
155.412 +
155.413 + /**
155.414 + * Associates the specified value with the specified key in this identity
155.415 + * hash map. If the map previously contained a mapping for the key, the
155.416 + * old value is replaced.
155.417 + *
155.418 + * @param key the key with which the specified value is to be associated
155.419 + * @param value the value to be associated with the specified key
155.420 + * @return the previous value associated with <tt>key</tt>, or
155.421 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
155.422 + * (A <tt>null</tt> return can also indicate that the map
155.423 + * previously associated <tt>null</tt> with <tt>key</tt>.)
155.424 + * @see Object#equals(Object)
155.425 + * @see #get(Object)
155.426 + * @see #containsKey(Object)
155.427 + */
155.428 + public V put(K key, V value) {
155.429 + Object k = maskNull(key);
155.430 + Object[] tab = table;
155.431 + int len = tab.length;
155.432 + int i = hash(k, len);
155.433 +
155.434 + Object item;
155.435 + while ( (item = tab[i]) != null) {
155.436 + if (item == k) {
155.437 + V oldValue = (V) tab[i + 1];
155.438 + tab[i + 1] = value;
155.439 + return oldValue;
155.440 + }
155.441 + i = nextKeyIndex(i, len);
155.442 + }
155.443 +
155.444 + modCount++;
155.445 + tab[i] = k;
155.446 + tab[i + 1] = value;
155.447 + if (++size >= threshold)
155.448 + resize(len); // len == 2 * current capacity.
155.449 + return null;
155.450 + }
155.451 +
155.452 + /**
155.453 + * Resize the table to hold given capacity.
155.454 + *
155.455 + * @param newCapacity the new capacity, must be a power of two.
155.456 + */
155.457 + private void resize(int newCapacity) {
155.458 + // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
155.459 + int newLength = newCapacity * 2;
155.460 +
155.461 + Object[] oldTable = table;
155.462 + int oldLength = oldTable.length;
155.463 + if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
155.464 + if (threshold == MAXIMUM_CAPACITY-1)
155.465 + throw new IllegalStateException("Capacity exhausted.");
155.466 + threshold = MAXIMUM_CAPACITY-1; // Gigantic map!
155.467 + return;
155.468 + }
155.469 + if (oldLength >= newLength)
155.470 + return;
155.471 +
155.472 + Object[] newTable = new Object[newLength];
155.473 + threshold = newLength / 3;
155.474 +
155.475 + for (int j = 0; j < oldLength; j += 2) {
155.476 + Object key = oldTable[j];
155.477 + if (key != null) {
155.478 + Object value = oldTable[j+1];
155.479 + oldTable[j] = null;
155.480 + oldTable[j+1] = null;
155.481 + int i = hash(key, newLength);
155.482 + while (newTable[i] != null)
155.483 + i = nextKeyIndex(i, newLength);
155.484 + newTable[i] = key;
155.485 + newTable[i + 1] = value;
155.486 + }
155.487 + }
155.488 + table = newTable;
155.489 + }
155.490 +
155.491 + /**
155.492 + * Copies all of the mappings from the specified map to this map.
155.493 + * These mappings will replace any mappings that this map had for
155.494 + * any of the keys currently in the specified map.
155.495 + *
155.496 + * @param m mappings to be stored in this map
155.497 + * @throws NullPointerException if the specified map is null
155.498 + */
155.499 + public void putAll(Map<? extends K, ? extends V> m) {
155.500 + int n = m.size();
155.501 + if (n == 0)
155.502 + return;
155.503 + if (n > threshold) // conservatively pre-expand
155.504 + resize(capacity(n));
155.505 +
155.506 + for (Entry<? extends K, ? extends V> e : m.entrySet())
155.507 + put(e.getKey(), e.getValue());
155.508 + }
155.509 +
155.510 + /**
155.511 + * Removes the mapping for this key from this map if present.
155.512 + *
155.513 + * @param key key whose mapping is to be removed from the map
155.514 + * @return the previous value associated with <tt>key</tt>, or
155.515 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
155.516 + * (A <tt>null</tt> return can also indicate that the map
155.517 + * previously associated <tt>null</tt> with <tt>key</tt>.)
155.518 + */
155.519 + public V remove(Object key) {
155.520 + Object k = maskNull(key);
155.521 + Object[] tab = table;
155.522 + int len = tab.length;
155.523 + int i = hash(k, len);
155.524 +
155.525 + while (true) {
155.526 + Object item = tab[i];
155.527 + if (item == k) {
155.528 + modCount++;
155.529 + size--;
155.530 + V oldValue = (V) tab[i + 1];
155.531 + tab[i + 1] = null;
155.532 + tab[i] = null;
155.533 + closeDeletion(i);
155.534 + return oldValue;
155.535 + }
155.536 + if (item == null)
155.537 + return null;
155.538 + i = nextKeyIndex(i, len);
155.539 + }
155.540 +
155.541 + }
155.542 +
155.543 + /**
155.544 + * Removes the specified key-value mapping from the map if it is present.
155.545 + *
155.546 + * @param key possible key
155.547 + * @param value possible value
155.548 + * @return <code>true</code> if and only if the specified key-value
155.549 + * mapping was in the map
155.550 + */
155.551 + private boolean removeMapping(Object key, Object value) {
155.552 + Object k = maskNull(key);
155.553 + Object[] tab = table;
155.554 + int len = tab.length;
155.555 + int i = hash(k, len);
155.556 +
155.557 + while (true) {
155.558 + Object item = tab[i];
155.559 + if (item == k) {
155.560 + if (tab[i + 1] != value)
155.561 + return false;
155.562 + modCount++;
155.563 + size--;
155.564 + tab[i] = null;
155.565 + tab[i + 1] = null;
155.566 + closeDeletion(i);
155.567 + return true;
155.568 + }
155.569 + if (item == null)
155.570 + return false;
155.571 + i = nextKeyIndex(i, len);
155.572 + }
155.573 + }
155.574 +
155.575 + /**
155.576 + * Rehash all possibly-colliding entries following a
155.577 + * deletion. This preserves the linear-probe
155.578 + * collision properties required by get, put, etc.
155.579 + *
155.580 + * @param d the index of a newly empty deleted slot
155.581 + */
155.582 + private void closeDeletion(int d) {
155.583 + // Adapted from Knuth Section 6.4 Algorithm R
155.584 + Object[] tab = table;
155.585 + int len = tab.length;
155.586 +
155.587 + // Look for items to swap into newly vacated slot
155.588 + // starting at index immediately following deletion,
155.589 + // and continuing until a null slot is seen, indicating
155.590 + // the end of a run of possibly-colliding keys.
155.591 + Object item;
155.592 + for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
155.593 + i = nextKeyIndex(i, len) ) {
155.594 + // The following test triggers if the item at slot i (which
155.595 + // hashes to be at slot r) should take the spot vacated by d.
155.596 + // If so, we swap it in, and then continue with d now at the
155.597 + // newly vacated i. This process will terminate when we hit
155.598 + // the null slot at the end of this run.
155.599 + // The test is messy because we are using a circular table.
155.600 + int r = hash(item, len);
155.601 + if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
155.602 + tab[d] = item;
155.603 + tab[d + 1] = tab[i + 1];
155.604 + tab[i] = null;
155.605 + tab[i + 1] = null;
155.606 + d = i;
155.607 + }
155.608 + }
155.609 + }
155.610 +
155.611 + /**
155.612 + * Removes all of the mappings from this map.
155.613 + * The map will be empty after this call returns.
155.614 + */
155.615 + public void clear() {
155.616 + modCount++;
155.617 + Object[] tab = table;
155.618 + for (int i = 0; i < tab.length; i++)
155.619 + tab[i] = null;
155.620 + size = 0;
155.621 + }
155.622 +
155.623 + /**
155.624 + * Compares the specified object with this map for equality. Returns
155.625 + * <tt>true</tt> if the given object is also a map and the two maps
155.626 + * represent identical object-reference mappings. More formally, this
155.627 + * map is equal to another map <tt>m</tt> if and only if
155.628 + * <tt>this.entrySet().equals(m.entrySet())</tt>.
155.629 + *
155.630 + * <p><b>Owing to the reference-equality-based semantics of this map it is
155.631 + * possible that the symmetry and transitivity requirements of the
155.632 + * <tt>Object.equals</tt> contract may be violated if this map is compared
155.633 + * to a normal map. However, the <tt>Object.equals</tt> contract is
155.634 + * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
155.635 + *
155.636 + * @param o object to be compared for equality with this map
155.637 + * @return <tt>true</tt> if the specified object is equal to this map
155.638 + * @see Object#equals(Object)
155.639 + */
155.640 + public boolean equals(Object o) {
155.641 + if (o == this) {
155.642 + return true;
155.643 + } else if (o instanceof IdentityHashMap) {
155.644 + IdentityHashMap m = (IdentityHashMap) o;
155.645 + if (m.size() != size)
155.646 + return false;
155.647 +
155.648 + Object[] tab = m.table;
155.649 + for (int i = 0; i < tab.length; i+=2) {
155.650 + Object k = tab[i];
155.651 + if (k != null && !containsMapping(k, tab[i + 1]))
155.652 + return false;
155.653 + }
155.654 + return true;
155.655 + } else if (o instanceof Map) {
155.656 + Map m = (Map)o;
155.657 + return entrySet().equals(m.entrySet());
155.658 + } else {
155.659 + return false; // o is not a Map
155.660 + }
155.661 + }
155.662 +
155.663 + /**
155.664 + * Returns the hash code value for this map. The hash code of a map is
155.665 + * defined to be the sum of the hash codes of each entry in the map's
155.666 + * <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>
155.667 + * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
155.668 + * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
155.669 + * required by the general contract of {@link Object#hashCode}.
155.670 + *
155.671 + * <p><b>Owing to the reference-equality-based semantics of the
155.672 + * <tt>Map.Entry</tt> instances in the set returned by this map's
155.673 + * <tt>entrySet</tt> method, it is possible that the contractual
155.674 + * requirement of <tt>Object.hashCode</tt> mentioned in the previous
155.675 + * paragraph will be violated if one of the two objects being compared is
155.676 + * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
155.677 + *
155.678 + * @return the hash code value for this map
155.679 + * @see Object#equals(Object)
155.680 + * @see #equals(Object)
155.681 + */
155.682 + public int hashCode() {
155.683 + int result = 0;
155.684 + Object[] tab = table;
155.685 + for (int i = 0; i < tab.length; i +=2) {
155.686 + Object key = tab[i];
155.687 + if (key != null) {
155.688 + Object k = unmaskNull(key);
155.689 + result += System.identityHashCode(k) ^
155.690 + System.identityHashCode(tab[i + 1]);
155.691 + }
155.692 + }
155.693 + return result;
155.694 + }
155.695 +
155.696 + /**
155.697 + * Returns a shallow copy of this identity hash map: the keys and values
155.698 + * themselves are not cloned.
155.699 + *
155.700 + * @return a shallow copy of this map
155.701 + */
155.702 + public Object clone() {
155.703 + try {
155.704 + IdentityHashMap<K,V> m = (IdentityHashMap<K,V>) super.clone();
155.705 + m.entrySet = null;
155.706 + m.table = table.clone();
155.707 + return m;
155.708 + } catch (CloneNotSupportedException e) {
155.709 + throw new InternalError();
155.710 + }
155.711 + }
155.712 +
155.713 + private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
155.714 + int index = (size != 0 ? 0 : table.length); // current slot.
155.715 + int expectedModCount = modCount; // to support fast-fail
155.716 + int lastReturnedIndex = -1; // to allow remove()
155.717 + boolean indexValid; // To avoid unnecessary next computation
155.718 + Object[] traversalTable = table; // reference to main table or copy
155.719 +
155.720 + public boolean hasNext() {
155.721 + Object[] tab = traversalTable;
155.722 + for (int i = index; i < tab.length; i+=2) {
155.723 + Object key = tab[i];
155.724 + if (key != null) {
155.725 + index = i;
155.726 + return indexValid = true;
155.727 + }
155.728 + }
155.729 + index = tab.length;
155.730 + return false;
155.731 + }
155.732 +
155.733 + protected int nextIndex() {
155.734 + if (modCount != expectedModCount)
155.735 + throw new ConcurrentModificationException();
155.736 + if (!indexValid && !hasNext())
155.737 + throw new NoSuchElementException();
155.738 +
155.739 + indexValid = false;
155.740 + lastReturnedIndex = index;
155.741 + index += 2;
155.742 + return lastReturnedIndex;
155.743 + }
155.744 +
155.745 + public void remove() {
155.746 + if (lastReturnedIndex == -1)
155.747 + throw new IllegalStateException();
155.748 + if (modCount != expectedModCount)
155.749 + throw new ConcurrentModificationException();
155.750 +
155.751 + expectedModCount = ++modCount;
155.752 + int deletedSlot = lastReturnedIndex;
155.753 + lastReturnedIndex = -1;
155.754 + // back up index to revisit new contents after deletion
155.755 + index = deletedSlot;
155.756 + indexValid = false;
155.757 +
155.758 + // Removal code proceeds as in closeDeletion except that
155.759 + // it must catch the rare case where an element already
155.760 + // seen is swapped into a vacant slot that will be later
155.761 + // traversed by this iterator. We cannot allow future
155.762 + // next() calls to return it again. The likelihood of
155.763 + // this occurring under 2/3 load factor is very slim, but
155.764 + // when it does happen, we must make a copy of the rest of
155.765 + // the table to use for the rest of the traversal. Since
155.766 + // this can only happen when we are near the end of the table,
155.767 + // even in these rare cases, this is not very expensive in
155.768 + // time or space.
155.769 +
155.770 + Object[] tab = traversalTable;
155.771 + int len = tab.length;
155.772 +
155.773 + int d = deletedSlot;
155.774 + K key = (K) tab[d];
155.775 + tab[d] = null; // vacate the slot
155.776 + tab[d + 1] = null;
155.777 +
155.778 + // If traversing a copy, remove in real table.
155.779 + // We can skip gap-closure on copy.
155.780 + if (tab != IdentityHashMap.this.table) {
155.781 + IdentityHashMap.this.remove(key);
155.782 + expectedModCount = modCount;
155.783 + return;
155.784 + }
155.785 +
155.786 + size--;
155.787 +
155.788 + Object item;
155.789 + for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
155.790 + i = nextKeyIndex(i, len)) {
155.791 + int r = hash(item, len);
155.792 + // See closeDeletion for explanation of this conditional
155.793 + if ((i < r && (r <= d || d <= i)) ||
155.794 + (r <= d && d <= i)) {
155.795 +
155.796 + // If we are about to swap an already-seen element
155.797 + // into a slot that may later be returned by next(),
155.798 + // then clone the rest of table for use in future
155.799 + // next() calls. It is OK that our copy will have
155.800 + // a gap in the "wrong" place, since it will never
155.801 + // be used for searching anyway.
155.802 +
155.803 + if (i < deletedSlot && d >= deletedSlot &&
155.804 + traversalTable == IdentityHashMap.this.table) {
155.805 + int remaining = len - deletedSlot;
155.806 + Object[] newTable = new Object[remaining];
155.807 + System.arraycopy(tab, deletedSlot,
155.808 + newTable, 0, remaining);
155.809 + traversalTable = newTable;
155.810 + index = 0;
155.811 + }
155.812 +
155.813 + tab[d] = item;
155.814 + tab[d + 1] = tab[i + 1];
155.815 + tab[i] = null;
155.816 + tab[i + 1] = null;
155.817 + d = i;
155.818 + }
155.819 + }
155.820 + }
155.821 + }
155.822 +
155.823 + private class KeyIterator extends IdentityHashMapIterator<K> {
155.824 + public K next() {
155.825 + return (K) unmaskNull(traversalTable[nextIndex()]);
155.826 + }
155.827 + }
155.828 +
155.829 + private class ValueIterator extends IdentityHashMapIterator<V> {
155.830 + public V next() {
155.831 + return (V) traversalTable[nextIndex() + 1];
155.832 + }
155.833 + }
155.834 +
155.835 + private class EntryIterator
155.836 + extends IdentityHashMapIterator<Map.Entry<K,V>>
155.837 + {
155.838 + private Entry lastReturnedEntry = null;
155.839 +
155.840 + public Map.Entry<K,V> next() {
155.841 + lastReturnedEntry = new Entry(nextIndex());
155.842 + return lastReturnedEntry;
155.843 + }
155.844 +
155.845 + public void remove() {
155.846 + lastReturnedIndex =
155.847 + ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
155.848 + super.remove();
155.849 + lastReturnedEntry.index = lastReturnedIndex;
155.850 + lastReturnedEntry = null;
155.851 + }
155.852 +
155.853 + private class Entry implements Map.Entry<K,V> {
155.854 + private int index;
155.855 +
155.856 + private Entry(int index) {
155.857 + this.index = index;
155.858 + }
155.859 +
155.860 + public K getKey() {
155.861 + checkIndexForEntryUse();
155.862 + return (K) unmaskNull(traversalTable[index]);
155.863 + }
155.864 +
155.865 + public V getValue() {
155.866 + checkIndexForEntryUse();
155.867 + return (V) traversalTable[index+1];
155.868 + }
155.869 +
155.870 + public V setValue(V value) {
155.871 + checkIndexForEntryUse();
155.872 + V oldValue = (V) traversalTable[index+1];
155.873 + traversalTable[index+1] = value;
155.874 + // if shadowing, force into main table
155.875 + if (traversalTable != IdentityHashMap.this.table)
155.876 + put((K) traversalTable[index], value);
155.877 + return oldValue;
155.878 + }
155.879 +
155.880 + public boolean equals(Object o) {
155.881 + if (index < 0)
155.882 + return super.equals(o);
155.883 +
155.884 + if (!(o instanceof Map.Entry))
155.885 + return false;
155.886 + Map.Entry e = (Map.Entry)o;
155.887 + return (e.getKey() == unmaskNull(traversalTable[index]) &&
155.888 + e.getValue() == traversalTable[index+1]);
155.889 + }
155.890 +
155.891 + public int hashCode() {
155.892 + if (lastReturnedIndex < 0)
155.893 + return super.hashCode();
155.894 +
155.895 + return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
155.896 + System.identityHashCode(traversalTable[index+1]));
155.897 + }
155.898 +
155.899 + public String toString() {
155.900 + if (index < 0)
155.901 + return super.toString();
155.902 +
155.903 + return (unmaskNull(traversalTable[index]) + "="
155.904 + + traversalTable[index+1]);
155.905 + }
155.906 +
155.907 + private void checkIndexForEntryUse() {
155.908 + if (index < 0)
155.909 + throw new IllegalStateException("Entry was removed");
155.910 + }
155.911 + }
155.912 + }
155.913 +
155.914 + // Views
155.915 +
155.916 + /**
155.917 + * This field is initialized to contain an instance of the entry set
155.918 + * view the first time this view is requested. The view is stateless,
155.919 + * so there's no reason to create more than one.
155.920 + */
155.921 + private transient Set<Map.Entry<K,V>> entrySet = null;
155.922 +
155.923 + /**
155.924 + * Returns an identity-based set view of the keys contained in this map.
155.925 + * The set is backed by the map, so changes to the map are reflected in
155.926 + * the set, and vice-versa. If the map is modified while an iteration
155.927 + * over the set is in progress, the results of the iteration are
155.928 + * undefined. The set supports element removal, which removes the
155.929 + * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
155.930 + * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
155.931 + * <tt>clear</tt> methods. It does not support the <tt>add</tt> or
155.932 + * <tt>addAll</tt> methods.
155.933 + *
155.934 + * <p><b>While the object returned by this method implements the
155.935 + * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
155.936 + * contract. Like its backing map, the set returned by this method
155.937 + * defines element equality as reference-equality rather than
155.938 + * object-equality. This affects the behavior of its <tt>contains</tt>,
155.939 + * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
155.940 + * <tt>hashCode</tt> methods.</b>
155.941 + *
155.942 + * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
155.943 + * only if the specified object is a set containing exactly the same
155.944 + * object references as the returned set. The symmetry and transitivity
155.945 + * requirements of the <tt>Object.equals</tt> contract may be violated if
155.946 + * the set returned by this method is compared to a normal set. However,
155.947 + * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
155.948 + * returned by this method.</b>
155.949 + *
155.950 + * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
155.951 + * the <i>identity hashcodes</i> of the elements in the set, rather than
155.952 + * the sum of their hashcodes. This is mandated by the change in the
155.953 + * semantics of the <tt>equals</tt> method, in order to enforce the
155.954 + * general contract of the <tt>Object.hashCode</tt> method among sets
155.955 + * returned by this method.
155.956 + *
155.957 + * @return an identity-based set view of the keys contained in this map
155.958 + * @see Object#equals(Object)
155.959 + * @see System#identityHashCode(Object)
155.960 + */
155.961 + public Set<K> keySet() {
155.962 + Set<K> ks = keySet;
155.963 + if (ks != null)
155.964 + return ks;
155.965 + else
155.966 + return keySet = new KeySet();
155.967 + }
155.968 +
155.969 + private class KeySet extends AbstractSet<K> {
155.970 + public Iterator<K> iterator() {
155.971 + return new KeyIterator();
155.972 + }
155.973 + public int size() {
155.974 + return size;
155.975 + }
155.976 + public boolean contains(Object o) {
155.977 + return containsKey(o);
155.978 + }
155.979 + public boolean remove(Object o) {
155.980 + int oldSize = size;
155.981 + IdentityHashMap.this.remove(o);
155.982 + return size != oldSize;
155.983 + }
155.984 + /*
155.985 + * Must revert from AbstractSet's impl to AbstractCollection's, as
155.986 + * the former contains an optimization that results in incorrect
155.987 + * behavior when c is a smaller "normal" (non-identity-based) Set.
155.988 + */
155.989 + public boolean removeAll(Collection<?> c) {
155.990 + boolean modified = false;
155.991 + for (Iterator<K> i = iterator(); i.hasNext(); ) {
155.992 + if (c.contains(i.next())) {
155.993 + i.remove();
155.994 + modified = true;
155.995 + }
155.996 + }
155.997 + return modified;
155.998 + }
155.999 + public void clear() {
155.1000 + IdentityHashMap.this.clear();
155.1001 + }
155.1002 + public int hashCode() {
155.1003 + int result = 0;
155.1004 + for (K key : this)
155.1005 + result += System.identityHashCode(key);
155.1006 + return result;
155.1007 + }
155.1008 + }
155.1009 +
155.1010 + /**
155.1011 + * Returns a {@link Collection} view of the values contained in this map.
155.1012 + * The collection is backed by the map, so changes to the map are
155.1013 + * reflected in the collection, and vice-versa. If the map is
155.1014 + * modified while an iteration over the collection is in progress,
155.1015 + * the results of the iteration are undefined. The collection
155.1016 + * supports element removal, which removes the corresponding
155.1017 + * mapping from the map, via the <tt>Iterator.remove</tt>,
155.1018 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
155.1019 + * <tt>retainAll</tt> and <tt>clear</tt> methods. It does not
155.1020 + * support the <tt>add</tt> or <tt>addAll</tt> methods.
155.1021 + *
155.1022 + * <p><b>While the object returned by this method implements the
155.1023 + * <tt>Collection</tt> interface, it does <i>not</i> obey
155.1024 + * <tt>Collection's</tt> general contract. Like its backing map,
155.1025 + * the collection returned by this method defines element equality as
155.1026 + * reference-equality rather than object-equality. This affects the
155.1027 + * behavior of its <tt>contains</tt>, <tt>remove</tt> and
155.1028 + * <tt>containsAll</tt> methods.</b>
155.1029 + */
155.1030 + public Collection<V> values() {
155.1031 + Collection<V> vs = values;
155.1032 + if (vs != null)
155.1033 + return vs;
155.1034 + else
155.1035 + return values = new Values();
155.1036 + }
155.1037 +
155.1038 + private class Values extends AbstractCollection<V> {
155.1039 + public Iterator<V> iterator() {
155.1040 + return new ValueIterator();
155.1041 + }
155.1042 + public int size() {
155.1043 + return size;
155.1044 + }
155.1045 + public boolean contains(Object o) {
155.1046 + return containsValue(o);
155.1047 + }
155.1048 + public boolean remove(Object o) {
155.1049 + for (Iterator<V> i = iterator(); i.hasNext(); ) {
155.1050 + if (i.next() == o) {
155.1051 + i.remove();
155.1052 + return true;
155.1053 + }
155.1054 + }
155.1055 + return false;
155.1056 + }
155.1057 + public void clear() {
155.1058 + IdentityHashMap.this.clear();
155.1059 + }
155.1060 + }
155.1061 +
155.1062 + /**
155.1063 + * Returns a {@link Set} view of the mappings contained in this map.
155.1064 + * Each element in the returned set is a reference-equality-based
155.1065 + * <tt>Map.Entry</tt>. The set is backed by the map, so changes
155.1066 + * to the map are reflected in the set, and vice-versa. If the
155.1067 + * map is modified while an iteration over the set is in progress,
155.1068 + * the results of the iteration are undefined. The set supports
155.1069 + * element removal, which removes the corresponding mapping from
155.1070 + * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
155.1071 + * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
155.1072 + * methods. It does not support the <tt>add</tt> or
155.1073 + * <tt>addAll</tt> methods.
155.1074 + *
155.1075 + * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
155.1076 + * returned by this method define key and value equality as
155.1077 + * reference-equality rather than object-equality. This affects the
155.1078 + * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
155.1079 + * <tt>Map.Entry</tt> objects. A reference-equality based <tt>Map.Entry
155.1080 + * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
155.1081 + * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &&
155.1082 + * e.getValue()==o.getValue()</tt>. To accommodate these equals
155.1083 + * semantics, the <tt>hashCode</tt> method returns
155.1084 + * <tt>System.identityHashCode(e.getKey()) ^
155.1085 + * System.identityHashCode(e.getValue())</tt>.
155.1086 + *
155.1087 + * <p><b>Owing to the reference-equality-based semantics of the
155.1088 + * <tt>Map.Entry</tt> instances in the set returned by this method,
155.1089 + * it is possible that the symmetry and transitivity requirements of
155.1090 + * the {@link Object#equals(Object)} contract may be violated if any of
155.1091 + * the entries in the set is compared to a normal map entry, or if
155.1092 + * the set returned by this method is compared to a set of normal map
155.1093 + * entries (such as would be returned by a call to this method on a normal
155.1094 + * map). However, the <tt>Object.equals</tt> contract is guaranteed to
155.1095 + * hold among identity-based map entries, and among sets of such entries.
155.1096 + * </b>
155.1097 + *
155.1098 + * @return a set view of the identity-mappings contained in this map
155.1099 + */
155.1100 + public Set<Map.Entry<K,V>> entrySet() {
155.1101 + Set<Map.Entry<K,V>> es = entrySet;
155.1102 + if (es != null)
155.1103 + return es;
155.1104 + else
155.1105 + return entrySet = new EntrySet();
155.1106 + }
155.1107 +
155.1108 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
155.1109 + public Iterator<Map.Entry<K,V>> iterator() {
155.1110 + return new EntryIterator();
155.1111 + }
155.1112 + public boolean contains(Object o) {
155.1113 + if (!(o instanceof Map.Entry))
155.1114 + return false;
155.1115 + Map.Entry entry = (Map.Entry)o;
155.1116 + return containsMapping(entry.getKey(), entry.getValue());
155.1117 + }
155.1118 + public boolean remove(Object o) {
155.1119 + if (!(o instanceof Map.Entry))
155.1120 + return false;
155.1121 + Map.Entry entry = (Map.Entry)o;
155.1122 + return removeMapping(entry.getKey(), entry.getValue());
155.1123 + }
155.1124 + public int size() {
155.1125 + return size;
155.1126 + }
155.1127 + public void clear() {
155.1128 + IdentityHashMap.this.clear();
155.1129 + }
155.1130 + /*
155.1131 + * Must revert from AbstractSet's impl to AbstractCollection's, as
155.1132 + * the former contains an optimization that results in incorrect
155.1133 + * behavior when c is a smaller "normal" (non-identity-based) Set.
155.1134 + */
155.1135 + public boolean removeAll(Collection<?> c) {
155.1136 + boolean modified = false;
155.1137 + for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
155.1138 + if (c.contains(i.next())) {
155.1139 + i.remove();
155.1140 + modified = true;
155.1141 + }
155.1142 + }
155.1143 + return modified;
155.1144 + }
155.1145 +
155.1146 + public Object[] toArray() {
155.1147 + int size = size();
155.1148 + Object[] result = new Object[size];
155.1149 + Iterator<Map.Entry<K,V>> it = iterator();
155.1150 + for (int i = 0; i < size; i++)
155.1151 + result[i] = new AbstractMap.SimpleEntry<>(it.next());
155.1152 + return result;
155.1153 + }
155.1154 +
155.1155 + @SuppressWarnings("unchecked")
155.1156 + public <T> T[] toArray(T[] a) {
155.1157 + int size = size();
155.1158 + if (a.length < size)
155.1159 + a = (T[])java.lang.reflect.Array
155.1160 + .newInstance(a.getClass().getComponentType(), size);
155.1161 + Iterator<Map.Entry<K,V>> it = iterator();
155.1162 + for (int i = 0; i < size; i++)
155.1163 + a[i] = (T) new AbstractMap.SimpleEntry<>(it.next());
155.1164 + if (a.length > size)
155.1165 + a[size] = null;
155.1166 + return a;
155.1167 + }
155.1168 + }
155.1169 +
155.1170 +
155.1171 + private static final long serialVersionUID = 8188218128353913216L;
155.1172 +
155.1173 + /**
155.1174 + * Save the state of the <tt>IdentityHashMap</tt> instance to a stream
155.1175 + * (i.e., serialize it).
155.1176 + *
155.1177 + * @serialData The <i>size</i> of the HashMap (the number of key-value
155.1178 + * mappings) (<tt>int</tt>), followed by the key (Object) and
155.1179 + * value (Object) for each key-value mapping represented by the
155.1180 + * IdentityHashMap. The key-value mappings are emitted in no
155.1181 + * particular order.
155.1182 + */
155.1183 + private void writeObject(java.io.ObjectOutputStream s)
155.1184 + throws java.io.IOException {
155.1185 + // Write out and any hidden stuff
155.1186 + s.defaultWriteObject();
155.1187 +
155.1188 + // Write out size (number of Mappings)
155.1189 + s.writeInt(size);
155.1190 +
155.1191 + // Write out keys and values (alternating)
155.1192 + Object[] tab = table;
155.1193 + for (int i = 0; i < tab.length; i += 2) {
155.1194 + Object key = tab[i];
155.1195 + if (key != null) {
155.1196 + s.writeObject(unmaskNull(key));
155.1197 + s.writeObject(tab[i + 1]);
155.1198 + }
155.1199 + }
155.1200 + }
155.1201 +
155.1202 + /**
155.1203 + * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
155.1204 + * deserialize it).
155.1205 + */
155.1206 + private void readObject(java.io.ObjectInputStream s)
155.1207 + throws java.io.IOException, ClassNotFoundException {
155.1208 + // Read in any hidden stuff
155.1209 + s.defaultReadObject();
155.1210 +
155.1211 + // Read in size (number of Mappings)
155.1212 + int size = s.readInt();
155.1213 +
155.1214 + // Allow for 33% growth (i.e., capacity is >= 2* size()).
155.1215 + init(capacity((size*4)/3));
155.1216 +
155.1217 + // Read the keys and values, and put the mappings in the table
155.1218 + for (int i=0; i<size; i++) {
155.1219 + K key = (K) s.readObject();
155.1220 + V value = (V) s.readObject();
155.1221 + putForCreate(key, value);
155.1222 + }
155.1223 + }
155.1224 +
155.1225 + /**
155.1226 + * The put method for readObject. It does not resize the table,
155.1227 + * update modCount, etc.
155.1228 + */
155.1229 + private void putForCreate(K key, V value)
155.1230 + throws IOException
155.1231 + {
155.1232 + K k = (K)maskNull(key);
155.1233 + Object[] tab = table;
155.1234 + int len = tab.length;
155.1235 + int i = hash(k, len);
155.1236 +
155.1237 + Object item;
155.1238 + while ( (item = tab[i]) != null) {
155.1239 + if (item == k)
155.1240 + throw new java.io.StreamCorruptedException();
155.1241 + i = nextKeyIndex(i, len);
155.1242 + }
155.1243 + tab[i] = k;
155.1244 + tab[i + 1] = value;
155.1245 + }
155.1246 +}
156.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
156.2 +++ b/rt/emul/compact/src/main/java/java/util/JumboEnumSet.java Mon Oct 07 14:20:58 2013 +0200
156.3 @@ -0,0 +1,375 @@
156.4 +/*
156.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
156.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
156.7 + *
156.8 + * This code is free software; you can redistribute it and/or modify it
156.9 + * under the terms of the GNU General Public License version 2 only, as
156.10 + * published by the Free Software Foundation. Oracle designates this
156.11 + * particular file as subject to the "Classpath" exception as provided
156.12 + * by Oracle in the LICENSE file that accompanied this code.
156.13 + *
156.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
156.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
156.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
156.17 + * version 2 for more details (a copy is included in the LICENSE file that
156.18 + * accompanied this code).
156.19 + *
156.20 + * You should have received a copy of the GNU General Public License version
156.21 + * 2 along with this work; if not, write to the Free Software Foundation,
156.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
156.23 + *
156.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
156.25 + * or visit www.oracle.com if you need additional information or have any
156.26 + * questions.
156.27 + */
156.28 +
156.29 +package java.util;
156.30 +
156.31 +/**
156.32 + * Private implementation class for EnumSet, for "jumbo" enum types
156.33 + * (i.e., those with more than 64 elements).
156.34 + *
156.35 + * @author Josh Bloch
156.36 + * @since 1.5
156.37 + * @serial exclude
156.38 + */
156.39 +class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
156.40 + private static final long serialVersionUID = 334349849919042784L;
156.41 +
156.42 + /**
156.43 + * Bit vector representation of this set. The ith bit of the jth
156.44 + * element of this array represents the presence of universe[64*j +i]
156.45 + * in this set.
156.46 + */
156.47 + private long elements[];
156.48 +
156.49 + // Redundant - maintained for performance
156.50 + private int size = 0;
156.51 +
156.52 + JumboEnumSet(Class<E>elementType, Enum[] universe) {
156.53 + super(elementType, universe);
156.54 + elements = new long[(universe.length + 63) >>> 6];
156.55 + }
156.56 +
156.57 + void addRange(E from, E to) {
156.58 + int fromIndex = from.ordinal() >>> 6;
156.59 + int toIndex = to.ordinal() >>> 6;
156.60 +
156.61 + if (fromIndex == toIndex) {
156.62 + elements[fromIndex] = (-1L >>> (from.ordinal() - to.ordinal() - 1))
156.63 + << from.ordinal();
156.64 + } else {
156.65 + elements[fromIndex] = (-1L << from.ordinal());
156.66 + for (int i = fromIndex + 1; i < toIndex; i++)
156.67 + elements[i] = -1;
156.68 + elements[toIndex] = -1L >>> (63 - to.ordinal());
156.69 + }
156.70 + size = to.ordinal() - from.ordinal() + 1;
156.71 + }
156.72 +
156.73 + void addAll() {
156.74 + for (int i = 0; i < elements.length; i++)
156.75 + elements[i] = -1;
156.76 + elements[elements.length - 1] >>>= -universe.length;
156.77 + size = universe.length;
156.78 + }
156.79 +
156.80 + void complement() {
156.81 + for (int i = 0; i < elements.length; i++)
156.82 + elements[i] = ~elements[i];
156.83 + elements[elements.length - 1] &= (-1L >>> -universe.length);
156.84 + size = universe.length - size;
156.85 + }
156.86 +
156.87 + /**
156.88 + * Returns an iterator over the elements contained in this set. The
156.89 + * iterator traverses the elements in their <i>natural order</i> (which is
156.90 + * the order in which the enum constants are declared). The returned
156.91 + * Iterator is a "weakly consistent" iterator that will never throw {@link
156.92 + * ConcurrentModificationException}.
156.93 + *
156.94 + * @return an iterator over the elements contained in this set
156.95 + */
156.96 + public Iterator<E> iterator() {
156.97 + return new EnumSetIterator<>();
156.98 + }
156.99 +
156.100 + private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
156.101 + /**
156.102 + * A bit vector representing the elements in the current "word"
156.103 + * of the set not yet returned by this iterator.
156.104 + */
156.105 + long unseen;
156.106 +
156.107 + /**
156.108 + * The index corresponding to unseen in the elements array.
156.109 + */
156.110 + int unseenIndex = 0;
156.111 +
156.112 + /**
156.113 + * The bit representing the last element returned by this iterator
156.114 + * but not removed, or zero if no such element exists.
156.115 + */
156.116 + long lastReturned = 0;
156.117 +
156.118 + /**
156.119 + * The index corresponding to lastReturned in the elements array.
156.120 + */
156.121 + int lastReturnedIndex = 0;
156.122 +
156.123 + EnumSetIterator() {
156.124 + unseen = elements[0];
156.125 + }
156.126 +
156.127 + public boolean hasNext() {
156.128 + while (unseen == 0 && unseenIndex < elements.length - 1)
156.129 + unseen = elements[++unseenIndex];
156.130 + return unseen != 0;
156.131 + }
156.132 +
156.133 + public E next() {
156.134 + if (!hasNext())
156.135 + throw new NoSuchElementException();
156.136 + lastReturned = unseen & -unseen;
156.137 + lastReturnedIndex = unseenIndex;
156.138 + unseen -= lastReturned;
156.139 + return (E) universe[(lastReturnedIndex << 6)
156.140 + + Long.numberOfTrailingZeros(lastReturned)];
156.141 + }
156.142 +
156.143 + public void remove() {
156.144 + if (lastReturned == 0)
156.145 + throw new IllegalStateException();
156.146 + final long oldElements = elements[lastReturnedIndex];
156.147 + elements[lastReturnedIndex] &= ~lastReturned;
156.148 + if (oldElements != elements[lastReturnedIndex]) {
156.149 + size--;
156.150 + }
156.151 + lastReturned = 0;
156.152 + }
156.153 + }
156.154 +
156.155 + /**
156.156 + * Returns the number of elements in this set.
156.157 + *
156.158 + * @return the number of elements in this set
156.159 + */
156.160 + public int size() {
156.161 + return size;
156.162 + }
156.163 +
156.164 + /**
156.165 + * Returns <tt>true</tt> if this set contains no elements.
156.166 + *
156.167 + * @return <tt>true</tt> if this set contains no elements
156.168 + */
156.169 + public boolean isEmpty() {
156.170 + return size == 0;
156.171 + }
156.172 +
156.173 + /**
156.174 + * Returns <tt>true</tt> if this set contains the specified element.
156.175 + *
156.176 + * @param e element to be checked for containment in this collection
156.177 + * @return <tt>true</tt> if this set contains the specified element
156.178 + */
156.179 + public boolean contains(Object e) {
156.180 + if (e == null)
156.181 + return false;
156.182 + Class eClass = e.getClass();
156.183 + if (eClass != elementType && eClass.getSuperclass() != elementType)
156.184 + return false;
156.185 +
156.186 + int eOrdinal = ((Enum)e).ordinal();
156.187 + return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
156.188 + }
156.189 +
156.190 + // Modification Operations
156.191 +
156.192 + /**
156.193 + * Adds the specified element to this set if it is not already present.
156.194 + *
156.195 + * @param e element to be added to this set
156.196 + * @return <tt>true</tt> if the set changed as a result of the call
156.197 + *
156.198 + * @throws NullPointerException if <tt>e</tt> is null
156.199 + */
156.200 + public boolean add(E e) {
156.201 + typeCheck(e);
156.202 +
156.203 + int eOrdinal = e.ordinal();
156.204 + int eWordNum = eOrdinal >>> 6;
156.205 +
156.206 + long oldElements = elements[eWordNum];
156.207 + elements[eWordNum] |= (1L << eOrdinal);
156.208 + boolean result = (elements[eWordNum] != oldElements);
156.209 + if (result)
156.210 + size++;
156.211 + return result;
156.212 + }
156.213 +
156.214 + /**
156.215 + * Removes the specified element from this set if it is present.
156.216 + *
156.217 + * @param e element to be removed from this set, if present
156.218 + * @return <tt>true</tt> if the set contained the specified element
156.219 + */
156.220 + public boolean remove(Object e) {
156.221 + if (e == null)
156.222 + return false;
156.223 + Class eClass = e.getClass();
156.224 + if (eClass != elementType && eClass.getSuperclass() != elementType)
156.225 + return false;
156.226 + int eOrdinal = ((Enum)e).ordinal();
156.227 + int eWordNum = eOrdinal >>> 6;
156.228 +
156.229 + long oldElements = elements[eWordNum];
156.230 + elements[eWordNum] &= ~(1L << eOrdinal);
156.231 + boolean result = (elements[eWordNum] != oldElements);
156.232 + if (result)
156.233 + size--;
156.234 + return result;
156.235 + }
156.236 +
156.237 + // Bulk Operations
156.238 +
156.239 + /**
156.240 + * Returns <tt>true</tt> if this set contains all of the elements
156.241 + * in the specified collection.
156.242 + *
156.243 + * @param c collection to be checked for containment in this set
156.244 + * @return <tt>true</tt> if this set contains all of the elements
156.245 + * in the specified collection
156.246 + * @throws NullPointerException if the specified collection is null
156.247 + */
156.248 + public boolean containsAll(Collection<?> c) {
156.249 + if (!(c instanceof JumboEnumSet))
156.250 + return super.containsAll(c);
156.251 +
156.252 + JumboEnumSet es = (JumboEnumSet)c;
156.253 + if (es.elementType != elementType)
156.254 + return es.isEmpty();
156.255 +
156.256 + for (int i = 0; i < elements.length; i++)
156.257 + if ((es.elements[i] & ~elements[i]) != 0)
156.258 + return false;
156.259 + return true;
156.260 + }
156.261 +
156.262 + /**
156.263 + * Adds all of the elements in the specified collection to this set.
156.264 + *
156.265 + * @param c collection whose elements are to be added to this set
156.266 + * @return <tt>true</tt> if this set changed as a result of the call
156.267 + * @throws NullPointerException if the specified collection or any of
156.268 + * its elements are null
156.269 + */
156.270 + public boolean addAll(Collection<? extends E> c) {
156.271 + if (!(c instanceof JumboEnumSet))
156.272 + return super.addAll(c);
156.273 +
156.274 + JumboEnumSet es = (JumboEnumSet)c;
156.275 + if (es.elementType != elementType) {
156.276 + if (es.isEmpty())
156.277 + return false;
156.278 + else
156.279 + throw new ClassCastException(
156.280 + es.elementType + " != " + elementType);
156.281 + }
156.282 +
156.283 + for (int i = 0; i < elements.length; i++)
156.284 + elements[i] |= es.elements[i];
156.285 + return recalculateSize();
156.286 + }
156.287 +
156.288 + /**
156.289 + * Removes from this set all of its elements that are contained in
156.290 + * the specified collection.
156.291 + *
156.292 + * @param c elements to be removed from this set
156.293 + * @return <tt>true</tt> if this set changed as a result of the call
156.294 + * @throws NullPointerException if the specified collection is null
156.295 + */
156.296 + public boolean removeAll(Collection<?> c) {
156.297 + if (!(c instanceof JumboEnumSet))
156.298 + return super.removeAll(c);
156.299 +
156.300 + JumboEnumSet es = (JumboEnumSet)c;
156.301 + if (es.elementType != elementType)
156.302 + return false;
156.303 +
156.304 + for (int i = 0; i < elements.length; i++)
156.305 + elements[i] &= ~es.elements[i];
156.306 + return recalculateSize();
156.307 + }
156.308 +
156.309 + /**
156.310 + * Retains only the elements in this set that are contained in the
156.311 + * specified collection.
156.312 + *
156.313 + * @param c elements to be retained in this set
156.314 + * @return <tt>true</tt> if this set changed as a result of the call
156.315 + * @throws NullPointerException if the specified collection is null
156.316 + */
156.317 + public boolean retainAll(Collection<?> c) {
156.318 + if (!(c instanceof JumboEnumSet))
156.319 + return super.retainAll(c);
156.320 +
156.321 + JumboEnumSet<?> es = (JumboEnumSet<?>)c;
156.322 + if (es.elementType != elementType) {
156.323 + boolean changed = (size != 0);
156.324 + clear();
156.325 + return changed;
156.326 + }
156.327 +
156.328 + for (int i = 0; i < elements.length; i++)
156.329 + elements[i] &= es.elements[i];
156.330 + return recalculateSize();
156.331 + }
156.332 +
156.333 + /**
156.334 + * Removes all of the elements from this set.
156.335 + */
156.336 + public void clear() {
156.337 + Arrays.fill(elements, 0);
156.338 + size = 0;
156.339 + }
156.340 +
156.341 + /**
156.342 + * Compares the specified object with this set for equality. Returns
156.343 + * <tt>true</tt> if the given object is also a set, the two sets have
156.344 + * the same size, and every member of the given set is contained in
156.345 + * this set.
156.346 + *
156.347 + * @param e object to be compared for equality with this set
156.348 + * @return <tt>true</tt> if the specified object is equal to this set
156.349 + */
156.350 + public boolean equals(Object o) {
156.351 + if (!(o instanceof JumboEnumSet))
156.352 + return super.equals(o);
156.353 +
156.354 + JumboEnumSet es = (JumboEnumSet)o;
156.355 + if (es.elementType != elementType)
156.356 + return size == 0 && es.size == 0;
156.357 +
156.358 + return Arrays.equals(es.elements, elements);
156.359 + }
156.360 +
156.361 + /**
156.362 + * Recalculates the size of the set. Returns true if it's changed.
156.363 + */
156.364 + private boolean recalculateSize() {
156.365 + int oldSize = size;
156.366 + size = 0;
156.367 + for (long elt : elements)
156.368 + size += Long.bitCount(elt);
156.369 +
156.370 + return size != oldSize;
156.371 + }
156.372 +
156.373 + public EnumSet<E> clone() {
156.374 + JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
156.375 + result.elements = result.elements.clone();
156.376 + return result;
156.377 + }
156.378 +}
157.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
157.2 +++ b/rt/emul/compact/src/main/java/java/util/LinkedHashSet.java Mon Oct 07 14:20:58 2013 +0200
157.3 @@ -0,0 +1,171 @@
157.4 +/*
157.5 + * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
157.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
157.7 + *
157.8 + * This code is free software; you can redistribute it and/or modify it
157.9 + * under the terms of the GNU General Public License version 2 only, as
157.10 + * published by the Free Software Foundation. Oracle designates this
157.11 + * particular file as subject to the "Classpath" exception as provided
157.12 + * by Oracle in the LICENSE file that accompanied this code.
157.13 + *
157.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
157.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
157.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
157.17 + * version 2 for more details (a copy is included in the LICENSE file that
157.18 + * accompanied this code).
157.19 + *
157.20 + * You should have received a copy of the GNU General Public License version
157.21 + * 2 along with this work; if not, write to the Free Software Foundation,
157.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
157.23 + *
157.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
157.25 + * or visit www.oracle.com if you need additional information or have any
157.26 + * questions.
157.27 + */
157.28 +
157.29 +package java.util;
157.30 +
157.31 +/**
157.32 + * <p>Hash table and linked list implementation of the <tt>Set</tt> interface,
157.33 + * with predictable iteration order. This implementation differs from
157.34 + * <tt>HashSet</tt> in that it maintains a doubly-linked list running through
157.35 + * all of its entries. This linked list defines the iteration ordering,
157.36 + * which is the order in which elements were inserted into the set
157.37 + * (<i>insertion-order</i>). Note that insertion order is <i>not</i> affected
157.38 + * if an element is <i>re-inserted</i> into the set. (An element <tt>e</tt>
157.39 + * is reinserted into a set <tt>s</tt> if <tt>s.add(e)</tt> is invoked when
157.40 + * <tt>s.contains(e)</tt> would return <tt>true</tt> immediately prior to
157.41 + * the invocation.)
157.42 + *
157.43 + * <p>This implementation spares its clients from the unspecified, generally
157.44 + * chaotic ordering provided by {@link HashSet}, without incurring the
157.45 + * increased cost associated with {@link TreeSet}. It can be used to
157.46 + * produce a copy of a set that has the same order as the original, regardless
157.47 + * of the original set's implementation:
157.48 + * <pre>
157.49 + * void foo(Set s) {
157.50 + * Set copy = new LinkedHashSet(s);
157.51 + * ...
157.52 + * }
157.53 + * </pre>
157.54 + * This technique is particularly useful if a module takes a set on input,
157.55 + * copies it, and later returns results whose order is determined by that of
157.56 + * the copy. (Clients generally appreciate having things returned in the same
157.57 + * order they were presented.)
157.58 + *
157.59 + * <p>This class provides all of the optional <tt>Set</tt> operations, and
157.60 + * permits null elements. Like <tt>HashSet</tt>, it provides constant-time
157.61 + * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
157.62 + * <tt>remove</tt>), assuming the hash function disperses elements
157.63 + * properly among the buckets. Performance is likely to be just slightly
157.64 + * below that of <tt>HashSet</tt>, due to the added expense of maintaining the
157.65 + * linked list, with one exception: Iteration over a <tt>LinkedHashSet</tt>
157.66 + * requires time proportional to the <i>size</i> of the set, regardless of
157.67 + * its capacity. Iteration over a <tt>HashSet</tt> is likely to be more
157.68 + * expensive, requiring time proportional to its <i>capacity</i>.
157.69 + *
157.70 + * <p>A linked hash set has two parameters that affect its performance:
157.71 + * <i>initial capacity</i> and <i>load factor</i>. They are defined precisely
157.72 + * as for <tt>HashSet</tt>. Note, however, that the penalty for choosing an
157.73 + * excessively high value for initial capacity is less severe for this class
157.74 + * than for <tt>HashSet</tt>, as iteration times for this class are unaffected
157.75 + * by capacity.
157.76 + *
157.77 + * <p><strong>Note that this implementation is not synchronized.</strong>
157.78 + * If multiple threads access a linked hash set concurrently, and at least
157.79 + * one of the threads modifies the set, it <em>must</em> be synchronized
157.80 + * externally. This is typically accomplished by synchronizing on some
157.81 + * object that naturally encapsulates the set.
157.82 + *
157.83 + * If no such object exists, the set should be "wrapped" using the
157.84 + * {@link Collections#synchronizedSet Collections.synchronizedSet}
157.85 + * method. This is best done at creation time, to prevent accidental
157.86 + * unsynchronized access to the set: <pre>
157.87 + * Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre>
157.88 + *
157.89 + * <p>The iterators returned by this class's <tt>iterator</tt> method are
157.90 + * <em>fail-fast</em>: if the set is modified at any time after the iterator
157.91 + * is created, in any way except through the iterator's own <tt>remove</tt>
157.92 + * method, the iterator will throw a {@link ConcurrentModificationException}.
157.93 + * Thus, in the face of concurrent modification, the iterator fails quickly
157.94 + * and cleanly, rather than risking arbitrary, non-deterministic behavior at
157.95 + * an undetermined time in the future.
157.96 + *
157.97 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
157.98 + * as it is, generally speaking, impossible to make any hard guarantees in the
157.99 + * presence of unsynchronized concurrent modification. Fail-fast iterators
157.100 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
157.101 + * Therefore, it would be wrong to write a program that depended on this
157.102 + * exception for its correctness: <i>the fail-fast behavior of iterators
157.103 + * should be used only to detect bugs.</i>
157.104 + *
157.105 + * <p>This class is a member of the
157.106 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
157.107 + * Java Collections Framework</a>.
157.108 + *
157.109 + * @param <E> the type of elements maintained by this set
157.110 + *
157.111 + * @author Josh Bloch
157.112 + * @see Object#hashCode()
157.113 + * @see Collection
157.114 + * @see Set
157.115 + * @see HashSet
157.116 + * @see TreeSet
157.117 + * @see Hashtable
157.118 + * @since 1.4
157.119 + */
157.120 +
157.121 +public class LinkedHashSet<E>
157.122 + extends HashSet<E>
157.123 + implements Set<E>, Cloneable, java.io.Serializable {
157.124 +
157.125 + private static final long serialVersionUID = -2851667679971038690L;
157.126 +
157.127 + /**
157.128 + * Constructs a new, empty linked hash set with the specified initial
157.129 + * capacity and load factor.
157.130 + *
157.131 + * @param initialCapacity the initial capacity of the linked hash set
157.132 + * @param loadFactor the load factor of the linked hash set
157.133 + * @throws IllegalArgumentException if the initial capacity is less
157.134 + * than zero, or if the load factor is nonpositive
157.135 + */
157.136 + public LinkedHashSet(int initialCapacity, float loadFactor) {
157.137 + super(initialCapacity, loadFactor, true);
157.138 + }
157.139 +
157.140 + /**
157.141 + * Constructs a new, empty linked hash set with the specified initial
157.142 + * capacity and the default load factor (0.75).
157.143 + *
157.144 + * @param initialCapacity the initial capacity of the LinkedHashSet
157.145 + * @throws IllegalArgumentException if the initial capacity is less
157.146 + * than zero
157.147 + */
157.148 + public LinkedHashSet(int initialCapacity) {
157.149 + super(initialCapacity, .75f, true);
157.150 + }
157.151 +
157.152 + /**
157.153 + * Constructs a new, empty linked hash set with the default initial
157.154 + * capacity (16) and load factor (0.75).
157.155 + */
157.156 + public LinkedHashSet() {
157.157 + super(16, .75f, true);
157.158 + }
157.159 +
157.160 + /**
157.161 + * Constructs a new linked hash set with the same elements as the
157.162 + * specified collection. The linked hash set is created with an initial
157.163 + * capacity sufficient to hold the elements in the specified collection
157.164 + * and the default load factor (0.75).
157.165 + *
157.166 + * @param c the collection whose elements are to be placed into
157.167 + * this set
157.168 + * @throws NullPointerException if the specified collection is null
157.169 + */
157.170 + public LinkedHashSet(Collection<? extends E> c) {
157.171 + super(Math.max(2*c.size(), 11), .75f, true);
157.172 + addAll(c);
157.173 + }
157.174 +}
158.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
158.2 +++ b/rt/emul/compact/src/main/java/java/util/NavigableMap.java Mon Oct 07 14:20:58 2013 +0200
158.3 @@ -0,0 +1,424 @@
158.4 +/*
158.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
158.6 + *
158.7 + * This code is free software; you can redistribute it and/or modify it
158.8 + * under the terms of the GNU General Public License version 2 only, as
158.9 + * published by the Free Software Foundation. Oracle designates this
158.10 + * particular file as subject to the "Classpath" exception as provided
158.11 + * by Oracle in the LICENSE file that accompanied this code.
158.12 + *
158.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
158.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
158.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
158.16 + * version 2 for more details (a copy is included in the LICENSE file that
158.17 + * accompanied this code).
158.18 + *
158.19 + * You should have received a copy of the GNU General Public License version
158.20 + * 2 along with this work; if not, write to the Free Software Foundation,
158.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
158.22 + *
158.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
158.24 + * or visit www.oracle.com if you need additional information or have any
158.25 + * questions.
158.26 + */
158.27 +
158.28 +/*
158.29 + * This file is available under and governed by the GNU General Public
158.30 + * License version 2 only, as published by the Free Software Foundation.
158.31 + * However, the following notice accompanied the original version of this
158.32 + * file:
158.33 + *
158.34 + * Written by Doug Lea and Josh Bloch with assistance from members of JCP
158.35 + * JSR-166 Expert Group and released to the public domain, as explained at
158.36 + * http://creativecommons.org/publicdomain/zero/1.0/
158.37 + */
158.38 +
158.39 +package java.util;
158.40 +
158.41 +/**
158.42 + * A {@link SortedMap} extended with navigation methods returning the
158.43 + * closest matches for given search targets. Methods
158.44 + * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry},
158.45 + * and {@code higherEntry} return {@code Map.Entry} objects
158.46 + * associated with keys respectively less than, less than or equal,
158.47 + * greater than or equal, and greater than a given key, returning
158.48 + * {@code null} if there is no such key. Similarly, methods
158.49 + * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and
158.50 + * {@code higherKey} return only the associated keys. All of these
158.51 + * methods are designed for locating, not traversing entries.
158.52 + *
158.53 + * <p>A {@code NavigableMap} may be accessed and traversed in either
158.54 + * ascending or descending key order. The {@code descendingMap}
158.55 + * method returns a view of the map with the senses of all relational
158.56 + * and directional methods inverted. The performance of ascending
158.57 + * operations and views is likely to be faster than that of descending
158.58 + * ones. Methods {@code subMap}, {@code headMap},
158.59 + * and {@code tailMap} differ from the like-named {@code
158.60 + * SortedMap} methods in accepting additional arguments describing
158.61 + * whether lower and upper bounds are inclusive versus exclusive.
158.62 + * Submaps of any {@code NavigableMap} must implement the {@code
158.63 + * NavigableMap} interface.
158.64 + *
158.65 + * <p>This interface additionally defines methods {@code firstEntry},
158.66 + * {@code pollFirstEntry}, {@code lastEntry}, and
158.67 + * {@code pollLastEntry} that return and/or remove the least and
158.68 + * greatest mappings, if any exist, else returning {@code null}.
158.69 + *
158.70 + * <p>Implementations of entry-returning methods are expected to
158.71 + * return {@code Map.Entry} pairs representing snapshots of mappings
158.72 + * at the time they were produced, and thus generally do <em>not</em>
158.73 + * support the optional {@code Entry.setValue} method. Note however
158.74 + * that it is possible to change mappings in the associated map using
158.75 + * method {@code put}.
158.76 + *
158.77 + * <p>Methods
158.78 + * {@link #subMap(Object, Object) subMap(K, K)},
158.79 + * {@link #headMap(Object) headMap(K)}, and
158.80 + * {@link #tailMap(Object) tailMap(K)}
158.81 + * are specified to return {@code SortedMap} to allow existing
158.82 + * implementations of {@code SortedMap} to be compatibly retrofitted to
158.83 + * implement {@code NavigableMap}, but extensions and implementations
158.84 + * of this interface are encouraged to override these methods to return
158.85 + * {@code NavigableMap}. Similarly,
158.86 + * {@link #keySet()} can be overriden to return {@code NavigableSet}.
158.87 + *
158.88 + * <p>This interface is a member of the
158.89 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
158.90 + * Java Collections Framework</a>.
158.91 + *
158.92 + * @author Doug Lea
158.93 + * @author Josh Bloch
158.94 + * @param <K> the type of keys maintained by this map
158.95 + * @param <V> the type of mapped values
158.96 + * @since 1.6
158.97 + */
158.98 +public interface NavigableMap<K,V> extends SortedMap<K,V> {
158.99 + /**
158.100 + * Returns a key-value mapping associated with the greatest key
158.101 + * strictly less than the given key, or {@code null} if there is
158.102 + * no such key.
158.103 + *
158.104 + * @param key the key
158.105 + * @return an entry with the greatest key less than {@code key},
158.106 + * or {@code null} if there is no such key
158.107 + * @throws ClassCastException if the specified key cannot be compared
158.108 + * with the keys currently in the map
158.109 + * @throws NullPointerException if the specified key is null
158.110 + * and this map does not permit null keys
158.111 + */
158.112 + Map.Entry<K,V> lowerEntry(K key);
158.113 +
158.114 + /**
158.115 + * Returns the greatest key strictly less than the given key, or
158.116 + * {@code null} if there is no such key.
158.117 + *
158.118 + * @param key the key
158.119 + * @return the greatest key less than {@code key},
158.120 + * or {@code null} if there is no such key
158.121 + * @throws ClassCastException if the specified key cannot be compared
158.122 + * with the keys currently in the map
158.123 + * @throws NullPointerException if the specified key is null
158.124 + * and this map does not permit null keys
158.125 + */
158.126 + K lowerKey(K key);
158.127 +
158.128 + /**
158.129 + * Returns a key-value mapping associated with the greatest key
158.130 + * less than or equal to the given key, or {@code null} if there
158.131 + * is no such key.
158.132 + *
158.133 + * @param key the key
158.134 + * @return an entry with the greatest key less than or equal to
158.135 + * {@code key}, or {@code null} if there is no such key
158.136 + * @throws ClassCastException if the specified key cannot be compared
158.137 + * with the keys currently in the map
158.138 + * @throws NullPointerException if the specified key is null
158.139 + * and this map does not permit null keys
158.140 + */
158.141 + Map.Entry<K,V> floorEntry(K key);
158.142 +
158.143 + /**
158.144 + * Returns the greatest key less than or equal to the given key,
158.145 + * or {@code null} if there is no such key.
158.146 + *
158.147 + * @param key the key
158.148 + * @return the greatest key less than or equal to {@code key},
158.149 + * or {@code null} if there is no such key
158.150 + * @throws ClassCastException if the specified key cannot be compared
158.151 + * with the keys currently in the map
158.152 + * @throws NullPointerException if the specified key is null
158.153 + * and this map does not permit null keys
158.154 + */
158.155 + K floorKey(K key);
158.156 +
158.157 + /**
158.158 + * Returns a key-value mapping associated with the least key
158.159 + * greater than or equal to the given key, or {@code null} if
158.160 + * there is no such key.
158.161 + *
158.162 + * @param key the key
158.163 + * @return an entry with the least key greater than or equal to
158.164 + * {@code key}, or {@code null} if there is no such key
158.165 + * @throws ClassCastException if the specified key cannot be compared
158.166 + * with the keys currently in the map
158.167 + * @throws NullPointerException if the specified key is null
158.168 + * and this map does not permit null keys
158.169 + */
158.170 + Map.Entry<K,V> ceilingEntry(K key);
158.171 +
158.172 + /**
158.173 + * Returns the least key greater than or equal to the given key,
158.174 + * or {@code null} if there is no such key.
158.175 + *
158.176 + * @param key the key
158.177 + * @return the least key greater than or equal to {@code key},
158.178 + * or {@code null} if there is no such key
158.179 + * @throws ClassCastException if the specified key cannot be compared
158.180 + * with the keys currently in the map
158.181 + * @throws NullPointerException if the specified key is null
158.182 + * and this map does not permit null keys
158.183 + */
158.184 + K ceilingKey(K key);
158.185 +
158.186 + /**
158.187 + * Returns a key-value mapping associated with the least key
158.188 + * strictly greater than the given key, or {@code null} if there
158.189 + * is no such key.
158.190 + *
158.191 + * @param key the key
158.192 + * @return an entry with the least key greater than {@code key},
158.193 + * or {@code null} if there is no such key
158.194 + * @throws ClassCastException if the specified key cannot be compared
158.195 + * with the keys currently in the map
158.196 + * @throws NullPointerException if the specified key is null
158.197 + * and this map does not permit null keys
158.198 + */
158.199 + Map.Entry<K,V> higherEntry(K key);
158.200 +
158.201 + /**
158.202 + * Returns the least key strictly greater than the given key, or
158.203 + * {@code null} if there is no such key.
158.204 + *
158.205 + * @param key the key
158.206 + * @return the least key greater than {@code key},
158.207 + * or {@code null} if there is no such key
158.208 + * @throws ClassCastException if the specified key cannot be compared
158.209 + * with the keys currently in the map
158.210 + * @throws NullPointerException if the specified key is null
158.211 + * and this map does not permit null keys
158.212 + */
158.213 + K higherKey(K key);
158.214 +
158.215 + /**
158.216 + * Returns a key-value mapping associated with the least
158.217 + * key in this map, or {@code null} if the map is empty.
158.218 + *
158.219 + * @return an entry with the least key,
158.220 + * or {@code null} if this map is empty
158.221 + */
158.222 + Map.Entry<K,V> firstEntry();
158.223 +
158.224 + /**
158.225 + * Returns a key-value mapping associated with the greatest
158.226 + * key in this map, or {@code null} if the map is empty.
158.227 + *
158.228 + * @return an entry with the greatest key,
158.229 + * or {@code null} if this map is empty
158.230 + */
158.231 + Map.Entry<K,V> lastEntry();
158.232 +
158.233 + /**
158.234 + * Removes and returns a key-value mapping associated with
158.235 + * the least key in this map, or {@code null} if the map is empty.
158.236 + *
158.237 + * @return the removed first entry of this map,
158.238 + * or {@code null} if this map is empty
158.239 + */
158.240 + Map.Entry<K,V> pollFirstEntry();
158.241 +
158.242 + /**
158.243 + * Removes and returns a key-value mapping associated with
158.244 + * the greatest key in this map, or {@code null} if the map is empty.
158.245 + *
158.246 + * @return the removed last entry of this map,
158.247 + * or {@code null} if this map is empty
158.248 + */
158.249 + Map.Entry<K,V> pollLastEntry();
158.250 +
158.251 + /**
158.252 + * Returns a reverse order view of the mappings contained in this map.
158.253 + * The descending map is backed by this map, so changes to the map are
158.254 + * reflected in the descending map, and vice-versa. If either map is
158.255 + * modified while an iteration over a collection view of either map
158.256 + * is in progress (except through the iterator's own {@code remove}
158.257 + * operation), the results of the iteration are undefined.
158.258 + *
158.259 + * <p>The returned map has an ordering equivalent to
158.260 + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
158.261 + * The expression {@code m.descendingMap().descendingMap()} returns a
158.262 + * view of {@code m} essentially equivalent to {@code m}.
158.263 + *
158.264 + * @return a reverse order view of this map
158.265 + */
158.266 + NavigableMap<K,V> descendingMap();
158.267 +
158.268 + /**
158.269 + * Returns a {@link NavigableSet} view of the keys contained in this map.
158.270 + * The set's iterator returns the keys in ascending order.
158.271 + * The set is backed by the map, so changes to the map are reflected in
158.272 + * the set, and vice-versa. If the map is modified while an iteration
158.273 + * over the set is in progress (except through the iterator's own {@code
158.274 + * remove} operation), the results of the iteration are undefined. The
158.275 + * set supports element removal, which removes the corresponding mapping
158.276 + * from the map, via the {@code Iterator.remove}, {@code Set.remove},
158.277 + * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
158.278 + * It does not support the {@code add} or {@code addAll} operations.
158.279 + *
158.280 + * @return a navigable set view of the keys in this map
158.281 + */
158.282 + NavigableSet<K> navigableKeySet();
158.283 +
158.284 + /**
158.285 + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
158.286 + * The set's iterator returns the keys in descending order.
158.287 + * The set is backed by the map, so changes to the map are reflected in
158.288 + * the set, and vice-versa. If the map is modified while an iteration
158.289 + * over the set is in progress (except through the iterator's own {@code
158.290 + * remove} operation), the results of the iteration are undefined. The
158.291 + * set supports element removal, which removes the corresponding mapping
158.292 + * from the map, via the {@code Iterator.remove}, {@code Set.remove},
158.293 + * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
158.294 + * It does not support the {@code add} or {@code addAll} operations.
158.295 + *
158.296 + * @return a reverse order navigable set view of the keys in this map
158.297 + */
158.298 + NavigableSet<K> descendingKeySet();
158.299 +
158.300 + /**
158.301 + * Returns a view of the portion of this map whose keys range from
158.302 + * {@code fromKey} to {@code toKey}. If {@code fromKey} and
158.303 + * {@code toKey} are equal, the returned map is empty unless
158.304 + * {@code fromInclusive} and {@code toInclusive} are both true. The
158.305 + * returned map is backed by this map, so changes in the returned map are
158.306 + * reflected in this map, and vice-versa. The returned map supports all
158.307 + * optional map operations that this map supports.
158.308 + *
158.309 + * <p>The returned map will throw an {@code IllegalArgumentException}
158.310 + * on an attempt to insert a key outside of its range, or to construct a
158.311 + * submap either of whose endpoints lie outside its range.
158.312 + *
158.313 + * @param fromKey low endpoint of the keys in the returned map
158.314 + * @param fromInclusive {@code true} if the low endpoint
158.315 + * is to be included in the returned view
158.316 + * @param toKey high endpoint of the keys in the returned map
158.317 + * @param toInclusive {@code true} if the high endpoint
158.318 + * is to be included in the returned view
158.319 + * @return a view of the portion of this map whose keys range from
158.320 + * {@code fromKey} to {@code toKey}
158.321 + * @throws ClassCastException if {@code fromKey} and {@code toKey}
158.322 + * cannot be compared to one another using this map's comparator
158.323 + * (or, if the map has no comparator, using natural ordering).
158.324 + * Implementations may, but are not required to, throw this
158.325 + * exception if {@code fromKey} or {@code toKey}
158.326 + * cannot be compared to keys currently in the map.
158.327 + * @throws NullPointerException if {@code fromKey} or {@code toKey}
158.328 + * is null and this map does not permit null keys
158.329 + * @throws IllegalArgumentException if {@code fromKey} is greater than
158.330 + * {@code toKey}; or if this map itself has a restricted
158.331 + * range, and {@code fromKey} or {@code toKey} lies
158.332 + * outside the bounds of the range
158.333 + */
158.334 + NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
158.335 + K toKey, boolean toInclusive);
158.336 +
158.337 + /**
158.338 + * Returns a view of the portion of this map whose keys are less than (or
158.339 + * equal to, if {@code inclusive} is true) {@code toKey}. The returned
158.340 + * map is backed by this map, so changes in the returned map are reflected
158.341 + * in this map, and vice-versa. The returned map supports all optional
158.342 + * map operations that this map supports.
158.343 + *
158.344 + * <p>The returned map will throw an {@code IllegalArgumentException}
158.345 + * on an attempt to insert a key outside its range.
158.346 + *
158.347 + * @param toKey high endpoint of the keys in the returned map
158.348 + * @param inclusive {@code true} if the high endpoint
158.349 + * is to be included in the returned view
158.350 + * @return a view of the portion of this map whose keys are less than
158.351 + * (or equal to, if {@code inclusive} is true) {@code toKey}
158.352 + * @throws ClassCastException if {@code toKey} is not compatible
158.353 + * with this map's comparator (or, if the map has no comparator,
158.354 + * if {@code toKey} does not implement {@link Comparable}).
158.355 + * Implementations may, but are not required to, throw this
158.356 + * exception if {@code toKey} cannot be compared to keys
158.357 + * currently in the map.
158.358 + * @throws NullPointerException if {@code toKey} is null
158.359 + * and this map does not permit null keys
158.360 + * @throws IllegalArgumentException if this map itself has a
158.361 + * restricted range, and {@code toKey} lies outside the
158.362 + * bounds of the range
158.363 + */
158.364 + NavigableMap<K,V> headMap(K toKey, boolean inclusive);
158.365 +
158.366 + /**
158.367 + * Returns a view of the portion of this map whose keys are greater than (or
158.368 + * equal to, if {@code inclusive} is true) {@code fromKey}. The returned
158.369 + * map is backed by this map, so changes in the returned map are reflected
158.370 + * in this map, and vice-versa. The returned map supports all optional
158.371 + * map operations that this map supports.
158.372 + *
158.373 + * <p>The returned map will throw an {@code IllegalArgumentException}
158.374 + * on an attempt to insert a key outside its range.
158.375 + *
158.376 + * @param fromKey low endpoint of the keys in the returned map
158.377 + * @param inclusive {@code true} if the low endpoint
158.378 + * is to be included in the returned view
158.379 + * @return a view of the portion of this map whose keys are greater than
158.380 + * (or equal to, if {@code inclusive} is true) {@code fromKey}
158.381 + * @throws ClassCastException if {@code fromKey} is not compatible
158.382 + * with this map's comparator (or, if the map has no comparator,
158.383 + * if {@code fromKey} does not implement {@link Comparable}).
158.384 + * Implementations may, but are not required to, throw this
158.385 + * exception if {@code fromKey} cannot be compared to keys
158.386 + * currently in the map.
158.387 + * @throws NullPointerException if {@code fromKey} is null
158.388 + * and this map does not permit null keys
158.389 + * @throws IllegalArgumentException if this map itself has a
158.390 + * restricted range, and {@code fromKey} lies outside the
158.391 + * bounds of the range
158.392 + */
158.393 + NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
158.394 +
158.395 + /**
158.396 + * {@inheritDoc}
158.397 + *
158.398 + * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}.
158.399 + *
158.400 + * @throws ClassCastException {@inheritDoc}
158.401 + * @throws NullPointerException {@inheritDoc}
158.402 + * @throws IllegalArgumentException {@inheritDoc}
158.403 + */
158.404 + SortedMap<K,V> subMap(K fromKey, K toKey);
158.405 +
158.406 + /**
158.407 + * {@inheritDoc}
158.408 + *
158.409 + * <p>Equivalent to {@code headMap(toKey, false)}.
158.410 + *
158.411 + * @throws ClassCastException {@inheritDoc}
158.412 + * @throws NullPointerException {@inheritDoc}
158.413 + * @throws IllegalArgumentException {@inheritDoc}
158.414 + */
158.415 + SortedMap<K,V> headMap(K toKey);
158.416 +
158.417 + /**
158.418 + * {@inheritDoc}
158.419 + *
158.420 + * <p>Equivalent to {@code tailMap(fromKey, true)}.
158.421 + *
158.422 + * @throws ClassCastException {@inheritDoc}
158.423 + * @throws NullPointerException {@inheritDoc}
158.424 + * @throws IllegalArgumentException {@inheritDoc}
158.425 + */
158.426 + SortedMap<K,V> tailMap(K fromKey);
158.427 +}
159.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
159.2 +++ b/rt/emul/compact/src/main/java/java/util/NavigableSet.java Mon Oct 07 14:20:58 2013 +0200
159.3 @@ -0,0 +1,319 @@
159.4 +/*
159.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
159.6 + *
159.7 + * This code is free software; you can redistribute it and/or modify it
159.8 + * under the terms of the GNU General Public License version 2 only, as
159.9 + * published by the Free Software Foundation. Oracle designates this
159.10 + * particular file as subject to the "Classpath" exception as provided
159.11 + * by Oracle in the LICENSE file that accompanied this code.
159.12 + *
159.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
159.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
159.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
159.16 + * version 2 for more details (a copy is included in the LICENSE file that
159.17 + * accompanied this code).
159.18 + *
159.19 + * You should have received a copy of the GNU General Public License version
159.20 + * 2 along with this work; if not, write to the Free Software Foundation,
159.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
159.22 + *
159.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
159.24 + * or visit www.oracle.com if you need additional information or have any
159.25 + * questions.
159.26 + */
159.27 +
159.28 +/*
159.29 + * This file is available under and governed by the GNU General Public
159.30 + * License version 2 only, as published by the Free Software Foundation.
159.31 + * However, the following notice accompanied the original version of this
159.32 + * file:
159.33 + *
159.34 + * Written by Doug Lea and Josh Bloch with assistance from members of JCP
159.35 + * JSR-166 Expert Group and released to the public domain, as explained at
159.36 + * http://creativecommons.org/publicdomain/zero/1.0/
159.37 + */
159.38 +
159.39 +package java.util;
159.40 +
159.41 +/**
159.42 + * A {@link SortedSet} extended with navigation methods reporting
159.43 + * closest matches for given search targets. Methods {@code lower},
159.44 + * {@code floor}, {@code ceiling}, and {@code higher} return elements
159.45 + * respectively less than, less than or equal, greater than or equal,
159.46 + * and greater than a given element, returning {@code null} if there
159.47 + * is no such element. A {@code NavigableSet} may be accessed and
159.48 + * traversed in either ascending or descending order. The {@code
159.49 + * descendingSet} method returns a view of the set with the senses of
159.50 + * all relational and directional methods inverted. The performance of
159.51 + * ascending operations and views is likely to be faster than that of
159.52 + * descending ones. This interface additionally defines methods
159.53 + * {@code pollFirst} and {@code pollLast} that return and remove the
159.54 + * lowest and highest element, if one exists, else returning {@code
159.55 + * null}. Methods {@code subSet}, {@code headSet},
159.56 + * and {@code tailSet} differ from the like-named {@code
159.57 + * SortedSet} methods in accepting additional arguments describing
159.58 + * whether lower and upper bounds are inclusive versus exclusive.
159.59 + * Subsets of any {@code NavigableSet} must implement the {@code
159.60 + * NavigableSet} interface.
159.61 + *
159.62 + * <p> The return values of navigation methods may be ambiguous in
159.63 + * implementations that permit {@code null} elements. However, even
159.64 + * in this case the result can be disambiguated by checking
159.65 + * {@code contains(null)}. To avoid such issues, implementations of
159.66 + * this interface are encouraged to <em>not</em> permit insertion of
159.67 + * {@code null} elements. (Note that sorted sets of {@link
159.68 + * Comparable} elements intrinsically do not permit {@code null}.)
159.69 + *
159.70 + * <p>Methods
159.71 + * {@link #subSet(Object, Object) subSet(E, E)},
159.72 + * {@link #headSet(Object) headSet(E)}, and
159.73 + * {@link #tailSet(Object) tailSet(E)}
159.74 + * are specified to return {@code SortedSet} to allow existing
159.75 + * implementations of {@code SortedSet} to be compatibly retrofitted to
159.76 + * implement {@code NavigableSet}, but extensions and implementations
159.77 + * of this interface are encouraged to override these methods to return
159.78 + * {@code NavigableSet}.
159.79 + *
159.80 + * <p>This interface is a member of the
159.81 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
159.82 + * Java Collections Framework</a>.
159.83 + *
159.84 + * @author Doug Lea
159.85 + * @author Josh Bloch
159.86 + * @param <E> the type of elements maintained by this set
159.87 + * @since 1.6
159.88 + */
159.89 +public interface NavigableSet<E> extends SortedSet<E> {
159.90 + /**
159.91 + * Returns the greatest element in this set strictly less than the
159.92 + * given element, or {@code null} if there is no such element.
159.93 + *
159.94 + * @param e the value to match
159.95 + * @return the greatest element less than {@code e},
159.96 + * or {@code null} if there is no such element
159.97 + * @throws ClassCastException if the specified element cannot be
159.98 + * compared with the elements currently in the set
159.99 + * @throws NullPointerException if the specified element is null
159.100 + * and this set does not permit null elements
159.101 + */
159.102 + E lower(E e);
159.103 +
159.104 + /**
159.105 + * Returns the greatest element in this set less than or equal to
159.106 + * the given element, or {@code null} if there is no such element.
159.107 + *
159.108 + * @param e the value to match
159.109 + * @return the greatest element less than or equal to {@code e},
159.110 + * or {@code null} if there is no such element
159.111 + * @throws ClassCastException if the specified element cannot be
159.112 + * compared with the elements currently in the set
159.113 + * @throws NullPointerException if the specified element is null
159.114 + * and this set does not permit null elements
159.115 + */
159.116 + E floor(E e);
159.117 +
159.118 + /**
159.119 + * Returns the least element in this set greater than or equal to
159.120 + * the given element, or {@code null} if there is no such element.
159.121 + *
159.122 + * @param e the value to match
159.123 + * @return the least element greater than or equal to {@code e},
159.124 + * or {@code null} if there is no such element
159.125 + * @throws ClassCastException if the specified element cannot be
159.126 + * compared with the elements currently in the set
159.127 + * @throws NullPointerException if the specified element is null
159.128 + * and this set does not permit null elements
159.129 + */
159.130 + E ceiling(E e);
159.131 +
159.132 + /**
159.133 + * Returns the least element in this set strictly greater than the
159.134 + * given element, or {@code null} if there is no such element.
159.135 + *
159.136 + * @param e the value to match
159.137 + * @return the least element greater than {@code e},
159.138 + * or {@code null} if there is no such element
159.139 + * @throws ClassCastException if the specified element cannot be
159.140 + * compared with the elements currently in the set
159.141 + * @throws NullPointerException if the specified element is null
159.142 + * and this set does not permit null elements
159.143 + */
159.144 + E higher(E e);
159.145 +
159.146 + /**
159.147 + * Retrieves and removes the first (lowest) element,
159.148 + * or returns {@code null} if this set is empty.
159.149 + *
159.150 + * @return the first element, or {@code null} if this set is empty
159.151 + */
159.152 + E pollFirst();
159.153 +
159.154 + /**
159.155 + * Retrieves and removes the last (highest) element,
159.156 + * or returns {@code null} if this set is empty.
159.157 + *
159.158 + * @return the last element, or {@code null} if this set is empty
159.159 + */
159.160 + E pollLast();
159.161 +
159.162 + /**
159.163 + * Returns an iterator over the elements in this set, in ascending order.
159.164 + *
159.165 + * @return an iterator over the elements in this set, in ascending order
159.166 + */
159.167 + Iterator<E> iterator();
159.168 +
159.169 + /**
159.170 + * Returns a reverse order view of the elements contained in this set.
159.171 + * The descending set is backed by this set, so changes to the set are
159.172 + * reflected in the descending set, and vice-versa. If either set is
159.173 + * modified while an iteration over either set is in progress (except
159.174 + * through the iterator's own {@code remove} operation), the results of
159.175 + * the iteration are undefined.
159.176 + *
159.177 + * <p>The returned set has an ordering equivalent to
159.178 + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
159.179 + * The expression {@code s.descendingSet().descendingSet()} returns a
159.180 + * view of {@code s} essentially equivalent to {@code s}.
159.181 + *
159.182 + * @return a reverse order view of this set
159.183 + */
159.184 + NavigableSet<E> descendingSet();
159.185 +
159.186 + /**
159.187 + * Returns an iterator over the elements in this set, in descending order.
159.188 + * Equivalent in effect to {@code descendingSet().iterator()}.
159.189 + *
159.190 + * @return an iterator over the elements in this set, in descending order
159.191 + */
159.192 + Iterator<E> descendingIterator();
159.193 +
159.194 + /**
159.195 + * Returns a view of the portion of this set whose elements range from
159.196 + * {@code fromElement} to {@code toElement}. If {@code fromElement} and
159.197 + * {@code toElement} are equal, the returned set is empty unless {@code
159.198 + * fromInclusive} and {@code toInclusive} are both true. The returned set
159.199 + * is backed by this set, so changes in the returned set are reflected in
159.200 + * this set, and vice-versa. The returned set supports all optional set
159.201 + * operations that this set supports.
159.202 + *
159.203 + * <p>The returned set will throw an {@code IllegalArgumentException}
159.204 + * on an attempt to insert an element outside its range.
159.205 + *
159.206 + * @param fromElement low endpoint of the returned set
159.207 + * @param fromInclusive {@code true} if the low endpoint
159.208 + * is to be included in the returned view
159.209 + * @param toElement high endpoint of the returned set
159.210 + * @param toInclusive {@code true} if the high endpoint
159.211 + * is to be included in the returned view
159.212 + * @return a view of the portion of this set whose elements range from
159.213 + * {@code fromElement}, inclusive, to {@code toElement}, exclusive
159.214 + * @throws ClassCastException if {@code fromElement} and
159.215 + * {@code toElement} cannot be compared to one another using this
159.216 + * set's comparator (or, if the set has no comparator, using
159.217 + * natural ordering). Implementations may, but are not required
159.218 + * to, throw this exception if {@code fromElement} or
159.219 + * {@code toElement} cannot be compared to elements currently in
159.220 + * the set.
159.221 + * @throws NullPointerException if {@code fromElement} or
159.222 + * {@code toElement} is null and this set does
159.223 + * not permit null elements
159.224 + * @throws IllegalArgumentException if {@code fromElement} is
159.225 + * greater than {@code toElement}; or if this set itself
159.226 + * has a restricted range, and {@code fromElement} or
159.227 + * {@code toElement} lies outside the bounds of the range.
159.228 + */
159.229 + NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
159.230 + E toElement, boolean toInclusive);
159.231 +
159.232 + /**
159.233 + * Returns a view of the portion of this set whose elements are less than
159.234 + * (or equal to, if {@code inclusive} is true) {@code toElement}. The
159.235 + * returned set is backed by this set, so changes in the returned set are
159.236 + * reflected in this set, and vice-versa. The returned set supports all
159.237 + * optional set operations that this set supports.
159.238 + *
159.239 + * <p>The returned set will throw an {@code IllegalArgumentException}
159.240 + * on an attempt to insert an element outside its range.
159.241 + *
159.242 + * @param toElement high endpoint of the returned set
159.243 + * @param inclusive {@code true} if the high endpoint
159.244 + * is to be included in the returned view
159.245 + * @return a view of the portion of this set whose elements are less than
159.246 + * (or equal to, if {@code inclusive} is true) {@code toElement}
159.247 + * @throws ClassCastException if {@code toElement} is not compatible
159.248 + * with this set's comparator (or, if the set has no comparator,
159.249 + * if {@code toElement} does not implement {@link Comparable}).
159.250 + * Implementations may, but are not required to, throw this
159.251 + * exception if {@code toElement} cannot be compared to elements
159.252 + * currently in the set.
159.253 + * @throws NullPointerException if {@code toElement} is null and
159.254 + * this set does not permit null elements
159.255 + * @throws IllegalArgumentException if this set itself has a
159.256 + * restricted range, and {@code toElement} lies outside the
159.257 + * bounds of the range
159.258 + */
159.259 + NavigableSet<E> headSet(E toElement, boolean inclusive);
159.260 +
159.261 + /**
159.262 + * Returns a view of the portion of this set whose elements are greater
159.263 + * than (or equal to, if {@code inclusive} is true) {@code fromElement}.
159.264 + * The returned set is backed by this set, so changes in the returned set
159.265 + * are reflected in this set, and vice-versa. The returned set supports
159.266 + * all optional set operations that this set supports.
159.267 + *
159.268 + * <p>The returned set will throw an {@code IllegalArgumentException}
159.269 + * on an attempt to insert an element outside its range.
159.270 + *
159.271 + * @param fromElement low endpoint of the returned set
159.272 + * @param inclusive {@code true} if the low endpoint
159.273 + * is to be included in the returned view
159.274 + * @return a view of the portion of this set whose elements are greater
159.275 + * than or equal to {@code fromElement}
159.276 + * @throws ClassCastException if {@code fromElement} is not compatible
159.277 + * with this set's comparator (or, if the set has no comparator,
159.278 + * if {@code fromElement} does not implement {@link Comparable}).
159.279 + * Implementations may, but are not required to, throw this
159.280 + * exception if {@code fromElement} cannot be compared to elements
159.281 + * currently in the set.
159.282 + * @throws NullPointerException if {@code fromElement} is null
159.283 + * and this set does not permit null elements
159.284 + * @throws IllegalArgumentException if this set itself has a
159.285 + * restricted range, and {@code fromElement} lies outside the
159.286 + * bounds of the range
159.287 + */
159.288 + NavigableSet<E> tailSet(E fromElement, boolean inclusive);
159.289 +
159.290 + /**
159.291 + * {@inheritDoc}
159.292 + *
159.293 + * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}.
159.294 + *
159.295 + * @throws ClassCastException {@inheritDoc}
159.296 + * @throws NullPointerException {@inheritDoc}
159.297 + * @throws IllegalArgumentException {@inheritDoc}
159.298 + */
159.299 + SortedSet<E> subSet(E fromElement, E toElement);
159.300 +
159.301 + /**
159.302 + * {@inheritDoc}
159.303 + *
159.304 + * <p>Equivalent to {@code headSet(toElement, false)}.
159.305 + *
159.306 + * @throws ClassCastException {@inheritDoc}
159.307 + * @throws NullPointerException {@inheritDoc}
159.308 + * @throws IllegalArgumentException {@inheritDoc}
159.309 +na */
159.310 + SortedSet<E> headSet(E toElement);
159.311 +
159.312 + /**
159.313 + * {@inheritDoc}
159.314 + *
159.315 + * <p>Equivalent to {@code tailSet(fromElement, true)}.
159.316 + *
159.317 + * @throws ClassCastException {@inheritDoc}
159.318 + * @throws NullPointerException {@inheritDoc}
159.319 + * @throws IllegalArgumentException {@inheritDoc}
159.320 + */
159.321 + SortedSet<E> tailSet(E fromElement);
159.322 +}
160.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
160.2 +++ b/rt/emul/compact/src/main/java/java/util/RegularEnumSet.java Mon Oct 07 14:20:58 2013 +0200
160.3 @@ -0,0 +1,303 @@
160.4 +/*
160.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
160.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
160.7 + *
160.8 + * This code is free software; you can redistribute it and/or modify it
160.9 + * under the terms of the GNU General Public License version 2 only, as
160.10 + * published by the Free Software Foundation. Oracle designates this
160.11 + * particular file as subject to the "Classpath" exception as provided
160.12 + * by Oracle in the LICENSE file that accompanied this code.
160.13 + *
160.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
160.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
160.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
160.17 + * version 2 for more details (a copy is included in the LICENSE file that
160.18 + * accompanied this code).
160.19 + *
160.20 + * You should have received a copy of the GNU General Public License version
160.21 + * 2 along with this work; if not, write to the Free Software Foundation,
160.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
160.23 + *
160.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
160.25 + * or visit www.oracle.com if you need additional information or have any
160.26 + * questions.
160.27 + */
160.28 +
160.29 +package java.util;
160.30 +
160.31 +/**
160.32 + * Private implementation class for EnumSet, for "regular sized" enum types
160.33 + * (i.e., those with 64 or fewer enum constants).
160.34 + *
160.35 + * @author Josh Bloch
160.36 + * @since 1.5
160.37 + * @serial exclude
160.38 + */
160.39 +class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
160.40 + private static final long serialVersionUID = 3411599620347842686L;
160.41 + /**
160.42 + * Bit vector representation of this set. The 2^k bit indicates the
160.43 + * presence of universe[k] in this set.
160.44 + */
160.45 + private long elements = 0L;
160.46 +
160.47 + RegularEnumSet(Class<E>elementType, Enum[] universe) {
160.48 + super(elementType, universe);
160.49 + }
160.50 +
160.51 + void addRange(E from, E to) {
160.52 + elements = (-1L >>> (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
160.53 + }
160.54 +
160.55 + void addAll() {
160.56 + if (universe.length != 0)
160.57 + elements = -1L >>> -universe.length;
160.58 + }
160.59 +
160.60 + void complement() {
160.61 + if (universe.length != 0) {
160.62 + elements = ~elements;
160.63 + elements &= -1L >>> -universe.length; // Mask unused bits
160.64 + }
160.65 + }
160.66 +
160.67 + /**
160.68 + * Returns an iterator over the elements contained in this set. The
160.69 + * iterator traverses the elements in their <i>natural order</i> (which is
160.70 + * the order in which the enum constants are declared). The returned
160.71 + * Iterator is a "snapshot" iterator that will never throw {@link
160.72 + * ConcurrentModificationException}; the elements are traversed as they
160.73 + * existed when this call was invoked.
160.74 + *
160.75 + * @return an iterator over the elements contained in this set
160.76 + */
160.77 + public Iterator<E> iterator() {
160.78 + return new EnumSetIterator<>();
160.79 + }
160.80 +
160.81 + private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
160.82 + /**
160.83 + * A bit vector representing the elements in the set not yet
160.84 + * returned by this iterator.
160.85 + */
160.86 + long unseen;
160.87 +
160.88 + /**
160.89 + * The bit representing the last element returned by this iterator
160.90 + * but not removed, or zero if no such element exists.
160.91 + */
160.92 + long lastReturned = 0;
160.93 +
160.94 + EnumSetIterator() {
160.95 + unseen = elements;
160.96 + }
160.97 +
160.98 + public boolean hasNext() {
160.99 + return unseen != 0;
160.100 + }
160.101 +
160.102 + public E next() {
160.103 + if (unseen == 0)
160.104 + throw new NoSuchElementException();
160.105 + lastReturned = unseen & -unseen;
160.106 + unseen -= lastReturned;
160.107 + return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
160.108 + }
160.109 +
160.110 + public void remove() {
160.111 + if (lastReturned == 0)
160.112 + throw new IllegalStateException();
160.113 + elements &= ~lastReturned;
160.114 + lastReturned = 0;
160.115 + }
160.116 + }
160.117 +
160.118 + /**
160.119 + * Returns the number of elements in this set.
160.120 + *
160.121 + * @return the number of elements in this set
160.122 + */
160.123 + public int size() {
160.124 + return Long.bitCount(elements);
160.125 + }
160.126 +
160.127 + /**
160.128 + * Returns <tt>true</tt> if this set contains no elements.
160.129 + *
160.130 + * @return <tt>true</tt> if this set contains no elements
160.131 + */
160.132 + public boolean isEmpty() {
160.133 + return elements == 0;
160.134 + }
160.135 +
160.136 + /**
160.137 + * Returns <tt>true</tt> if this set contains the specified element.
160.138 + *
160.139 + * @param e element to be checked for containment in this collection
160.140 + * @return <tt>true</tt> if this set contains the specified element
160.141 + */
160.142 + public boolean contains(Object e) {
160.143 + if (e == null)
160.144 + return false;
160.145 + Class eClass = e.getClass();
160.146 + if (eClass != elementType && eClass.getSuperclass() != elementType)
160.147 + return false;
160.148 +
160.149 + return (elements & (1L << ((Enum)e).ordinal())) != 0;
160.150 + }
160.151 +
160.152 + // Modification Operations
160.153 +
160.154 + /**
160.155 + * Adds the specified element to this set if it is not already present.
160.156 + *
160.157 + * @param e element to be added to this set
160.158 + * @return <tt>true</tt> if the set changed as a result of the call
160.159 + *
160.160 + * @throws NullPointerException if <tt>e</tt> is null
160.161 + */
160.162 + public boolean add(E e) {
160.163 + typeCheck(e);
160.164 +
160.165 + long oldElements = elements;
160.166 + elements |= (1L << ((Enum)e).ordinal());
160.167 + return elements != oldElements;
160.168 + }
160.169 +
160.170 + /**
160.171 + * Removes the specified element from this set if it is present.
160.172 + *
160.173 + * @param e element to be removed from this set, if present
160.174 + * @return <tt>true</tt> if the set contained the specified element
160.175 + */
160.176 + public boolean remove(Object e) {
160.177 + if (e == null)
160.178 + return false;
160.179 + Class eClass = e.getClass();
160.180 + if (eClass != elementType && eClass.getSuperclass() != elementType)
160.181 + return false;
160.182 +
160.183 + long oldElements = elements;
160.184 + elements &= ~(1L << ((Enum)e).ordinal());
160.185 + return elements != oldElements;
160.186 + }
160.187 +
160.188 + // Bulk Operations
160.189 +
160.190 + /**
160.191 + * Returns <tt>true</tt> if this set contains all of the elements
160.192 + * in the specified collection.
160.193 + *
160.194 + * @param c collection to be checked for containment in this set
160.195 + * @return <tt>true</tt> if this set contains all of the elements
160.196 + * in the specified collection
160.197 + * @throws NullPointerException if the specified collection is null
160.198 + */
160.199 + public boolean containsAll(Collection<?> c) {
160.200 + if (!(c instanceof RegularEnumSet))
160.201 + return super.containsAll(c);
160.202 +
160.203 + RegularEnumSet es = (RegularEnumSet)c;
160.204 + if (es.elementType != elementType)
160.205 + return es.isEmpty();
160.206 +
160.207 + return (es.elements & ~elements) == 0;
160.208 + }
160.209 +
160.210 + /**
160.211 + * Adds all of the elements in the specified collection to this set.
160.212 + *
160.213 + * @param c collection whose elements are to be added to this set
160.214 + * @return <tt>true</tt> if this set changed as a result of the call
160.215 + * @throws NullPointerException if the specified collection or any
160.216 + * of its elements are null
160.217 + */
160.218 + public boolean addAll(Collection<? extends E> c) {
160.219 + if (!(c instanceof RegularEnumSet))
160.220 + return super.addAll(c);
160.221 +
160.222 + RegularEnumSet es = (RegularEnumSet)c;
160.223 + if (es.elementType != elementType) {
160.224 + if (es.isEmpty())
160.225 + return false;
160.226 + else
160.227 + throw new ClassCastException(
160.228 + es.elementType + " != " + elementType);
160.229 + }
160.230 +
160.231 + long oldElements = elements;
160.232 + elements |= es.elements;
160.233 + return elements != oldElements;
160.234 + }
160.235 +
160.236 + /**
160.237 + * Removes from this set all of its elements that are contained in
160.238 + * the specified collection.
160.239 + *
160.240 + * @param c elements to be removed from this set
160.241 + * @return <tt>true</tt> if this set changed as a result of the call
160.242 + * @throws NullPointerException if the specified collection is null
160.243 + */
160.244 + public boolean removeAll(Collection<?> c) {
160.245 + if (!(c instanceof RegularEnumSet))
160.246 + return super.removeAll(c);
160.247 +
160.248 + RegularEnumSet es = (RegularEnumSet)c;
160.249 + if (es.elementType != elementType)
160.250 + return false;
160.251 +
160.252 + long oldElements = elements;
160.253 + elements &= ~es.elements;
160.254 + return elements != oldElements;
160.255 + }
160.256 +
160.257 + /**
160.258 + * Retains only the elements in this set that are contained in the
160.259 + * specified collection.
160.260 + *
160.261 + * @param c elements to be retained in this set
160.262 + * @return <tt>true</tt> if this set changed as a result of the call
160.263 + * @throws NullPointerException if the specified collection is null
160.264 + */
160.265 + public boolean retainAll(Collection<?> c) {
160.266 + if (!(c instanceof RegularEnumSet))
160.267 + return super.retainAll(c);
160.268 +
160.269 + RegularEnumSet<?> es = (RegularEnumSet<?>)c;
160.270 + if (es.elementType != elementType) {
160.271 + boolean changed = (elements != 0);
160.272 + elements = 0;
160.273 + return changed;
160.274 + }
160.275 +
160.276 + long oldElements = elements;
160.277 + elements &= es.elements;
160.278 + return elements != oldElements;
160.279 + }
160.280 +
160.281 + /**
160.282 + * Removes all of the elements from this set.
160.283 + */
160.284 + public void clear() {
160.285 + elements = 0;
160.286 + }
160.287 +
160.288 + /**
160.289 + * Compares the specified object with this set for equality. Returns
160.290 + * <tt>true</tt> if the given object is also a set, the two sets have
160.291 + * the same size, and every member of the given set is contained in
160.292 + * this set.
160.293 + *
160.294 + * @param e object to be compared for equality with this set
160.295 + * @return <tt>true</tt> if the specified object is equal to this set
160.296 + */
160.297 + public boolean equals(Object o) {
160.298 + if (!(o instanceof RegularEnumSet))
160.299 + return super.equals(o);
160.300 +
160.301 + RegularEnumSet es = (RegularEnumSet)o;
160.302 + if (es.elementType != elementType)
160.303 + return elements == 0 && es.elements == 0;
160.304 + return es.elements == elements;
160.305 + }
160.306 +}
161.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
161.2 +++ b/rt/emul/compact/src/main/java/java/util/TreeMap.java Mon Oct 07 14:20:58 2013 +0200
161.3 @@ -0,0 +1,2442 @@
161.4 +/*
161.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
161.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
161.7 + *
161.8 + * This code is free software; you can redistribute it and/or modify it
161.9 + * under the terms of the GNU General Public License version 2 only, as
161.10 + * published by the Free Software Foundation. Oracle designates this
161.11 + * particular file as subject to the "Classpath" exception as provided
161.12 + * by Oracle in the LICENSE file that accompanied this code.
161.13 + *
161.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
161.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
161.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
161.17 + * version 2 for more details (a copy is included in the LICENSE file that
161.18 + * accompanied this code).
161.19 + *
161.20 + * You should have received a copy of the GNU General Public License version
161.21 + * 2 along with this work; if not, write to the Free Software Foundation,
161.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
161.23 + *
161.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
161.25 + * or visit www.oracle.com if you need additional information or have any
161.26 + * questions.
161.27 + */
161.28 +
161.29 +package java.util;
161.30 +
161.31 +/**
161.32 + * A Red-Black tree based {@link NavigableMap} implementation.
161.33 + * The map is sorted according to the {@linkplain Comparable natural
161.34 + * ordering} of its keys, or by a {@link Comparator} provided at map
161.35 + * creation time, depending on which constructor is used.
161.36 + *
161.37 + * <p>This implementation provides guaranteed log(n) time cost for the
161.38 + * {@code containsKey}, {@code get}, {@code put} and {@code remove}
161.39 + * operations. Algorithms are adaptations of those in Cormen, Leiserson, and
161.40 + * Rivest's <em>Introduction to Algorithms</em>.
161.41 + *
161.42 + * <p>Note that the ordering maintained by a tree map, like any sorted map, and
161.43 + * whether or not an explicit comparator is provided, must be <em>consistent
161.44 + * with {@code equals}</em> if this sorted map is to correctly implement the
161.45 + * {@code Map} interface. (See {@code Comparable} or {@code Comparator} for a
161.46 + * precise definition of <em>consistent with equals</em>.) This is so because
161.47 + * the {@code Map} interface is defined in terms of the {@code equals}
161.48 + * operation, but a sorted map performs all key comparisons using its {@code
161.49 + * compareTo} (or {@code compare}) method, so two keys that are deemed equal by
161.50 + * this method are, from the standpoint of the sorted map, equal. The behavior
161.51 + * of a sorted map <em>is</em> well-defined even if its ordering is
161.52 + * inconsistent with {@code equals}; it just fails to obey the general contract
161.53 + * of the {@code Map} interface.
161.54 + *
161.55 + * <p><strong>Note that this implementation is not synchronized.</strong>
161.56 + * If multiple threads access a map concurrently, and at least one of the
161.57 + * threads modifies the map structurally, it <em>must</em> be synchronized
161.58 + * externally. (A structural modification is any operation that adds or
161.59 + * deletes one or more mappings; merely changing the value associated
161.60 + * with an existing key is not a structural modification.) This is
161.61 + * typically accomplished by synchronizing on some object that naturally
161.62 + * encapsulates the map.
161.63 + * If no such object exists, the map should be "wrapped" using the
161.64 + * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap}
161.65 + * method. This is best done at creation time, to prevent accidental
161.66 + * unsynchronized access to the map: <pre>
161.67 + * SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</pre>
161.68 + *
161.69 + * <p>The iterators returned by the {@code iterator} method of the collections
161.70 + * returned by all of this class's "collection view methods" are
161.71 + * <em>fail-fast</em>: if the map is structurally modified at any time after
161.72 + * the iterator is created, in any way except through the iterator's own
161.73 + * {@code remove} method, the iterator will throw a {@link
161.74 + * ConcurrentModificationException}. Thus, in the face of concurrent
161.75 + * modification, the iterator fails quickly and cleanly, rather than risking
161.76 + * arbitrary, non-deterministic behavior at an undetermined time in the future.
161.77 + *
161.78 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
161.79 + * as it is, generally speaking, impossible to make any hard guarantees in the
161.80 + * presence of unsynchronized concurrent modification. Fail-fast iterators
161.81 + * throw {@code ConcurrentModificationException} on a best-effort basis.
161.82 + * Therefore, it would be wrong to write a program that depended on this
161.83 + * exception for its correctness: <em>the fail-fast behavior of iterators
161.84 + * should be used only to detect bugs.</em>
161.85 + *
161.86 + * <p>All {@code Map.Entry} pairs returned by methods in this class
161.87 + * and its views represent snapshots of mappings at the time they were
161.88 + * produced. They do <strong>not</strong> support the {@code Entry.setValue}
161.89 + * method. (Note however that it is possible to change mappings in the
161.90 + * associated map using {@code put}.)
161.91 + *
161.92 + * <p>This class is a member of the
161.93 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
161.94 + * Java Collections Framework</a>.
161.95 + *
161.96 + * @param <K> the type of keys maintained by this map
161.97 + * @param <V> the type of mapped values
161.98 + *
161.99 + * @author Josh Bloch and Doug Lea
161.100 + * @see Map
161.101 + * @see HashMap
161.102 + * @see Hashtable
161.103 + * @see Comparable
161.104 + * @see Comparator
161.105 + * @see Collection
161.106 + * @since 1.2
161.107 + */
161.108 +
161.109 +public class TreeMap<K,V>
161.110 + extends AbstractMap<K,V>
161.111 + implements NavigableMap<K,V>, Cloneable, java.io.Serializable
161.112 +{
161.113 + /**
161.114 + * The comparator used to maintain order in this tree map, or
161.115 + * null if it uses the natural ordering of its keys.
161.116 + *
161.117 + * @serial
161.118 + */
161.119 + private final Comparator<? super K> comparator;
161.120 +
161.121 + private transient Entry<K,V> root = null;
161.122 +
161.123 + /**
161.124 + * The number of entries in the tree
161.125 + */
161.126 + private transient int size = 0;
161.127 +
161.128 + /**
161.129 + * The number of structural modifications to the tree.
161.130 + */
161.131 + private transient int modCount = 0;
161.132 +
161.133 + /**
161.134 + * Constructs a new, empty tree map, using the natural ordering of its
161.135 + * keys. All keys inserted into the map must implement the {@link
161.136 + * Comparable} interface. Furthermore, all such keys must be
161.137 + * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
161.138 + * a {@code ClassCastException} for any keys {@code k1} and
161.139 + * {@code k2} in the map. If the user attempts to put a key into the
161.140 + * map that violates this constraint (for example, the user attempts to
161.141 + * put a string key into a map whose keys are integers), the
161.142 + * {@code put(Object key, Object value)} call will throw a
161.143 + * {@code ClassCastException}.
161.144 + */
161.145 + public TreeMap() {
161.146 + comparator = null;
161.147 + }
161.148 +
161.149 + /**
161.150 + * Constructs a new, empty tree map, ordered according to the given
161.151 + * comparator. All keys inserted into the map must be <em>mutually
161.152 + * comparable</em> by the given comparator: {@code comparator.compare(k1,
161.153 + * k2)} must not throw a {@code ClassCastException} for any keys
161.154 + * {@code k1} and {@code k2} in the map. If the user attempts to put
161.155 + * a key into the map that violates this constraint, the {@code put(Object
161.156 + * key, Object value)} call will throw a
161.157 + * {@code ClassCastException}.
161.158 + *
161.159 + * @param comparator the comparator that will be used to order this map.
161.160 + * If {@code null}, the {@linkplain Comparable natural
161.161 + * ordering} of the keys will be used.
161.162 + */
161.163 + public TreeMap(Comparator<? super K> comparator) {
161.164 + this.comparator = comparator;
161.165 + }
161.166 +
161.167 + /**
161.168 + * Constructs a new tree map containing the same mappings as the given
161.169 + * map, ordered according to the <em>natural ordering</em> of its keys.
161.170 + * All keys inserted into the new map must implement the {@link
161.171 + * Comparable} interface. Furthermore, all such keys must be
161.172 + * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
161.173 + * a {@code ClassCastException} for any keys {@code k1} and
161.174 + * {@code k2} in the map. This method runs in n*log(n) time.
161.175 + *
161.176 + * @param m the map whose mappings are to be placed in this map
161.177 + * @throws ClassCastException if the keys in m are not {@link Comparable},
161.178 + * or are not mutually comparable
161.179 + * @throws NullPointerException if the specified map is null
161.180 + */
161.181 + public TreeMap(Map<? extends K, ? extends V> m) {
161.182 + comparator = null;
161.183 + putAll(m);
161.184 + }
161.185 +
161.186 + /**
161.187 + * Constructs a new tree map containing the same mappings and
161.188 + * using the same ordering as the specified sorted map. This
161.189 + * method runs in linear time.
161.190 + *
161.191 + * @param m the sorted map whose mappings are to be placed in this map,
161.192 + * and whose comparator is to be used to sort this map
161.193 + * @throws NullPointerException if the specified map is null
161.194 + */
161.195 + public TreeMap(SortedMap<K, ? extends V> m) {
161.196 + comparator = m.comparator();
161.197 + try {
161.198 + buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
161.199 + } catch (java.io.IOException cannotHappen) {
161.200 + } catch (ClassNotFoundException cannotHappen) {
161.201 + }
161.202 + }
161.203 +
161.204 +
161.205 + // Query Operations
161.206 +
161.207 + /**
161.208 + * Returns the number of key-value mappings in this map.
161.209 + *
161.210 + * @return the number of key-value mappings in this map
161.211 + */
161.212 + public int size() {
161.213 + return size;
161.214 + }
161.215 +
161.216 + /**
161.217 + * Returns {@code true} if this map contains a mapping for the specified
161.218 + * key.
161.219 + *
161.220 + * @param key key whose presence in this map is to be tested
161.221 + * @return {@code true} if this map contains a mapping for the
161.222 + * specified key
161.223 + * @throws ClassCastException if the specified key cannot be compared
161.224 + * with the keys currently in the map
161.225 + * @throws NullPointerException if the specified key is null
161.226 + * and this map uses natural ordering, or its comparator
161.227 + * does not permit null keys
161.228 + */
161.229 + public boolean containsKey(Object key) {
161.230 + return getEntry(key) != null;
161.231 + }
161.232 +
161.233 + /**
161.234 + * Returns {@code true} if this map maps one or more keys to the
161.235 + * specified value. More formally, returns {@code true} if and only if
161.236 + * this map contains at least one mapping to a value {@code v} such
161.237 + * that {@code (value==null ? v==null : value.equals(v))}. This
161.238 + * operation will probably require time linear in the map size for
161.239 + * most implementations.
161.240 + *
161.241 + * @param value value whose presence in this map is to be tested
161.242 + * @return {@code true} if a mapping to {@code value} exists;
161.243 + * {@code false} otherwise
161.244 + * @since 1.2
161.245 + */
161.246 + public boolean containsValue(Object value) {
161.247 + for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
161.248 + if (valEquals(value, e.value))
161.249 + return true;
161.250 + return false;
161.251 + }
161.252 +
161.253 + /**
161.254 + * Returns the value to which the specified key is mapped,
161.255 + * or {@code null} if this map contains no mapping for the key.
161.256 + *
161.257 + * <p>More formally, if this map contains a mapping from a key
161.258 + * {@code k} to a value {@code v} such that {@code key} compares
161.259 + * equal to {@code k} according to the map's ordering, then this
161.260 + * method returns {@code v}; otherwise it returns {@code null}.
161.261 + * (There can be at most one such mapping.)
161.262 + *
161.263 + * <p>A return value of {@code null} does not <em>necessarily</em>
161.264 + * indicate that the map contains no mapping for the key; it's also
161.265 + * possible that the map explicitly maps the key to {@code null}.
161.266 + * The {@link #containsKey containsKey} operation may be used to
161.267 + * distinguish these two cases.
161.268 + *
161.269 + * @throws ClassCastException if the specified key cannot be compared
161.270 + * with the keys currently in the map
161.271 + * @throws NullPointerException if the specified key is null
161.272 + * and this map uses natural ordering, or its comparator
161.273 + * does not permit null keys
161.274 + */
161.275 + public V get(Object key) {
161.276 + Entry<K,V> p = getEntry(key);
161.277 + return (p==null ? null : p.value);
161.278 + }
161.279 +
161.280 + public Comparator<? super K> comparator() {
161.281 + return comparator;
161.282 + }
161.283 +
161.284 + /**
161.285 + * @throws NoSuchElementException {@inheritDoc}
161.286 + */
161.287 + public K firstKey() {
161.288 + return key(getFirstEntry());
161.289 + }
161.290 +
161.291 + /**
161.292 + * @throws NoSuchElementException {@inheritDoc}
161.293 + */
161.294 + public K lastKey() {
161.295 + return key(getLastEntry());
161.296 + }
161.297 +
161.298 + /**
161.299 + * Copies all of the mappings from the specified map to this map.
161.300 + * These mappings replace any mappings that this map had for any
161.301 + * of the keys currently in the specified map.
161.302 + *
161.303 + * @param map mappings to be stored in this map
161.304 + * @throws ClassCastException if the class of a key or value in
161.305 + * the specified map prevents it from being stored in this map
161.306 + * @throws NullPointerException if the specified map is null or
161.307 + * the specified map contains a null key and this map does not
161.308 + * permit null keys
161.309 + */
161.310 + public void putAll(Map<? extends K, ? extends V> map) {
161.311 + int mapSize = map.size();
161.312 + if (size==0 && mapSize!=0 && map instanceof SortedMap) {
161.313 + Comparator c = ((SortedMap)map).comparator();
161.314 + if (c == comparator || (c != null && c.equals(comparator))) {
161.315 + ++modCount;
161.316 + try {
161.317 + buildFromSorted(mapSize, map.entrySet().iterator(),
161.318 + null, null);
161.319 + } catch (java.io.IOException cannotHappen) {
161.320 + } catch (ClassNotFoundException cannotHappen) {
161.321 + }
161.322 + return;
161.323 + }
161.324 + }
161.325 + super.putAll(map);
161.326 + }
161.327 +
161.328 + /**
161.329 + * Returns this map's entry for the given key, or {@code null} if the map
161.330 + * does not contain an entry for the key.
161.331 + *
161.332 + * @return this map's entry for the given key, or {@code null} if the map
161.333 + * does not contain an entry for the key
161.334 + * @throws ClassCastException if the specified key cannot be compared
161.335 + * with the keys currently in the map
161.336 + * @throws NullPointerException if the specified key is null
161.337 + * and this map uses natural ordering, or its comparator
161.338 + * does not permit null keys
161.339 + */
161.340 + final Entry<K,V> getEntry(Object key) {
161.341 + // Offload comparator-based version for sake of performance
161.342 + if (comparator != null)
161.343 + return getEntryUsingComparator(key);
161.344 + if (key == null)
161.345 + throw new NullPointerException();
161.346 + Comparable<? super K> k = (Comparable<? super K>) key;
161.347 + Entry<K,V> p = root;
161.348 + while (p != null) {
161.349 + int cmp = k.compareTo(p.key);
161.350 + if (cmp < 0)
161.351 + p = p.left;
161.352 + else if (cmp > 0)
161.353 + p = p.right;
161.354 + else
161.355 + return p;
161.356 + }
161.357 + return null;
161.358 + }
161.359 +
161.360 + /**
161.361 + * Version of getEntry using comparator. Split off from getEntry
161.362 + * for performance. (This is not worth doing for most methods,
161.363 + * that are less dependent on comparator performance, but is
161.364 + * worthwhile here.)
161.365 + */
161.366 + final Entry<K,V> getEntryUsingComparator(Object key) {
161.367 + K k = (K) key;
161.368 + Comparator<? super K> cpr = comparator;
161.369 + if (cpr != null) {
161.370 + Entry<K,V> p = root;
161.371 + while (p != null) {
161.372 + int cmp = cpr.compare(k, p.key);
161.373 + if (cmp < 0)
161.374 + p = p.left;
161.375 + else if (cmp > 0)
161.376 + p = p.right;
161.377 + else
161.378 + return p;
161.379 + }
161.380 + }
161.381 + return null;
161.382 + }
161.383 +
161.384 + /**
161.385 + * Gets the entry corresponding to the specified key; if no such entry
161.386 + * exists, returns the entry for the least key greater than the specified
161.387 + * key; if no such entry exists (i.e., the greatest key in the Tree is less
161.388 + * than the specified key), returns {@code null}.
161.389 + */
161.390 + final Entry<K,V> getCeilingEntry(K key) {
161.391 + Entry<K,V> p = root;
161.392 + while (p != null) {
161.393 + int cmp = compare(key, p.key);
161.394 + if (cmp < 0) {
161.395 + if (p.left != null)
161.396 + p = p.left;
161.397 + else
161.398 + return p;
161.399 + } else if (cmp > 0) {
161.400 + if (p.right != null) {
161.401 + p = p.right;
161.402 + } else {
161.403 + Entry<K,V> parent = p.parent;
161.404 + Entry<K,V> ch = p;
161.405 + while (parent != null && ch == parent.right) {
161.406 + ch = parent;
161.407 + parent = parent.parent;
161.408 + }
161.409 + return parent;
161.410 + }
161.411 + } else
161.412 + return p;
161.413 + }
161.414 + return null;
161.415 + }
161.416 +
161.417 + /**
161.418 + * Gets the entry corresponding to the specified key; if no such entry
161.419 + * exists, returns the entry for the greatest key less than the specified
161.420 + * key; if no such entry exists, returns {@code null}.
161.421 + */
161.422 + final Entry<K,V> getFloorEntry(K key) {
161.423 + Entry<K,V> p = root;
161.424 + while (p != null) {
161.425 + int cmp = compare(key, p.key);
161.426 + if (cmp > 0) {
161.427 + if (p.right != null)
161.428 + p = p.right;
161.429 + else
161.430 + return p;
161.431 + } else if (cmp < 0) {
161.432 + if (p.left != null) {
161.433 + p = p.left;
161.434 + } else {
161.435 + Entry<K,V> parent = p.parent;
161.436 + Entry<K,V> ch = p;
161.437 + while (parent != null && ch == parent.left) {
161.438 + ch = parent;
161.439 + parent = parent.parent;
161.440 + }
161.441 + return parent;
161.442 + }
161.443 + } else
161.444 + return p;
161.445 +
161.446 + }
161.447 + return null;
161.448 + }
161.449 +
161.450 + /**
161.451 + * Gets the entry for the least key greater than the specified
161.452 + * key; if no such entry exists, returns the entry for the least
161.453 + * key greater than the specified key; if no such entry exists
161.454 + * returns {@code null}.
161.455 + */
161.456 + final Entry<K,V> getHigherEntry(K key) {
161.457 + Entry<K,V> p = root;
161.458 + while (p != null) {
161.459 + int cmp = compare(key, p.key);
161.460 + if (cmp < 0) {
161.461 + if (p.left != null)
161.462 + p = p.left;
161.463 + else
161.464 + return p;
161.465 + } else {
161.466 + if (p.right != null) {
161.467 + p = p.right;
161.468 + } else {
161.469 + Entry<K,V> parent = p.parent;
161.470 + Entry<K,V> ch = p;
161.471 + while (parent != null && ch == parent.right) {
161.472 + ch = parent;
161.473 + parent = parent.parent;
161.474 + }
161.475 + return parent;
161.476 + }
161.477 + }
161.478 + }
161.479 + return null;
161.480 + }
161.481 +
161.482 + /**
161.483 + * Returns the entry for the greatest key less than the specified key; if
161.484 + * no such entry exists (i.e., the least key in the Tree is greater than
161.485 + * the specified key), returns {@code null}.
161.486 + */
161.487 + final Entry<K,V> getLowerEntry(K key) {
161.488 + Entry<K,V> p = root;
161.489 + while (p != null) {
161.490 + int cmp = compare(key, p.key);
161.491 + if (cmp > 0) {
161.492 + if (p.right != null)
161.493 + p = p.right;
161.494 + else
161.495 + return p;
161.496 + } else {
161.497 + if (p.left != null) {
161.498 + p = p.left;
161.499 + } else {
161.500 + Entry<K,V> parent = p.parent;
161.501 + Entry<K,V> ch = p;
161.502 + while (parent != null && ch == parent.left) {
161.503 + ch = parent;
161.504 + parent = parent.parent;
161.505 + }
161.506 + return parent;
161.507 + }
161.508 + }
161.509 + }
161.510 + return null;
161.511 + }
161.512 +
161.513 + /**
161.514 + * Associates the specified value with the specified key in this map.
161.515 + * If the map previously contained a mapping for the key, the old
161.516 + * value is replaced.
161.517 + *
161.518 + * @param key key with which the specified value is to be associated
161.519 + * @param value value to be associated with the specified key
161.520 + *
161.521 + * @return the previous value associated with {@code key}, or
161.522 + * {@code null} if there was no mapping for {@code key}.
161.523 + * (A {@code null} return can also indicate that the map
161.524 + * previously associated {@code null} with {@code key}.)
161.525 + * @throws ClassCastException if the specified key cannot be compared
161.526 + * with the keys currently in the map
161.527 + * @throws NullPointerException if the specified key is null
161.528 + * and this map uses natural ordering, or its comparator
161.529 + * does not permit null keys
161.530 + */
161.531 + public V put(K key, V value) {
161.532 + Entry<K,V> t = root;
161.533 + if (t == null) {
161.534 + compare(key, key); // type (and possibly null) check
161.535 +
161.536 + root = new Entry<>(key, value, null);
161.537 + size = 1;
161.538 + modCount++;
161.539 + return null;
161.540 + }
161.541 + int cmp;
161.542 + Entry<K,V> parent;
161.543 + // split comparator and comparable paths
161.544 + Comparator<? super K> cpr = comparator;
161.545 + if (cpr != null) {
161.546 + do {
161.547 + parent = t;
161.548 + cmp = cpr.compare(key, t.key);
161.549 + if (cmp < 0)
161.550 + t = t.left;
161.551 + else if (cmp > 0)
161.552 + t = t.right;
161.553 + else
161.554 + return t.setValue(value);
161.555 + } while (t != null);
161.556 + }
161.557 + else {
161.558 + if (key == null)
161.559 + throw new NullPointerException();
161.560 + Comparable<? super K> k = (Comparable<? super K>) key;
161.561 + do {
161.562 + parent = t;
161.563 + cmp = k.compareTo(t.key);
161.564 + if (cmp < 0)
161.565 + t = t.left;
161.566 + else if (cmp > 0)
161.567 + t = t.right;
161.568 + else
161.569 + return t.setValue(value);
161.570 + } while (t != null);
161.571 + }
161.572 + Entry<K,V> e = new Entry<>(key, value, parent);
161.573 + if (cmp < 0)
161.574 + parent.left = e;
161.575 + else
161.576 + parent.right = e;
161.577 + fixAfterInsertion(e);
161.578 + size++;
161.579 + modCount++;
161.580 + return null;
161.581 + }
161.582 +
161.583 + /**
161.584 + * Removes the mapping for this key from this TreeMap if present.
161.585 + *
161.586 + * @param key key for which mapping should be removed
161.587 + * @return the previous value associated with {@code key}, or
161.588 + * {@code null} if there was no mapping for {@code key}.
161.589 + * (A {@code null} return can also indicate that the map
161.590 + * previously associated {@code null} with {@code key}.)
161.591 + * @throws ClassCastException if the specified key cannot be compared
161.592 + * with the keys currently in the map
161.593 + * @throws NullPointerException if the specified key is null
161.594 + * and this map uses natural ordering, or its comparator
161.595 + * does not permit null keys
161.596 + */
161.597 + public V remove(Object key) {
161.598 + Entry<K,V> p = getEntry(key);
161.599 + if (p == null)
161.600 + return null;
161.601 +
161.602 + V oldValue = p.value;
161.603 + deleteEntry(p);
161.604 + return oldValue;
161.605 + }
161.606 +
161.607 + /**
161.608 + * Removes all of the mappings from this map.
161.609 + * The map will be empty after this call returns.
161.610 + */
161.611 + public void clear() {
161.612 + modCount++;
161.613 + size = 0;
161.614 + root = null;
161.615 + }
161.616 +
161.617 + /**
161.618 + * Returns a shallow copy of this {@code TreeMap} instance. (The keys and
161.619 + * values themselves are not cloned.)
161.620 + *
161.621 + * @return a shallow copy of this map
161.622 + */
161.623 + public Object clone() {
161.624 + TreeMap<K,V> clone = null;
161.625 + try {
161.626 + clone = (TreeMap<K,V>) super.clone();
161.627 + } catch (CloneNotSupportedException e) {
161.628 + throw new InternalError();
161.629 + }
161.630 +
161.631 + // Put clone into "virgin" state (except for comparator)
161.632 + clone.root = null;
161.633 + clone.size = 0;
161.634 + clone.modCount = 0;
161.635 + clone.entrySet = null;
161.636 + clone.navigableKeySet = null;
161.637 + clone.descendingMap = null;
161.638 +
161.639 + // Initialize clone with our mappings
161.640 + try {
161.641 + clone.buildFromSorted(size, entrySet().iterator(), null, null);
161.642 + } catch (java.io.IOException cannotHappen) {
161.643 + } catch (ClassNotFoundException cannotHappen) {
161.644 + }
161.645 +
161.646 + return clone;
161.647 + }
161.648 +
161.649 + // NavigableMap API methods
161.650 +
161.651 + /**
161.652 + * @since 1.6
161.653 + */
161.654 + public Map.Entry<K,V> firstEntry() {
161.655 + return exportEntry(getFirstEntry());
161.656 + }
161.657 +
161.658 + /**
161.659 + * @since 1.6
161.660 + */
161.661 + public Map.Entry<K,V> lastEntry() {
161.662 + return exportEntry(getLastEntry());
161.663 + }
161.664 +
161.665 + /**
161.666 + * @since 1.6
161.667 + */
161.668 + public Map.Entry<K,V> pollFirstEntry() {
161.669 + Entry<K,V> p = getFirstEntry();
161.670 + Map.Entry<K,V> result = exportEntry(p);
161.671 + if (p != null)
161.672 + deleteEntry(p);
161.673 + return result;
161.674 + }
161.675 +
161.676 + /**
161.677 + * @since 1.6
161.678 + */
161.679 + public Map.Entry<K,V> pollLastEntry() {
161.680 + Entry<K,V> p = getLastEntry();
161.681 + Map.Entry<K,V> result = exportEntry(p);
161.682 + if (p != null)
161.683 + deleteEntry(p);
161.684 + return result;
161.685 + }
161.686 +
161.687 + /**
161.688 + * @throws ClassCastException {@inheritDoc}
161.689 + * @throws NullPointerException if the specified key is null
161.690 + * and this map uses natural ordering, or its comparator
161.691 + * does not permit null keys
161.692 + * @since 1.6
161.693 + */
161.694 + public Map.Entry<K,V> lowerEntry(K key) {
161.695 + return exportEntry(getLowerEntry(key));
161.696 + }
161.697 +
161.698 + /**
161.699 + * @throws ClassCastException {@inheritDoc}
161.700 + * @throws NullPointerException if the specified key is null
161.701 + * and this map uses natural ordering, or its comparator
161.702 + * does not permit null keys
161.703 + * @since 1.6
161.704 + */
161.705 + public K lowerKey(K key) {
161.706 + return keyOrNull(getLowerEntry(key));
161.707 + }
161.708 +
161.709 + /**
161.710 + * @throws ClassCastException {@inheritDoc}
161.711 + * @throws NullPointerException if the specified key is null
161.712 + * and this map uses natural ordering, or its comparator
161.713 + * does not permit null keys
161.714 + * @since 1.6
161.715 + */
161.716 + public Map.Entry<K,V> floorEntry(K key) {
161.717 + return exportEntry(getFloorEntry(key));
161.718 + }
161.719 +
161.720 + /**
161.721 + * @throws ClassCastException {@inheritDoc}
161.722 + * @throws NullPointerException if the specified key is null
161.723 + * and this map uses natural ordering, or its comparator
161.724 + * does not permit null keys
161.725 + * @since 1.6
161.726 + */
161.727 + public K floorKey(K key) {
161.728 + return keyOrNull(getFloorEntry(key));
161.729 + }
161.730 +
161.731 + /**
161.732 + * @throws ClassCastException {@inheritDoc}
161.733 + * @throws NullPointerException if the specified key is null
161.734 + * and this map uses natural ordering, or its comparator
161.735 + * does not permit null keys
161.736 + * @since 1.6
161.737 + */
161.738 + public Map.Entry<K,V> ceilingEntry(K key) {
161.739 + return exportEntry(getCeilingEntry(key));
161.740 + }
161.741 +
161.742 + /**
161.743 + * @throws ClassCastException {@inheritDoc}
161.744 + * @throws NullPointerException if the specified key is null
161.745 + * and this map uses natural ordering, or its comparator
161.746 + * does not permit null keys
161.747 + * @since 1.6
161.748 + */
161.749 + public K ceilingKey(K key) {
161.750 + return keyOrNull(getCeilingEntry(key));
161.751 + }
161.752 +
161.753 + /**
161.754 + * @throws ClassCastException {@inheritDoc}
161.755 + * @throws NullPointerException if the specified key is null
161.756 + * and this map uses natural ordering, or its comparator
161.757 + * does not permit null keys
161.758 + * @since 1.6
161.759 + */
161.760 + public Map.Entry<K,V> higherEntry(K key) {
161.761 + return exportEntry(getHigherEntry(key));
161.762 + }
161.763 +
161.764 + /**
161.765 + * @throws ClassCastException {@inheritDoc}
161.766 + * @throws NullPointerException if the specified key is null
161.767 + * and this map uses natural ordering, or its comparator
161.768 + * does not permit null keys
161.769 + * @since 1.6
161.770 + */
161.771 + public K higherKey(K key) {
161.772 + return keyOrNull(getHigherEntry(key));
161.773 + }
161.774 +
161.775 + // Views
161.776 +
161.777 + /**
161.778 + * Fields initialized to contain an instance of the entry set view
161.779 + * the first time this view is requested. Views are stateless, so
161.780 + * there's no reason to create more than one.
161.781 + */
161.782 + private transient EntrySet entrySet = null;
161.783 + private transient KeySet<K> navigableKeySet = null;
161.784 + private transient NavigableMap<K,V> descendingMap = null;
161.785 +
161.786 + /**
161.787 + * Returns a {@link Set} view of the keys contained in this map.
161.788 + * The set's iterator returns the keys in ascending order.
161.789 + * The set is backed by the map, so changes to the map are
161.790 + * reflected in the set, and vice-versa. If the map is modified
161.791 + * while an iteration over the set is in progress (except through
161.792 + * the iterator's own {@code remove} operation), the results of
161.793 + * the iteration are undefined. The set supports element removal,
161.794 + * which removes the corresponding mapping from the map, via the
161.795 + * {@code Iterator.remove}, {@code Set.remove},
161.796 + * {@code removeAll}, {@code retainAll}, and {@code clear}
161.797 + * operations. It does not support the {@code add} or {@code addAll}
161.798 + * operations.
161.799 + */
161.800 + public Set<K> keySet() {
161.801 + return navigableKeySet();
161.802 + }
161.803 +
161.804 + /**
161.805 + * @since 1.6
161.806 + */
161.807 + public NavigableSet<K> navigableKeySet() {
161.808 + KeySet<K> nks = navigableKeySet;
161.809 + return (nks != null) ? nks : (navigableKeySet = new KeySet(this));
161.810 + }
161.811 +
161.812 + /**
161.813 + * @since 1.6
161.814 + */
161.815 + public NavigableSet<K> descendingKeySet() {
161.816 + return descendingMap().navigableKeySet();
161.817 + }
161.818 +
161.819 + /**
161.820 + * Returns a {@link Collection} view of the values contained in this map.
161.821 + * The collection's iterator returns the values in ascending order
161.822 + * of the corresponding keys.
161.823 + * The collection is backed by the map, so changes to the map are
161.824 + * reflected in the collection, and vice-versa. If the map is
161.825 + * modified while an iteration over the collection is in progress
161.826 + * (except through the iterator's own {@code remove} operation),
161.827 + * the results of the iteration are undefined. The collection
161.828 + * supports element removal, which removes the corresponding
161.829 + * mapping from the map, via the {@code Iterator.remove},
161.830 + * {@code Collection.remove}, {@code removeAll},
161.831 + * {@code retainAll} and {@code clear} operations. It does not
161.832 + * support the {@code add} or {@code addAll} operations.
161.833 + */
161.834 + public Collection<V> values() {
161.835 + Collection<V> vs = values;
161.836 + return (vs != null) ? vs : (values = new Values());
161.837 + }
161.838 +
161.839 + /**
161.840 + * Returns a {@link Set} view of the mappings contained in this map.
161.841 + * The set's iterator returns the entries in ascending key order.
161.842 + * The set is backed by the map, so changes to the map are
161.843 + * reflected in the set, and vice-versa. If the map is modified
161.844 + * while an iteration over the set is in progress (except through
161.845 + * the iterator's own {@code remove} operation, or through the
161.846 + * {@code setValue} operation on a map entry returned by the
161.847 + * iterator) the results of the iteration are undefined. The set
161.848 + * supports element removal, which removes the corresponding
161.849 + * mapping from the map, via the {@code Iterator.remove},
161.850 + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
161.851 + * {@code clear} operations. It does not support the
161.852 + * {@code add} or {@code addAll} operations.
161.853 + */
161.854 + public Set<Map.Entry<K,V>> entrySet() {
161.855 + EntrySet es = entrySet;
161.856 + return (es != null) ? es : (entrySet = new EntrySet());
161.857 + }
161.858 +
161.859 + /**
161.860 + * @since 1.6
161.861 + */
161.862 + public NavigableMap<K, V> descendingMap() {
161.863 + NavigableMap<K, V> km = descendingMap;
161.864 + return (km != null) ? km :
161.865 + (descendingMap = new DescendingSubMap(this,
161.866 + true, null, true,
161.867 + true, null, true));
161.868 + }
161.869 +
161.870 + /**
161.871 + * @throws ClassCastException {@inheritDoc}
161.872 + * @throws NullPointerException if {@code fromKey} or {@code toKey} is
161.873 + * null and this map uses natural ordering, or its comparator
161.874 + * does not permit null keys
161.875 + * @throws IllegalArgumentException {@inheritDoc}
161.876 + * @since 1.6
161.877 + */
161.878 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
161.879 + K toKey, boolean toInclusive) {
161.880 + return new AscendingSubMap(this,
161.881 + false, fromKey, fromInclusive,
161.882 + false, toKey, toInclusive);
161.883 + }
161.884 +
161.885 + /**
161.886 + * @throws ClassCastException {@inheritDoc}
161.887 + * @throws NullPointerException if {@code toKey} is null
161.888 + * and this map uses natural ordering, or its comparator
161.889 + * does not permit null keys
161.890 + * @throws IllegalArgumentException {@inheritDoc}
161.891 + * @since 1.6
161.892 + */
161.893 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
161.894 + return new AscendingSubMap(this,
161.895 + true, null, true,
161.896 + false, toKey, inclusive);
161.897 + }
161.898 +
161.899 + /**
161.900 + * @throws ClassCastException {@inheritDoc}
161.901 + * @throws NullPointerException if {@code fromKey} is null
161.902 + * and this map uses natural ordering, or its comparator
161.903 + * does not permit null keys
161.904 + * @throws IllegalArgumentException {@inheritDoc}
161.905 + * @since 1.6
161.906 + */
161.907 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
161.908 + return new AscendingSubMap(this,
161.909 + false, fromKey, inclusive,
161.910 + true, null, true);
161.911 + }
161.912 +
161.913 + /**
161.914 + * @throws ClassCastException {@inheritDoc}
161.915 + * @throws NullPointerException if {@code fromKey} or {@code toKey} is
161.916 + * null and this map uses natural ordering, or its comparator
161.917 + * does not permit null keys
161.918 + * @throws IllegalArgumentException {@inheritDoc}
161.919 + */
161.920 + public SortedMap<K,V> subMap(K fromKey, K toKey) {
161.921 + return subMap(fromKey, true, toKey, false);
161.922 + }
161.923 +
161.924 + /**
161.925 + * @throws ClassCastException {@inheritDoc}
161.926 + * @throws NullPointerException if {@code toKey} is null
161.927 + * and this map uses natural ordering, or its comparator
161.928 + * does not permit null keys
161.929 + * @throws IllegalArgumentException {@inheritDoc}
161.930 + */
161.931 + public SortedMap<K,V> headMap(K toKey) {
161.932 + return headMap(toKey, false);
161.933 + }
161.934 +
161.935 + /**
161.936 + * @throws ClassCastException {@inheritDoc}
161.937 + * @throws NullPointerException if {@code fromKey} is null
161.938 + * and this map uses natural ordering, or its comparator
161.939 + * does not permit null keys
161.940 + * @throws IllegalArgumentException {@inheritDoc}
161.941 + */
161.942 + public SortedMap<K,V> tailMap(K fromKey) {
161.943 + return tailMap(fromKey, true);
161.944 + }
161.945 +
161.946 + // View class support
161.947 +
161.948 + class Values extends AbstractCollection<V> {
161.949 + public Iterator<V> iterator() {
161.950 + return new ValueIterator(getFirstEntry());
161.951 + }
161.952 +
161.953 + public int size() {
161.954 + return TreeMap.this.size();
161.955 + }
161.956 +
161.957 + public boolean contains(Object o) {
161.958 + return TreeMap.this.containsValue(o);
161.959 + }
161.960 +
161.961 + public boolean remove(Object o) {
161.962 + for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e)) {
161.963 + if (valEquals(e.getValue(), o)) {
161.964 + deleteEntry(e);
161.965 + return true;
161.966 + }
161.967 + }
161.968 + return false;
161.969 + }
161.970 +
161.971 + public void clear() {
161.972 + TreeMap.this.clear();
161.973 + }
161.974 + }
161.975 +
161.976 + class EntrySet extends AbstractSet<Map.Entry<K,V>> {
161.977 + public Iterator<Map.Entry<K,V>> iterator() {
161.978 + return new EntryIterator(getFirstEntry());
161.979 + }
161.980 +
161.981 + public boolean contains(Object o) {
161.982 + if (!(o instanceof Map.Entry))
161.983 + return false;
161.984 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
161.985 + V value = entry.getValue();
161.986 + Entry<K,V> p = getEntry(entry.getKey());
161.987 + return p != null && valEquals(p.getValue(), value);
161.988 + }
161.989 +
161.990 + public boolean remove(Object o) {
161.991 + if (!(o instanceof Map.Entry))
161.992 + return false;
161.993 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
161.994 + V value = entry.getValue();
161.995 + Entry<K,V> p = getEntry(entry.getKey());
161.996 + if (p != null && valEquals(p.getValue(), value)) {
161.997 + deleteEntry(p);
161.998 + return true;
161.999 + }
161.1000 + return false;
161.1001 + }
161.1002 +
161.1003 + public int size() {
161.1004 + return TreeMap.this.size();
161.1005 + }
161.1006 +
161.1007 + public void clear() {
161.1008 + TreeMap.this.clear();
161.1009 + }
161.1010 + }
161.1011 +
161.1012 + /*
161.1013 + * Unlike Values and EntrySet, the KeySet class is static,
161.1014 + * delegating to a NavigableMap to allow use by SubMaps, which
161.1015 + * outweighs the ugliness of needing type-tests for the following
161.1016 + * Iterator methods that are defined appropriately in main versus
161.1017 + * submap classes.
161.1018 + */
161.1019 +
161.1020 + Iterator<K> keyIterator() {
161.1021 + return new KeyIterator(getFirstEntry());
161.1022 + }
161.1023 +
161.1024 + Iterator<K> descendingKeyIterator() {
161.1025 + return new DescendingKeyIterator(getLastEntry());
161.1026 + }
161.1027 +
161.1028 + static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
161.1029 + private final NavigableMap<E, Object> m;
161.1030 + KeySet(NavigableMap<E,Object> map) { m = map; }
161.1031 +
161.1032 + public Iterator<E> iterator() {
161.1033 + if (m instanceof TreeMap)
161.1034 + return ((TreeMap<E,Object>)m).keyIterator();
161.1035 + else
161.1036 + return (Iterator<E>)(((TreeMap.NavigableSubMap)m).keyIterator());
161.1037 + }
161.1038 +
161.1039 + public Iterator<E> descendingIterator() {
161.1040 + if (m instanceof TreeMap)
161.1041 + return ((TreeMap<E,Object>)m).descendingKeyIterator();
161.1042 + else
161.1043 + return (Iterator<E>)(((TreeMap.NavigableSubMap)m).descendingKeyIterator());
161.1044 + }
161.1045 +
161.1046 + public int size() { return m.size(); }
161.1047 + public boolean isEmpty() { return m.isEmpty(); }
161.1048 + public boolean contains(Object o) { return m.containsKey(o); }
161.1049 + public void clear() { m.clear(); }
161.1050 + public E lower(E e) { return m.lowerKey(e); }
161.1051 + public E floor(E e) { return m.floorKey(e); }
161.1052 + public E ceiling(E e) { return m.ceilingKey(e); }
161.1053 + public E higher(E e) { return m.higherKey(e); }
161.1054 + public E first() { return m.firstKey(); }
161.1055 + public E last() { return m.lastKey(); }
161.1056 + public Comparator<? super E> comparator() { return m.comparator(); }
161.1057 + public E pollFirst() {
161.1058 + Map.Entry<E,Object> e = m.pollFirstEntry();
161.1059 + return (e == null) ? null : e.getKey();
161.1060 + }
161.1061 + public E pollLast() {
161.1062 + Map.Entry<E,Object> e = m.pollLastEntry();
161.1063 + return (e == null) ? null : e.getKey();
161.1064 + }
161.1065 + public boolean remove(Object o) {
161.1066 + int oldSize = size();
161.1067 + m.remove(o);
161.1068 + return size() != oldSize;
161.1069 + }
161.1070 + public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
161.1071 + E toElement, boolean toInclusive) {
161.1072 + return new KeySet<>(m.subMap(fromElement, fromInclusive,
161.1073 + toElement, toInclusive));
161.1074 + }
161.1075 + public NavigableSet<E> headSet(E toElement, boolean inclusive) {
161.1076 + return new KeySet<>(m.headMap(toElement, inclusive));
161.1077 + }
161.1078 + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
161.1079 + return new KeySet<>(m.tailMap(fromElement, inclusive));
161.1080 + }
161.1081 + public SortedSet<E> subSet(E fromElement, E toElement) {
161.1082 + return subSet(fromElement, true, toElement, false);
161.1083 + }
161.1084 + public SortedSet<E> headSet(E toElement) {
161.1085 + return headSet(toElement, false);
161.1086 + }
161.1087 + public SortedSet<E> tailSet(E fromElement) {
161.1088 + return tailSet(fromElement, true);
161.1089 + }
161.1090 + public NavigableSet<E> descendingSet() {
161.1091 + return new KeySet(m.descendingMap());
161.1092 + }
161.1093 + }
161.1094 +
161.1095 + /**
161.1096 + * Base class for TreeMap Iterators
161.1097 + */
161.1098 + abstract class PrivateEntryIterator<T> implements Iterator<T> {
161.1099 + Entry<K,V> next;
161.1100 + Entry<K,V> lastReturned;
161.1101 + int expectedModCount;
161.1102 +
161.1103 + PrivateEntryIterator(Entry<K,V> first) {
161.1104 + expectedModCount = modCount;
161.1105 + lastReturned = null;
161.1106 + next = first;
161.1107 + }
161.1108 +
161.1109 + public final boolean hasNext() {
161.1110 + return next != null;
161.1111 + }
161.1112 +
161.1113 + final Entry<K,V> nextEntry() {
161.1114 + Entry<K,V> e = next;
161.1115 + if (e == null)
161.1116 + throw new NoSuchElementException();
161.1117 + if (modCount != expectedModCount)
161.1118 + throw new ConcurrentModificationException();
161.1119 + next = successor(e);
161.1120 + lastReturned = e;
161.1121 + return e;
161.1122 + }
161.1123 +
161.1124 + final Entry<K,V> prevEntry() {
161.1125 + Entry<K,V> e = next;
161.1126 + if (e == null)
161.1127 + throw new NoSuchElementException();
161.1128 + if (modCount != expectedModCount)
161.1129 + throw new ConcurrentModificationException();
161.1130 + next = predecessor(e);
161.1131 + lastReturned = e;
161.1132 + return e;
161.1133 + }
161.1134 +
161.1135 + public void remove() {
161.1136 + if (lastReturned == null)
161.1137 + throw new IllegalStateException();
161.1138 + if (modCount != expectedModCount)
161.1139 + throw new ConcurrentModificationException();
161.1140 + // deleted entries are replaced by their successors
161.1141 + if (lastReturned.left != null && lastReturned.right != null)
161.1142 + next = lastReturned;
161.1143 + deleteEntry(lastReturned);
161.1144 + expectedModCount = modCount;
161.1145 + lastReturned = null;
161.1146 + }
161.1147 + }
161.1148 +
161.1149 + final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
161.1150 + EntryIterator(Entry<K,V> first) {
161.1151 + super(first);
161.1152 + }
161.1153 + public Map.Entry<K,V> next() {
161.1154 + return nextEntry();
161.1155 + }
161.1156 + }
161.1157 +
161.1158 + final class ValueIterator extends PrivateEntryIterator<V> {
161.1159 + ValueIterator(Entry<K,V> first) {
161.1160 + super(first);
161.1161 + }
161.1162 + public V next() {
161.1163 + return nextEntry().value;
161.1164 + }
161.1165 + }
161.1166 +
161.1167 + final class KeyIterator extends PrivateEntryIterator<K> {
161.1168 + KeyIterator(Entry<K,V> first) {
161.1169 + super(first);
161.1170 + }
161.1171 + public K next() {
161.1172 + return nextEntry().key;
161.1173 + }
161.1174 + }
161.1175 +
161.1176 + final class DescendingKeyIterator extends PrivateEntryIterator<K> {
161.1177 + DescendingKeyIterator(Entry<K,V> first) {
161.1178 + super(first);
161.1179 + }
161.1180 + public K next() {
161.1181 + return prevEntry().key;
161.1182 + }
161.1183 + }
161.1184 +
161.1185 + // Little utilities
161.1186 +
161.1187 + /**
161.1188 + * Compares two keys using the correct comparison method for this TreeMap.
161.1189 + */
161.1190 + final int compare(Object k1, Object k2) {
161.1191 + return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
161.1192 + : comparator.compare((K)k1, (K)k2);
161.1193 + }
161.1194 +
161.1195 + /**
161.1196 + * Test two values for equality. Differs from o1.equals(o2) only in
161.1197 + * that it copes with {@code null} o1 properly.
161.1198 + */
161.1199 + static final boolean valEquals(Object o1, Object o2) {
161.1200 + return (o1==null ? o2==null : o1.equals(o2));
161.1201 + }
161.1202 +
161.1203 + /**
161.1204 + * Return SimpleImmutableEntry for entry, or null if null
161.1205 + */
161.1206 + static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
161.1207 + return (e == null) ? null :
161.1208 + new AbstractMap.SimpleImmutableEntry<>(e);
161.1209 + }
161.1210 +
161.1211 + /**
161.1212 + * Return key for entry, or null if null
161.1213 + */
161.1214 + static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) {
161.1215 + return (e == null) ? null : e.key;
161.1216 + }
161.1217 +
161.1218 + /**
161.1219 + * Returns the key corresponding to the specified Entry.
161.1220 + * @throws NoSuchElementException if the Entry is null
161.1221 + */
161.1222 + static <K> K key(Entry<K,?> e) {
161.1223 + if (e==null)
161.1224 + throw new NoSuchElementException();
161.1225 + return e.key;
161.1226 + }
161.1227 +
161.1228 +
161.1229 + // SubMaps
161.1230 +
161.1231 + /**
161.1232 + * Dummy value serving as unmatchable fence key for unbounded
161.1233 + * SubMapIterators
161.1234 + */
161.1235 + private static final Object UNBOUNDED = new Object();
161.1236 +
161.1237 + /**
161.1238 + * @serial include
161.1239 + */
161.1240 + abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
161.1241 + implements NavigableMap<K,V>, java.io.Serializable {
161.1242 + /**
161.1243 + * The backing map.
161.1244 + */
161.1245 + final TreeMap<K,V> m;
161.1246 +
161.1247 + /**
161.1248 + * Endpoints are represented as triples (fromStart, lo,
161.1249 + * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
161.1250 + * true, then the low (absolute) bound is the start of the
161.1251 + * backing map, and the other values are ignored. Otherwise,
161.1252 + * if loInclusive is true, lo is the inclusive bound, else lo
161.1253 + * is the exclusive bound. Similarly for the upper bound.
161.1254 + */
161.1255 + final K lo, hi;
161.1256 + final boolean fromStart, toEnd;
161.1257 + final boolean loInclusive, hiInclusive;
161.1258 +
161.1259 + NavigableSubMap(TreeMap<K,V> m,
161.1260 + boolean fromStart, K lo, boolean loInclusive,
161.1261 + boolean toEnd, K hi, boolean hiInclusive) {
161.1262 + if (!fromStart && !toEnd) {
161.1263 + if (m.compare(lo, hi) > 0)
161.1264 + throw new IllegalArgumentException("fromKey > toKey");
161.1265 + } else {
161.1266 + if (!fromStart) // type check
161.1267 + m.compare(lo, lo);
161.1268 + if (!toEnd)
161.1269 + m.compare(hi, hi);
161.1270 + }
161.1271 +
161.1272 + this.m = m;
161.1273 + this.fromStart = fromStart;
161.1274 + this.lo = lo;
161.1275 + this.loInclusive = loInclusive;
161.1276 + this.toEnd = toEnd;
161.1277 + this.hi = hi;
161.1278 + this.hiInclusive = hiInclusive;
161.1279 + }
161.1280 +
161.1281 + // internal utilities
161.1282 +
161.1283 + final boolean tooLow(Object key) {
161.1284 + if (!fromStart) {
161.1285 + int c = m.compare(key, lo);
161.1286 + if (c < 0 || (c == 0 && !loInclusive))
161.1287 + return true;
161.1288 + }
161.1289 + return false;
161.1290 + }
161.1291 +
161.1292 + final boolean tooHigh(Object key) {
161.1293 + if (!toEnd) {
161.1294 + int c = m.compare(key, hi);
161.1295 + if (c > 0 || (c == 0 && !hiInclusive))
161.1296 + return true;
161.1297 + }
161.1298 + return false;
161.1299 + }
161.1300 +
161.1301 + final boolean inRange(Object key) {
161.1302 + return !tooLow(key) && !tooHigh(key);
161.1303 + }
161.1304 +
161.1305 + final boolean inClosedRange(Object key) {
161.1306 + return (fromStart || m.compare(key, lo) >= 0)
161.1307 + && (toEnd || m.compare(hi, key) >= 0);
161.1308 + }
161.1309 +
161.1310 + final boolean inRange(Object key, boolean inclusive) {
161.1311 + return inclusive ? inRange(key) : inClosedRange(key);
161.1312 + }
161.1313 +
161.1314 + /*
161.1315 + * Absolute versions of relation operations.
161.1316 + * Subclasses map to these using like-named "sub"
161.1317 + * versions that invert senses for descending maps
161.1318 + */
161.1319 +
161.1320 + final TreeMap.Entry<K,V> absLowest() {
161.1321 + TreeMap.Entry<K,V> e =
161.1322 + (fromStart ? m.getFirstEntry() :
161.1323 + (loInclusive ? m.getCeilingEntry(lo) :
161.1324 + m.getHigherEntry(lo)));
161.1325 + return (e == null || tooHigh(e.key)) ? null : e;
161.1326 + }
161.1327 +
161.1328 + final TreeMap.Entry<K,V> absHighest() {
161.1329 + TreeMap.Entry<K,V> e =
161.1330 + (toEnd ? m.getLastEntry() :
161.1331 + (hiInclusive ? m.getFloorEntry(hi) :
161.1332 + m.getLowerEntry(hi)));
161.1333 + return (e == null || tooLow(e.key)) ? null : e;
161.1334 + }
161.1335 +
161.1336 + final TreeMap.Entry<K,V> absCeiling(K key) {
161.1337 + if (tooLow(key))
161.1338 + return absLowest();
161.1339 + TreeMap.Entry<K,V> e = m.getCeilingEntry(key);
161.1340 + return (e == null || tooHigh(e.key)) ? null : e;
161.1341 + }
161.1342 +
161.1343 + final TreeMap.Entry<K,V> absHigher(K key) {
161.1344 + if (tooLow(key))
161.1345 + return absLowest();
161.1346 + TreeMap.Entry<K,V> e = m.getHigherEntry(key);
161.1347 + return (e == null || tooHigh(e.key)) ? null : e;
161.1348 + }
161.1349 +
161.1350 + final TreeMap.Entry<K,V> absFloor(K key) {
161.1351 + if (tooHigh(key))
161.1352 + return absHighest();
161.1353 + TreeMap.Entry<K,V> e = m.getFloorEntry(key);
161.1354 + return (e == null || tooLow(e.key)) ? null : e;
161.1355 + }
161.1356 +
161.1357 + final TreeMap.Entry<K,V> absLower(K key) {
161.1358 + if (tooHigh(key))
161.1359 + return absHighest();
161.1360 + TreeMap.Entry<K,V> e = m.getLowerEntry(key);
161.1361 + return (e == null || tooLow(e.key)) ? null : e;
161.1362 + }
161.1363 +
161.1364 + /** Returns the absolute high fence for ascending traversal */
161.1365 + final TreeMap.Entry<K,V> absHighFence() {
161.1366 + return (toEnd ? null : (hiInclusive ?
161.1367 + m.getHigherEntry(hi) :
161.1368 + m.getCeilingEntry(hi)));
161.1369 + }
161.1370 +
161.1371 + /** Return the absolute low fence for descending traversal */
161.1372 + final TreeMap.Entry<K,V> absLowFence() {
161.1373 + return (fromStart ? null : (loInclusive ?
161.1374 + m.getLowerEntry(lo) :
161.1375 + m.getFloorEntry(lo)));
161.1376 + }
161.1377 +
161.1378 + // Abstract methods defined in ascending vs descending classes
161.1379 + // These relay to the appropriate absolute versions
161.1380 +
161.1381 + abstract TreeMap.Entry<K,V> subLowest();
161.1382 + abstract TreeMap.Entry<K,V> subHighest();
161.1383 + abstract TreeMap.Entry<K,V> subCeiling(K key);
161.1384 + abstract TreeMap.Entry<K,V> subHigher(K key);
161.1385 + abstract TreeMap.Entry<K,V> subFloor(K key);
161.1386 + abstract TreeMap.Entry<K,V> subLower(K key);
161.1387 +
161.1388 + /** Returns ascending iterator from the perspective of this submap */
161.1389 + abstract Iterator<K> keyIterator();
161.1390 +
161.1391 + /** Returns descending iterator from the perspective of this submap */
161.1392 + abstract Iterator<K> descendingKeyIterator();
161.1393 +
161.1394 + // public methods
161.1395 +
161.1396 + public boolean isEmpty() {
161.1397 + return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
161.1398 + }
161.1399 +
161.1400 + public int size() {
161.1401 + return (fromStart && toEnd) ? m.size() : entrySet().size();
161.1402 + }
161.1403 +
161.1404 + public final boolean containsKey(Object key) {
161.1405 + return inRange(key) && m.containsKey(key);
161.1406 + }
161.1407 +
161.1408 + public final V put(K key, V value) {
161.1409 + if (!inRange(key))
161.1410 + throw new IllegalArgumentException("key out of range");
161.1411 + return m.put(key, value);
161.1412 + }
161.1413 +
161.1414 + public final V get(Object key) {
161.1415 + return !inRange(key) ? null : m.get(key);
161.1416 + }
161.1417 +
161.1418 + public final V remove(Object key) {
161.1419 + return !inRange(key) ? null : m.remove(key);
161.1420 + }
161.1421 +
161.1422 + public final Map.Entry<K,V> ceilingEntry(K key) {
161.1423 + return exportEntry(subCeiling(key));
161.1424 + }
161.1425 +
161.1426 + public final K ceilingKey(K key) {
161.1427 + return keyOrNull(subCeiling(key));
161.1428 + }
161.1429 +
161.1430 + public final Map.Entry<K,V> higherEntry(K key) {
161.1431 + return exportEntry(subHigher(key));
161.1432 + }
161.1433 +
161.1434 + public final K higherKey(K key) {
161.1435 + return keyOrNull(subHigher(key));
161.1436 + }
161.1437 +
161.1438 + public final Map.Entry<K,V> floorEntry(K key) {
161.1439 + return exportEntry(subFloor(key));
161.1440 + }
161.1441 +
161.1442 + public final K floorKey(K key) {
161.1443 + return keyOrNull(subFloor(key));
161.1444 + }
161.1445 +
161.1446 + public final Map.Entry<K,V> lowerEntry(K key) {
161.1447 + return exportEntry(subLower(key));
161.1448 + }
161.1449 +
161.1450 + public final K lowerKey(K key) {
161.1451 + return keyOrNull(subLower(key));
161.1452 + }
161.1453 +
161.1454 + public final K firstKey() {
161.1455 + return key(subLowest());
161.1456 + }
161.1457 +
161.1458 + public final K lastKey() {
161.1459 + return key(subHighest());
161.1460 + }
161.1461 +
161.1462 + public final Map.Entry<K,V> firstEntry() {
161.1463 + return exportEntry(subLowest());
161.1464 + }
161.1465 +
161.1466 + public final Map.Entry<K,V> lastEntry() {
161.1467 + return exportEntry(subHighest());
161.1468 + }
161.1469 +
161.1470 + public final Map.Entry<K,V> pollFirstEntry() {
161.1471 + TreeMap.Entry<K,V> e = subLowest();
161.1472 + Map.Entry<K,V> result = exportEntry(e);
161.1473 + if (e != null)
161.1474 + m.deleteEntry(e);
161.1475 + return result;
161.1476 + }
161.1477 +
161.1478 + public final Map.Entry<K,V> pollLastEntry() {
161.1479 + TreeMap.Entry<K,V> e = subHighest();
161.1480 + Map.Entry<K,V> result = exportEntry(e);
161.1481 + if (e != null)
161.1482 + m.deleteEntry(e);
161.1483 + return result;
161.1484 + }
161.1485 +
161.1486 + // Views
161.1487 + transient NavigableMap<K,V> descendingMapView = null;
161.1488 + transient EntrySetView entrySetView = null;
161.1489 + transient KeySet<K> navigableKeySetView = null;
161.1490 +
161.1491 + public final NavigableSet<K> navigableKeySet() {
161.1492 + KeySet<K> nksv = navigableKeySetView;
161.1493 + return (nksv != null) ? nksv :
161.1494 + (navigableKeySetView = new TreeMap.KeySet(this));
161.1495 + }
161.1496 +
161.1497 + public final Set<K> keySet() {
161.1498 + return navigableKeySet();
161.1499 + }
161.1500 +
161.1501 + public NavigableSet<K> descendingKeySet() {
161.1502 + return descendingMap().navigableKeySet();
161.1503 + }
161.1504 +
161.1505 + public final SortedMap<K,V> subMap(K fromKey, K toKey) {
161.1506 + return subMap(fromKey, true, toKey, false);
161.1507 + }
161.1508 +
161.1509 + public final SortedMap<K,V> headMap(K toKey) {
161.1510 + return headMap(toKey, false);
161.1511 + }
161.1512 +
161.1513 + public final SortedMap<K,V> tailMap(K fromKey) {
161.1514 + return tailMap(fromKey, true);
161.1515 + }
161.1516 +
161.1517 + // View classes
161.1518 +
161.1519 + abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
161.1520 + private transient int size = -1, sizeModCount;
161.1521 +
161.1522 + public int size() {
161.1523 + if (fromStart && toEnd)
161.1524 + return m.size();
161.1525 + if (size == -1 || sizeModCount != m.modCount) {
161.1526 + sizeModCount = m.modCount;
161.1527 + size = 0;
161.1528 + Iterator i = iterator();
161.1529 + while (i.hasNext()) {
161.1530 + size++;
161.1531 + i.next();
161.1532 + }
161.1533 + }
161.1534 + return size;
161.1535 + }
161.1536 +
161.1537 + public boolean isEmpty() {
161.1538 + TreeMap.Entry<K,V> n = absLowest();
161.1539 + return n == null || tooHigh(n.key);
161.1540 + }
161.1541 +
161.1542 + public boolean contains(Object o) {
161.1543 + if (!(o instanceof Map.Entry))
161.1544 + return false;
161.1545 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
161.1546 + K key = entry.getKey();
161.1547 + if (!inRange(key))
161.1548 + return false;
161.1549 + TreeMap.Entry node = m.getEntry(key);
161.1550 + return node != null &&
161.1551 + valEquals(node.getValue(), entry.getValue());
161.1552 + }
161.1553 +
161.1554 + public boolean remove(Object o) {
161.1555 + if (!(o instanceof Map.Entry))
161.1556 + return false;
161.1557 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
161.1558 + K key = entry.getKey();
161.1559 + if (!inRange(key))
161.1560 + return false;
161.1561 + TreeMap.Entry<K,V> node = m.getEntry(key);
161.1562 + if (node!=null && valEquals(node.getValue(),
161.1563 + entry.getValue())) {
161.1564 + m.deleteEntry(node);
161.1565 + return true;
161.1566 + }
161.1567 + return false;
161.1568 + }
161.1569 + }
161.1570 +
161.1571 + /**
161.1572 + * Iterators for SubMaps
161.1573 + */
161.1574 + abstract class SubMapIterator<T> implements Iterator<T> {
161.1575 + TreeMap.Entry<K,V> lastReturned;
161.1576 + TreeMap.Entry<K,V> next;
161.1577 + final Object fenceKey;
161.1578 + int expectedModCount;
161.1579 +
161.1580 + SubMapIterator(TreeMap.Entry<K,V> first,
161.1581 + TreeMap.Entry<K,V> fence) {
161.1582 + expectedModCount = m.modCount;
161.1583 + lastReturned = null;
161.1584 + next = first;
161.1585 + fenceKey = fence == null ? UNBOUNDED : fence.key;
161.1586 + }
161.1587 +
161.1588 + public final boolean hasNext() {
161.1589 + return next != null && next.key != fenceKey;
161.1590 + }
161.1591 +
161.1592 + final TreeMap.Entry<K,V> nextEntry() {
161.1593 + TreeMap.Entry<K,V> e = next;
161.1594 + if (e == null || e.key == fenceKey)
161.1595 + throw new NoSuchElementException();
161.1596 + if (m.modCount != expectedModCount)
161.1597 + throw new ConcurrentModificationException();
161.1598 + next = successor(e);
161.1599 + lastReturned = e;
161.1600 + return e;
161.1601 + }
161.1602 +
161.1603 + final TreeMap.Entry<K,V> prevEntry() {
161.1604 + TreeMap.Entry<K,V> e = next;
161.1605 + if (e == null || e.key == fenceKey)
161.1606 + throw new NoSuchElementException();
161.1607 + if (m.modCount != expectedModCount)
161.1608 + throw new ConcurrentModificationException();
161.1609 + next = predecessor(e);
161.1610 + lastReturned = e;
161.1611 + return e;
161.1612 + }
161.1613 +
161.1614 + final void removeAscending() {
161.1615 + if (lastReturned == null)
161.1616 + throw new IllegalStateException();
161.1617 + if (m.modCount != expectedModCount)
161.1618 + throw new ConcurrentModificationException();
161.1619 + // deleted entries are replaced by their successors
161.1620 + if (lastReturned.left != null && lastReturned.right != null)
161.1621 + next = lastReturned;
161.1622 + m.deleteEntry(lastReturned);
161.1623 + lastReturned = null;
161.1624 + expectedModCount = m.modCount;
161.1625 + }
161.1626 +
161.1627 + final void removeDescending() {
161.1628 + if (lastReturned == null)
161.1629 + throw new IllegalStateException();
161.1630 + if (m.modCount != expectedModCount)
161.1631 + throw new ConcurrentModificationException();
161.1632 + m.deleteEntry(lastReturned);
161.1633 + lastReturned = null;
161.1634 + expectedModCount = m.modCount;
161.1635 + }
161.1636 +
161.1637 + }
161.1638 +
161.1639 + final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
161.1640 + SubMapEntryIterator(TreeMap.Entry<K,V> first,
161.1641 + TreeMap.Entry<K,V> fence) {
161.1642 + super(first, fence);
161.1643 + }
161.1644 + public Map.Entry<K,V> next() {
161.1645 + return nextEntry();
161.1646 + }
161.1647 + public void remove() {
161.1648 + removeAscending();
161.1649 + }
161.1650 + }
161.1651 +
161.1652 + final class SubMapKeyIterator extends SubMapIterator<K> {
161.1653 + SubMapKeyIterator(TreeMap.Entry<K,V> first,
161.1654 + TreeMap.Entry<K,V> fence) {
161.1655 + super(first, fence);
161.1656 + }
161.1657 + public K next() {
161.1658 + return nextEntry().key;
161.1659 + }
161.1660 + public void remove() {
161.1661 + removeAscending();
161.1662 + }
161.1663 + }
161.1664 +
161.1665 + final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
161.1666 + DescendingSubMapEntryIterator(TreeMap.Entry<K,V> last,
161.1667 + TreeMap.Entry<K,V> fence) {
161.1668 + super(last, fence);
161.1669 + }
161.1670 +
161.1671 + public Map.Entry<K,V> next() {
161.1672 + return prevEntry();
161.1673 + }
161.1674 + public void remove() {
161.1675 + removeDescending();
161.1676 + }
161.1677 + }
161.1678 +
161.1679 + final class DescendingSubMapKeyIterator extends SubMapIterator<K> {
161.1680 + DescendingSubMapKeyIterator(TreeMap.Entry<K,V> last,
161.1681 + TreeMap.Entry<K,V> fence) {
161.1682 + super(last, fence);
161.1683 + }
161.1684 + public K next() {
161.1685 + return prevEntry().key;
161.1686 + }
161.1687 + public void remove() {
161.1688 + removeDescending();
161.1689 + }
161.1690 + }
161.1691 + }
161.1692 +
161.1693 + /**
161.1694 + * @serial include
161.1695 + */
161.1696 + static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
161.1697 + private static final long serialVersionUID = 912986545866124060L;
161.1698 +
161.1699 + AscendingSubMap(TreeMap<K,V> m,
161.1700 + boolean fromStart, K lo, boolean loInclusive,
161.1701 + boolean toEnd, K hi, boolean hiInclusive) {
161.1702 + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
161.1703 + }
161.1704 +
161.1705 + public Comparator<? super K> comparator() {
161.1706 + return m.comparator();
161.1707 + }
161.1708 +
161.1709 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
161.1710 + K toKey, boolean toInclusive) {
161.1711 + if (!inRange(fromKey, fromInclusive))
161.1712 + throw new IllegalArgumentException("fromKey out of range");
161.1713 + if (!inRange(toKey, toInclusive))
161.1714 + throw new IllegalArgumentException("toKey out of range");
161.1715 + return new AscendingSubMap(m,
161.1716 + false, fromKey, fromInclusive,
161.1717 + false, toKey, toInclusive);
161.1718 + }
161.1719 +
161.1720 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
161.1721 + if (!inRange(toKey, inclusive))
161.1722 + throw new IllegalArgumentException("toKey out of range");
161.1723 + return new AscendingSubMap(m,
161.1724 + fromStart, lo, loInclusive,
161.1725 + false, toKey, inclusive);
161.1726 + }
161.1727 +
161.1728 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
161.1729 + if (!inRange(fromKey, inclusive))
161.1730 + throw new IllegalArgumentException("fromKey out of range");
161.1731 + return new AscendingSubMap(m,
161.1732 + false, fromKey, inclusive,
161.1733 + toEnd, hi, hiInclusive);
161.1734 + }
161.1735 +
161.1736 + public NavigableMap<K,V> descendingMap() {
161.1737 + NavigableMap<K,V> mv = descendingMapView;
161.1738 + return (mv != null) ? mv :
161.1739 + (descendingMapView =
161.1740 + new DescendingSubMap(m,
161.1741 + fromStart, lo, loInclusive,
161.1742 + toEnd, hi, hiInclusive));
161.1743 + }
161.1744 +
161.1745 + Iterator<K> keyIterator() {
161.1746 + return new SubMapKeyIterator(absLowest(), absHighFence());
161.1747 + }
161.1748 +
161.1749 + Iterator<K> descendingKeyIterator() {
161.1750 + return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
161.1751 + }
161.1752 +
161.1753 + final class AscendingEntrySetView extends EntrySetView {
161.1754 + public Iterator<Map.Entry<K,V>> iterator() {
161.1755 + return new SubMapEntryIterator(absLowest(), absHighFence());
161.1756 + }
161.1757 + }
161.1758 +
161.1759 + public Set<Map.Entry<K,V>> entrySet() {
161.1760 + EntrySetView es = entrySetView;
161.1761 + return (es != null) ? es : new AscendingEntrySetView();
161.1762 + }
161.1763 +
161.1764 + TreeMap.Entry<K,V> subLowest() { return absLowest(); }
161.1765 + TreeMap.Entry<K,V> subHighest() { return absHighest(); }
161.1766 + TreeMap.Entry<K,V> subCeiling(K key) { return absCeiling(key); }
161.1767 + TreeMap.Entry<K,V> subHigher(K key) { return absHigher(key); }
161.1768 + TreeMap.Entry<K,V> subFloor(K key) { return absFloor(key); }
161.1769 + TreeMap.Entry<K,V> subLower(K key) { return absLower(key); }
161.1770 + }
161.1771 +
161.1772 + /**
161.1773 + * @serial include
161.1774 + */
161.1775 + static final class DescendingSubMap<K,V> extends NavigableSubMap<K,V> {
161.1776 + private static final long serialVersionUID = 912986545866120460L;
161.1777 + DescendingSubMap(TreeMap<K,V> m,
161.1778 + boolean fromStart, K lo, boolean loInclusive,
161.1779 + boolean toEnd, K hi, boolean hiInclusive) {
161.1780 + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
161.1781 + }
161.1782 +
161.1783 + private final Comparator<? super K> reverseComparator =
161.1784 + Collections.reverseOrder(m.comparator);
161.1785 +
161.1786 + public Comparator<? super K> comparator() {
161.1787 + return reverseComparator;
161.1788 + }
161.1789 +
161.1790 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
161.1791 + K toKey, boolean toInclusive) {
161.1792 + if (!inRange(fromKey, fromInclusive))
161.1793 + throw new IllegalArgumentException("fromKey out of range");
161.1794 + if (!inRange(toKey, toInclusive))
161.1795 + throw new IllegalArgumentException("toKey out of range");
161.1796 + return new DescendingSubMap(m,
161.1797 + false, toKey, toInclusive,
161.1798 + false, fromKey, fromInclusive);
161.1799 + }
161.1800 +
161.1801 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
161.1802 + if (!inRange(toKey, inclusive))
161.1803 + throw new IllegalArgumentException("toKey out of range");
161.1804 + return new DescendingSubMap(m,
161.1805 + false, toKey, inclusive,
161.1806 + toEnd, hi, hiInclusive);
161.1807 + }
161.1808 +
161.1809 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
161.1810 + if (!inRange(fromKey, inclusive))
161.1811 + throw new IllegalArgumentException("fromKey out of range");
161.1812 + return new DescendingSubMap(m,
161.1813 + fromStart, lo, loInclusive,
161.1814 + false, fromKey, inclusive);
161.1815 + }
161.1816 +
161.1817 + public NavigableMap<K,V> descendingMap() {
161.1818 + NavigableMap<K,V> mv = descendingMapView;
161.1819 + return (mv != null) ? mv :
161.1820 + (descendingMapView =
161.1821 + new AscendingSubMap(m,
161.1822 + fromStart, lo, loInclusive,
161.1823 + toEnd, hi, hiInclusive));
161.1824 + }
161.1825 +
161.1826 + Iterator<K> keyIterator() {
161.1827 + return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
161.1828 + }
161.1829 +
161.1830 + Iterator<K> descendingKeyIterator() {
161.1831 + return new SubMapKeyIterator(absLowest(), absHighFence());
161.1832 + }
161.1833 +
161.1834 + final class DescendingEntrySetView extends EntrySetView {
161.1835 + public Iterator<Map.Entry<K,V>> iterator() {
161.1836 + return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
161.1837 + }
161.1838 + }
161.1839 +
161.1840 + public Set<Map.Entry<K,V>> entrySet() {
161.1841 + EntrySetView es = entrySetView;
161.1842 + return (es != null) ? es : new DescendingEntrySetView();
161.1843 + }
161.1844 +
161.1845 + TreeMap.Entry<K,V> subLowest() { return absHighest(); }
161.1846 + TreeMap.Entry<K,V> subHighest() { return absLowest(); }
161.1847 + TreeMap.Entry<K,V> subCeiling(K key) { return absFloor(key); }
161.1848 + TreeMap.Entry<K,V> subHigher(K key) { return absLower(key); }
161.1849 + TreeMap.Entry<K,V> subFloor(K key) { return absCeiling(key); }
161.1850 + TreeMap.Entry<K,V> subLower(K key) { return absHigher(key); }
161.1851 + }
161.1852 +
161.1853 + /**
161.1854 + * This class exists solely for the sake of serialization
161.1855 + * compatibility with previous releases of TreeMap that did not
161.1856 + * support NavigableMap. It translates an old-version SubMap into
161.1857 + * a new-version AscendingSubMap. This class is never otherwise
161.1858 + * used.
161.1859 + *
161.1860 + * @serial include
161.1861 + */
161.1862 + private class SubMap extends AbstractMap<K,V>
161.1863 + implements SortedMap<K,V>, java.io.Serializable {
161.1864 + private static final long serialVersionUID = -6520786458950516097L;
161.1865 + private boolean fromStart = false, toEnd = false;
161.1866 + private K fromKey, toKey;
161.1867 + private Object readResolve() {
161.1868 + return new AscendingSubMap(TreeMap.this,
161.1869 + fromStart, fromKey, true,
161.1870 + toEnd, toKey, false);
161.1871 + }
161.1872 + public Set<Map.Entry<K,V>> entrySet() { throw new InternalError(); }
161.1873 + public K lastKey() { throw new InternalError(); }
161.1874 + public K firstKey() { throw new InternalError(); }
161.1875 + public SortedMap<K,V> subMap(K fromKey, K toKey) { throw new InternalError(); }
161.1876 + public SortedMap<K,V> headMap(K toKey) { throw new InternalError(); }
161.1877 + public SortedMap<K,V> tailMap(K fromKey) { throw new InternalError(); }
161.1878 + public Comparator<? super K> comparator() { throw new InternalError(); }
161.1879 + }
161.1880 +
161.1881 +
161.1882 + // Red-black mechanics
161.1883 +
161.1884 + private static final boolean RED = false;
161.1885 + private static final boolean BLACK = true;
161.1886 +
161.1887 + /**
161.1888 + * Node in the Tree. Doubles as a means to pass key-value pairs back to
161.1889 + * user (see Map.Entry).
161.1890 + */
161.1891 +
161.1892 + static final class Entry<K,V> implements Map.Entry<K,V> {
161.1893 + K key;
161.1894 + V value;
161.1895 + Entry<K,V> left = null;
161.1896 + Entry<K,V> right = null;
161.1897 + Entry<K,V> parent;
161.1898 + boolean color = BLACK;
161.1899 +
161.1900 + /**
161.1901 + * Make a new cell with given key, value, and parent, and with
161.1902 + * {@code null} child links, and BLACK color.
161.1903 + */
161.1904 + Entry(K key, V value, Entry<K,V> parent) {
161.1905 + this.key = key;
161.1906 + this.value = value;
161.1907 + this.parent = parent;
161.1908 + }
161.1909 +
161.1910 + /**
161.1911 + * Returns the key.
161.1912 + *
161.1913 + * @return the key
161.1914 + */
161.1915 + public K getKey() {
161.1916 + return key;
161.1917 + }
161.1918 +
161.1919 + /**
161.1920 + * Returns the value associated with the key.
161.1921 + *
161.1922 + * @return the value associated with the key
161.1923 + */
161.1924 + public V getValue() {
161.1925 + return value;
161.1926 + }
161.1927 +
161.1928 + /**
161.1929 + * Replaces the value currently associated with the key with the given
161.1930 + * value.
161.1931 + *
161.1932 + * @return the value associated with the key before this method was
161.1933 + * called
161.1934 + */
161.1935 + public V setValue(V value) {
161.1936 + V oldValue = this.value;
161.1937 + this.value = value;
161.1938 + return oldValue;
161.1939 + }
161.1940 +
161.1941 + public boolean equals(Object o) {
161.1942 + if (!(o instanceof Map.Entry))
161.1943 + return false;
161.1944 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
161.1945 +
161.1946 + return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
161.1947 + }
161.1948 +
161.1949 + public int hashCode() {
161.1950 + int keyHash = (key==null ? 0 : key.hashCode());
161.1951 + int valueHash = (value==null ? 0 : value.hashCode());
161.1952 + return keyHash ^ valueHash;
161.1953 + }
161.1954 +
161.1955 + public String toString() {
161.1956 + return key + "=" + value;
161.1957 + }
161.1958 + }
161.1959 +
161.1960 + /**
161.1961 + * Returns the first Entry in the TreeMap (according to the TreeMap's
161.1962 + * key-sort function). Returns null if the TreeMap is empty.
161.1963 + */
161.1964 + final Entry<K,V> getFirstEntry() {
161.1965 + Entry<K,V> p = root;
161.1966 + if (p != null)
161.1967 + while (p.left != null)
161.1968 + p = p.left;
161.1969 + return p;
161.1970 + }
161.1971 +
161.1972 + /**
161.1973 + * Returns the last Entry in the TreeMap (according to the TreeMap's
161.1974 + * key-sort function). Returns null if the TreeMap is empty.
161.1975 + */
161.1976 + final Entry<K,V> getLastEntry() {
161.1977 + Entry<K,V> p = root;
161.1978 + if (p != null)
161.1979 + while (p.right != null)
161.1980 + p = p.right;
161.1981 + return p;
161.1982 + }
161.1983 +
161.1984 + /**
161.1985 + * Returns the successor of the specified Entry, or null if no such.
161.1986 + */
161.1987 + static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
161.1988 + if (t == null)
161.1989 + return null;
161.1990 + else if (t.right != null) {
161.1991 + Entry<K,V> p = t.right;
161.1992 + while (p.left != null)
161.1993 + p = p.left;
161.1994 + return p;
161.1995 + } else {
161.1996 + Entry<K,V> p = t.parent;
161.1997 + Entry<K,V> ch = t;
161.1998 + while (p != null && ch == p.right) {
161.1999 + ch = p;
161.2000 + p = p.parent;
161.2001 + }
161.2002 + return p;
161.2003 + }
161.2004 + }
161.2005 +
161.2006 + /**
161.2007 + * Returns the predecessor of the specified Entry, or null if no such.
161.2008 + */
161.2009 + static <K,V> Entry<K,V> predecessor(Entry<K,V> t) {
161.2010 + if (t == null)
161.2011 + return null;
161.2012 + else if (t.left != null) {
161.2013 + Entry<K,V> p = t.left;
161.2014 + while (p.right != null)
161.2015 + p = p.right;
161.2016 + return p;
161.2017 + } else {
161.2018 + Entry<K,V> p = t.parent;
161.2019 + Entry<K,V> ch = t;
161.2020 + while (p != null && ch == p.left) {
161.2021 + ch = p;
161.2022 + p = p.parent;
161.2023 + }
161.2024 + return p;
161.2025 + }
161.2026 + }
161.2027 +
161.2028 + /**
161.2029 + * Balancing operations.
161.2030 + *
161.2031 + * Implementations of rebalancings during insertion and deletion are
161.2032 + * slightly different than the CLR version. Rather than using dummy
161.2033 + * nilnodes, we use a set of accessors that deal properly with null. They
161.2034 + * are used to avoid messiness surrounding nullness checks in the main
161.2035 + * algorithms.
161.2036 + */
161.2037 +
161.2038 + private static <K,V> boolean colorOf(Entry<K,V> p) {
161.2039 + return (p == null ? BLACK : p.color);
161.2040 + }
161.2041 +
161.2042 + private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {
161.2043 + return (p == null ? null: p.parent);
161.2044 + }
161.2045 +
161.2046 + private static <K,V> void setColor(Entry<K,V> p, boolean c) {
161.2047 + if (p != null)
161.2048 + p.color = c;
161.2049 + }
161.2050 +
161.2051 + private static <K,V> Entry<K,V> leftOf(Entry<K,V> p) {
161.2052 + return (p == null) ? null: p.left;
161.2053 + }
161.2054 +
161.2055 + private static <K,V> Entry<K,V> rightOf(Entry<K,V> p) {
161.2056 + return (p == null) ? null: p.right;
161.2057 + }
161.2058 +
161.2059 + /** From CLR */
161.2060 + private void rotateLeft(Entry<K,V> p) {
161.2061 + if (p != null) {
161.2062 + Entry<K,V> r = p.right;
161.2063 + p.right = r.left;
161.2064 + if (r.left != null)
161.2065 + r.left.parent = p;
161.2066 + r.parent = p.parent;
161.2067 + if (p.parent == null)
161.2068 + root = r;
161.2069 + else if (p.parent.left == p)
161.2070 + p.parent.left = r;
161.2071 + else
161.2072 + p.parent.right = r;
161.2073 + r.left = p;
161.2074 + p.parent = r;
161.2075 + }
161.2076 + }
161.2077 +
161.2078 + /** From CLR */
161.2079 + private void rotateRight(Entry<K,V> p) {
161.2080 + if (p != null) {
161.2081 + Entry<K,V> l = p.left;
161.2082 + p.left = l.right;
161.2083 + if (l.right != null) l.right.parent = p;
161.2084 + l.parent = p.parent;
161.2085 + if (p.parent == null)
161.2086 + root = l;
161.2087 + else if (p.parent.right == p)
161.2088 + p.parent.right = l;
161.2089 + else p.parent.left = l;
161.2090 + l.right = p;
161.2091 + p.parent = l;
161.2092 + }
161.2093 + }
161.2094 +
161.2095 + /** From CLR */
161.2096 + private void fixAfterInsertion(Entry<K,V> x) {
161.2097 + x.color = RED;
161.2098 +
161.2099 + while (x != null && x != root && x.parent.color == RED) {
161.2100 + if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
161.2101 + Entry<K,V> y = rightOf(parentOf(parentOf(x)));
161.2102 + if (colorOf(y) == RED) {
161.2103 + setColor(parentOf(x), BLACK);
161.2104 + setColor(y, BLACK);
161.2105 + setColor(parentOf(parentOf(x)), RED);
161.2106 + x = parentOf(parentOf(x));
161.2107 + } else {
161.2108 + if (x == rightOf(parentOf(x))) {
161.2109 + x = parentOf(x);
161.2110 + rotateLeft(x);
161.2111 + }
161.2112 + setColor(parentOf(x), BLACK);
161.2113 + setColor(parentOf(parentOf(x)), RED);
161.2114 + rotateRight(parentOf(parentOf(x)));
161.2115 + }
161.2116 + } else {
161.2117 + Entry<K,V> y = leftOf(parentOf(parentOf(x)));
161.2118 + if (colorOf(y) == RED) {
161.2119 + setColor(parentOf(x), BLACK);
161.2120 + setColor(y, BLACK);
161.2121 + setColor(parentOf(parentOf(x)), RED);
161.2122 + x = parentOf(parentOf(x));
161.2123 + } else {
161.2124 + if (x == leftOf(parentOf(x))) {
161.2125 + x = parentOf(x);
161.2126 + rotateRight(x);
161.2127 + }
161.2128 + setColor(parentOf(x), BLACK);
161.2129 + setColor(parentOf(parentOf(x)), RED);
161.2130 + rotateLeft(parentOf(parentOf(x)));
161.2131 + }
161.2132 + }
161.2133 + }
161.2134 + root.color = BLACK;
161.2135 + }
161.2136 +
161.2137 + /**
161.2138 + * Delete node p, and then rebalance the tree.
161.2139 + */
161.2140 + private void deleteEntry(Entry<K,V> p) {
161.2141 + modCount++;
161.2142 + size--;
161.2143 +
161.2144 + // If strictly internal, copy successor's element to p and then make p
161.2145 + // point to successor.
161.2146 + if (p.left != null && p.right != null) {
161.2147 + Entry<K,V> s = successor(p);
161.2148 + p.key = s.key;
161.2149 + p.value = s.value;
161.2150 + p = s;
161.2151 + } // p has 2 children
161.2152 +
161.2153 + // Start fixup at replacement node, if it exists.
161.2154 + Entry<K,V> replacement = (p.left != null ? p.left : p.right);
161.2155 +
161.2156 + if (replacement != null) {
161.2157 + // Link replacement to parent
161.2158 + replacement.parent = p.parent;
161.2159 + if (p.parent == null)
161.2160 + root = replacement;
161.2161 + else if (p == p.parent.left)
161.2162 + p.parent.left = replacement;
161.2163 + else
161.2164 + p.parent.right = replacement;
161.2165 +
161.2166 + // Null out links so they are OK to use by fixAfterDeletion.
161.2167 + p.left = p.right = p.parent = null;
161.2168 +
161.2169 + // Fix replacement
161.2170 + if (p.color == BLACK)
161.2171 + fixAfterDeletion(replacement);
161.2172 + } else if (p.parent == null) { // return if we are the only node.
161.2173 + root = null;
161.2174 + } else { // No children. Use self as phantom replacement and unlink.
161.2175 + if (p.color == BLACK)
161.2176 + fixAfterDeletion(p);
161.2177 +
161.2178 + if (p.parent != null) {
161.2179 + if (p == p.parent.left)
161.2180 + p.parent.left = null;
161.2181 + else if (p == p.parent.right)
161.2182 + p.parent.right = null;
161.2183 + p.parent = null;
161.2184 + }
161.2185 + }
161.2186 + }
161.2187 +
161.2188 + /** From CLR */
161.2189 + private void fixAfterDeletion(Entry<K,V> x) {
161.2190 + while (x != root && colorOf(x) == BLACK) {
161.2191 + if (x == leftOf(parentOf(x))) {
161.2192 + Entry<K,V> sib = rightOf(parentOf(x));
161.2193 +
161.2194 + if (colorOf(sib) == RED) {
161.2195 + setColor(sib, BLACK);
161.2196 + setColor(parentOf(x), RED);
161.2197 + rotateLeft(parentOf(x));
161.2198 + sib = rightOf(parentOf(x));
161.2199 + }
161.2200 +
161.2201 + if (colorOf(leftOf(sib)) == BLACK &&
161.2202 + colorOf(rightOf(sib)) == BLACK) {
161.2203 + setColor(sib, RED);
161.2204 + x = parentOf(x);
161.2205 + } else {
161.2206 + if (colorOf(rightOf(sib)) == BLACK) {
161.2207 + setColor(leftOf(sib), BLACK);
161.2208 + setColor(sib, RED);
161.2209 + rotateRight(sib);
161.2210 + sib = rightOf(parentOf(x));
161.2211 + }
161.2212 + setColor(sib, colorOf(parentOf(x)));
161.2213 + setColor(parentOf(x), BLACK);
161.2214 + setColor(rightOf(sib), BLACK);
161.2215 + rotateLeft(parentOf(x));
161.2216 + x = root;
161.2217 + }
161.2218 + } else { // symmetric
161.2219 + Entry<K,V> sib = leftOf(parentOf(x));
161.2220 +
161.2221 + if (colorOf(sib) == RED) {
161.2222 + setColor(sib, BLACK);
161.2223 + setColor(parentOf(x), RED);
161.2224 + rotateRight(parentOf(x));
161.2225 + sib = leftOf(parentOf(x));
161.2226 + }
161.2227 +
161.2228 + if (colorOf(rightOf(sib)) == BLACK &&
161.2229 + colorOf(leftOf(sib)) == BLACK) {
161.2230 + setColor(sib, RED);
161.2231 + x = parentOf(x);
161.2232 + } else {
161.2233 + if (colorOf(leftOf(sib)) == BLACK) {
161.2234 + setColor(rightOf(sib), BLACK);
161.2235 + setColor(sib, RED);
161.2236 + rotateLeft(sib);
161.2237 + sib = leftOf(parentOf(x));
161.2238 + }
161.2239 + setColor(sib, colorOf(parentOf(x)));
161.2240 + setColor(parentOf(x), BLACK);
161.2241 + setColor(leftOf(sib), BLACK);
161.2242 + rotateRight(parentOf(x));
161.2243 + x = root;
161.2244 + }
161.2245 + }
161.2246 + }
161.2247 +
161.2248 + setColor(x, BLACK);
161.2249 + }
161.2250 +
161.2251 + private static final long serialVersionUID = 919286545866124006L;
161.2252 +
161.2253 + /**
161.2254 + * Save the state of the {@code TreeMap} instance to a stream (i.e.,
161.2255 + * serialize it).
161.2256 + *
161.2257 + * @serialData The <em>size</em> of the TreeMap (the number of key-value
161.2258 + * mappings) is emitted (int), followed by the key (Object)
161.2259 + * and value (Object) for each key-value mapping represented
161.2260 + * by the TreeMap. The key-value mappings are emitted in
161.2261 + * key-order (as determined by the TreeMap's Comparator,
161.2262 + * or by the keys' natural ordering if the TreeMap has no
161.2263 + * Comparator).
161.2264 + */
161.2265 + private void writeObject(java.io.ObjectOutputStream s)
161.2266 + throws java.io.IOException {
161.2267 + // Write out the Comparator and any hidden stuff
161.2268 + s.defaultWriteObject();
161.2269 +
161.2270 + // Write out size (number of Mappings)
161.2271 + s.writeInt(size);
161.2272 +
161.2273 + // Write out keys and values (alternating)
161.2274 + for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
161.2275 + Map.Entry<K,V> e = i.next();
161.2276 + s.writeObject(e.getKey());
161.2277 + s.writeObject(e.getValue());
161.2278 + }
161.2279 + }
161.2280 +
161.2281 + /**
161.2282 + * Reconstitute the {@code TreeMap} instance from a stream (i.e.,
161.2283 + * deserialize it).
161.2284 + */
161.2285 + private void readObject(final java.io.ObjectInputStream s)
161.2286 + throws java.io.IOException, ClassNotFoundException {
161.2287 + // Read in the Comparator and any hidden stuff
161.2288 + s.defaultReadObject();
161.2289 +
161.2290 + // Read in size
161.2291 + int size = s.readInt();
161.2292 +
161.2293 + buildFromSorted(size, null, s, null);
161.2294 + }
161.2295 +
161.2296 + /** Intended to be called only from TreeSet.readObject */
161.2297 + void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)
161.2298 + throws java.io.IOException, ClassNotFoundException {
161.2299 + buildFromSorted(size, null, s, defaultVal);
161.2300 + }
161.2301 +
161.2302 + /** Intended to be called only from TreeSet.addAll */
161.2303 + void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
161.2304 + try {
161.2305 + buildFromSorted(set.size(), set.iterator(), null, defaultVal);
161.2306 + } catch (java.io.IOException cannotHappen) {
161.2307 + } catch (ClassNotFoundException cannotHappen) {
161.2308 + }
161.2309 + }
161.2310 +
161.2311 +
161.2312 + /**
161.2313 + * Linear time tree building algorithm from sorted data. Can accept keys
161.2314 + * and/or values from iterator or stream. This leads to too many
161.2315 + * parameters, but seems better than alternatives. The four formats
161.2316 + * that this method accepts are:
161.2317 + *
161.2318 + * 1) An iterator of Map.Entries. (it != null, defaultVal == null).
161.2319 + * 2) An iterator of keys. (it != null, defaultVal != null).
161.2320 + * 3) A stream of alternating serialized keys and values.
161.2321 + * (it == null, defaultVal == null).
161.2322 + * 4) A stream of serialized keys. (it == null, defaultVal != null).
161.2323 + *
161.2324 + * It is assumed that the comparator of the TreeMap is already set prior
161.2325 + * to calling this method.
161.2326 + *
161.2327 + * @param size the number of keys (or key-value pairs) to be read from
161.2328 + * the iterator or stream
161.2329 + * @param it If non-null, new entries are created from entries
161.2330 + * or keys read from this iterator.
161.2331 + * @param str If non-null, new entries are created from keys and
161.2332 + * possibly values read from this stream in serialized form.
161.2333 + * Exactly one of it and str should be non-null.
161.2334 + * @param defaultVal if non-null, this default value is used for
161.2335 + * each value in the map. If null, each value is read from
161.2336 + * iterator or stream, as described above.
161.2337 + * @throws IOException propagated from stream reads. This cannot
161.2338 + * occur if str is null.
161.2339 + * @throws ClassNotFoundException propagated from readObject.
161.2340 + * This cannot occur if str is null.
161.2341 + */
161.2342 + private void buildFromSorted(int size, Iterator it,
161.2343 + java.io.ObjectInputStream str,
161.2344 + V defaultVal)
161.2345 + throws java.io.IOException, ClassNotFoundException {
161.2346 + this.size = size;
161.2347 + root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
161.2348 + it, str, defaultVal);
161.2349 + }
161.2350 +
161.2351 + /**
161.2352 + * Recursive "helper method" that does the real work of the
161.2353 + * previous method. Identically named parameters have
161.2354 + * identical definitions. Additional parameters are documented below.
161.2355 + * It is assumed that the comparator and size fields of the TreeMap are
161.2356 + * already set prior to calling this method. (It ignores both fields.)
161.2357 + *
161.2358 + * @param level the current level of tree. Initial call should be 0.
161.2359 + * @param lo the first element index of this subtree. Initial should be 0.
161.2360 + * @param hi the last element index of this subtree. Initial should be
161.2361 + * size-1.
161.2362 + * @param redLevel the level at which nodes should be red.
161.2363 + * Must be equal to computeRedLevel for tree of this size.
161.2364 + */
161.2365 + private final Entry<K,V> buildFromSorted(int level, int lo, int hi,
161.2366 + int redLevel,
161.2367 + Iterator it,
161.2368 + java.io.ObjectInputStream str,
161.2369 + V defaultVal)
161.2370 + throws java.io.IOException, ClassNotFoundException {
161.2371 + /*
161.2372 + * Strategy: The root is the middlemost element. To get to it, we
161.2373 + * have to first recursively construct the entire left subtree,
161.2374 + * so as to grab all of its elements. We can then proceed with right
161.2375 + * subtree.
161.2376 + *
161.2377 + * The lo and hi arguments are the minimum and maximum
161.2378 + * indices to pull out of the iterator or stream for current subtree.
161.2379 + * They are not actually indexed, we just proceed sequentially,
161.2380 + * ensuring that items are extracted in corresponding order.
161.2381 + */
161.2382 +
161.2383 + if (hi < lo) return null;
161.2384 +
161.2385 + int mid = (lo + hi) >>> 1;
161.2386 +
161.2387 + Entry<K,V> left = null;
161.2388 + if (lo < mid)
161.2389 + left = buildFromSorted(level+1, lo, mid - 1, redLevel,
161.2390 + it, str, defaultVal);
161.2391 +
161.2392 + // extract key and/or value from iterator or stream
161.2393 + K key;
161.2394 + V value;
161.2395 + if (it != null) {
161.2396 + if (defaultVal==null) {
161.2397 + Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
161.2398 + key = entry.getKey();
161.2399 + value = entry.getValue();
161.2400 + } else {
161.2401 + key = (K)it.next();
161.2402 + value = defaultVal;
161.2403 + }
161.2404 + } else { // use stream
161.2405 + key = (K) str.readObject();
161.2406 + value = (defaultVal != null ? defaultVal : (V) str.readObject());
161.2407 + }
161.2408 +
161.2409 + Entry<K,V> middle = new Entry<>(key, value, null);
161.2410 +
161.2411 + // color nodes in non-full bottommost level red
161.2412 + if (level == redLevel)
161.2413 + middle.color = RED;
161.2414 +
161.2415 + if (left != null) {
161.2416 + middle.left = left;
161.2417 + left.parent = middle;
161.2418 + }
161.2419 +
161.2420 + if (mid < hi) {
161.2421 + Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
161.2422 + it, str, defaultVal);
161.2423 + middle.right = right;
161.2424 + right.parent = middle;
161.2425 + }
161.2426 +
161.2427 + return middle;
161.2428 + }
161.2429 +
161.2430 + /**
161.2431 + * Find the level down to which to assign all nodes BLACK. This is the
161.2432 + * last `full' level of the complete binary tree produced by
161.2433 + * buildTree. The remaining nodes are colored RED. (This makes a `nice'
161.2434 + * set of color assignments wrt future insertions.) This level number is
161.2435 + * computed by finding the number of splits needed to reach the zeroeth
161.2436 + * node. (The answer is ~lg(N), but in any case must be computed by same
161.2437 + * quick O(lg(N)) loop.)
161.2438 + */
161.2439 + private static int computeRedLevel(int sz) {
161.2440 + int level = 0;
161.2441 + for (int m = sz - 1; m >= 0; m = m / 2 - 1)
161.2442 + level++;
161.2443 + return level;
161.2444 + }
161.2445 +}
162.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
162.2 +++ b/rt/emul/compact/src/main/java/java/util/TreeSet.java Mon Oct 07 14:20:58 2013 +0200
162.3 @@ -0,0 +1,539 @@
162.4 +/*
162.5 + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
162.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
162.7 + *
162.8 + * This code is free software; you can redistribute it and/or modify it
162.9 + * under the terms of the GNU General Public License version 2 only, as
162.10 + * published by the Free Software Foundation. Oracle designates this
162.11 + * particular file as subject to the "Classpath" exception as provided
162.12 + * by Oracle in the LICENSE file that accompanied this code.
162.13 + *
162.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
162.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
162.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
162.17 + * version 2 for more details (a copy is included in the LICENSE file that
162.18 + * accompanied this code).
162.19 + *
162.20 + * You should have received a copy of the GNU General Public License version
162.21 + * 2 along with this work; if not, write to the Free Software Foundation,
162.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
162.23 + *
162.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
162.25 + * or visit www.oracle.com if you need additional information or have any
162.26 + * questions.
162.27 + */
162.28 +
162.29 +package java.util;
162.30 +
162.31 +/**
162.32 + * A {@link NavigableSet} implementation based on a {@link TreeMap}.
162.33 + * The elements are ordered using their {@linkplain Comparable natural
162.34 + * ordering}, or by a {@link Comparator} provided at set creation
162.35 + * time, depending on which constructor is used.
162.36 + *
162.37 + * <p>This implementation provides guaranteed log(n) time cost for the basic
162.38 + * operations ({@code add}, {@code remove} and {@code contains}).
162.39 + *
162.40 + * <p>Note that the ordering maintained by a set (whether or not an explicit
162.41 + * comparator is provided) must be <i>consistent with equals</i> if it is to
162.42 + * correctly implement the {@code Set} interface. (See {@code Comparable}
162.43 + * or {@code Comparator} for a precise definition of <i>consistent with
162.44 + * equals</i>.) This is so because the {@code Set} interface is defined in
162.45 + * terms of the {@code equals} operation, but a {@code TreeSet} instance
162.46 + * performs all element comparisons using its {@code compareTo} (or
162.47 + * {@code compare}) method, so two elements that are deemed equal by this method
162.48 + * are, from the standpoint of the set, equal. The behavior of a set
162.49 + * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
162.50 + * just fails to obey the general contract of the {@code Set} interface.
162.51 + *
162.52 + * <p><strong>Note that this implementation is not synchronized.</strong>
162.53 + * If multiple threads access a tree set concurrently, and at least one
162.54 + * of the threads modifies the set, it <i>must</i> be synchronized
162.55 + * externally. This is typically accomplished by synchronizing on some
162.56 + * object that naturally encapsulates the set.
162.57 + * If no such object exists, the set should be "wrapped" using the
162.58 + * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
162.59 + * method. This is best done at creation time, to prevent accidental
162.60 + * unsynchronized access to the set: <pre>
162.61 + * SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
162.62 + *
162.63 + * <p>The iterators returned by this class's {@code iterator} method are
162.64 + * <i>fail-fast</i>: if the set is modified at any time after the iterator is
162.65 + * created, in any way except through the iterator's own {@code remove}
162.66 + * method, the iterator will throw a {@link ConcurrentModificationException}.
162.67 + * Thus, in the face of concurrent modification, the iterator fails quickly
162.68 + * and cleanly, rather than risking arbitrary, non-deterministic behavior at
162.69 + * an undetermined time in the future.
162.70 + *
162.71 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
162.72 + * as it is, generally speaking, impossible to make any hard guarantees in the
162.73 + * presence of unsynchronized concurrent modification. Fail-fast iterators
162.74 + * throw {@code ConcurrentModificationException} on a best-effort basis.
162.75 + * Therefore, it would be wrong to write a program that depended on this
162.76 + * exception for its correctness: <i>the fail-fast behavior of iterators
162.77 + * should be used only to detect bugs.</i>
162.78 + *
162.79 + * <p>This class is a member of the
162.80 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
162.81 + * Java Collections Framework</a>.
162.82 + *
162.83 + * @param <E> the type of elements maintained by this set
162.84 + *
162.85 + * @author Josh Bloch
162.86 + * @see Collection
162.87 + * @see Set
162.88 + * @see HashSet
162.89 + * @see Comparable
162.90 + * @see Comparator
162.91 + * @see TreeMap
162.92 + * @since 1.2
162.93 + */
162.94 +
162.95 +public class TreeSet<E> extends AbstractSet<E>
162.96 + implements NavigableSet<E>, Cloneable, java.io.Serializable
162.97 +{
162.98 + /**
162.99 + * The backing map.
162.100 + */
162.101 + private transient NavigableMap<E,Object> m;
162.102 +
162.103 + // Dummy value to associate with an Object in the backing Map
162.104 + private static final Object PRESENT = new Object();
162.105 +
162.106 + /**
162.107 + * Constructs a set backed by the specified navigable map.
162.108 + */
162.109 + TreeSet(NavigableMap<E,Object> m) {
162.110 + this.m = m;
162.111 + }
162.112 +
162.113 + /**
162.114 + * Constructs a new, empty tree set, sorted according to the
162.115 + * natural ordering of its elements. All elements inserted into
162.116 + * the set must implement the {@link Comparable} interface.
162.117 + * Furthermore, all such elements must be <i>mutually
162.118 + * comparable</i>: {@code e1.compareTo(e2)} must not throw a
162.119 + * {@code ClassCastException} for any elements {@code e1} and
162.120 + * {@code e2} in the set. If the user attempts to add an element
162.121 + * to the set that violates this constraint (for example, the user
162.122 + * attempts to add a string element to a set whose elements are
162.123 + * integers), the {@code add} call will throw a
162.124 + * {@code ClassCastException}.
162.125 + */
162.126 + public TreeSet() {
162.127 + this(new TreeMap<E,Object>());
162.128 + }
162.129 +
162.130 + /**
162.131 + * Constructs a new, empty tree set, sorted according to the specified
162.132 + * comparator. All elements inserted into the set must be <i>mutually
162.133 + * comparable</i> by the specified comparator: {@code comparator.compare(e1,
162.134 + * e2)} must not throw a {@code ClassCastException} for any elements
162.135 + * {@code e1} and {@code e2} in the set. If the user attempts to add
162.136 + * an element to the set that violates this constraint, the
162.137 + * {@code add} call will throw a {@code ClassCastException}.
162.138 + *
162.139 + * @param comparator the comparator that will be used to order this set.
162.140 + * If {@code null}, the {@linkplain Comparable natural
162.141 + * ordering} of the elements will be used.
162.142 + */
162.143 + public TreeSet(Comparator<? super E> comparator) {
162.144 + this(new TreeMap<>(comparator));
162.145 + }
162.146 +
162.147 + /**
162.148 + * Constructs a new tree set containing the elements in the specified
162.149 + * collection, sorted according to the <i>natural ordering</i> of its
162.150 + * elements. All elements inserted into the set must implement the
162.151 + * {@link Comparable} interface. Furthermore, all such elements must be
162.152 + * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
162.153 + * {@code ClassCastException} for any elements {@code e1} and
162.154 + * {@code e2} in the set.
162.155 + *
162.156 + * @param c collection whose elements will comprise the new set
162.157 + * @throws ClassCastException if the elements in {@code c} are
162.158 + * not {@link Comparable}, or are not mutually comparable
162.159 + * @throws NullPointerException if the specified collection is null
162.160 + */
162.161 + public TreeSet(Collection<? extends E> c) {
162.162 + this();
162.163 + addAll(c);
162.164 + }
162.165 +
162.166 + /**
162.167 + * Constructs a new tree set containing the same elements and
162.168 + * using the same ordering as the specified sorted set.
162.169 + *
162.170 + * @param s sorted set whose elements will comprise the new set
162.171 + * @throws NullPointerException if the specified sorted set is null
162.172 + */
162.173 + public TreeSet(SortedSet<E> s) {
162.174 + this(s.comparator());
162.175 + addAll(s);
162.176 + }
162.177 +
162.178 + /**
162.179 + * Returns an iterator over the elements in this set in ascending order.
162.180 + *
162.181 + * @return an iterator over the elements in this set in ascending order
162.182 + */
162.183 + public Iterator<E> iterator() {
162.184 + return m.navigableKeySet().iterator();
162.185 + }
162.186 +
162.187 + /**
162.188 + * Returns an iterator over the elements in this set in descending order.
162.189 + *
162.190 + * @return an iterator over the elements in this set in descending order
162.191 + * @since 1.6
162.192 + */
162.193 + public Iterator<E> descendingIterator() {
162.194 + return m.descendingKeySet().iterator();
162.195 + }
162.196 +
162.197 + /**
162.198 + * @since 1.6
162.199 + */
162.200 + public NavigableSet<E> descendingSet() {
162.201 + return new TreeSet<>(m.descendingMap());
162.202 + }
162.203 +
162.204 + /**
162.205 + * Returns the number of elements in this set (its cardinality).
162.206 + *
162.207 + * @return the number of elements in this set (its cardinality)
162.208 + */
162.209 + public int size() {
162.210 + return m.size();
162.211 + }
162.212 +
162.213 + /**
162.214 + * Returns {@code true} if this set contains no elements.
162.215 + *
162.216 + * @return {@code true} if this set contains no elements
162.217 + */
162.218 + public boolean isEmpty() {
162.219 + return m.isEmpty();
162.220 + }
162.221 +
162.222 + /**
162.223 + * Returns {@code true} if this set contains the specified element.
162.224 + * More formally, returns {@code true} if and only if this set
162.225 + * contains an element {@code e} such that
162.226 + * <tt>(o==null ? e==null : o.equals(e))</tt>.
162.227 + *
162.228 + * @param o object to be checked for containment in this set
162.229 + * @return {@code true} if this set contains the specified element
162.230 + * @throws ClassCastException if the specified object cannot be compared
162.231 + * with the elements currently in the set
162.232 + * @throws NullPointerException if the specified element is null
162.233 + * and this set uses natural ordering, or its comparator
162.234 + * does not permit null elements
162.235 + */
162.236 + public boolean contains(Object o) {
162.237 + return m.containsKey(o);
162.238 + }
162.239 +
162.240 + /**
162.241 + * Adds the specified element to this set if it is not already present.
162.242 + * More formally, adds the specified element {@code e} to this set if
162.243 + * the set contains no element {@code e2} such that
162.244 + * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
162.245 + * If this set already contains the element, the call leaves the set
162.246 + * unchanged and returns {@code false}.
162.247 + *
162.248 + * @param e element to be added to this set
162.249 + * @return {@code true} if this set did not already contain the specified
162.250 + * element
162.251 + * @throws ClassCastException if the specified object cannot be compared
162.252 + * with the elements currently in this set
162.253 + * @throws NullPointerException if the specified element is null
162.254 + * and this set uses natural ordering, or its comparator
162.255 + * does not permit null elements
162.256 + */
162.257 + public boolean add(E e) {
162.258 + return m.put(e, PRESENT)==null;
162.259 + }
162.260 +
162.261 + /**
162.262 + * Removes the specified element from this set if it is present.
162.263 + * More formally, removes an element {@code e} such that
162.264 + * <tt>(o==null ? e==null : o.equals(e))</tt>,
162.265 + * if this set contains such an element. Returns {@code true} if
162.266 + * this set contained the element (or equivalently, if this set
162.267 + * changed as a result of the call). (This set will not contain the
162.268 + * element once the call returns.)
162.269 + *
162.270 + * @param o object to be removed from this set, if present
162.271 + * @return {@code true} if this set contained the specified element
162.272 + * @throws ClassCastException if the specified object cannot be compared
162.273 + * with the elements currently in this set
162.274 + * @throws NullPointerException if the specified element is null
162.275 + * and this set uses natural ordering, or its comparator
162.276 + * does not permit null elements
162.277 + */
162.278 + public boolean remove(Object o) {
162.279 + return m.remove(o)==PRESENT;
162.280 + }
162.281 +
162.282 + /**
162.283 + * Removes all of the elements from this set.
162.284 + * The set will be empty after this call returns.
162.285 + */
162.286 + public void clear() {
162.287 + m.clear();
162.288 + }
162.289 +
162.290 + /**
162.291 + * Adds all of the elements in the specified collection to this set.
162.292 + *
162.293 + * @param c collection containing elements to be added to this set
162.294 + * @return {@code true} if this set changed as a result of the call
162.295 + * @throws ClassCastException if the elements provided cannot be compared
162.296 + * with the elements currently in the set
162.297 + * @throws NullPointerException if the specified collection is null or
162.298 + * if any element is null and this set uses natural ordering, or
162.299 + * its comparator does not permit null elements
162.300 + */
162.301 + public boolean addAll(Collection<? extends E> c) {
162.302 + // Use linear-time version if applicable
162.303 + if (m.size()==0 && c.size() > 0 &&
162.304 + c instanceof SortedSet &&
162.305 + m instanceof TreeMap) {
162.306 + SortedSet<? extends E> set = (SortedSet<? extends E>) c;
162.307 + TreeMap<E,Object> map = (TreeMap<E, Object>) m;
162.308 + Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
162.309 + Comparator<? super E> mc = map.comparator();
162.310 + if (cc==mc || (cc != null && cc.equals(mc))) {
162.311 + map.addAllForTreeSet(set, PRESENT);
162.312 + return true;
162.313 + }
162.314 + }
162.315 + return super.addAll(c);
162.316 + }
162.317 +
162.318 + /**
162.319 + * @throws ClassCastException {@inheritDoc}
162.320 + * @throws NullPointerException if {@code fromElement} or {@code toElement}
162.321 + * is null and this set uses natural ordering, or its comparator
162.322 + * does not permit null elements
162.323 + * @throws IllegalArgumentException {@inheritDoc}
162.324 + * @since 1.6
162.325 + */
162.326 + public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
162.327 + E toElement, boolean toInclusive) {
162.328 + return new TreeSet<>(m.subMap(fromElement, fromInclusive,
162.329 + toElement, toInclusive));
162.330 + }
162.331 +
162.332 + /**
162.333 + * @throws ClassCastException {@inheritDoc}
162.334 + * @throws NullPointerException if {@code toElement} is null and
162.335 + * this set uses natural ordering, or its comparator does
162.336 + * not permit null elements
162.337 + * @throws IllegalArgumentException {@inheritDoc}
162.338 + * @since 1.6
162.339 + */
162.340 + public NavigableSet<E> headSet(E toElement, boolean inclusive) {
162.341 + return new TreeSet<>(m.headMap(toElement, inclusive));
162.342 + }
162.343 +
162.344 + /**
162.345 + * @throws ClassCastException {@inheritDoc}
162.346 + * @throws NullPointerException if {@code fromElement} is null and
162.347 + * this set uses natural ordering, or its comparator does
162.348 + * not permit null elements
162.349 + * @throws IllegalArgumentException {@inheritDoc}
162.350 + * @since 1.6
162.351 + */
162.352 + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
162.353 + return new TreeSet<>(m.tailMap(fromElement, inclusive));
162.354 + }
162.355 +
162.356 + /**
162.357 + * @throws ClassCastException {@inheritDoc}
162.358 + * @throws NullPointerException if {@code fromElement} or
162.359 + * {@code toElement} is null and this set uses natural ordering,
162.360 + * or its comparator does not permit null elements
162.361 + * @throws IllegalArgumentException {@inheritDoc}
162.362 + */
162.363 + public SortedSet<E> subSet(E fromElement, E toElement) {
162.364 + return subSet(fromElement, true, toElement, false);
162.365 + }
162.366 +
162.367 + /**
162.368 + * @throws ClassCastException {@inheritDoc}
162.369 + * @throws NullPointerException if {@code toElement} is null
162.370 + * and this set uses natural ordering, or its comparator does
162.371 + * not permit null elements
162.372 + * @throws IllegalArgumentException {@inheritDoc}
162.373 + */
162.374 + public SortedSet<E> headSet(E toElement) {
162.375 + return headSet(toElement, false);
162.376 + }
162.377 +
162.378 + /**
162.379 + * @throws ClassCastException {@inheritDoc}
162.380 + * @throws NullPointerException if {@code fromElement} is null
162.381 + * and this set uses natural ordering, or its comparator does
162.382 + * not permit null elements
162.383 + * @throws IllegalArgumentException {@inheritDoc}
162.384 + */
162.385 + public SortedSet<E> tailSet(E fromElement) {
162.386 + return tailSet(fromElement, true);
162.387 + }
162.388 +
162.389 + public Comparator<? super E> comparator() {
162.390 + return m.comparator();
162.391 + }
162.392 +
162.393 + /**
162.394 + * @throws NoSuchElementException {@inheritDoc}
162.395 + */
162.396 + public E first() {
162.397 + return m.firstKey();
162.398 + }
162.399 +
162.400 + /**
162.401 + * @throws NoSuchElementException {@inheritDoc}
162.402 + */
162.403 + public E last() {
162.404 + return m.lastKey();
162.405 + }
162.406 +
162.407 + // NavigableSet API methods
162.408 +
162.409 + /**
162.410 + * @throws ClassCastException {@inheritDoc}
162.411 + * @throws NullPointerException if the specified element is null
162.412 + * and this set uses natural ordering, or its comparator
162.413 + * does not permit null elements
162.414 + * @since 1.6
162.415 + */
162.416 + public E lower(E e) {
162.417 + return m.lowerKey(e);
162.418 + }
162.419 +
162.420 + /**
162.421 + * @throws ClassCastException {@inheritDoc}
162.422 + * @throws NullPointerException if the specified element is null
162.423 + * and this set uses natural ordering, or its comparator
162.424 + * does not permit null elements
162.425 + * @since 1.6
162.426 + */
162.427 + public E floor(E e) {
162.428 + return m.floorKey(e);
162.429 + }
162.430 +
162.431 + /**
162.432 + * @throws ClassCastException {@inheritDoc}
162.433 + * @throws NullPointerException if the specified element is null
162.434 + * and this set uses natural ordering, or its comparator
162.435 + * does not permit null elements
162.436 + * @since 1.6
162.437 + */
162.438 + public E ceiling(E e) {
162.439 + return m.ceilingKey(e);
162.440 + }
162.441 +
162.442 + /**
162.443 + * @throws ClassCastException {@inheritDoc}
162.444 + * @throws NullPointerException if the specified element is null
162.445 + * and this set uses natural ordering, or its comparator
162.446 + * does not permit null elements
162.447 + * @since 1.6
162.448 + */
162.449 + public E higher(E e) {
162.450 + return m.higherKey(e);
162.451 + }
162.452 +
162.453 + /**
162.454 + * @since 1.6
162.455 + */
162.456 + public E pollFirst() {
162.457 + Map.Entry<E,?> e = m.pollFirstEntry();
162.458 + return (e == null) ? null : e.getKey();
162.459 + }
162.460 +
162.461 + /**
162.462 + * @since 1.6
162.463 + */
162.464 + public E pollLast() {
162.465 + Map.Entry<E,?> e = m.pollLastEntry();
162.466 + return (e == null) ? null : e.getKey();
162.467 + }
162.468 +
162.469 + /**
162.470 + * Returns a shallow copy of this {@code TreeSet} instance. (The elements
162.471 + * themselves are not cloned.)
162.472 + *
162.473 + * @return a shallow copy of this set
162.474 + */
162.475 + public Object clone() {
162.476 + TreeSet<E> clone = null;
162.477 + try {
162.478 + clone = (TreeSet<E>) super.clone();
162.479 + } catch (CloneNotSupportedException e) {
162.480 + throw new InternalError();
162.481 + }
162.482 +
162.483 + clone.m = new TreeMap<>(m);
162.484 + return clone;
162.485 + }
162.486 +
162.487 + /**
162.488 + * Save the state of the {@code TreeSet} instance to a stream (that is,
162.489 + * serialize it).
162.490 + *
162.491 + * @serialData Emits the comparator used to order this set, or
162.492 + * {@code null} if it obeys its elements' natural ordering
162.493 + * (Object), followed by the size of the set (the number of
162.494 + * elements it contains) (int), followed by all of its
162.495 + * elements (each an Object) in order (as determined by the
162.496 + * set's Comparator, or by the elements' natural ordering if
162.497 + * the set has no Comparator).
162.498 + */
162.499 + private void writeObject(java.io.ObjectOutputStream s)
162.500 + throws java.io.IOException {
162.501 + // Write out any hidden stuff
162.502 + s.defaultWriteObject();
162.503 +
162.504 + // Write out Comparator
162.505 + s.writeObject(m.comparator());
162.506 +
162.507 + // Write out size
162.508 + s.writeInt(m.size());
162.509 +
162.510 + // Write out all elements in the proper order.
162.511 + for (E e : m.keySet())
162.512 + s.writeObject(e);
162.513 + }
162.514 +
162.515 + /**
162.516 + * Reconstitute the {@code TreeSet} instance from a stream (that is,
162.517 + * deserialize it).
162.518 + */
162.519 + private void readObject(java.io.ObjectInputStream s)
162.520 + throws java.io.IOException, ClassNotFoundException {
162.521 + // Read in any hidden stuff
162.522 + s.defaultReadObject();
162.523 +
162.524 + // Read in Comparator
162.525 + Comparator<? super E> c = (Comparator<? super E>) s.readObject();
162.526 +
162.527 + // Create backing TreeMap
162.528 + TreeMap<E,Object> tm;
162.529 + if (c==null)
162.530 + tm = new TreeMap<>();
162.531 + else
162.532 + tm = new TreeMap<>(c);
162.533 + m = tm;
162.534 +
162.535 + // Read in size
162.536 + int size = s.readInt();
162.537 +
162.538 + tm.readTreeSet(size, s, PRESENT);
162.539 + }
162.540 +
162.541 + private static final long serialVersionUID = -2479143000061671589L;
162.542 +}
163.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
163.2 +++ b/rt/emul/compact/src/main/java/java/util/WeakHashMap.java Mon Oct 07 14:20:58 2013 +0200
163.3 @@ -0,0 +1,972 @@
163.4 +/*
163.5 + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
163.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
163.7 + *
163.8 + * This code is free software; you can redistribute it and/or modify it
163.9 + * under the terms of the GNU General Public License version 2 only, as
163.10 + * published by the Free Software Foundation. Oracle designates this
163.11 + * particular file as subject to the "Classpath" exception as provided
163.12 + * by Oracle in the LICENSE file that accompanied this code.
163.13 + *
163.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
163.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
163.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
163.17 + * version 2 for more details (a copy is included in the LICENSE file that
163.18 + * accompanied this code).
163.19 + *
163.20 + * You should have received a copy of the GNU General Public License version
163.21 + * 2 along with this work; if not, write to the Free Software Foundation,
163.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
163.23 + *
163.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
163.25 + * or visit www.oracle.com if you need additional information or have any
163.26 + * questions.
163.27 + */
163.28 +
163.29 +package java.util;
163.30 +import java.lang.ref.WeakReference;
163.31 +import java.lang.ref.ReferenceQueue;
163.32 +
163.33 +
163.34 +/**
163.35 + * Hash table based implementation of the <tt>Map</tt> interface, with
163.36 + * <em>weak keys</em>.
163.37 + * An entry in a <tt>WeakHashMap</tt> will automatically be removed when
163.38 + * its key is no longer in ordinary use. More precisely, the presence of a
163.39 + * mapping for a given key will not prevent the key from being discarded by the
163.40 + * garbage collector, that is, made finalizable, finalized, and then reclaimed.
163.41 + * When a key has been discarded its entry is effectively removed from the map,
163.42 + * so this class behaves somewhat differently from other <tt>Map</tt>
163.43 + * implementations.
163.44 + *
163.45 + * <p> Both null values and the null key are supported. This class has
163.46 + * performance characteristics similar to those of the <tt>HashMap</tt>
163.47 + * class, and has the same efficiency parameters of <em>initial capacity</em>
163.48 + * and <em>load factor</em>.
163.49 + *
163.50 + * <p> Like most collection classes, this class is not synchronized.
163.51 + * A synchronized <tt>WeakHashMap</tt> may be constructed using the
163.52 + * {@link Collections#synchronizedMap Collections.synchronizedMap}
163.53 + * method.
163.54 + *
163.55 + * <p> This class is intended primarily for use with key objects whose
163.56 + * <tt>equals</tt> methods test for object identity using the
163.57 + * <tt>==</tt> operator. Once such a key is discarded it can never be
163.58 + * recreated, so it is impossible to do a lookup of that key in a
163.59 + * <tt>WeakHashMap</tt> at some later time and be surprised that its entry
163.60 + * has been removed. This class will work perfectly well with key objects
163.61 + * whose <tt>equals</tt> methods are not based upon object identity, such
163.62 + * as <tt>String</tt> instances. With such recreatable key objects,
163.63 + * however, the automatic removal of <tt>WeakHashMap</tt> entries whose
163.64 + * keys have been discarded may prove to be confusing.
163.65 + *
163.66 + * <p> The behavior of the <tt>WeakHashMap</tt> class depends in part upon
163.67 + * the actions of the garbage collector, so several familiar (though not
163.68 + * required) <tt>Map</tt> invariants do not hold for this class. Because
163.69 + * the garbage collector may discard keys at any time, a
163.70 + * <tt>WeakHashMap</tt> may behave as though an unknown thread is silently
163.71 + * removing entries. In particular, even if you synchronize on a
163.72 + * <tt>WeakHashMap</tt> instance and invoke none of its mutator methods, it
163.73 + * is possible for the <tt>size</tt> method to return smaller values over
163.74 + * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and
163.75 + * then <tt>true</tt>, for the <tt>containsKey</tt> method to return
163.76 + * <tt>true</tt> and later <tt>false</tt> for a given key, for the
163.77 + * <tt>get</tt> method to return a value for a given key but later return
163.78 + * <tt>null</tt>, for the <tt>put</tt> method to return
163.79 + * <tt>null</tt> and the <tt>remove</tt> method to return
163.80 + * <tt>false</tt> for a key that previously appeared to be in the map, and
163.81 + * for successive examinations of the key set, the value collection, and
163.82 + * the entry set to yield successively smaller numbers of elements.
163.83 + *
163.84 + * <p> Each key object in a <tt>WeakHashMap</tt> is stored indirectly as
163.85 + * the referent of a weak reference. Therefore a key will automatically be
163.86 + * removed only after the weak references to it, both inside and outside of the
163.87 + * map, have been cleared by the garbage collector.
163.88 + *
163.89 + * <p> <strong>Implementation note:</strong> The value objects in a
163.90 + * <tt>WeakHashMap</tt> are held by ordinary strong references. Thus care
163.91 + * should be taken to ensure that value objects do not strongly refer to their
163.92 + * own keys, either directly or indirectly, since that will prevent the keys
163.93 + * from being discarded. Note that a value object may refer indirectly to its
163.94 + * key via the <tt>WeakHashMap</tt> itself; that is, a value object may
163.95 + * strongly refer to some other key object whose associated value object, in
163.96 + * turn, strongly refers to the key of the first value object. One way
163.97 + * to deal with this is to wrap values themselves within
163.98 + * <tt>WeakReferences</tt> before
163.99 + * inserting, as in: <tt>m.put(key, new WeakReference(value))</tt>,
163.100 + * and then unwrapping upon each <tt>get</tt>.
163.101 + *
163.102 + * <p>The iterators returned by the <tt>iterator</tt> method of the collections
163.103 + * returned by all of this class's "collection view methods" are
163.104 + * <i>fail-fast</i>: if the map is structurally modified at any time after the
163.105 + * iterator is created, in any way except through the iterator's own
163.106 + * <tt>remove</tt> method, the iterator will throw a {@link
163.107 + * ConcurrentModificationException}. Thus, in the face of concurrent
163.108 + * modification, the iterator fails quickly and cleanly, rather than risking
163.109 + * arbitrary, non-deterministic behavior at an undetermined time in the future.
163.110 + *
163.111 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
163.112 + * as it is, generally speaking, impossible to make any hard guarantees in the
163.113 + * presence of unsynchronized concurrent modification. Fail-fast iterators
163.114 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
163.115 + * Therefore, it would be wrong to write a program that depended on this
163.116 + * exception for its correctness: <i>the fail-fast behavior of iterators
163.117 + * should be used only to detect bugs.</i>
163.118 + *
163.119 + * <p>This class is a member of the
163.120 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
163.121 + * Java Collections Framework</a>.
163.122 + *
163.123 + * @param <K> the type of keys maintained by this map
163.124 + * @param <V> the type of mapped values
163.125 + *
163.126 + * @author Doug Lea
163.127 + * @author Josh Bloch
163.128 + * @author Mark Reinhold
163.129 + * @since 1.2
163.130 + * @see java.util.HashMap
163.131 + * @see java.lang.ref.WeakReference
163.132 + */
163.133 +public class WeakHashMap<K,V>
163.134 + extends AbstractMap<K,V>
163.135 + implements Map<K,V> {
163.136 +
163.137 + /**
163.138 + * The default initial capacity -- MUST be a power of two.
163.139 + */
163.140 + private static final int DEFAULT_INITIAL_CAPACITY = 16;
163.141 +
163.142 + /**
163.143 + * The maximum capacity, used if a higher value is implicitly specified
163.144 + * by either of the constructors with arguments.
163.145 + * MUST be a power of two <= 1<<30.
163.146 + */
163.147 + private static final int MAXIMUM_CAPACITY = 1 << 30;
163.148 +
163.149 + /**
163.150 + * The load factor used when none specified in constructor.
163.151 + */
163.152 + private static final float DEFAULT_LOAD_FACTOR = 0.75f;
163.153 +
163.154 + /**
163.155 + * The table, resized as necessary. Length MUST Always be a power of two.
163.156 + */
163.157 + Entry<K,V>[] table;
163.158 +
163.159 + /**
163.160 + * The number of key-value mappings contained in this weak hash map.
163.161 + */
163.162 + private int size;
163.163 +
163.164 + /**
163.165 + * The next size value at which to resize (capacity * load factor).
163.166 + */
163.167 + private int threshold;
163.168 +
163.169 + /**
163.170 + * The load factor for the hash table.
163.171 + */
163.172 + private final float loadFactor;
163.173 +
163.174 + /**
163.175 + * Reference queue for cleared WeakEntries
163.176 + */
163.177 + private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
163.178 +
163.179 + /**
163.180 + * The number of times this WeakHashMap has been structurally modified.
163.181 + * Structural modifications are those that change the number of
163.182 + * mappings in the map or otherwise modify its internal structure
163.183 + * (e.g., rehash). This field is used to make iterators on
163.184 + * Collection-views of the map fail-fast.
163.185 + *
163.186 + * @see ConcurrentModificationException
163.187 + */
163.188 + int modCount;
163.189 +
163.190 + @SuppressWarnings("unchecked")
163.191 + private Entry<K,V>[] newTable(int n) {
163.192 + return (Entry<K,V>[]) new Entry[n];
163.193 + }
163.194 +
163.195 + /**
163.196 + * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
163.197 + * capacity and the given load factor.
163.198 + *
163.199 + * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
163.200 + * @param loadFactor The load factor of the <tt>WeakHashMap</tt>
163.201 + * @throws IllegalArgumentException if the initial capacity is negative,
163.202 + * or if the load factor is nonpositive.
163.203 + */
163.204 + public WeakHashMap(int initialCapacity, float loadFactor) {
163.205 + if (initialCapacity < 0)
163.206 + throw new IllegalArgumentException("Illegal Initial Capacity: "+
163.207 + initialCapacity);
163.208 + if (initialCapacity > MAXIMUM_CAPACITY)
163.209 + initialCapacity = MAXIMUM_CAPACITY;
163.210 +
163.211 + if (loadFactor <= 0 || Float.isNaN(loadFactor))
163.212 + throw new IllegalArgumentException("Illegal Load factor: "+
163.213 + loadFactor);
163.214 + int capacity = 1;
163.215 + while (capacity < initialCapacity)
163.216 + capacity <<= 1;
163.217 + table = newTable(capacity);
163.218 + this.loadFactor = loadFactor;
163.219 + threshold = (int)(capacity * loadFactor);
163.220 + }
163.221 +
163.222 + /**
163.223 + * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
163.224 + * capacity and the default load factor (0.75).
163.225 + *
163.226 + * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
163.227 + * @throws IllegalArgumentException if the initial capacity is negative
163.228 + */
163.229 + public WeakHashMap(int initialCapacity) {
163.230 + this(initialCapacity, DEFAULT_LOAD_FACTOR);
163.231 + }
163.232 +
163.233 + /**
163.234 + * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial
163.235 + * capacity (16) and load factor (0.75).
163.236 + */
163.237 + public WeakHashMap() {
163.238 + this.loadFactor = DEFAULT_LOAD_FACTOR;
163.239 + threshold = DEFAULT_INITIAL_CAPACITY;
163.240 + table = newTable(DEFAULT_INITIAL_CAPACITY);
163.241 + }
163.242 +
163.243 + /**
163.244 + * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the
163.245 + * specified map. The <tt>WeakHashMap</tt> is created with the default
163.246 + * load factor (0.75) and an initial capacity sufficient to hold the
163.247 + * mappings in the specified map.
163.248 + *
163.249 + * @param m the map whose mappings are to be placed in this map
163.250 + * @throws NullPointerException if the specified map is null
163.251 + * @since 1.3
163.252 + */
163.253 + public WeakHashMap(Map<? extends K, ? extends V> m) {
163.254 + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
163.255 + DEFAULT_LOAD_FACTOR);
163.256 + putAll(m);
163.257 + }
163.258 +
163.259 + // internal utilities
163.260 +
163.261 + /**
163.262 + * Value representing null keys inside tables.
163.263 + */
163.264 + private static final Object NULL_KEY = new Object();
163.265 +
163.266 + /**
163.267 + * Use NULL_KEY for key if it is null.
163.268 + */
163.269 + private static Object maskNull(Object key) {
163.270 + return (key == null) ? NULL_KEY : key;
163.271 + }
163.272 +
163.273 + /**
163.274 + * Returns internal representation of null key back to caller as null.
163.275 + */
163.276 + static Object unmaskNull(Object key) {
163.277 + return (key == NULL_KEY) ? null : key;
163.278 + }
163.279 +
163.280 + /**
163.281 + * Checks for equality of non-null reference x and possibly-null y. By
163.282 + * default uses Object.equals.
163.283 + */
163.284 + private static boolean eq(Object x, Object y) {
163.285 + return x == y || x.equals(y);
163.286 + }
163.287 +
163.288 + /**
163.289 + * Returns index for hash code h.
163.290 + */
163.291 + private static int indexFor(int h, int length) {
163.292 + return h & (length-1);
163.293 + }
163.294 +
163.295 + /**
163.296 + * Expunges stale entries from the table.
163.297 + */
163.298 + private void expungeStaleEntries() {
163.299 + for (Object x; (x = queue.poll()) != null; ) {
163.300 + synchronized (queue) {
163.301 + @SuppressWarnings("unchecked")
163.302 + Entry<K,V> e = (Entry<K,V>) x;
163.303 + int i = indexFor(e.hash, table.length);
163.304 +
163.305 + Entry<K,V> prev = table[i];
163.306 + Entry<K,V> p = prev;
163.307 + while (p != null) {
163.308 + Entry<K,V> next = p.next;
163.309 + if (p == e) {
163.310 + if (prev == e)
163.311 + table[i] = next;
163.312 + else
163.313 + prev.next = next;
163.314 + // Must not null out e.next;
163.315 + // stale entries may be in use by a HashIterator
163.316 + e.value = null; // Help GC
163.317 + size--;
163.318 + break;
163.319 + }
163.320 + prev = p;
163.321 + p = next;
163.322 + }
163.323 + }
163.324 + }
163.325 + }
163.326 +
163.327 + /**
163.328 + * Returns the table after first expunging stale entries.
163.329 + */
163.330 + private Entry<K,V>[] getTable() {
163.331 + expungeStaleEntries();
163.332 + return table;
163.333 + }
163.334 +
163.335 + /**
163.336 + * Returns the number of key-value mappings in this map.
163.337 + * This result is a snapshot, and may not reflect unprocessed
163.338 + * entries that will be removed before next attempted access
163.339 + * because they are no longer referenced.
163.340 + */
163.341 + public int size() {
163.342 + if (size == 0)
163.343 + return 0;
163.344 + expungeStaleEntries();
163.345 + return size;
163.346 + }
163.347 +
163.348 + /**
163.349 + * Returns <tt>true</tt> if this map contains no key-value mappings.
163.350 + * This result is a snapshot, and may not reflect unprocessed
163.351 + * entries that will be removed before next attempted access
163.352 + * because they are no longer referenced.
163.353 + */
163.354 + public boolean isEmpty() {
163.355 + return size() == 0;
163.356 + }
163.357 +
163.358 + /**
163.359 + * Returns the value to which the specified key is mapped,
163.360 + * or {@code null} if this map contains no mapping for the key.
163.361 + *
163.362 + * <p>More formally, if this map contains a mapping from a key
163.363 + * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
163.364 + * key.equals(k))}, then this method returns {@code v}; otherwise
163.365 + * it returns {@code null}. (There can be at most one such mapping.)
163.366 + *
163.367 + * <p>A return value of {@code null} does not <i>necessarily</i>
163.368 + * indicate that the map contains no mapping for the key; it's also
163.369 + * possible that the map explicitly maps the key to {@code null}.
163.370 + * The {@link #containsKey containsKey} operation may be used to
163.371 + * distinguish these two cases.
163.372 + *
163.373 + * @see #put(Object, Object)
163.374 + */
163.375 + public V get(Object key) {
163.376 + Object k = maskNull(key);
163.377 + int h = HashMap.hash(k.hashCode());
163.378 + Entry<K,V>[] tab = getTable();
163.379 + int index = indexFor(h, tab.length);
163.380 + Entry<K,V> e = tab[index];
163.381 + while (e != null) {
163.382 + if (e.hash == h && eq(k, e.get()))
163.383 + return e.value;
163.384 + e = e.next;
163.385 + }
163.386 + return null;
163.387 + }
163.388 +
163.389 + /**
163.390 + * Returns <tt>true</tt> if this map contains a mapping for the
163.391 + * specified key.
163.392 + *
163.393 + * @param key The key whose presence in this map is to be tested
163.394 + * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
163.395 + * <tt>false</tt> otherwise
163.396 + */
163.397 + public boolean containsKey(Object key) {
163.398 + return getEntry(key) != null;
163.399 + }
163.400 +
163.401 + /**
163.402 + * Returns the entry associated with the specified key in this map.
163.403 + * Returns null if the map contains no mapping for this key.
163.404 + */
163.405 + Entry<K,V> getEntry(Object key) {
163.406 + Object k = maskNull(key);
163.407 + int h = HashMap.hash(k.hashCode());
163.408 + Entry<K,V>[] tab = getTable();
163.409 + int index = indexFor(h, tab.length);
163.410 + Entry<K,V> e = tab[index];
163.411 + while (e != null && !(e.hash == h && eq(k, e.get())))
163.412 + e = e.next;
163.413 + return e;
163.414 + }
163.415 +
163.416 + /**
163.417 + * Associates the specified value with the specified key in this map.
163.418 + * If the map previously contained a mapping for this key, the old
163.419 + * value is replaced.
163.420 + *
163.421 + * @param key key with which the specified value is to be associated.
163.422 + * @param value value to be associated with the specified key.
163.423 + * @return the previous value associated with <tt>key</tt>, or
163.424 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
163.425 + * (A <tt>null</tt> return can also indicate that the map
163.426 + * previously associated <tt>null</tt> with <tt>key</tt>.)
163.427 + */
163.428 + public V put(K key, V value) {
163.429 + Object k = maskNull(key);
163.430 + int h = HashMap.hash(k.hashCode());
163.431 + Entry<K,V>[] tab = getTable();
163.432 + int i = indexFor(h, tab.length);
163.433 +
163.434 + for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
163.435 + if (h == e.hash && eq(k, e.get())) {
163.436 + V oldValue = e.value;
163.437 + if (value != oldValue)
163.438 + e.value = value;
163.439 + return oldValue;
163.440 + }
163.441 + }
163.442 +
163.443 + modCount++;
163.444 + Entry<K,V> e = tab[i];
163.445 + tab[i] = new Entry<>(k, value, queue, h, e);
163.446 + if (++size >= threshold)
163.447 + resize(tab.length * 2);
163.448 + return null;
163.449 + }
163.450 +
163.451 + /**
163.452 + * Rehashes the contents of this map into a new array with a
163.453 + * larger capacity. This method is called automatically when the
163.454 + * number of keys in this map reaches its threshold.
163.455 + *
163.456 + * If current capacity is MAXIMUM_CAPACITY, this method does not
163.457 + * resize the map, but sets threshold to Integer.MAX_VALUE.
163.458 + * This has the effect of preventing future calls.
163.459 + *
163.460 + * @param newCapacity the new capacity, MUST be a power of two;
163.461 + * must be greater than current capacity unless current
163.462 + * capacity is MAXIMUM_CAPACITY (in which case value
163.463 + * is irrelevant).
163.464 + */
163.465 + void resize(int newCapacity) {
163.466 + Entry<K,V>[] oldTable = getTable();
163.467 + int oldCapacity = oldTable.length;
163.468 + if (oldCapacity == MAXIMUM_CAPACITY) {
163.469 + threshold = Integer.MAX_VALUE;
163.470 + return;
163.471 + }
163.472 +
163.473 + Entry<K,V>[] newTable = newTable(newCapacity);
163.474 + transfer(oldTable, newTable);
163.475 + table = newTable;
163.476 +
163.477 + /*
163.478 + * If ignoring null elements and processing ref queue caused massive
163.479 + * shrinkage, then restore old table. This should be rare, but avoids
163.480 + * unbounded expansion of garbage-filled tables.
163.481 + */
163.482 + if (size >= threshold / 2) {
163.483 + threshold = (int)(newCapacity * loadFactor);
163.484 + } else {
163.485 + expungeStaleEntries();
163.486 + transfer(newTable, oldTable);
163.487 + table = oldTable;
163.488 + }
163.489 + }
163.490 +
163.491 + /** Transfers all entries from src to dest tables */
163.492 + private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
163.493 + for (int j = 0; j < src.length; ++j) {
163.494 + Entry<K,V> e = src[j];
163.495 + src[j] = null;
163.496 + while (e != null) {
163.497 + Entry<K,V> next = e.next;
163.498 + Object key = e.get();
163.499 + if (key == null) {
163.500 + e.next = null; // Help GC
163.501 + e.value = null; // " "
163.502 + size--;
163.503 + } else {
163.504 + int i = indexFor(e.hash, dest.length);
163.505 + e.next = dest[i];
163.506 + dest[i] = e;
163.507 + }
163.508 + e = next;
163.509 + }
163.510 + }
163.511 + }
163.512 +
163.513 + /**
163.514 + * Copies all of the mappings from the specified map to this map.
163.515 + * These mappings will replace any mappings that this map had for any
163.516 + * of the keys currently in the specified map.
163.517 + *
163.518 + * @param m mappings to be stored in this map.
163.519 + * @throws NullPointerException if the specified map is null.
163.520 + */
163.521 + public void putAll(Map<? extends K, ? extends V> m) {
163.522 + int numKeysToBeAdded = m.size();
163.523 + if (numKeysToBeAdded == 0)
163.524 + return;
163.525 +
163.526 + /*
163.527 + * Expand the map if the map if the number of mappings to be added
163.528 + * is greater than or equal to threshold. This is conservative; the
163.529 + * obvious condition is (m.size() + size) >= threshold, but this
163.530 + * condition could result in a map with twice the appropriate capacity,
163.531 + * if the keys to be added overlap with the keys already in this map.
163.532 + * By using the conservative calculation, we subject ourself
163.533 + * to at most one extra resize.
163.534 + */
163.535 + if (numKeysToBeAdded > threshold) {
163.536 + int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
163.537 + if (targetCapacity > MAXIMUM_CAPACITY)
163.538 + targetCapacity = MAXIMUM_CAPACITY;
163.539 + int newCapacity = table.length;
163.540 + while (newCapacity < targetCapacity)
163.541 + newCapacity <<= 1;
163.542 + if (newCapacity > table.length)
163.543 + resize(newCapacity);
163.544 + }
163.545 +
163.546 + for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
163.547 + put(e.getKey(), e.getValue());
163.548 + }
163.549 +
163.550 + /**
163.551 + * Removes the mapping for a key from this weak hash map if it is present.
163.552 + * More formally, if this map contains a mapping from key <tt>k</tt> to
163.553 + * value <tt>v</tt> such that <code>(key==null ? k==null :
163.554 + * key.equals(k))</code>, that mapping is removed. (The map can contain
163.555 + * at most one such mapping.)
163.556 + *
163.557 + * <p>Returns the value to which this map previously associated the key,
163.558 + * or <tt>null</tt> if the map contained no mapping for the key. A
163.559 + * return value of <tt>null</tt> does not <i>necessarily</i> indicate
163.560 + * that the map contained no mapping for the key; it's also possible
163.561 + * that the map explicitly mapped the key to <tt>null</tt>.
163.562 + *
163.563 + * <p>The map will not contain a mapping for the specified key once the
163.564 + * call returns.
163.565 + *
163.566 + * @param key key whose mapping is to be removed from the map
163.567 + * @return the previous value associated with <tt>key</tt>, or
163.568 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
163.569 + */
163.570 + public V remove(Object key) {
163.571 + Object k = maskNull(key);
163.572 + int h = HashMap.hash(k.hashCode());
163.573 + Entry<K,V>[] tab = getTable();
163.574 + int i = indexFor(h, tab.length);
163.575 + Entry<K,V> prev = tab[i];
163.576 + Entry<K,V> e = prev;
163.577 +
163.578 + while (e != null) {
163.579 + Entry<K,V> next = e.next;
163.580 + if (h == e.hash && eq(k, e.get())) {
163.581 + modCount++;
163.582 + size--;
163.583 + if (prev == e)
163.584 + tab[i] = next;
163.585 + else
163.586 + prev.next = next;
163.587 + return e.value;
163.588 + }
163.589 + prev = e;
163.590 + e = next;
163.591 + }
163.592 +
163.593 + return null;
163.594 + }
163.595 +
163.596 + /** Special version of remove needed by Entry set */
163.597 + boolean removeMapping(Object o) {
163.598 + if (!(o instanceof Map.Entry))
163.599 + return false;
163.600 + Entry<K,V>[] tab = getTable();
163.601 + Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
163.602 + Object k = maskNull(entry.getKey());
163.603 + int h = HashMap.hash(k.hashCode());
163.604 + int i = indexFor(h, tab.length);
163.605 + Entry<K,V> prev = tab[i];
163.606 + Entry<K,V> e = prev;
163.607 +
163.608 + while (e != null) {
163.609 + Entry<K,V> next = e.next;
163.610 + if (h == e.hash && e.equals(entry)) {
163.611 + modCount++;
163.612 + size--;
163.613 + if (prev == e)
163.614 + tab[i] = next;
163.615 + else
163.616 + prev.next = next;
163.617 + return true;
163.618 + }
163.619 + prev = e;
163.620 + e = next;
163.621 + }
163.622 +
163.623 + return false;
163.624 + }
163.625 +
163.626 + /**
163.627 + * Removes all of the mappings from this map.
163.628 + * The map will be empty after this call returns.
163.629 + */
163.630 + public void clear() {
163.631 + // clear out ref queue. We don't need to expunge entries
163.632 + // since table is getting cleared.
163.633 + while (queue.poll() != null)
163.634 + ;
163.635 +
163.636 + modCount++;
163.637 + Arrays.fill(table, null);
163.638 + size = 0;
163.639 +
163.640 + // Allocation of array may have caused GC, which may have caused
163.641 + // additional entries to go stale. Removing these entries from the
163.642 + // reference queue will make them eligible for reclamation.
163.643 + while (queue.poll() != null)
163.644 + ;
163.645 + }
163.646 +
163.647 + /**
163.648 + * Returns <tt>true</tt> if this map maps one or more keys to the
163.649 + * specified value.
163.650 + *
163.651 + * @param value value whose presence in this map is to be tested
163.652 + * @return <tt>true</tt> if this map maps one or more keys to the
163.653 + * specified value
163.654 + */
163.655 + public boolean containsValue(Object value) {
163.656 + if (value==null)
163.657 + return containsNullValue();
163.658 +
163.659 + Entry<K,V>[] tab = getTable();
163.660 + for (int i = tab.length; i-- > 0;)
163.661 + for (Entry<K,V> e = tab[i]; e != null; e = e.next)
163.662 + if (value.equals(e.value))
163.663 + return true;
163.664 + return false;
163.665 + }
163.666 +
163.667 + /**
163.668 + * Special-case code for containsValue with null argument
163.669 + */
163.670 + private boolean containsNullValue() {
163.671 + Entry<K,V>[] tab = getTable();
163.672 + for (int i = tab.length; i-- > 0;)
163.673 + for (Entry<K,V> e = tab[i]; e != null; e = e.next)
163.674 + if (e.value==null)
163.675 + return true;
163.676 + return false;
163.677 + }
163.678 +
163.679 + /**
163.680 + * The entries in this hash table extend WeakReference, using its main ref
163.681 + * field as the key.
163.682 + */
163.683 + private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
163.684 + V value;
163.685 + final int hash;
163.686 + Entry<K,V> next;
163.687 +
163.688 + /**
163.689 + * Creates new entry.
163.690 + */
163.691 + Entry(Object key, V value,
163.692 + ReferenceQueue<Object> queue,
163.693 + int hash, Entry<K,V> next) {
163.694 + super(key, queue);
163.695 + this.value = value;
163.696 + this.hash = hash;
163.697 + this.next = next;
163.698 + }
163.699 +
163.700 + @SuppressWarnings("unchecked")
163.701 + public K getKey() {
163.702 + return (K) WeakHashMap.unmaskNull(get());
163.703 + }
163.704 +
163.705 + public V getValue() {
163.706 + return value;
163.707 + }
163.708 +
163.709 + public V setValue(V newValue) {
163.710 + V oldValue = value;
163.711 + value = newValue;
163.712 + return oldValue;
163.713 + }
163.714 +
163.715 + public boolean equals(Object o) {
163.716 + if (!(o instanceof Map.Entry))
163.717 + return false;
163.718 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
163.719 + K k1 = getKey();
163.720 + Object k2 = e.getKey();
163.721 + if (k1 == k2 || (k1 != null && k1.equals(k2))) {
163.722 + V v1 = getValue();
163.723 + Object v2 = e.getValue();
163.724 + if (v1 == v2 || (v1 != null && v1.equals(v2)))
163.725 + return true;
163.726 + }
163.727 + return false;
163.728 + }
163.729 +
163.730 + public int hashCode() {
163.731 + K k = getKey();
163.732 + V v = getValue();
163.733 + return ((k==null ? 0 : k.hashCode()) ^
163.734 + (v==null ? 0 : v.hashCode()));
163.735 + }
163.736 +
163.737 + public String toString() {
163.738 + return getKey() + "=" + getValue();
163.739 + }
163.740 + }
163.741 +
163.742 + private abstract class HashIterator<T> implements Iterator<T> {
163.743 + private int index;
163.744 + private Entry<K,V> entry = null;
163.745 + private Entry<K,V> lastReturned = null;
163.746 + private int expectedModCount = modCount;
163.747 +
163.748 + /**
163.749 + * Strong reference needed to avoid disappearance of key
163.750 + * between hasNext and next
163.751 + */
163.752 + private Object nextKey = null;
163.753 +
163.754 + /**
163.755 + * Strong reference needed to avoid disappearance of key
163.756 + * between nextEntry() and any use of the entry
163.757 + */
163.758 + private Object currentKey = null;
163.759 +
163.760 + HashIterator() {
163.761 + index = isEmpty() ? 0 : table.length;
163.762 + }
163.763 +
163.764 + public boolean hasNext() {
163.765 + Entry<K,V>[] t = table;
163.766 +
163.767 + while (nextKey == null) {
163.768 + Entry<K,V> e = entry;
163.769 + int i = index;
163.770 + while (e == null && i > 0)
163.771 + e = t[--i];
163.772 + entry = e;
163.773 + index = i;
163.774 + if (e == null) {
163.775 + currentKey = null;
163.776 + return false;
163.777 + }
163.778 + nextKey = e.get(); // hold on to key in strong ref
163.779 + if (nextKey == null)
163.780 + entry = entry.next;
163.781 + }
163.782 + return true;
163.783 + }
163.784 +
163.785 + /** The common parts of next() across different types of iterators */
163.786 + protected Entry<K,V> nextEntry() {
163.787 + if (modCount != expectedModCount)
163.788 + throw new ConcurrentModificationException();
163.789 + if (nextKey == null && !hasNext())
163.790 + throw new NoSuchElementException();
163.791 +
163.792 + lastReturned = entry;
163.793 + entry = entry.next;
163.794 + currentKey = nextKey;
163.795 + nextKey = null;
163.796 + return lastReturned;
163.797 + }
163.798 +
163.799 + public void remove() {
163.800 + if (lastReturned == null)
163.801 + throw new IllegalStateException();
163.802 + if (modCount != expectedModCount)
163.803 + throw new ConcurrentModificationException();
163.804 +
163.805 + WeakHashMap.this.remove(currentKey);
163.806 + expectedModCount = modCount;
163.807 + lastReturned = null;
163.808 + currentKey = null;
163.809 + }
163.810 +
163.811 + }
163.812 +
163.813 + private class ValueIterator extends HashIterator<V> {
163.814 + public V next() {
163.815 + return nextEntry().value;
163.816 + }
163.817 + }
163.818 +
163.819 + private class KeyIterator extends HashIterator<K> {
163.820 + public K next() {
163.821 + return nextEntry().getKey();
163.822 + }
163.823 + }
163.824 +
163.825 + private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
163.826 + public Map.Entry<K,V> next() {
163.827 + return nextEntry();
163.828 + }
163.829 + }
163.830 +
163.831 + // Views
163.832 +
163.833 + private transient Set<Map.Entry<K,V>> entrySet = null;
163.834 +
163.835 + /**
163.836 + * Returns a {@link Set} view of the keys contained in this map.
163.837 + * The set is backed by the map, so changes to the map are
163.838 + * reflected in the set, and vice-versa. If the map is modified
163.839 + * while an iteration over the set is in progress (except through
163.840 + * the iterator's own <tt>remove</tt> operation), the results of
163.841 + * the iteration are undefined. The set supports element removal,
163.842 + * which removes the corresponding mapping from the map, via the
163.843 + * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
163.844 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
163.845 + * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
163.846 + * operations.
163.847 + */
163.848 + public Set<K> keySet() {
163.849 + Set<K> ks = keySet;
163.850 + return (ks != null ? ks : (keySet = new KeySet()));
163.851 + }
163.852 +
163.853 + private class KeySet extends AbstractSet<K> {
163.854 + public Iterator<K> iterator() {
163.855 + return new KeyIterator();
163.856 + }
163.857 +
163.858 + public int size() {
163.859 + return WeakHashMap.this.size();
163.860 + }
163.861 +
163.862 + public boolean contains(Object o) {
163.863 + return containsKey(o);
163.864 + }
163.865 +
163.866 + public boolean remove(Object o) {
163.867 + if (containsKey(o)) {
163.868 + WeakHashMap.this.remove(o);
163.869 + return true;
163.870 + }
163.871 + else
163.872 + return false;
163.873 + }
163.874 +
163.875 + public void clear() {
163.876 + WeakHashMap.this.clear();
163.877 + }
163.878 + }
163.879 +
163.880 + /**
163.881 + * Returns a {@link Collection} view of the values contained in this map.
163.882 + * The collection is backed by the map, so changes to the map are
163.883 + * reflected in the collection, and vice-versa. If the map is
163.884 + * modified while an iteration over the collection is in progress
163.885 + * (except through the iterator's own <tt>remove</tt> operation),
163.886 + * the results of the iteration are undefined. The collection
163.887 + * supports element removal, which removes the corresponding
163.888 + * mapping from the map, via the <tt>Iterator.remove</tt>,
163.889 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
163.890 + * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
163.891 + * support the <tt>add</tt> or <tt>addAll</tt> operations.
163.892 + */
163.893 + public Collection<V> values() {
163.894 + Collection<V> vs = values;
163.895 + return (vs != null) ? vs : (values = new Values());
163.896 + }
163.897 +
163.898 + private class Values extends AbstractCollection<V> {
163.899 + public Iterator<V> iterator() {
163.900 + return new ValueIterator();
163.901 + }
163.902 +
163.903 + public int size() {
163.904 + return WeakHashMap.this.size();
163.905 + }
163.906 +
163.907 + public boolean contains(Object o) {
163.908 + return containsValue(o);
163.909 + }
163.910 +
163.911 + public void clear() {
163.912 + WeakHashMap.this.clear();
163.913 + }
163.914 + }
163.915 +
163.916 + /**
163.917 + * Returns a {@link Set} view of the mappings contained in this map.
163.918 + * The set is backed by the map, so changes to the map are
163.919 + * reflected in the set, and vice-versa. If the map is modified
163.920 + * while an iteration over the set is in progress (except through
163.921 + * the iterator's own <tt>remove</tt> operation, or through the
163.922 + * <tt>setValue</tt> operation on a map entry returned by the
163.923 + * iterator) the results of the iteration are undefined. The set
163.924 + * supports element removal, which removes the corresponding
163.925 + * mapping from the map, via the <tt>Iterator.remove</tt>,
163.926 + * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
163.927 + * <tt>clear</tt> operations. It does not support the
163.928 + * <tt>add</tt> or <tt>addAll</tt> operations.
163.929 + */
163.930 + public Set<Map.Entry<K,V>> entrySet() {
163.931 + Set<Map.Entry<K,V>> es = entrySet;
163.932 + return es != null ? es : (entrySet = new EntrySet());
163.933 + }
163.934 +
163.935 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
163.936 + public Iterator<Map.Entry<K,V>> iterator() {
163.937 + return new EntryIterator();
163.938 + }
163.939 +
163.940 + public boolean contains(Object o) {
163.941 + if (!(o instanceof Map.Entry))
163.942 + return false;
163.943 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
163.944 + Entry<K,V> candidate = getEntry(e.getKey());
163.945 + return candidate != null && candidate.equals(e);
163.946 + }
163.947 +
163.948 + public boolean remove(Object o) {
163.949 + return removeMapping(o);
163.950 + }
163.951 +
163.952 + public int size() {
163.953 + return WeakHashMap.this.size();
163.954 + }
163.955 +
163.956 + public void clear() {
163.957 + WeakHashMap.this.clear();
163.958 + }
163.959 +
163.960 + private List<Map.Entry<K,V>> deepCopy() {
163.961 + List<Map.Entry<K,V>> list = new ArrayList<>(size());
163.962 + for (Map.Entry<K,V> e : this)
163.963 + list.add(new AbstractMap.SimpleEntry<>(e));
163.964 + return list;
163.965 + }
163.966 +
163.967 + public Object[] toArray() {
163.968 + return deepCopy().toArray();
163.969 + }
163.970 +
163.971 + public <T> T[] toArray(T[] a) {
163.972 + return deepCopy().toArray(a);
163.973 + }
163.974 + }
163.975 +}
164.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
164.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Executor.java Mon Oct 07 14:20:58 2013 +0200
164.3 @@ -0,0 +1,141 @@
164.4 +/*
164.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
164.6 + *
164.7 + * This code is free software; you can redistribute it and/or modify it
164.8 + * under the terms of the GNU General Public License version 2 only, as
164.9 + * published by the Free Software Foundation. Oracle designates this
164.10 + * particular file as subject to the "Classpath" exception as provided
164.11 + * by Oracle in the LICENSE file that accompanied this code.
164.12 + *
164.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
164.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
164.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
164.16 + * version 2 for more details (a copy is included in the LICENSE file that
164.17 + * accompanied this code).
164.18 + *
164.19 + * You should have received a copy of the GNU General Public License version
164.20 + * 2 along with this work; if not, write to the Free Software Foundation,
164.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
164.22 + *
164.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
164.24 + * or visit www.oracle.com if you need additional information or have any
164.25 + * questions.
164.26 + */
164.27 +
164.28 +/*
164.29 + * This file is available under and governed by the GNU General Public
164.30 + * License version 2 only, as published by the Free Software Foundation.
164.31 + * However, the following notice accompanied the original version of this
164.32 + * file:
164.33 + *
164.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
164.35 + * Expert Group and released to the public domain, as explained at
164.36 + * http://creativecommons.org/publicdomain/zero/1.0/
164.37 + */
164.38 +
164.39 +package java.util.concurrent;
164.40 +
164.41 +/**
164.42 + * An object that executes submitted {@link Runnable} tasks. This
164.43 + * interface provides a way of decoupling task submission from the
164.44 + * mechanics of how each task will be run, including details of thread
164.45 + * use, scheduling, etc. An <tt>Executor</tt> is normally used
164.46 + * instead of explicitly creating threads. For example, rather than
164.47 + * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each
164.48 + * of a set of tasks, you might use:
164.49 + *
164.50 + * <pre>
164.51 + * Executor executor = <em>anExecutor</em>;
164.52 + * executor.execute(new RunnableTask1());
164.53 + * executor.execute(new RunnableTask2());
164.54 + * ...
164.55 + * </pre>
164.56 + *
164.57 + * However, the <tt>Executor</tt> interface does not strictly
164.58 + * require that execution be asynchronous. In the simplest case, an
164.59 + * executor can run the submitted task immediately in the caller's
164.60 + * thread:
164.61 + *
164.62 + * <pre>
164.63 + * class DirectExecutor implements Executor {
164.64 + * public void execute(Runnable r) {
164.65 + * r.run();
164.66 + * }
164.67 + * }</pre>
164.68 + *
164.69 + * More typically, tasks are executed in some thread other
164.70 + * than the caller's thread. The executor below spawns a new thread
164.71 + * for each task.
164.72 + *
164.73 + * <pre>
164.74 + * class ThreadPerTaskExecutor implements Executor {
164.75 + * public void execute(Runnable r) {
164.76 + * new Thread(r).start();
164.77 + * }
164.78 + * }</pre>
164.79 + *
164.80 + * Many <tt>Executor</tt> implementations impose some sort of
164.81 + * limitation on how and when tasks are scheduled. The executor below
164.82 + * serializes the submission of tasks to a second executor,
164.83 + * illustrating a composite executor.
164.84 + *
164.85 + * <pre> {@code
164.86 + * class SerialExecutor implements Executor {
164.87 + * final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
164.88 + * final Executor executor;
164.89 + * Runnable active;
164.90 + *
164.91 + * SerialExecutor(Executor executor) {
164.92 + * this.executor = executor;
164.93 + * }
164.94 + *
164.95 + * public synchronized void execute(final Runnable r) {
164.96 + * tasks.offer(new Runnable() {
164.97 + * public void run() {
164.98 + * try {
164.99 + * r.run();
164.100 + * } finally {
164.101 + * scheduleNext();
164.102 + * }
164.103 + * }
164.104 + * });
164.105 + * if (active == null) {
164.106 + * scheduleNext();
164.107 + * }
164.108 + * }
164.109 + *
164.110 + * protected synchronized void scheduleNext() {
164.111 + * if ((active = tasks.poll()) != null) {
164.112 + * executor.execute(active);
164.113 + * }
164.114 + * }
164.115 + * }}</pre>
164.116 + *
164.117 + * The <tt>Executor</tt> implementations provided in this package
164.118 + * implement {@link ExecutorService}, which is a more extensive
164.119 + * interface. The {@link ThreadPoolExecutor} class provides an
164.120 + * extensible thread pool implementation. The {@link Executors} class
164.121 + * provides convenient factory methods for these Executors.
164.122 + *
164.123 + * <p>Memory consistency effects: Actions in a thread prior to
164.124 + * submitting a {@code Runnable} object to an {@code Executor}
164.125 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
164.126 + * its execution begins, perhaps in another thread.
164.127 + *
164.128 + * @since 1.5
164.129 + * @author Doug Lea
164.130 + */
164.131 +public interface Executor {
164.132 +
164.133 + /**
164.134 + * Executes the given command at some time in the future. The command
164.135 + * may execute in a new thread, in a pooled thread, or in the calling
164.136 + * thread, at the discretion of the <tt>Executor</tt> implementation.
164.137 + *
164.138 + * @param command the runnable task
164.139 + * @throws RejectedExecutionException if this task cannot be
164.140 + * accepted for execution.
164.141 + * @throws NullPointerException if command is null
164.142 + */
164.143 + void execute(Runnable command);
164.144 +}
165.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
165.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/Level.java Mon Oct 07 14:20:58 2013 +0200
165.3 @@ -0,0 +1,372 @@
165.4 +/*
165.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
165.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
165.7 + *
165.8 + * This code is free software; you can redistribute it and/or modify it
165.9 + * under the terms of the GNU General Public License version 2 only, as
165.10 + * published by the Free Software Foundation. Oracle designates this
165.11 + * particular file as subject to the "Classpath" exception as provided
165.12 + * by Oracle in the LICENSE file that accompanied this code.
165.13 + *
165.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
165.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
165.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
165.17 + * version 2 for more details (a copy is included in the LICENSE file that
165.18 + * accompanied this code).
165.19 + *
165.20 + * You should have received a copy of the GNU General Public License version
165.21 + * 2 along with this work; if not, write to the Free Software Foundation,
165.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
165.23 + *
165.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
165.25 + * or visit www.oracle.com if you need additional information or have any
165.26 + * questions.
165.27 + */
165.28 +
165.29 +package java.util.logging;
165.30 +
165.31 +/**
165.32 + * The Level class defines a set of standard logging levels that
165.33 + * can be used to control logging output. The logging Level objects
165.34 + * are ordered and are specified by ordered integers. Enabling logging
165.35 + * at a given level also enables logging at all higher levels.
165.36 + * <p>
165.37 + * Clients should normally use the predefined Level constants such
165.38 + * as Level.SEVERE.
165.39 + * <p>
165.40 + * The levels in descending order are:
165.41 + * <ul>
165.42 + * <li>SEVERE (highest value)
165.43 + * <li>WARNING
165.44 + * <li>INFO
165.45 + * <li>CONFIG
165.46 + * <li>FINE
165.47 + * <li>FINER
165.48 + * <li>FINEST (lowest value)
165.49 + * </ul>
165.50 + * In addition there is a level OFF that can be used to turn
165.51 + * off logging, and a level ALL that can be used to enable
165.52 + * logging of all messages.
165.53 + * <p>
165.54 + * It is possible for third parties to define additional logging
165.55 + * levels by subclassing Level. In such cases subclasses should
165.56 + * take care to chose unique integer level values and to ensure that
165.57 + * they maintain the Object uniqueness property across serialization
165.58 + * by defining a suitable readResolve method.
165.59 + *
165.60 + * @since 1.4
165.61 + */
165.62 +
165.63 +public class Level implements java.io.Serializable {
165.64 + private static java.util.ArrayList<Level> known = new java.util.ArrayList<>();
165.65 + private static String defaultBundle = "sun.util.logging.resources.logging";
165.66 +
165.67 + /**
165.68 + * @serial The non-localized name of the level.
165.69 + */
165.70 + private final String name;
165.71 +
165.72 + /**
165.73 + * @serial The integer value of the level.
165.74 + */
165.75 + private final int value;
165.76 +
165.77 + /**
165.78 + * @serial The resource bundle name to be used in localizing the level name.
165.79 + */
165.80 + private final String resourceBundleName;
165.81 +
165.82 + /**
165.83 + * OFF is a special level that can be used to turn off logging.
165.84 + * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
165.85 + */
165.86 + public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
165.87 +
165.88 + /**
165.89 + * SEVERE is a message level indicating a serious failure.
165.90 + * <p>
165.91 + * In general SEVERE messages should describe events that are
165.92 + * of considerable importance and which will prevent normal
165.93 + * program execution. They should be reasonably intelligible
165.94 + * to end users and to system administrators.
165.95 + * This level is initialized to <CODE>1000</CODE>.
165.96 + */
165.97 + public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
165.98 +
165.99 + /**
165.100 + * WARNING is a message level indicating a potential problem.
165.101 + * <p>
165.102 + * In general WARNING messages should describe events that will
165.103 + * be of interest to end users or system managers, or which
165.104 + * indicate potential problems.
165.105 + * This level is initialized to <CODE>900</CODE>.
165.106 + */
165.107 + public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
165.108 +
165.109 + /**
165.110 + * INFO is a message level for informational messages.
165.111 + * <p>
165.112 + * Typically INFO messages will be written to the console
165.113 + * or its equivalent. So the INFO level should only be
165.114 + * used for reasonably significant messages that will
165.115 + * make sense to end users and system administrators.
165.116 + * This level is initialized to <CODE>800</CODE>.
165.117 + */
165.118 + public static final Level INFO = new Level("INFO", 800, defaultBundle);
165.119 +
165.120 + /**
165.121 + * CONFIG is a message level for static configuration messages.
165.122 + * <p>
165.123 + * CONFIG messages are intended to provide a variety of static
165.124 + * configuration information, to assist in debugging problems
165.125 + * that may be associated with particular configurations.
165.126 + * For example, CONFIG message might include the CPU type,
165.127 + * the graphics depth, the GUI look-and-feel, etc.
165.128 + * This level is initialized to <CODE>700</CODE>.
165.129 + */
165.130 + public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
165.131 +
165.132 + /**
165.133 + * FINE is a message level providing tracing information.
165.134 + * <p>
165.135 + * All of FINE, FINER, and FINEST are intended for relatively
165.136 + * detailed tracing. The exact meaning of the three levels will
165.137 + * vary between subsystems, but in general, FINEST should be used
165.138 + * for the most voluminous detailed output, FINER for somewhat
165.139 + * less detailed output, and FINE for the lowest volume (and
165.140 + * most important) messages.
165.141 + * <p>
165.142 + * In general the FINE level should be used for information
165.143 + * that will be broadly interesting to developers who do not have
165.144 + * a specialized interest in the specific subsystem.
165.145 + * <p>
165.146 + * FINE messages might include things like minor (recoverable)
165.147 + * failures. Issues indicating potential performance problems
165.148 + * are also worth logging as FINE.
165.149 + * This level is initialized to <CODE>500</CODE>.
165.150 + */
165.151 + public static final Level FINE = new Level("FINE", 500, defaultBundle);
165.152 +
165.153 + /**
165.154 + * FINER indicates a fairly detailed tracing message.
165.155 + * By default logging calls for entering, returning, or throwing
165.156 + * an exception are traced at this level.
165.157 + * This level is initialized to <CODE>400</CODE>.
165.158 + */
165.159 + public static final Level FINER = new Level("FINER", 400, defaultBundle);
165.160 +
165.161 + /**
165.162 + * FINEST indicates a highly detailed tracing message.
165.163 + * This level is initialized to <CODE>300</CODE>.
165.164 + */
165.165 + public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
165.166 +
165.167 + /**
165.168 + * ALL indicates that all messages should be logged.
165.169 + * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
165.170 + */
165.171 + public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
165.172 +
165.173 + /**
165.174 + * Create a named Level with a given integer value.
165.175 + * <p>
165.176 + * Note that this constructor is "protected" to allow subclassing.
165.177 + * In general clients of logging should use one of the constant Level
165.178 + * objects such as SEVERE or FINEST. However, if clients need to
165.179 + * add new logging levels, they may subclass Level and define new
165.180 + * constants.
165.181 + * @param name the name of the Level, for example "SEVERE".
165.182 + * @param value an integer value for the level.
165.183 + * @throws NullPointerException if the name is null
165.184 + */
165.185 + protected Level(String name, int value) {
165.186 + this(name, value, null);
165.187 + }
165.188 +
165.189 + /**
165.190 + * Create a named Level with a given integer value and a
165.191 + * given localization resource name.
165.192 + * <p>
165.193 + * @param name the name of the Level, for example "SEVERE".
165.194 + * @param value an integer value for the level.
165.195 + * @param resourceBundleName name of a resource bundle to use in
165.196 + * localizing the given name. If the resourceBundleName is null
165.197 + * or an empty string, it is ignored.
165.198 + * @throws NullPointerException if the name is null
165.199 + */
165.200 + protected Level(String name, int value, String resourceBundleName) {
165.201 + if (name == null) {
165.202 + throw new NullPointerException();
165.203 + }
165.204 + this.name = name;
165.205 + this.value = value;
165.206 + this.resourceBundleName = resourceBundleName;
165.207 + synchronized (Level.class) {
165.208 + known.add(this);
165.209 + }
165.210 + }
165.211 +
165.212 + /**
165.213 + * Return the level's localization resource bundle name, or
165.214 + * null if no localization bundle is defined.
165.215 + *
165.216 + * @return localization resource bundle name
165.217 + */
165.218 + public String getResourceBundleName() {
165.219 + return resourceBundleName;
165.220 + }
165.221 +
165.222 + /**
165.223 + * Return the non-localized string name of the Level.
165.224 + *
165.225 + * @return non-localized name
165.226 + */
165.227 + public String getName() {
165.228 + return name;
165.229 + }
165.230 +
165.231 + /**
165.232 + * Return the localized string name of the Level, for
165.233 + * the current default locale.
165.234 + * <p>
165.235 + * If no localization information is available, the
165.236 + * non-localized name is returned.
165.237 + *
165.238 + * @return localized name
165.239 + */
165.240 + public String getLocalizedName() {
165.241 + return getName();
165.242 + }
165.243 +
165.244 + /**
165.245 + * Returns a string representation of this Level.
165.246 + *
165.247 + * @return the non-localized name of the Level, for example "INFO".
165.248 + */
165.249 + public final String toString() {
165.250 + return name;
165.251 + }
165.252 +
165.253 + /**
165.254 + * Get the integer value for this level. This integer value
165.255 + * can be used for efficient ordering comparisons between
165.256 + * Level objects.
165.257 + * @return the integer value for this level.
165.258 + */
165.259 + public final int intValue() {
165.260 + return value;
165.261 + }
165.262 +
165.263 + private static final long serialVersionUID = -8176160795706313070L;
165.264 +
165.265 + // Serialization magic to prevent "doppelgangers".
165.266 + // This is a performance optimization.
165.267 + private Object readResolve() {
165.268 + synchronized (Level.class) {
165.269 + for (int i = 0; i < known.size(); i++) {
165.270 + Level other = known.get(i);
165.271 + if (this.name.equals(other.name) && this.value == other.value
165.272 + && (this.resourceBundleName == other.resourceBundleName ||
165.273 + (this.resourceBundleName != null &&
165.274 + this.resourceBundleName.equals(other.resourceBundleName)))) {
165.275 + return other;
165.276 + }
165.277 + }
165.278 + // Woops. Whoever sent us this object knows
165.279 + // about a new log level. Add it to our list.
165.280 + known.add(this);
165.281 + return this;
165.282 + }
165.283 + }
165.284 +
165.285 + /**
165.286 + * Parse a level name string into a Level.
165.287 + * <p>
165.288 + * The argument string may consist of either a level name
165.289 + * or an integer value.
165.290 + * <p>
165.291 + * For example:
165.292 + * <ul>
165.293 + * <li> "SEVERE"
165.294 + * <li> "1000"
165.295 + * </ul>
165.296 + * @param name string to be parsed
165.297 + * @throws NullPointerException if the name is null
165.298 + * @throws IllegalArgumentException if the value is not valid.
165.299 + * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
165.300 + * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
165.301 + * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
165.302 + * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
165.303 + * appropriate package access, or new levels defined or created
165.304 + * by subclasses.
165.305 + *
165.306 + * @return The parsed value. Passing an integer that corresponds to a known name
165.307 + * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
165.308 + * Passing an integer that does not (e.g., 1) will return a new level name
165.309 + * initialized to that value.
165.310 + */
165.311 + public static synchronized Level parse(String name) throws IllegalArgumentException {
165.312 + // Check that name is not null.
165.313 + name.length();
165.314 +
165.315 + // Look for a known Level with the given non-localized name.
165.316 + for (int i = 0; i < known.size(); i++) {
165.317 + Level l = known.get(i);
165.318 + if (name.equals(l.name)) {
165.319 + return l;
165.320 + }
165.321 + }
165.322 +
165.323 + // Now, check if the given name is an integer. If so,
165.324 + // first look for a Level with the given value and then
165.325 + // if necessary create one.
165.326 + try {
165.327 + int x = Integer.parseInt(name);
165.328 + for (int i = 0; i < known.size(); i++) {
165.329 + Level l = known.get(i);
165.330 + if (l.value == x) {
165.331 + return l;
165.332 + }
165.333 + }
165.334 + // Create a new Level.
165.335 + return new Level(name, x);
165.336 + } catch (NumberFormatException ex) {
165.337 + // Not an integer.
165.338 + // Drop through.
165.339 + }
165.340 +
165.341 + // Finally, look for a known level with the given localized name,
165.342 + // in the current default locale.
165.343 + // This is relatively expensive, but not excessively so.
165.344 + for (int i = 0; i < known.size(); i++) {
165.345 + Level l = known.get(i);
165.346 + if (name.equals(l.getLocalizedName())) {
165.347 + return l;
165.348 + }
165.349 + }
165.350 +
165.351 + // OK, we've tried everything and failed
165.352 + throw new IllegalArgumentException("Bad level \"" + name + "\"");
165.353 + }
165.354 +
165.355 + /**
165.356 + * Compare two objects for value equality.
165.357 + * @return true if and only if the two objects have the same level value.
165.358 + */
165.359 + public boolean equals(Object ox) {
165.360 + try {
165.361 + Level lx = (Level)ox;
165.362 + return (lx.value == this.value);
165.363 + } catch (Exception ex) {
165.364 + return false;
165.365 + }
165.366 + }
165.367 +
165.368 + /**
165.369 + * Generate a hashcode.
165.370 + * @return a hashcode based on the level value
165.371 + */
165.372 + public int hashCode() {
165.373 + return this.value;
165.374 + }
165.375 +}
166.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
166.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/LogRecord.java Mon Oct 07 14:20:58 2013 +0200
166.3 @@ -0,0 +1,468 @@
166.4 +/*
166.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
166.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
166.7 + *
166.8 + * This code is free software; you can redistribute it and/or modify it
166.9 + * under the terms of the GNU General Public License version 2 only, as
166.10 + * published by the Free Software Foundation. Oracle designates this
166.11 + * particular file as subject to the "Classpath" exception as provided
166.12 + * by Oracle in the LICENSE file that accompanied this code.
166.13 + *
166.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
166.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
166.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
166.17 + * version 2 for more details (a copy is included in the LICENSE file that
166.18 + * accompanied this code).
166.19 + *
166.20 + * You should have received a copy of the GNU General Public License version
166.21 + * 2 along with this work; if not, write to the Free Software Foundation,
166.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
166.23 + *
166.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
166.25 + * or visit www.oracle.com if you need additional information or have any
166.26 + * questions.
166.27 + */
166.28 +
166.29 +package java.util.logging;
166.30 +import java.io.*;
166.31 +
166.32 +/**
166.33 + * LogRecord objects are used to pass logging requests between
166.34 + * the logging framework and individual log Handlers.
166.35 + * <p>
166.36 + * When a LogRecord is passed into the logging framework it
166.37 + * logically belongs to the framework and should no longer be
166.38 + * used or updated by the client application.
166.39 + * <p>
166.40 + * Note that if the client application has not specified an
166.41 + * explicit source method name and source class name, then the
166.42 + * LogRecord class will infer them automatically when they are
166.43 + * first accessed (due to a call on getSourceMethodName or
166.44 + * getSourceClassName) by analyzing the call stack. Therefore,
166.45 + * if a logging Handler wants to pass off a LogRecord to another
166.46 + * thread, or to transmit it over RMI, and if it wishes to subsequently
166.47 + * obtain method name or class name information it should call
166.48 + * one of getSourceClassName or getSourceMethodName to force
166.49 + * the values to be filled in.
166.50 + * <p>
166.51 + * <b> Serialization notes:</b>
166.52 + * <ul>
166.53 + * <li>The LogRecord class is serializable.
166.54 + *
166.55 + * <li> Because objects in the parameters array may not be serializable,
166.56 + * during serialization all objects in the parameters array are
166.57 + * written as the corresponding Strings (using Object.toString).
166.58 + *
166.59 + * <li> The ResourceBundle is not transmitted as part of the serialized
166.60 + * form, but the resource bundle name is, and the recipient object's
166.61 + * readObject method will attempt to locate a suitable resource bundle.
166.62 + *
166.63 + * </ul>
166.64 + *
166.65 + * @since 1.4
166.66 + */
166.67 +
166.68 +public class LogRecord implements java.io.Serializable {
166.69 + private static long globalSequenceNumber = 0;
166.70 +
166.71 + /**
166.72 + * The default value of threadID will be the current thread's
166.73 + * thread id, for ease of correlation, unless it is greater than
166.74 + * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
166.75 + * our promise to keep threadIDs unique by avoiding collisions due
166.76 + * to 32-bit wraparound. Unfortunately, LogRecord.getThreadID()
166.77 + * returns int, while Thread.getId() returns long.
166.78 + */
166.79 + private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
166.80 +
166.81 + /**
166.82 + * @serial Logging message level
166.83 + */
166.84 + private Level level;
166.85 +
166.86 + /**
166.87 + * @serial Sequence number
166.88 + */
166.89 + private long sequenceNumber;
166.90 +
166.91 + /**
166.92 + * @serial Class that issued logging call
166.93 + */
166.94 + private String sourceClassName;
166.95 +
166.96 + /**
166.97 + * @serial Method that issued logging call
166.98 + */
166.99 + private String sourceMethodName;
166.100 +
166.101 + /**
166.102 + * @serial Non-localized raw message text
166.103 + */
166.104 + private String message;
166.105 +
166.106 + /**
166.107 + * @serial Thread ID for thread that issued logging call.
166.108 + */
166.109 + private int threadID;
166.110 +
166.111 + /**
166.112 + * @serial Event time in milliseconds since 1970
166.113 + */
166.114 + private long millis;
166.115 +
166.116 + /**
166.117 + * @serial The Throwable (if any) associated with log message
166.118 + */
166.119 + private Throwable thrown;
166.120 +
166.121 + /**
166.122 + * @serial Name of the source Logger.
166.123 + */
166.124 + private String loggerName;
166.125 +
166.126 + /**
166.127 + * @serial Resource bundle name to localized log message.
166.128 + */
166.129 + private String resourceBundleName;
166.130 +
166.131 + private transient boolean needToInferCaller;
166.132 + private transient Object parameters[];
166.133 +
166.134 + /**
166.135 + * Returns the default value for a new LogRecord's threadID.
166.136 + */
166.137 + private int defaultThreadID() {
166.138 + return 0;
166.139 + }
166.140 +
166.141 + /**
166.142 + * Construct a LogRecord with the given level and message values.
166.143 + * <p>
166.144 + * The sequence property will be initialized with a new unique value.
166.145 + * These sequence values are allocated in increasing order within a VM.
166.146 + * <p>
166.147 + * The millis property will be initialized to the current time.
166.148 + * <p>
166.149 + * The thread ID property will be initialized with a unique ID for
166.150 + * the current thread.
166.151 + * <p>
166.152 + * All other properties will be initialized to "null".
166.153 + *
166.154 + * @param level a logging level value
166.155 + * @param msg the raw non-localized logging message (may be null)
166.156 + */
166.157 + public LogRecord(Level level, String msg) {
166.158 + // Make sure level isn't null, by calling random method.
166.159 + level.getClass();
166.160 + this.level = level;
166.161 + message = msg;
166.162 + // Assign a thread ID and a unique sequence number.
166.163 + sequenceNumber = globalSequenceNumber++;
166.164 + threadID = defaultThreadID();
166.165 + millis = System.currentTimeMillis();
166.166 + needToInferCaller = true;
166.167 + }
166.168 +
166.169 + /**
166.170 + * Get the source Logger's name.
166.171 + *
166.172 + * @return source logger name (may be null)
166.173 + */
166.174 + public String getLoggerName() {
166.175 + return loggerName;
166.176 + }
166.177 +
166.178 + /**
166.179 + * Set the source Logger's name.
166.180 + *
166.181 + * @param name the source logger name (may be null)
166.182 + */
166.183 + public void setLoggerName(String name) {
166.184 + loggerName = name;
166.185 + }
166.186 +
166.187 + /**
166.188 + * Get the localization resource bundle
166.189 + * <p>
166.190 + * This is the ResourceBundle that should be used to localize
166.191 + * the message string before formatting it. The result may
166.192 + * be null if the message is not localizable, or if no suitable
166.193 + * ResourceBundle is available.
166.194 + */
166.195 +// public ResourceBundle getResourceBundle() {
166.196 +// return resourceBundle;
166.197 +// }
166.198 +
166.199 + /**
166.200 + * Set the localization resource bundle.
166.201 + *
166.202 + * @param bundle localization bundle (may be null)
166.203 + */
166.204 +// public void setResourceBundle(ResourceBundle bundle) {
166.205 +// resourceBundle = bundle;
166.206 +// }
166.207 +
166.208 + /**
166.209 + * Get the localization resource bundle name
166.210 + * <p>
166.211 + * This is the name for the ResourceBundle that should be
166.212 + * used to localize the message string before formatting it.
166.213 + * The result may be null if the message is not localizable.
166.214 + */
166.215 + public String getResourceBundleName() {
166.216 + return resourceBundleName;
166.217 + }
166.218 +
166.219 + /**
166.220 + * Set the localization resource bundle name.
166.221 + *
166.222 + * @param name localization bundle name (may be null)
166.223 + */
166.224 + public void setResourceBundleName(String name) {
166.225 + resourceBundleName = name;
166.226 + }
166.227 +
166.228 + /**
166.229 + * Get the logging message level, for example Level.SEVERE.
166.230 + * @return the logging message level
166.231 + */
166.232 + public Level getLevel() {
166.233 + return level;
166.234 + }
166.235 +
166.236 + /**
166.237 + * Set the logging message level, for example Level.SEVERE.
166.238 + * @param level the logging message level
166.239 + */
166.240 + public void setLevel(Level level) {
166.241 + if (level == null) {
166.242 + throw new NullPointerException();
166.243 + }
166.244 + this.level = level;
166.245 + }
166.246 +
166.247 + /**
166.248 + * Get the sequence number.
166.249 + * <p>
166.250 + * Sequence numbers are normally assigned in the LogRecord
166.251 + * constructor, which assigns unique sequence numbers to
166.252 + * each new LogRecord in increasing order.
166.253 + * @return the sequence number
166.254 + */
166.255 + public long getSequenceNumber() {
166.256 + return sequenceNumber;
166.257 + }
166.258 +
166.259 + /**
166.260 + * Set the sequence number.
166.261 + * <p>
166.262 + * Sequence numbers are normally assigned in the LogRecord constructor,
166.263 + * so it should not normally be necessary to use this method.
166.264 + */
166.265 + public void setSequenceNumber(long seq) {
166.266 + sequenceNumber = seq;
166.267 + }
166.268 +
166.269 + /**
166.270 + * Get the name of the class that (allegedly) issued the logging request.
166.271 + * <p>
166.272 + * Note that this sourceClassName is not verified and may be spoofed.
166.273 + * This information may either have been provided as part of the
166.274 + * logging call, or it may have been inferred automatically by the
166.275 + * logging framework. In the latter case, the information may only
166.276 + * be approximate and may in fact describe an earlier call on the
166.277 + * stack frame.
166.278 + * <p>
166.279 + * May be null if no information could be obtained.
166.280 + *
166.281 + * @return the source class name
166.282 + */
166.283 + public String getSourceClassName() {
166.284 + return sourceClassName;
166.285 + }
166.286 +
166.287 + /**
166.288 + * Set the name of the class that (allegedly) issued the logging request.
166.289 + *
166.290 + * @param sourceClassName the source class name (may be null)
166.291 + */
166.292 + public void setSourceClassName(String sourceClassName) {
166.293 + this.sourceClassName = sourceClassName;
166.294 + needToInferCaller = false;
166.295 + }
166.296 +
166.297 + /**
166.298 + * Get the name of the method that (allegedly) issued the logging request.
166.299 + * <p>
166.300 + * Note that this sourceMethodName is not verified and may be spoofed.
166.301 + * This information may either have been provided as part of the
166.302 + * logging call, or it may have been inferred automatically by the
166.303 + * logging framework. In the latter case, the information may only
166.304 + * be approximate and may in fact describe an earlier call on the
166.305 + * stack frame.
166.306 + * <p>
166.307 + * May be null if no information could be obtained.
166.308 + *
166.309 + * @return the source method name
166.310 + */
166.311 + public String getSourceMethodName() {
166.312 + return sourceMethodName;
166.313 + }
166.314 +
166.315 + /**
166.316 + * Set the name of the method that (allegedly) issued the logging request.
166.317 + *
166.318 + * @param sourceMethodName the source method name (may be null)
166.319 + */
166.320 + public void setSourceMethodName(String sourceMethodName) {
166.321 + this.sourceMethodName = sourceMethodName;
166.322 + needToInferCaller = false;
166.323 + }
166.324 +
166.325 + /**
166.326 + * Get the "raw" log message, before localization or formatting.
166.327 + * <p>
166.328 + * May be null, which is equivalent to the empty string "".
166.329 + * <p>
166.330 + * This message may be either the final text or a localization key.
166.331 + * <p>
166.332 + * During formatting, if the source logger has a localization
166.333 + * ResourceBundle and if that ResourceBundle has an entry for
166.334 + * this message string, then the message string is replaced
166.335 + * with the localized value.
166.336 + *
166.337 + * @return the raw message string
166.338 + */
166.339 + public String getMessage() {
166.340 + return message;
166.341 + }
166.342 +
166.343 + /**
166.344 + * Set the "raw" log message, before localization or formatting.
166.345 + *
166.346 + * @param message the raw message string (may be null)
166.347 + */
166.348 + public void setMessage(String message) {
166.349 + this.message = message;
166.350 + }
166.351 +
166.352 + /**
166.353 + * Get the parameters to the log message.
166.354 + *
166.355 + * @return the log message parameters. May be null if
166.356 + * there are no parameters.
166.357 + */
166.358 + public Object[] getParameters() {
166.359 + return parameters;
166.360 + }
166.361 +
166.362 + /**
166.363 + * Set the parameters to the log message.
166.364 + *
166.365 + * @param parameters the log message parameters. (may be null)
166.366 + */
166.367 + public void setParameters(Object parameters[]) {
166.368 + this.parameters = parameters;
166.369 + }
166.370 +
166.371 + /**
166.372 + * Get an identifier for the thread where the message originated.
166.373 + * <p>
166.374 + * This is a thread identifier within the Java VM and may or
166.375 + * may not map to any operating system ID.
166.376 + *
166.377 + * @return thread ID
166.378 + */
166.379 + public int getThreadID() {
166.380 + return threadID;
166.381 + }
166.382 +
166.383 + /**
166.384 + * Set an identifier for the thread where the message originated.
166.385 + * @param threadID the thread ID
166.386 + */
166.387 + public void setThreadID(int threadID) {
166.388 + this.threadID = threadID;
166.389 + }
166.390 +
166.391 + /**
166.392 + * Get event time in milliseconds since 1970.
166.393 + *
166.394 + * @return event time in millis since 1970
166.395 + */
166.396 + public long getMillis() {
166.397 + return millis;
166.398 + }
166.399 +
166.400 + /**
166.401 + * Set event time.
166.402 + *
166.403 + * @param millis event time in millis since 1970
166.404 + */
166.405 + public void setMillis(long millis) {
166.406 + this.millis = millis;
166.407 + }
166.408 +
166.409 + /**
166.410 + * Get any throwable associated with the log record.
166.411 + * <p>
166.412 + * If the event involved an exception, this will be the
166.413 + * exception object. Otherwise null.
166.414 + *
166.415 + * @return a throwable
166.416 + */
166.417 + public Throwable getThrown() {
166.418 + return thrown;
166.419 + }
166.420 +
166.421 + /**
166.422 + * Set a throwable associated with the log event.
166.423 + *
166.424 + * @param thrown a throwable (may be null)
166.425 + */
166.426 + public void setThrown(Throwable thrown) {
166.427 + this.thrown = thrown;
166.428 + }
166.429 +
166.430 + private static final long serialVersionUID = 5372048053134512534L;
166.431 +
166.432 + /**
166.433 + * @serialData Default fields, followed by a two byte version number
166.434 + * (major byte, followed by minor byte), followed by information on
166.435 + * the log record parameter array. If there is no parameter array,
166.436 + * then -1 is written. If there is a parameter array (possible of zero
166.437 + * length) then the array length is written as an integer, followed
166.438 + * by String values for each parameter. If a parameter is null, then
166.439 + * a null String is written. Otherwise the output of Object.toString()
166.440 + * is written.
166.441 + */
166.442 + private void writeObject(ObjectOutputStream out) throws IOException {
166.443 + // We have to call defaultWriteObject first.
166.444 + out.defaultWriteObject();
166.445 +
166.446 + // Write our version number.
166.447 + out.writeByte(1);
166.448 + out.writeByte(0);
166.449 + if (parameters == null) {
166.450 + out.writeInt(-1);
166.451 + return;
166.452 + }
166.453 + out.writeInt(parameters.length);
166.454 + // Write string values for the parameters.
166.455 + for (int i = 0; i < parameters.length; i++) {
166.456 + if (parameters[i] == null) {
166.457 + out.writeObject(null);
166.458 + } else {
166.459 + out.writeObject(parameters[i].toString());
166.460 + }
166.461 + }
166.462 + }
166.463 +
166.464 +
166.465 + private boolean isLoggerImplFrame(String cname) {
166.466 + // the log record could be created for a platform logger
166.467 + return (cname.equals("java.util.logging.Logger") ||
166.468 + cname.startsWith("java.util.logging.LoggingProxyImpl") ||
166.469 + cname.startsWith("sun.util.logging."));
166.470 + }
166.471 +}
167.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
167.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/Logger.java Mon Oct 07 14:20:58 2013 +0200
167.3 @@ -0,0 +1,1258 @@
167.4 +/*
167.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
167.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
167.7 + *
167.8 + * This code is free software; you can redistribute it and/or modify it
167.9 + * under the terms of the GNU General Public License version 2 only, as
167.10 + * published by the Free Software Foundation. Oracle designates this
167.11 + * particular file as subject to the "Classpath" exception as provided
167.12 + * by Oracle in the LICENSE file that accompanied this code.
167.13 + *
167.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
167.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
167.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
167.17 + * version 2 for more details (a copy is included in the LICENSE file that
167.18 + * accompanied this code).
167.19 + *
167.20 + * You should have received a copy of the GNU General Public License version
167.21 + * 2 along with this work; if not, write to the Free Software Foundation,
167.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
167.23 + *
167.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
167.25 + * or visit www.oracle.com if you need additional information or have any
167.26 + * questions.
167.27 + */
167.28 +
167.29 +
167.30 +package java.util.logging;
167.31 +
167.32 +import java.util.HashMap;
167.33 +import java.util.Map;
167.34 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
167.35 +
167.36 +/**
167.37 + * A Logger object is used to log messages for a specific
167.38 + * system or application component. Loggers are normally named,
167.39 + * using a hierarchical dot-separated namespace. Logger names
167.40 + * can be arbitrary strings, but they should normally be based on
167.41 + * the package name or class name of the logged component, such
167.42 + * as java.net or javax.swing. In addition it is possible to create
167.43 + * "anonymous" Loggers that are not stored in the Logger namespace.
167.44 + * <p>
167.45 + * Logger objects may be obtained by calls on one of the getLogger
167.46 + * factory methods. These will either create a new Logger or
167.47 + * return a suitable existing Logger. It is important to note that
167.48 + * the Logger returned by one of the {@code getLogger} factory methods
167.49 + * may be garbage collected at any time if a strong reference to the
167.50 + * Logger is not kept.
167.51 + * <p>
167.52 + * Logging messages will be forwarded to registered Handler
167.53 + * objects, which can forward the messages to a variety of
167.54 + * destinations, including consoles, files, OS logs, etc.
167.55 + * <p>
167.56 + * Each Logger keeps track of a "parent" Logger, which is its
167.57 + * nearest existing ancestor in the Logger namespace.
167.58 + * <p>
167.59 + * Each Logger has a "Level" associated with it. This reflects
167.60 + * a minimum Level that this logger cares about. If a Logger's
167.61 + * level is set to <tt>null</tt>, then its effective level is inherited
167.62 + * from its parent, which may in turn obtain it recursively from its
167.63 + * parent, and so on up the tree.
167.64 + * <p>
167.65 + * The log level can be configured based on the properties from the
167.66 + * logging configuration file, as described in the description
167.67 + * of the LogManager class. However it may also be dynamically changed
167.68 + * by calls on the Logger.setLevel method. If a logger's level is
167.69 + * changed the change may also affect child loggers, since any child
167.70 + * logger that has <tt>null</tt> as its level will inherit its
167.71 + * effective level from its parent.
167.72 + * <p>
167.73 + * On each logging call the Logger initially performs a cheap
167.74 + * check of the request level (e.g., SEVERE or FINE) against the
167.75 + * effective log level of the logger. If the request level is
167.76 + * lower than the log level, the logging call returns immediately.
167.77 + * <p>
167.78 + * After passing this initial (cheap) test, the Logger will allocate
167.79 + * a LogRecord to describe the logging message. It will then call a
167.80 + * Filter (if present) to do a more detailed check on whether the
167.81 + * record should be published. If that passes it will then publish
167.82 + * the LogRecord to its output Handlers. By default, loggers also
167.83 + * publish to their parent's Handlers, recursively up the tree.
167.84 + * <p>
167.85 + * Each Logger may have a ResourceBundle name associated with it.
167.86 + * The named bundle will be used for localizing logging messages.
167.87 + * If a Logger does not have its own ResourceBundle name, then
167.88 + * it will inherit the ResourceBundle name from its parent,
167.89 + * recursively up the tree.
167.90 + * <p>
167.91 + * Most of the logger output methods take a "msg" argument. This
167.92 + * msg argument may be either a raw value or a localization key.
167.93 + * During formatting, if the logger has (or inherits) a localization
167.94 + * ResourceBundle and if the ResourceBundle has a mapping for the msg
167.95 + * string, then the msg string is replaced by the localized value.
167.96 + * Otherwise the original msg string is used. Typically, formatters use
167.97 + * java.text.MessageFormat style formatting to format parameters, so
167.98 + * for example a format string "{0} {1}" would format two parameters
167.99 + * as strings.
167.100 + * <p>
167.101 + * When mapping ResourceBundle names to ResourceBundles, the Logger
167.102 + * will first try to use the Thread's ContextClassLoader. If that
167.103 + * is null it will try the SystemClassLoader instead. As a temporary
167.104 + * transition feature in the initial implementation, if the Logger is
167.105 + * unable to locate a ResourceBundle from the ContextClassLoader or
167.106 + * SystemClassLoader the Logger will also search up the class stack
167.107 + * and use successive calling ClassLoaders to try to locate a ResourceBundle.
167.108 + * (This call stack search is to allow containers to transition to
167.109 + * using ContextClassLoaders and is likely to be removed in future
167.110 + * versions.)
167.111 + * <p>
167.112 + * Formatting (including localization) is the responsibility of
167.113 + * the output Handler, which will typically call a Formatter.
167.114 + * <p>
167.115 + * Note that formatting need not occur synchronously. It may be delayed
167.116 + * until a LogRecord is actually written to an external sink.
167.117 + * <p>
167.118 + * The logging methods are grouped in five main categories:
167.119 + * <ul>
167.120 + * <li><p>
167.121 + * There are a set of "log" methods that take a log level, a message
167.122 + * string, and optionally some parameters to the message string.
167.123 + * <li><p>
167.124 + * There are a set of "logp" methods (for "log precise") that are
167.125 + * like the "log" methods, but also take an explicit source class name
167.126 + * and method name.
167.127 + * <li><p>
167.128 + * There are a set of "logrb" method (for "log with resource bundle")
167.129 + * that are like the "logp" method, but also take an explicit resource
167.130 + * bundle name for use in localizing the log message.
167.131 + * <li><p>
167.132 + * There are convenience methods for tracing method entries (the
167.133 + * "entering" methods), method returns (the "exiting" methods) and
167.134 + * throwing exceptions (the "throwing" methods).
167.135 + * <li><p>
167.136 + * Finally, there are a set of convenience methods for use in the
167.137 + * very simplest cases, when a developer simply wants to log a
167.138 + * simple string at a given log level. These methods are named
167.139 + * after the standard Level names ("severe", "warning", "info", etc.)
167.140 + * and take a single argument, a message string.
167.141 + * </ul>
167.142 + * <p>
167.143 + * For the methods that do not take an explicit source name and
167.144 + * method name, the Logging framework will make a "best effort"
167.145 + * to determine which class and method called into the logging method.
167.146 + * However, it is important to realize that this automatically inferred
167.147 + * information may only be approximate (or may even be quite wrong!).
167.148 + * Virtual machines are allowed to do extensive optimizations when
167.149 + * JITing and may entirely remove stack frames, making it impossible
167.150 + * to reliably locate the calling class and method.
167.151 + * <P>
167.152 + * All methods on Logger are multi-thread safe.
167.153 + * <p>
167.154 + * <b>Subclassing Information:</b> Note that a LogManager class may
167.155 + * provide its own implementation of named Loggers for any point in
167.156 + * the namespace. Therefore, any subclasses of Logger (unless they
167.157 + * are implemented in conjunction with a new LogManager class) should
167.158 + * take care to obtain a Logger instance from the LogManager class and
167.159 + * should delegate operations such as "isLoggable" and "log(LogRecord)"
167.160 + * to that instance. Note that in order to intercept all logging
167.161 + * output, subclasses need only override the log(LogRecord) method.
167.162 + * All the other logging methods are implemented as calls on this
167.163 + * log(LogRecord) method.
167.164 + *
167.165 + * @since 1.4
167.166 + */
167.167 +
167.168 +
167.169 +public class Logger {
167.170 + private static int offValue = Level.OFF.intValue();
167.171 + private static final Map<String,Logger> ALL = new HashMap<>();
167.172 + private String name;
167.173 +
167.174 + private volatile int levelValue; // current effective level value
167.175 + private Level levelObject;
167.176 +
167.177 + /**
167.178 + * GLOBAL_LOGGER_NAME is a name for the global logger.
167.179 + *
167.180 + * @since 1.6
167.181 + */
167.182 + public static final String GLOBAL_LOGGER_NAME = "global";
167.183 +
167.184 + /**
167.185 + * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
167.186 + *
167.187 + * @return global logger object
167.188 + * @since 1.7
167.189 + */
167.190 + public static final Logger getGlobal() {
167.191 + return global;
167.192 + }
167.193 +
167.194 + /**
167.195 + * The "global" Logger object is provided as a convenience to developers
167.196 + * who are making casual use of the Logging package. Developers
167.197 + * who are making serious use of the logging package (for example
167.198 + * in products) should create and use their own Logger objects,
167.199 + * with appropriate names, so that logging can be controlled on a
167.200 + * suitable per-Logger granularity. Developers also need to keep a
167.201 + * strong reference to their Logger objects to prevent them from
167.202 + * being garbage collected.
167.203 + * <p>
167.204 + * @deprecated Initialization of this field is prone to deadlocks.
167.205 + * The field must be initialized by the Logger class initialization
167.206 + * which may cause deadlocks with the LogManager class initialization.
167.207 + * In such cases two class initialization wait for each other to complete.
167.208 + * The preferred way to get the global logger object is via the call
167.209 + * <code>Logger.getGlobal()</code>.
167.210 + * For compatibility with old JDK versions where the
167.211 + * <code>Logger.getGlobal()</code> is not available use the call
167.212 + * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
167.213 + * or <code>Logger.getLogger("global")</code>.
167.214 + */
167.215 + @Deprecated
167.216 + public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
167.217 +
167.218 + /**
167.219 + * Protected method to construct a logger for a named subsystem.
167.220 + * <p>
167.221 + * The logger will be initially configured with a null Level
167.222 + * and with useParentHandlers set to true.
167.223 + *
167.224 + * @param name A name for the logger. This should
167.225 + * be a dot-separated name and should normally
167.226 + * be based on the package name or class name
167.227 + * of the subsystem, such as java.net
167.228 + * or javax.swing. It may be null for anonymous Loggers.
167.229 + * @param resourceBundleName name of ResourceBundle to be used for localizing
167.230 + * messages for this logger. May be null if none
167.231 + * of the messages require localization.
167.232 + * @throws MissingResourceException if the resourceBundleName is non-null and
167.233 + * no corresponding resource can be found.
167.234 + */
167.235 + protected Logger(String name, String resourceBundleName) {
167.236 + this.name = name;
167.237 + levelValue = Level.INFO.intValue();
167.238 + }
167.239 +
167.240 + // This constructor is used only to create the global Logger.
167.241 + // It is needed to break a cyclic dependence between the LogManager
167.242 + // and Logger static initializers causing deadlocks.
167.243 + private Logger(String name) {
167.244 + // The manager field is not initialized here.
167.245 + this.name = name;
167.246 + levelValue = Level.INFO.intValue();
167.247 + }
167.248 +
167.249 + private void checkAccess() throws SecurityException {
167.250 + throw new SecurityException();
167.251 + }
167.252 +
167.253 + /**
167.254 + * Find or create a logger for a named subsystem. If a logger has
167.255 + * already been created with the given name it is returned. Otherwise
167.256 + * a new logger is created.
167.257 + * <p>
167.258 + * If a new logger is created its log level will be configured
167.259 + * based on the LogManager configuration and it will configured
167.260 + * to also send logging output to its parent's Handlers. It will
167.261 + * be registered in the LogManager global namespace.
167.262 + * <p>
167.263 + * Note: The LogManager may only retain a weak reference to the newly
167.264 + * created Logger. It is important to understand that a previously
167.265 + * created Logger with the given name may be garbage collected at any
167.266 + * time if there is no strong reference to the Logger. In particular,
167.267 + * this means that two back-to-back calls like
167.268 + * {@code getLogger("MyLogger").log(...)} may use different Logger
167.269 + * objects named "MyLogger" if there is no strong reference to the
167.270 + * Logger named "MyLogger" elsewhere in the program.
167.271 + *
167.272 + * @param name A name for the logger. This should
167.273 + * be a dot-separated name and should normally
167.274 + * be based on the package name or class name
167.275 + * of the subsystem, such as java.net
167.276 + * or javax.swing
167.277 + * @return a suitable Logger
167.278 + * @throws NullPointerException if the name is null.
167.279 + */
167.280 +
167.281 + // Synchronization is not required here. All synchronization for
167.282 + // adding a new Logger object is handled by LogManager.addLogger().
167.283 + public static Logger getLogger(String name) {
167.284 + return getLogger(name, null);
167.285 + }
167.286 +
167.287 + /**
167.288 + * Find or create a logger for a named subsystem. If a logger has
167.289 + * already been created with the given name it is returned. Otherwise
167.290 + * a new logger is created.
167.291 + * <p>
167.292 + * If a new logger is created its log level will be configured
167.293 + * based on the LogManager and it will configured to also send logging
167.294 + * output to its parent's Handlers. It will be registered in
167.295 + * the LogManager global namespace.
167.296 + * <p>
167.297 + * Note: The LogManager may only retain a weak reference to the newly
167.298 + * created Logger. It is important to understand that a previously
167.299 + * created Logger with the given name may be garbage collected at any
167.300 + * time if there is no strong reference to the Logger. In particular,
167.301 + * this means that two back-to-back calls like
167.302 + * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
167.303 + * objects named "MyLogger" if there is no strong reference to the
167.304 + * Logger named "MyLogger" elsewhere in the program.
167.305 + * <p>
167.306 + * If the named Logger already exists and does not yet have a
167.307 + * localization resource bundle then the given resource bundle
167.308 + * name is used. If the named Logger already exists and has
167.309 + * a different resource bundle name then an IllegalArgumentException
167.310 + * is thrown.
167.311 + * <p>
167.312 + * @param name A name for the logger. This should
167.313 + * be a dot-separated name and should normally
167.314 + * be based on the package name or class name
167.315 + * of the subsystem, such as java.net
167.316 + * or javax.swing
167.317 + * @param resourceBundleName name of ResourceBundle to be used for localizing
167.318 + * messages for this logger. May be <CODE>null</CODE> if none of
167.319 + * the messages require localization.
167.320 + * @return a suitable Logger
167.321 + * @throws MissingResourceException if the resourceBundleName is non-null and
167.322 + * no corresponding resource can be found.
167.323 + * @throws IllegalArgumentException if the Logger already exists and uses
167.324 + * a different resource bundle name.
167.325 + * @throws NullPointerException if the name is null.
167.326 + */
167.327 +
167.328 + // Synchronization is not required here. All synchronization for
167.329 + // adding a new Logger object is handled by LogManager.addLogger().
167.330 + public static Logger getLogger(String name, String resourceBundleName) {
167.331 + Logger l = ALL.get(name);
167.332 + if (l == null) {
167.333 + l = new Logger(name, resourceBundleName);
167.334 + ALL.put(name, l);
167.335 + }
167.336 + return l;
167.337 + }
167.338 +
167.339 +
167.340 + /**
167.341 + * Create an anonymous Logger. The newly created Logger is not
167.342 + * registered in the LogManager namespace. There will be no
167.343 + * access checks on updates to the logger.
167.344 + * <p>
167.345 + * This factory method is primarily intended for use from applets.
167.346 + * Because the resulting Logger is anonymous it can be kept private
167.347 + * by the creating class. This removes the need for normal security
167.348 + * checks, which in turn allows untrusted applet code to update
167.349 + * the control state of the Logger. For example an applet can do
167.350 + * a setLevel or an addHandler on an anonymous Logger.
167.351 + * <p>
167.352 + * Even although the new logger is anonymous, it is configured
167.353 + * to have the root logger ("") as its parent. This means that
167.354 + * by default it inherits its effective level and handlers
167.355 + * from the root logger.
167.356 + * <p>
167.357 + *
167.358 + * @return a newly created private Logger
167.359 + */
167.360 + public static Logger getAnonymousLogger() {
167.361 + return getAnonymousLogger(null);
167.362 + }
167.363 +
167.364 + /**
167.365 + * Create an anonymous Logger. The newly created Logger is not
167.366 + * registered in the LogManager namespace. There will be no
167.367 + * access checks on updates to the logger.
167.368 + * <p>
167.369 + * This factory method is primarily intended for use from applets.
167.370 + * Because the resulting Logger is anonymous it can be kept private
167.371 + * by the creating class. This removes the need for normal security
167.372 + * checks, which in turn allows untrusted applet code to update
167.373 + * the control state of the Logger. For example an applet can do
167.374 + * a setLevel or an addHandler on an anonymous Logger.
167.375 + * <p>
167.376 + * Even although the new logger is anonymous, it is configured
167.377 + * to have the root logger ("") as its parent. This means that
167.378 + * by default it inherits its effective level and handlers
167.379 + * from the root logger.
167.380 + * <p>
167.381 + * @param resourceBundleName name of ResourceBundle to be used for localizing
167.382 + * messages for this logger.
167.383 + * May be null if none of the messages require localization.
167.384 + * @return a newly created private Logger
167.385 + * @throws MissingResourceException if the resourceBundleName is non-null and
167.386 + * no corresponding resource can be found.
167.387 + */
167.388 +
167.389 + // Synchronization is not required here. All synchronization for
167.390 + // adding a new anonymous Logger object is handled by doSetParent().
167.391 + public static Logger getAnonymousLogger(String resourceBundleName) {
167.392 + return new Logger(null, resourceBundleName);
167.393 + }
167.394 +
167.395 + /**
167.396 + * Retrieve the localization resource bundle for this
167.397 + * logger for the current default locale. Note that if
167.398 + * the result is null, then the Logger will use a resource
167.399 + * bundle inherited from its parent.
167.400 + *
167.401 + * @return localization bundle (may be null)
167.402 + */
167.403 +// public ResourceBundle getResourceBundle() {
167.404 +// return findResourceBundle(getResourceBundleName());
167.405 +// }
167.406 +
167.407 + /**
167.408 + * Retrieve the localization resource bundle name for this
167.409 + * logger. Note that if the result is null, then the Logger
167.410 + * will use a resource bundle name inherited from its parent.
167.411 + *
167.412 + * @return localization bundle name (may be null)
167.413 + */
167.414 + public String getResourceBundleName() {
167.415 + return null;
167.416 + }
167.417 +
167.418 + /**
167.419 + * Set a filter to control output on this Logger.
167.420 + * <P>
167.421 + * After passing the initial "level" check, the Logger will
167.422 + * call this Filter to check if a log record should really
167.423 + * be published.
167.424 + *
167.425 + * @param newFilter a filter object (may be null)
167.426 + * @exception SecurityException if a security manager exists and if
167.427 + * the caller does not have LoggingPermission("control").
167.428 + */
167.429 +// public void setFilter(Filter newFilter) throws SecurityException {
167.430 +// checkAccess();
167.431 +// }
167.432 +
167.433 + /**
167.434 + * Get the current filter for this Logger.
167.435 + *
167.436 + * @return a filter object (may be null)
167.437 + */
167.438 +// public Filter getFilter() {
167.439 +// return filter;
167.440 +// }
167.441 +
167.442 + /**
167.443 + * Log a LogRecord.
167.444 + * <p>
167.445 + * All the other logging methods in this class call through
167.446 + * this method to actually perform any logging. Subclasses can
167.447 + * override this single method to capture all log activity.
167.448 + *
167.449 + * @param record the LogRecord to be published
167.450 + */
167.451 + public void log(LogRecord record) {
167.452 + if (record.getLevel().intValue() < levelValue) {
167.453 + return;
167.454 + }
167.455 +
167.456 + String method;
167.457 + switch (record.getLevel().toString()) {
167.458 + case "INFO": method = "info"; break;
167.459 + case "SEVERE": method = "error"; break;
167.460 + case "WARNING": method = "warn"; break;
167.461 + default: method = "log"; break;
167.462 + }
167.463 +
167.464 + consoleLog(
167.465 + method,
167.466 + record.getLoggerName(),
167.467 + record.getMessage()
167.468 + );
167.469 + }
167.470 +
167.471 + @JavaScriptBody(args = { "method", "logger", "msg" }, body =
167.472 + "window.console[method]('[' + logger + ']: ' + msg);"
167.473 + )
167.474 + private static native void consoleLog(
167.475 + String method, String logger, String msg
167.476 + );
167.477 +
167.478 + // private support method for logging.
167.479 + // We fill in the logger name, resource bundle name, and
167.480 + // resource bundle and then call "void log(LogRecord)".
167.481 + private void doLog(LogRecord lr) {
167.482 + doLog(lr, lr.getResourceBundleName());
167.483 + }
167.484 + private void doLog(LogRecord lr, String bundleName) {
167.485 + lr.setLoggerName(name);
167.486 + log(lr);
167.487 + }
167.488 +
167.489 +
167.490 + //================================================================
167.491 + // Start of convenience methods WITHOUT className and methodName
167.492 + //================================================================
167.493 +
167.494 + /**
167.495 + * Log a message, with no arguments.
167.496 + * <p>
167.497 + * If the logger is currently enabled for the given message
167.498 + * level then the given message is forwarded to all the
167.499 + * registered output Handler objects.
167.500 + * <p>
167.501 + * @param level One of the message level identifiers, e.g., SEVERE
167.502 + * @param msg The string message (or a key in the message catalog)
167.503 + */
167.504 + public void log(Level level, String msg) {
167.505 + if (level.intValue() < levelValue || levelValue == offValue) {
167.506 + return;
167.507 + }
167.508 + LogRecord lr = new LogRecord(level, msg);
167.509 + doLog(lr);
167.510 + }
167.511 +
167.512 + /**
167.513 + * Log a message, with one object parameter.
167.514 + * <p>
167.515 + * If the logger is currently enabled for the given message
167.516 + * level then a corresponding LogRecord is created and forwarded
167.517 + * to all the registered output Handler objects.
167.518 + * <p>
167.519 + * @param level One of the message level identifiers, e.g., SEVERE
167.520 + * @param msg The string message (or a key in the message catalog)
167.521 + * @param param1 parameter to the message
167.522 + */
167.523 + public void log(Level level, String msg, Object param1) {
167.524 + if (level.intValue() < levelValue || levelValue == offValue) {
167.525 + return;
167.526 + }
167.527 + LogRecord lr = new LogRecord(level, msg);
167.528 + Object params[] = { param1 };
167.529 + lr.setParameters(params);
167.530 + doLog(lr);
167.531 + }
167.532 +
167.533 + /**
167.534 + * Log a message, with an array of object arguments.
167.535 + * <p>
167.536 + * If the logger is currently enabled for the given message
167.537 + * level then a corresponding LogRecord is created and forwarded
167.538 + * to all the registered output Handler objects.
167.539 + * <p>
167.540 + * @param level One of the message level identifiers, e.g., SEVERE
167.541 + * @param msg The string message (or a key in the message catalog)
167.542 + * @param params array of parameters to the message
167.543 + */
167.544 + public void log(Level level, String msg, Object params[]) {
167.545 + if (level.intValue() < levelValue || levelValue == offValue) {
167.546 + return;
167.547 + }
167.548 + LogRecord lr = new LogRecord(level, msg);
167.549 + lr.setParameters(params);
167.550 + doLog(lr);
167.551 + }
167.552 +
167.553 + /**
167.554 + * Log a message, with associated Throwable information.
167.555 + * <p>
167.556 + * If the logger is currently enabled for the given message
167.557 + * level then the given arguments are stored in a LogRecord
167.558 + * which is forwarded to all registered output handlers.
167.559 + * <p>
167.560 + * Note that the thrown argument is stored in the LogRecord thrown
167.561 + * property, rather than the LogRecord parameters property. Thus is it
167.562 + * processed specially by output Formatters and is not treated
167.563 + * as a formatting parameter to the LogRecord message property.
167.564 + * <p>
167.565 + * @param level One of the message level identifiers, e.g., SEVERE
167.566 + * @param msg The string message (or a key in the message catalog)
167.567 + * @param thrown Throwable associated with log message.
167.568 + */
167.569 + public void log(Level level, String msg, Throwable thrown) {
167.570 + if (level.intValue() < levelValue || levelValue == offValue) {
167.571 + return;
167.572 + }
167.573 + LogRecord lr = new LogRecord(level, msg);
167.574 + lr.setThrown(thrown);
167.575 + doLog(lr);
167.576 + }
167.577 +
167.578 + //================================================================
167.579 + // Start of convenience methods WITH className and methodName
167.580 + //================================================================
167.581 +
167.582 + /**
167.583 + * Log a message, specifying source class and method,
167.584 + * with no arguments.
167.585 + * <p>
167.586 + * If the logger is currently enabled for the given message
167.587 + * level then the given message is forwarded to all the
167.588 + * registered output Handler objects.
167.589 + * <p>
167.590 + * @param level One of the message level identifiers, e.g., SEVERE
167.591 + * @param sourceClass name of class that issued the logging request
167.592 + * @param sourceMethod name of method that issued the logging request
167.593 + * @param msg The string message (or a key in the message catalog)
167.594 + */
167.595 + public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
167.596 + if (level.intValue() < levelValue || levelValue == offValue) {
167.597 + return;
167.598 + }
167.599 + LogRecord lr = new LogRecord(level, msg);
167.600 + lr.setSourceClassName(sourceClass);
167.601 + lr.setSourceMethodName(sourceMethod);
167.602 + doLog(lr);
167.603 + }
167.604 +
167.605 + /**
167.606 + * Log a message, specifying source class and method,
167.607 + * with a single object parameter to the log message.
167.608 + * <p>
167.609 + * If the logger is currently enabled for the given message
167.610 + * level then a corresponding LogRecord is created and forwarded
167.611 + * to all the registered output Handler objects.
167.612 + * <p>
167.613 + * @param level One of the message level identifiers, e.g., SEVERE
167.614 + * @param sourceClass name of class that issued the logging request
167.615 + * @param sourceMethod name of method that issued the logging request
167.616 + * @param msg The string message (or a key in the message catalog)
167.617 + * @param param1 Parameter to the log message.
167.618 + */
167.619 + public void logp(Level level, String sourceClass, String sourceMethod,
167.620 + String msg, Object param1) {
167.621 + if (level.intValue() < levelValue || levelValue == offValue) {
167.622 + return;
167.623 + }
167.624 + LogRecord lr = new LogRecord(level, msg);
167.625 + lr.setSourceClassName(sourceClass);
167.626 + lr.setSourceMethodName(sourceMethod);
167.627 + Object params[] = { param1 };
167.628 + lr.setParameters(params);
167.629 + doLog(lr);
167.630 + }
167.631 +
167.632 + /**
167.633 + * Log a message, specifying source class and method,
167.634 + * with an array of object arguments.
167.635 + * <p>
167.636 + * If the logger is currently enabled for the given message
167.637 + * level then a corresponding LogRecord is created and forwarded
167.638 + * to all the registered output Handler objects.
167.639 + * <p>
167.640 + * @param level One of the message level identifiers, e.g., SEVERE
167.641 + * @param sourceClass name of class that issued the logging request
167.642 + * @param sourceMethod name of method that issued the logging request
167.643 + * @param msg The string message (or a key in the message catalog)
167.644 + * @param params Array of parameters to the message
167.645 + */
167.646 + public void logp(Level level, String sourceClass, String sourceMethod,
167.647 + String msg, Object params[]) {
167.648 + if (level.intValue() < levelValue || levelValue == offValue) {
167.649 + return;
167.650 + }
167.651 + LogRecord lr = new LogRecord(level, msg);
167.652 + lr.setSourceClassName(sourceClass);
167.653 + lr.setSourceMethodName(sourceMethod);
167.654 + lr.setParameters(params);
167.655 + doLog(lr);
167.656 + }
167.657 +
167.658 + /**
167.659 + * Log a message, specifying source class and method,
167.660 + * with associated Throwable information.
167.661 + * <p>
167.662 + * If the logger is currently enabled for the given message
167.663 + * level then the given arguments are stored in a LogRecord
167.664 + * which is forwarded to all registered output handlers.
167.665 + * <p>
167.666 + * Note that the thrown argument is stored in the LogRecord thrown
167.667 + * property, rather than the LogRecord parameters property. Thus is it
167.668 + * processed specially by output Formatters and is not treated
167.669 + * as a formatting parameter to the LogRecord message property.
167.670 + * <p>
167.671 + * @param level One of the message level identifiers, e.g., SEVERE
167.672 + * @param sourceClass name of class that issued the logging request
167.673 + * @param sourceMethod name of method that issued the logging request
167.674 + * @param msg The string message (or a key in the message catalog)
167.675 + * @param thrown Throwable associated with log message.
167.676 + */
167.677 + public void logp(Level level, String sourceClass, String sourceMethod,
167.678 + String msg, Throwable thrown) {
167.679 + if (level.intValue() < levelValue || levelValue == offValue) {
167.680 + return;
167.681 + }
167.682 + LogRecord lr = new LogRecord(level, msg);
167.683 + lr.setSourceClassName(sourceClass);
167.684 + lr.setSourceMethodName(sourceMethod);
167.685 + lr.setThrown(thrown);
167.686 + doLog(lr);
167.687 + }
167.688 +
167.689 +
167.690 + //=========================================================================
167.691 + // Start of convenience methods WITH className, methodName and bundle name.
167.692 + //=========================================================================
167.693 +
167.694 +
167.695 + /**
167.696 + * Log a message, specifying source class, method, and resource bundle name
167.697 + * with no arguments.
167.698 + * <p>
167.699 + * If the logger is currently enabled for the given message
167.700 + * level then the given message is forwarded to all the
167.701 + * registered output Handler objects.
167.702 + * <p>
167.703 + * The msg string is localized using the named resource bundle. If the
167.704 + * resource bundle name is null, or an empty String or invalid
167.705 + * then the msg string is not localized.
167.706 + * <p>
167.707 + * @param level One of the message level identifiers, e.g., SEVERE
167.708 + * @param sourceClass name of class that issued the logging request
167.709 + * @param sourceMethod name of method that issued the logging request
167.710 + * @param bundleName name of resource bundle to localize msg,
167.711 + * can be null
167.712 + * @param msg The string message (or a key in the message catalog)
167.713 + */
167.714 +
167.715 + public void logrb(Level level, String sourceClass, String sourceMethod,
167.716 + String bundleName, String msg) {
167.717 + if (level.intValue() < levelValue || levelValue == offValue) {
167.718 + return;
167.719 + }
167.720 + LogRecord lr = new LogRecord(level, msg);
167.721 + lr.setSourceClassName(sourceClass);
167.722 + lr.setSourceMethodName(sourceMethod);
167.723 + doLog(lr, bundleName);
167.724 + }
167.725 +
167.726 + /**
167.727 + * Log a message, specifying source class, method, and resource bundle name,
167.728 + * with a single object parameter to the log message.
167.729 + * <p>
167.730 + * If the logger is currently enabled for the given message
167.731 + * level then a corresponding LogRecord is created and forwarded
167.732 + * to all the registered output Handler objects.
167.733 + * <p>
167.734 + * The msg string is localized using the named resource bundle. If the
167.735 + * resource bundle name is null, or an empty String or invalid
167.736 + * then the msg string is not localized.
167.737 + * <p>
167.738 + * @param level One of the message level identifiers, e.g., SEVERE
167.739 + * @param sourceClass name of class that issued the logging request
167.740 + * @param sourceMethod name of method that issued the logging request
167.741 + * @param bundleName name of resource bundle to localize msg,
167.742 + * can be null
167.743 + * @param msg The string message (or a key in the message catalog)
167.744 + * @param param1 Parameter to the log message.
167.745 + */
167.746 + public void logrb(Level level, String sourceClass, String sourceMethod,
167.747 + String bundleName, String msg, Object param1) {
167.748 + if (level.intValue() < levelValue || levelValue == offValue) {
167.749 + return;
167.750 + }
167.751 + LogRecord lr = new LogRecord(level, msg);
167.752 + lr.setSourceClassName(sourceClass);
167.753 + lr.setSourceMethodName(sourceMethod);
167.754 + Object params[] = { param1 };
167.755 + lr.setParameters(params);
167.756 + doLog(lr, bundleName);
167.757 + }
167.758 +
167.759 + /**
167.760 + * Log a message, specifying source class, method, and resource bundle name,
167.761 + * with an array of object arguments.
167.762 + * <p>
167.763 + * If the logger is currently enabled for the given message
167.764 + * level then a corresponding LogRecord is created and forwarded
167.765 + * to all the registered output Handler objects.
167.766 + * <p>
167.767 + * The msg string is localized using the named resource bundle. If the
167.768 + * resource bundle name is null, or an empty String or invalid
167.769 + * then the msg string is not localized.
167.770 + * <p>
167.771 + * @param level One of the message level identifiers, e.g., SEVERE
167.772 + * @param sourceClass name of class that issued the logging request
167.773 + * @param sourceMethod name of method that issued the logging request
167.774 + * @param bundleName name of resource bundle to localize msg,
167.775 + * can be null.
167.776 + * @param msg The string message (or a key in the message catalog)
167.777 + * @param params Array of parameters to the message
167.778 + */
167.779 + public void logrb(Level level, String sourceClass, String sourceMethod,
167.780 + String bundleName, String msg, Object params[]) {
167.781 + if (level.intValue() < levelValue || levelValue == offValue) {
167.782 + return;
167.783 + }
167.784 + LogRecord lr = new LogRecord(level, msg);
167.785 + lr.setSourceClassName(sourceClass);
167.786 + lr.setSourceMethodName(sourceMethod);
167.787 + lr.setParameters(params);
167.788 + doLog(lr, bundleName);
167.789 + }
167.790 +
167.791 + /**
167.792 + * Log a message, specifying source class, method, and resource bundle name,
167.793 + * with associated Throwable information.
167.794 + * <p>
167.795 + * If the logger is currently enabled for the given message
167.796 + * level then the given arguments are stored in a LogRecord
167.797 + * which is forwarded to all registered output handlers.
167.798 + * <p>
167.799 + * The msg string is localized using the named resource bundle. If the
167.800 + * resource bundle name is null, or an empty String or invalid
167.801 + * then the msg string is not localized.
167.802 + * <p>
167.803 + * Note that the thrown argument is stored in the LogRecord thrown
167.804 + * property, rather than the LogRecord parameters property. Thus is it
167.805 + * processed specially by output Formatters and is not treated
167.806 + * as a formatting parameter to the LogRecord message property.
167.807 + * <p>
167.808 + * @param level One of the message level identifiers, e.g., SEVERE
167.809 + * @param sourceClass name of class that issued the logging request
167.810 + * @param sourceMethod name of method that issued the logging request
167.811 + * @param bundleName name of resource bundle to localize msg,
167.812 + * can be null
167.813 + * @param msg The string message (or a key in the message catalog)
167.814 + * @param thrown Throwable associated with log message.
167.815 + */
167.816 + public void logrb(Level level, String sourceClass, String sourceMethod,
167.817 + String bundleName, String msg, Throwable thrown) {
167.818 + if (level.intValue() < levelValue || levelValue == offValue) {
167.819 + return;
167.820 + }
167.821 + LogRecord lr = new LogRecord(level, msg);
167.822 + lr.setSourceClassName(sourceClass);
167.823 + lr.setSourceMethodName(sourceMethod);
167.824 + lr.setThrown(thrown);
167.825 + doLog(lr, bundleName);
167.826 + }
167.827 +
167.828 +
167.829 + //======================================================================
167.830 + // Start of convenience methods for logging method entries and returns.
167.831 + //======================================================================
167.832 +
167.833 + /**
167.834 + * Log a method entry.
167.835 + * <p>
167.836 + * This is a convenience method that can be used to log entry
167.837 + * to a method. A LogRecord with message "ENTRY", log level
167.838 + * FINER, and the given sourceMethod and sourceClass is logged.
167.839 + * <p>
167.840 + * @param sourceClass name of class that issued the logging request
167.841 + * @param sourceMethod name of method that is being entered
167.842 + */
167.843 + public void entering(String sourceClass, String sourceMethod) {
167.844 + if (Level.FINER.intValue() < levelValue) {
167.845 + return;
167.846 + }
167.847 + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
167.848 + }
167.849 +
167.850 + /**
167.851 + * Log a method entry, with one parameter.
167.852 + * <p>
167.853 + * This is a convenience method that can be used to log entry
167.854 + * to a method. A LogRecord with message "ENTRY {0}", log level
167.855 + * FINER, and the given sourceMethod, sourceClass, and parameter
167.856 + * is logged.
167.857 + * <p>
167.858 + * @param sourceClass name of class that issued the logging request
167.859 + * @param sourceMethod name of method that is being entered
167.860 + * @param param1 parameter to the method being entered
167.861 + */
167.862 + public void entering(String sourceClass, String sourceMethod, Object param1) {
167.863 + if (Level.FINER.intValue() < levelValue) {
167.864 + return;
167.865 + }
167.866 + Object params[] = { param1 };
167.867 + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
167.868 + }
167.869 +
167.870 + /**
167.871 + * Log a method entry, with an array of parameters.
167.872 + * <p>
167.873 + * This is a convenience method that can be used to log entry
167.874 + * to a method. A LogRecord with message "ENTRY" (followed by a
167.875 + * format {N} indicator for each entry in the parameter array),
167.876 + * log level FINER, and the given sourceMethod, sourceClass, and
167.877 + * parameters is logged.
167.878 + * <p>
167.879 + * @param sourceClass name of class that issued the logging request
167.880 + * @param sourceMethod name of method that is being entered
167.881 + * @param params array of parameters to the method being entered
167.882 + */
167.883 + public void entering(String sourceClass, String sourceMethod, Object params[]) {
167.884 + if (Level.FINER.intValue() < levelValue) {
167.885 + return;
167.886 + }
167.887 + String msg = "ENTRY";
167.888 + if (params == null ) {
167.889 + logp(Level.FINER, sourceClass, sourceMethod, msg);
167.890 + return;
167.891 + }
167.892 + for (int i = 0; i < params.length; i++) {
167.893 + msg = msg + " {" + i + "}";
167.894 + }
167.895 + logp(Level.FINER, sourceClass, sourceMethod, msg, params);
167.896 + }
167.897 +
167.898 + /**
167.899 + * Log a method return.
167.900 + * <p>
167.901 + * This is a convenience method that can be used to log returning
167.902 + * from a method. A LogRecord with message "RETURN", log level
167.903 + * FINER, and the given sourceMethod and sourceClass is logged.
167.904 + * <p>
167.905 + * @param sourceClass name of class that issued the logging request
167.906 + * @param sourceMethod name of the method
167.907 + */
167.908 + public void exiting(String sourceClass, String sourceMethod) {
167.909 + if (Level.FINER.intValue() < levelValue) {
167.910 + return;
167.911 + }
167.912 + logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
167.913 + }
167.914 +
167.915 +
167.916 + /**
167.917 + * Log a method return, with result object.
167.918 + * <p>
167.919 + * This is a convenience method that can be used to log returning
167.920 + * from a method. A LogRecord with message "RETURN {0}", log level
167.921 + * FINER, and the gives sourceMethod, sourceClass, and result
167.922 + * object is logged.
167.923 + * <p>
167.924 + * @param sourceClass name of class that issued the logging request
167.925 + * @param sourceMethod name of the method
167.926 + * @param result Object that is being returned
167.927 + */
167.928 + public void exiting(String sourceClass, String sourceMethod, Object result) {
167.929 + if (Level.FINER.intValue() < levelValue) {
167.930 + return;
167.931 + }
167.932 + Object params[] = { result };
167.933 + logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
167.934 + }
167.935 +
167.936 + /**
167.937 + * Log throwing an exception.
167.938 + * <p>
167.939 + * This is a convenience method to log that a method is
167.940 + * terminating by throwing an exception. The logging is done
167.941 + * using the FINER level.
167.942 + * <p>
167.943 + * If the logger is currently enabled for the given message
167.944 + * level then the given arguments are stored in a LogRecord
167.945 + * which is forwarded to all registered output handlers. The
167.946 + * LogRecord's message is set to "THROW".
167.947 + * <p>
167.948 + * Note that the thrown argument is stored in the LogRecord thrown
167.949 + * property, rather than the LogRecord parameters property. Thus is it
167.950 + * processed specially by output Formatters and is not treated
167.951 + * as a formatting parameter to the LogRecord message property.
167.952 + * <p>
167.953 + * @param sourceClass name of class that issued the logging request
167.954 + * @param sourceMethod name of the method.
167.955 + * @param thrown The Throwable that is being thrown.
167.956 + */
167.957 + public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
167.958 + if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
167.959 + return;
167.960 + }
167.961 + LogRecord lr = new LogRecord(Level.FINER, "THROW");
167.962 + lr.setSourceClassName(sourceClass);
167.963 + lr.setSourceMethodName(sourceMethod);
167.964 + lr.setThrown(thrown);
167.965 + doLog(lr);
167.966 + }
167.967 +
167.968 + //=======================================================================
167.969 + // Start of simple convenience methods using level names as method names
167.970 + //=======================================================================
167.971 +
167.972 + /**
167.973 + * Log a SEVERE message.
167.974 + * <p>
167.975 + * If the logger is currently enabled for the SEVERE message
167.976 + * level then the given message is forwarded to all the
167.977 + * registered output Handler objects.
167.978 + * <p>
167.979 + * @param msg The string message (or a key in the message catalog)
167.980 + */
167.981 + public void severe(String msg) {
167.982 + if (Level.SEVERE.intValue() < levelValue) {
167.983 + return;
167.984 + }
167.985 + log(Level.SEVERE, msg);
167.986 + }
167.987 +
167.988 + /**
167.989 + * Log a WARNING message.
167.990 + * <p>
167.991 + * If the logger is currently enabled for the WARNING message
167.992 + * level then the given message is forwarded to all the
167.993 + * registered output Handler objects.
167.994 + * <p>
167.995 + * @param msg The string message (or a key in the message catalog)
167.996 + */
167.997 + public void warning(String msg) {
167.998 + if (Level.WARNING.intValue() < levelValue) {
167.999 + return;
167.1000 + }
167.1001 + log(Level.WARNING, msg);
167.1002 + }
167.1003 +
167.1004 + /**
167.1005 + * Log an INFO message.
167.1006 + * <p>
167.1007 + * If the logger is currently enabled for the INFO message
167.1008 + * level then the given message is forwarded to all the
167.1009 + * registered output Handler objects.
167.1010 + * <p>
167.1011 + * @param msg The string message (or a key in the message catalog)
167.1012 + */
167.1013 + public void info(String msg) {
167.1014 + if (Level.INFO.intValue() < levelValue) {
167.1015 + return;
167.1016 + }
167.1017 + log(Level.INFO, msg);
167.1018 + }
167.1019 +
167.1020 + /**
167.1021 + * Log a CONFIG message.
167.1022 + * <p>
167.1023 + * If the logger is currently enabled for the CONFIG message
167.1024 + * level then the given message is forwarded to all the
167.1025 + * registered output Handler objects.
167.1026 + * <p>
167.1027 + * @param msg The string message (or a key in the message catalog)
167.1028 + */
167.1029 + public void config(String msg) {
167.1030 + if (Level.CONFIG.intValue() < levelValue) {
167.1031 + return;
167.1032 + }
167.1033 + log(Level.CONFIG, msg);
167.1034 + }
167.1035 +
167.1036 + /**
167.1037 + * Log a FINE message.
167.1038 + * <p>
167.1039 + * If the logger is currently enabled for the FINE message
167.1040 + * level then the given message is forwarded to all the
167.1041 + * registered output Handler objects.
167.1042 + * <p>
167.1043 + * @param msg The string message (or a key in the message catalog)
167.1044 + */
167.1045 + public void fine(String msg) {
167.1046 + if (Level.FINE.intValue() < levelValue) {
167.1047 + return;
167.1048 + }
167.1049 + log(Level.FINE, msg);
167.1050 + }
167.1051 +
167.1052 + /**
167.1053 + * Log a FINER message.
167.1054 + * <p>
167.1055 + * If the logger is currently enabled for the FINER message
167.1056 + * level then the given message is forwarded to all the
167.1057 + * registered output Handler objects.
167.1058 + * <p>
167.1059 + * @param msg The string message (or a key in the message catalog)
167.1060 + */
167.1061 + public void finer(String msg) {
167.1062 + if (Level.FINER.intValue() < levelValue) {
167.1063 + return;
167.1064 + }
167.1065 + log(Level.FINER, msg);
167.1066 + }
167.1067 +
167.1068 + /**
167.1069 + * Log a FINEST message.
167.1070 + * <p>
167.1071 + * If the logger is currently enabled for the FINEST message
167.1072 + * level then the given message is forwarded to all the
167.1073 + * registered output Handler objects.
167.1074 + * <p>
167.1075 + * @param msg The string message (or a key in the message catalog)
167.1076 + */
167.1077 + public void finest(String msg) {
167.1078 + if (Level.FINEST.intValue() < levelValue) {
167.1079 + return;
167.1080 + }
167.1081 + log(Level.FINEST, msg);
167.1082 + }
167.1083 +
167.1084 + //================================================================
167.1085 + // End of convenience methods
167.1086 + //================================================================
167.1087 +
167.1088 + /**
167.1089 + * Set the log level specifying which message levels will be
167.1090 + * logged by this logger. Message levels lower than this
167.1091 + * value will be discarded. The level value Level.OFF
167.1092 + * can be used to turn off logging.
167.1093 + * <p>
167.1094 + * If the new level is null, it means that this node should
167.1095 + * inherit its level from its nearest ancestor with a specific
167.1096 + * (non-null) level value.
167.1097 + *
167.1098 + * @param newLevel the new value for the log level (may be null)
167.1099 + * @exception SecurityException if a security manager exists and if
167.1100 + * the caller does not have LoggingPermission("control").
167.1101 + */
167.1102 + public void setLevel(Level newLevel) throws SecurityException {
167.1103 + levelValue = newLevel.intValue();
167.1104 + levelObject = newLevel;
167.1105 + }
167.1106 +
167.1107 + /**
167.1108 + * Get the log Level that has been specified for this Logger.
167.1109 + * The result may be null, which means that this logger's
167.1110 + * effective level will be inherited from its parent.
167.1111 + *
167.1112 + * @return this Logger's level
167.1113 + */
167.1114 + public Level getLevel() {
167.1115 + return levelObject;
167.1116 + }
167.1117 +
167.1118 + /**
167.1119 + * Check if a message of the given level would actually be logged
167.1120 + * by this logger. This check is based on the Loggers effective level,
167.1121 + * which may be inherited from its parent.
167.1122 + *
167.1123 + * @param level a message logging level
167.1124 + * @return true if the given message level is currently being logged.
167.1125 + */
167.1126 + public boolean isLoggable(Level level) {
167.1127 + if (level.intValue() < levelValue || levelValue == offValue) {
167.1128 + return false;
167.1129 + }
167.1130 + return true;
167.1131 + }
167.1132 +
167.1133 + /**
167.1134 + * Get the name for this logger.
167.1135 + * @return logger name. Will be null for anonymous Loggers.
167.1136 + */
167.1137 + public String getName() {
167.1138 + return name;
167.1139 + }
167.1140 +
167.1141 + /**
167.1142 + * Add a log Handler to receive logging messages.
167.1143 + * <p>
167.1144 + * By default, Loggers also send their output to their parent logger.
167.1145 + * Typically the root Logger is configured with a set of Handlers
167.1146 + * that essentially act as default handlers for all loggers.
167.1147 + *
167.1148 + * @param handler a logging Handler
167.1149 + * @exception SecurityException if a security manager exists and if
167.1150 + * the caller does not have LoggingPermission("control").
167.1151 + */
167.1152 +// public void addHandler(Handler handler) throws SecurityException {
167.1153 +// // Check for null handler
167.1154 +// handler.getClass();
167.1155 +// checkAccess();
167.1156 +// handlers.add(handler);
167.1157 +// }
167.1158 +
167.1159 + /**
167.1160 + * Remove a log Handler.
167.1161 + * <P>
167.1162 + * Returns silently if the given Handler is not found or is null
167.1163 + *
167.1164 + * @param handler a logging Handler
167.1165 + * @exception SecurityException if a security manager exists and if
167.1166 + * the caller does not have LoggingPermission("control").
167.1167 + */
167.1168 +// public void removeHandler(Handler handler) throws SecurityException {
167.1169 +// checkAccess();
167.1170 +// if (handler == null) {
167.1171 +// return;
167.1172 +// }
167.1173 +// handlers.remove(handler);
167.1174 +// }
167.1175 +
167.1176 + /**
167.1177 + * Get the Handlers associated with this logger.
167.1178 + * <p>
167.1179 + * @return an array of all registered Handlers
167.1180 + */
167.1181 +// public Handler[] getHandlers() {
167.1182 +// return handlers.toArray(emptyHandlers);
167.1183 +// }
167.1184 +
167.1185 + /**
167.1186 + * Specify whether or not this logger should send its output
167.1187 + * to its parent Logger. This means that any LogRecords will
167.1188 + * also be written to the parent's Handlers, and potentially
167.1189 + * to its parent, recursively up the namespace.
167.1190 + *
167.1191 + * @param useParentHandlers true if output is to be sent to the
167.1192 + * logger's parent.
167.1193 + * @exception SecurityException if a security manager exists and if
167.1194 + * the caller does not have LoggingPermission("control").
167.1195 + */
167.1196 + public void setUseParentHandlers(boolean useParentHandlers) {
167.1197 + checkAccess();
167.1198 + }
167.1199 +
167.1200 + /**
167.1201 + * Discover whether or not this logger is sending its output
167.1202 + * to its parent logger.
167.1203 + *
167.1204 + * @return true if output is to be sent to the logger's parent
167.1205 + */
167.1206 + public boolean getUseParentHandlers() {
167.1207 + return true;
167.1208 + }
167.1209 +
167.1210 + /**
167.1211 + * Return the parent for this Logger.
167.1212 + * <p>
167.1213 + * This method returns the nearest extant parent in the namespace.
167.1214 + * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
167.1215 + * has been created but no logger "a.b.c" exists, then a call of
167.1216 + * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
167.1217 + * <p>
167.1218 + * The result will be null if it is called on the root Logger
167.1219 + * in the namespace.
167.1220 + *
167.1221 + * @return nearest existing parent Logger
167.1222 + */
167.1223 + public Logger getParent() {
167.1224 + // Note: this used to be synchronized on treeLock. However, this only
167.1225 + // provided memory semantics, as there was no guarantee that the caller
167.1226 + // would synchronize on treeLock (in fact, there is no way for external
167.1227 + // callers to so synchronize). Therefore, we have made parent volatile
167.1228 + // instead.
167.1229 + String n = getName();
167.1230 + int at = n.length();
167.1231 + for (;;) {
167.1232 + int last = n.lastIndexOf('.', at - 1);
167.1233 + if (last == -1) {
167.1234 + return getGlobal();
167.1235 + }
167.1236 + Logger p = ALL.get(n.substring(0, last));
167.1237 + if (p != null) {
167.1238 + return p;
167.1239 + }
167.1240 + at = last;
167.1241 + }
167.1242 + }
167.1243 +
167.1244 + /**
167.1245 + * Set the parent for this Logger. This method is used by
167.1246 + * the LogManager to update a Logger when the namespace changes.
167.1247 + * <p>
167.1248 + * It should not be called from application code.
167.1249 + * <p>
167.1250 + * @param parent the new parent logger
167.1251 + * @exception SecurityException if a security manager exists and if
167.1252 + * the caller does not have LoggingPermission("control").
167.1253 + */
167.1254 + public void setParent(Logger parent) {
167.1255 + if (parent == null) {
167.1256 + throw new NullPointerException();
167.1257 + }
167.1258 + checkAccess();
167.1259 + }
167.1260 +
167.1261 +}
168.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java Wed Feb 27 17:50:47 2013 +0100
168.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java Mon Oct 07 14:20:58 2013 +0200
168.3 @@ -18,8 +18,10 @@
168.4 package org.apidesign.bck2brwsr.compact.tck;
168.5
168.6 import java.io.ByteArrayInputStream;
168.7 +import java.io.ByteArrayOutputStream;
168.8 import java.io.IOException;
168.9 import java.io.InputStreamReader;
168.10 +import java.io.OutputStreamWriter;
168.11 import java.io.UnsupportedEncodingException;
168.12 import java.util.Arrays;
168.13 import org.apidesign.bck2brwsr.vmtest.Compare;
168.14 @@ -40,7 +42,10 @@
168.15 };
168.16 ByteArrayInputStream is = new ByteArrayInputStream(arr);
168.17 InputStreamReader r = new InputStreamReader(is, "UTF-8");
168.18 -
168.19 + return readReader(r);
168.20 + }
168.21 +
168.22 + private String readReader(InputStreamReader r) throws IOException {
168.23 StringBuilder sb = new StringBuilder();
168.24 for (;;) {
168.25 int ch = r.read();
168.26 @@ -52,7 +57,19 @@
168.27 return sb.toString().toString();
168.28 }
168.29 @Compare public String stringToBytes() throws UnsupportedEncodingException {
168.30 - return Arrays.toString("\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("UTF-8"));
168.31 + return Arrays.toString(YellowHorse.getBytes("UTF-8"));
168.32 + }
168.33 + private final String YellowHorse = "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148";
168.34 +
168.35 + @Compare public String readAndWrite() throws Exception {
168.36 + ByteArrayOutputStream arr = new ByteArrayOutputStream();
168.37 + OutputStreamWriter w = new OutputStreamWriter(arr);
168.38 + w.write(YellowHorse);
168.39 + w.close();
168.40 +
168.41 + ByteArrayInputStream is = new ByteArrayInputStream(arr.toByteArray());
168.42 + InputStreamReader r = new InputStreamReader(is, "UTF-8");
168.43 + return readReader(r);
168.44 }
168.45
168.46 @Factory public static Object[] create() {
169.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipCompatibilityTest.java Wed Feb 27 17:50:47 2013 +0100
169.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipCompatibilityTest.java Mon Oct 07 14:20:58 2013 +0200
169.3 @@ -30,9 +30,10 @@
169.4 public class ZipCompatibilityTest {
169.5 @Compare
169.6 public String testDemoStaticCalculator() throws IOException {
169.7 - InputStream is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar");
169.8 + InputStream is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar");
169.9 ZipArchive zip = ZipArchive.createZip(is);
169.10 - return zip.toString();
169.11 + final String ts = zip.toString();
169.12 + return ts.substring(0, 4096) + ts.hashCode();
169.13 }
169.14
169.15 @Factory
170.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipVsJzLibTest.java Wed Feb 27 17:50:47 2013 +0100
170.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipVsJzLibTest.java Mon Oct 07 14:20:58 2013 +0200
170.3 @@ -27,10 +27,10 @@
170.4 */
170.5 public class ZipVsJzLibTest {
170.6 @Test public void r() throws IOException {
170.7 - InputStream is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar");
170.8 + InputStream is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar");
170.9 ZipArchive zip = ZipArchive.createZip(is);
170.10
170.11 - is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar");
170.12 + is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar");
170.13 ZipArchive real = ZipArchive.createReal(is);
170.14
170.15 real.assertEquals(zip, "Are they the same?");
171.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
171.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Mon Oct 07 14:20:58 2013 +0200
171.3 @@ -0,0 +1,43 @@
171.4 +/**
171.5 + * Back 2 Browser Bytecode Translator
171.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
171.7 + *
171.8 + * This program is free software: you can redistribute it and/or modify
171.9 + * it under the terms of the GNU General Public License as published by
171.10 + * the Free Software Foundation, version 2 of the License.
171.11 + *
171.12 + * This program is distributed in the hope that it will be useful,
171.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
171.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
171.15 + * GNU General Public License for more details.
171.16 + *
171.17 + * You should have received a copy of the GNU General Public License
171.18 + * along with this program. Look for COPYING file in the top folder.
171.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
171.20 + */
171.21 +package org.apidesign.bck2brwsr.tck;
171.22 +
171.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
171.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
171.25 +import org.testng.annotations.Factory;
171.26 +
171.27 +/**
171.28 + *
171.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
171.30 + */
171.31 +public class AssertionTest {
171.32 +
171.33 + @Compare public Object checkAssert() throws ClassNotFoundException {
171.34 + try {
171.35 + assert false : "Is assertion status on?";
171.36 + return null;
171.37 + } catch (AssertionError ex) {
171.38 + return ex.getClass().getName();
171.39 + }
171.40 + }
171.41 +
171.42 + @Factory
171.43 + public static Object[] create() {
171.44 + return VMTest.create(AssertionTest.class);
171.45 + }
171.46 +}
172.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
172.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Mon Oct 07 14:20:58 2013 +0200
172.3 @@ -0,0 +1,57 @@
172.4 +/**
172.5 + * Back 2 Browser Bytecode Translator
172.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
172.7 + *
172.8 + * This program is free software: you can redistribute it and/or modify
172.9 + * it under the terms of the GNU General Public License as published by
172.10 + * the Free Software Foundation, version 2 of the License.
172.11 + *
172.12 + * This program is distributed in the hope that it will be useful,
172.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
172.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
172.15 + * GNU General Public License for more details.
172.16 + *
172.17 + * You should have received a copy of the GNU General Public License
172.18 + * along with this program. Look for COPYING file in the top folder.
172.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
172.20 + */
172.21 +package org.apidesign.bck2brwsr.tck;
172.22 +
172.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
172.24 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
172.25 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
172.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
172.27 +import org.testng.annotations.Factory;
172.28 +
172.29 +/**
172.30 + *
172.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
172.32 + */
172.33 +public class BrwsrCheckTest {
172.34 +
172.35 + @BrwsrTest public void assertWindowObjectIsDefined() {
172.36 + assert window() != null : "No window object found!";
172.37 + }
172.38 +
172.39 +
172.40 +
172.41 +
172.42 + @HtmlFragment("<h1 id='hello'>\n"
172.43 + + "Hello!\n"
172.44 + + "</h1>\n")
172.45 + @BrwsrTest public void accessProvidedFragment() {
172.46 + assert getElementById("hello") != null : "Element with 'hello' ID found";
172.47 + }
172.48 +
172.49 + @Factory
172.50 + public static Object[] create() {
172.51 + return VMTest.create(BrwsrCheckTest.class);
172.52 + }
172.53 +
172.54 +
172.55 + @JavaScriptBody(args = {}, body = "return window;")
172.56 + private static native Object window();
172.57 +
172.58 + @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);")
172.59 + private static native Object getElementById(String id);
172.60 +}
173.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
173.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Mon Oct 07 14:20:58 2013 +0200
173.3 @@ -0,0 +1,147 @@
173.4 +/**
173.5 + * Back 2 Browser Bytecode Translator
173.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
173.7 + *
173.8 + * This program is free software: you can redistribute it and/or modify
173.9 + * it under the terms of the GNU General Public License as published by
173.10 + * the Free Software Foundation, version 2 of the License.
173.11 + *
173.12 + * This program is distributed in the hope that it will be useful,
173.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
173.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
173.15 + * GNU General Public License for more details.
173.16 + *
173.17 + * You should have received a copy of the GNU General Public License
173.18 + * along with this program. Look for COPYING file in the top folder.
173.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
173.20 + */
173.21 +package org.apidesign.bck2brwsr.tck;
173.22 +
173.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
173.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
173.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
173.26 +import org.testng.annotations.Factory;
173.27 +
173.28 +/**
173.29 + *
173.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
173.31 + */
173.32 +public class ByteArithmeticTest {
173.33 +
173.34 + private static byte add(byte x, byte y) {
173.35 + return (byte)(x + y);
173.36 + }
173.37 +
173.38 + private static byte sub(byte x, byte y) {
173.39 + return (byte)(x - y);
173.40 + }
173.41 +
173.42 + private static byte mul(byte x, byte y) {
173.43 + return (byte)(x * y);
173.44 + }
173.45 +
173.46 + private static byte div(byte x, byte y) {
173.47 + return (byte)(x / y);
173.48 + }
173.49 +
173.50 + private static byte mod(byte x, byte y) {
173.51 + return (byte)(x % y);
173.52 + }
173.53 +
173.54 + @Compare public byte conversion() {
173.55 + return (byte)123456;
173.56 + }
173.57 +
173.58 + @Compare public byte addOverflow() {
173.59 + return add(Byte.MAX_VALUE, (byte)1);
173.60 + }
173.61 +
173.62 + @Compare public byte subUnderflow() {
173.63 + return sub(Byte.MIN_VALUE, (byte)1);
173.64 + }
173.65 +
173.66 + @Compare public byte addMaxByteAndMaxByte() {
173.67 + return add(Byte.MAX_VALUE, Byte.MAX_VALUE);
173.68 + }
173.69 +
173.70 + @Compare public byte subMinByteAndMinByte() {
173.71 + return sub(Byte.MIN_VALUE, Byte.MIN_VALUE);
173.72 + }
173.73 +
173.74 + @Compare public byte multiplyMaxByte() {
173.75 + return mul(Byte.MAX_VALUE, (byte)2);
173.76 + }
173.77 +
173.78 + @Compare public byte multiplyMaxByteAndMaxByte() {
173.79 + return mul(Byte.MAX_VALUE, Byte.MAX_VALUE);
173.80 + }
173.81 +
173.82 + @Compare public byte multiplyMinByte() {
173.83 + return mul(Byte.MIN_VALUE, (byte)2);
173.84 + }
173.85 +
173.86 + @Compare public byte multiplyMinByteAndMinByte() {
173.87 + return mul(Byte.MIN_VALUE, Byte.MIN_VALUE);
173.88 + }
173.89 +
173.90 + @Compare public byte multiplyPrecision() {
173.91 + return mul((byte)17638, (byte)1103);
173.92 + }
173.93 +
173.94 + @Compare public byte division() {
173.95 + return div((byte)1, (byte)2);
173.96 + }
173.97 +
173.98 + @Compare public byte divisionReminder() {
173.99 + return mod((byte)1, (byte)2);
173.100 + }
173.101 +
173.102 + private static int readShort(byte[] byteCodes, int offset) {
173.103 + int signed = byteCodes[offset];
173.104 + byte b0 = (byte)signed;
173.105 + return (b0 << 8) | (byteCodes[offset + 1] & 0xff);
173.106 + }
173.107 +
173.108 + private static int readShortArg(byte[] byteCodes, int offsetInstruction) {
173.109 + return readShort(byteCodes, offsetInstruction + 1);
173.110 + }
173.111 +
173.112 + @Compare public int readIntArgs255and156() {
173.113 + final byte[] arr = new byte[] { (byte)0, (byte)255, (byte)156 };
173.114 +
173.115 + assert arr[1] == -1 : "First byte: " + arr[1];
173.116 + assert arr[2] == -100 : "Second byte: " + arr[2];
173.117 + final int ret = readShortArg(arr, 0);
173.118 + assert ret < 65000: "Value: " + ret;
173.119 + return ret;
173.120 + }
173.121 +
173.122 + @JavaScriptBody(args = { "arr" }, body = "arr[1] = 255; arr[2] = 156; return arr;")
173.123 + private static byte[] fill255and156(byte[] arr) {
173.124 + arr[1] = (byte)255;
173.125 + arr[2] = (byte)156;
173.126 + return arr;
173.127 + }
173.128 +
173.129 + @Compare public int readIntArgs255and156JSArray() {
173.130 + final byte[] arr = fill255and156(new byte[] { 0, 0, 0 });
173.131 +
173.132 + final int ret = readShortArg(arr, 0);
173.133 + assert ret < 65000: "Value: " + ret;
173.134 + return ret;
173.135 + }
173.136 +
173.137 + @Compare public int readIntArgsMinus1andMinus100() {
173.138 + final byte[] arr = new byte[] { (byte)0, (byte)-1, (byte)-100 };
173.139 +
173.140 + assert arr[1] == -1 : "First byte: " + arr[1];
173.141 + assert arr[2] == -100 : "Second byte: " + arr[2];
173.142 +
173.143 + return readShortArg(arr, 0);
173.144 + }
173.145 +
173.146 + @Factory
173.147 + public static Object[] create() {
173.148 + return VMTest.create(ByteArithmeticTest.class);
173.149 + }
173.150 +}
174.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
174.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java Mon Oct 07 14:20:58 2013 +0200
174.3 @@ -0,0 +1,73 @@
174.4 +/**
174.5 + * Back 2 Browser Bytecode Translator
174.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
174.7 + *
174.8 + * This program is free software: you can redistribute it and/or modify
174.9 + * it under the terms of the GNU General Public License as published by
174.10 + * the Free Software Foundation, version 2 of the License.
174.11 + *
174.12 + * This program is distributed in the hope that it will be useful,
174.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
174.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
174.15 + * GNU General Public License for more details.
174.16 + *
174.17 + * You should have received a copy of the GNU General Public License
174.18 + * along with this program. Look for COPYING file in the top folder.
174.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
174.20 + */
174.21 +package org.apidesign.bck2brwsr.tck;
174.22 +
174.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
174.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
174.25 +import org.testng.annotations.Factory;
174.26 +
174.27 +/**
174.28 + *
174.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
174.30 + */
174.31 +public class CloneTest {
174.32 + private int value;
174.33 +
174.34 + @Compare
174.35 + public Object notSupported() throws CloneNotSupportedException {
174.36 + return this.clone();
174.37 + }
174.38 +
174.39 + @Compare public String sameClass() throws CloneNotSupportedException {
174.40 + return new Clnbl().clone().getClass().getName();
174.41 + }
174.42 +
174.43 + @Compare public boolean differentInstance() throws CloneNotSupportedException {
174.44 + Clnbl orig = new Clnbl();
174.45 + return orig == orig.clone();
174.46 + }
174.47 +
174.48 + @Compare public int sameReference() throws CloneNotSupportedException {
174.49 + CloneTest self = this;
174.50 + Clnbl orig = new Clnbl();
174.51 + self.value = 33;
174.52 + orig.ref = self;
174.53 + return ((Clnbl)orig.clone()).ref.value;
174.54 + }
174.55 +
174.56 + @Compare public int sameValue() throws CloneNotSupportedException {
174.57 + Clnbl orig = new Clnbl();
174.58 + orig.value = 10;
174.59 + return ((Clnbl)orig.clone()).value;
174.60 + }
174.61 +
174.62 + @Factory
174.63 + public static Object[] create() {
174.64 + return VMTest.create(CloneTest.class);
174.65 + }
174.66 +
174.67 + public static final class Clnbl implements Cloneable {
174.68 + public CloneTest ref;
174.69 + private int value;
174.70 +
174.71 + @Override
174.72 + public Object clone() throws CloneNotSupportedException {
174.73 + return super.clone();
174.74 + }
174.75 + }
174.76 +}
175.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
175.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Mon Oct 07 14:20:58 2013 +0200
175.3 @@ -0,0 +1,103 @@
175.4 +/**
175.5 + * Back 2 Browser Bytecode Translator
175.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
175.7 + *
175.8 + * This program is free software: you can redistribute it and/or modify
175.9 + * it under the terms of the GNU General Public License as published by
175.10 + * the Free Software Foundation, version 2 of the License.
175.11 + *
175.12 + * This program is distributed in the hope that it will be useful,
175.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
175.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
175.15 + * GNU General Public License for more details.
175.16 + *
175.17 + * You should have received a copy of the GNU General Public License
175.18 + * along with this program. Look for COPYING file in the top folder.
175.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
175.20 + */
175.21 +package org.apidesign.bck2brwsr.tck;
175.22 +
175.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
175.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
175.25 +import org.testng.annotations.Factory;
175.26 +
175.27 +/**
175.28 + *
175.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
175.30 + */
175.31 +public class CompareByteArrayTest {
175.32 + @Compare public int byteArraySum() {
175.33 + byte[] arr = createArray();
175.34 + return sumByteArr(arr);
175.35 + }
175.36 +
175.37 + @Compare public int countZeros() {
175.38 + int zeros = 0;
175.39 + for (Byte b : createArray()) {
175.40 + if (b == 0) {
175.41 + zeros++;
175.42 + }
175.43 + }
175.44 + return zeros;
175.45 + }
175.46 +
175.47 + private static int sumByteArr(byte[] arr) {
175.48 + int sum = 0;
175.49 + for (int i = 0; i < arr.length; i++) {
175.50 + sum += arr[i];
175.51 + }
175.52 + return sum;
175.53 + }
175.54 +
175.55 + @Compare public String noOutOfBounds() {
175.56 + return atIndex(1);
175.57 + }
175.58 +
175.59 + @Compare public String outOfBounds() {
175.60 + return atIndex(5);
175.61 + }
175.62 +
175.63 + @Compare public String outOfBoundsMinus() {
175.64 + return atIndex(-1);
175.65 + }
175.66 +
175.67 + @Compare public String toOfBounds() {
175.68 + return toIndex(5);
175.69 + }
175.70 +
175.71 + @Compare public String toOfBoundsMinus() {
175.72 + return toIndex(-1);
175.73 + }
175.74 +
175.75 + @Compare public int multiArrayLength() {
175.76 + int[][] arr = new int[1][0];
175.77 + return arr[0].length;
175.78 + }
175.79 +
175.80 + @Compare public int multiObjectArrayLength() {
175.81 + Object[][] arr = new Object[1][0];
175.82 + return arr[0].length;
175.83 + }
175.84 +
175.85 + private static final int[] arr = { 0, 1, 2 };
175.86 + public static String atIndex(int at) {
175.87 + return "at@" + arr[at];
175.88 + }
175.89 + public static String toIndex(int at) {
175.90 + arr[at] = 10;
175.91 + return "ok";
175.92 + }
175.93 +
175.94 +
175.95 + @Factory
175.96 + public static Object[] create() {
175.97 + return VMTest.create(CompareByteArrayTest.class);
175.98 + }
175.99 +
175.100 + private byte[] createArray() {
175.101 + byte[] arr = new byte[10];
175.102 + arr[5] = 3;
175.103 + arr[7] = 8;
175.104 + return arr;
175.105 + }
175.106 +}
176.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
176.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Mon Oct 07 14:20:58 2013 +0200
176.3 @@ -0,0 +1,60 @@
176.4 +/**
176.5 + * Back 2 Browser Bytecode Translator
176.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
176.7 + *
176.8 + * This program is free software: you can redistribute it and/or modify
176.9 + * it under the terms of the GNU General Public License as published by
176.10 + * the Free Software Foundation, version 2 of the License.
176.11 + *
176.12 + * This program is distributed in the hope that it will be useful,
176.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
176.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
176.15 + * GNU General Public License for more details.
176.16 + *
176.17 + * You should have received a copy of the GNU General Public License
176.18 + * along with this program. Look for COPYING file in the top folder.
176.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
176.20 + */
176.21 +package org.apidesign.bck2brwsr.tck;
176.22 +
176.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
176.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
176.25 +import org.testng.annotations.Factory;
176.26 +
176.27 +/**
176.28 + *
176.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
176.30 + */
176.31 +public class CompareHashTest {
176.32 + @Compare public int hashOfString() {
176.33 + return "Ahoj".hashCode();
176.34 + }
176.35 +
176.36 + @Compare public boolean hashOfIntegerDifferentToOwnHash() {
176.37 + Integer i = 120;
176.38 + return System.identityHashCode(i) != i.hashCode();
176.39 + }
176.40 +
176.41 + @Compare public int hashOfObjectSameAsOwnHash() {
176.42 + Object o = new Object();
176.43 + return System.identityHashCode(o) - o.hashCode();
176.44 + }
176.45 +
176.46 + @Compare public int hashRemainsYieldsZero() {
176.47 + Object o = new Object();
176.48 + return o.hashCode() - o.hashCode();
176.49 + }
176.50 +
176.51 + @Compare public int initializeInStatic() {
176.52 + return StaticUse.NON_NULL.hashCode() - StaticUse.NON_NULL.hashCode();
176.53 + }
176.54 +
176.55 + @Compare public int hashOfInt() {
176.56 + return Integer.valueOf(Integer.MAX_VALUE).hashCode();
176.57 + }
176.58 +
176.59 + @Factory
176.60 + public static Object[] create() {
176.61 + return VMTest.create(CompareHashTest.class);
176.62 + }
176.63 +}
177.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
177.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java Mon Oct 07 14:20:58 2013 +0200
177.3 @@ -0,0 +1,63 @@
177.4 +/**
177.5 + * Back 2 Browser Bytecode Translator
177.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
177.7 + *
177.8 + * This program is free software: you can redistribute it and/or modify
177.9 + * it under the terms of the GNU General Public License as published by
177.10 + * the Free Software Foundation, version 2 of the License.
177.11 + *
177.12 + * This program is distributed in the hope that it will be useful,
177.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
177.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
177.15 + * GNU General Public License for more details.
177.16 + *
177.17 + * You should have received a copy of the GNU General Public License
177.18 + * along with this program. Look for COPYING file in the top folder.
177.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
177.20 + */
177.21 +package org.apidesign.bck2brwsr.tck;
177.22 +
177.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
177.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
177.25 +import org.testng.annotations.Factory;
177.26 +
177.27 +/**
177.28 + *
177.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
177.30 + */
177.31 +public class CompareIntArrayTest {
177.32 + @Compare public int integerArraySum() {
177.33 + int[] arr = createArray();
177.34 + return sumIntArr(arr);
177.35 + }
177.36 +
177.37 + @Compare public int countZeros() {
177.38 + int zeros = 0;
177.39 + for (Integer i : createArray()) {
177.40 + if (i == 0) {
177.41 + zeros++;
177.42 + }
177.43 + }
177.44 + return zeros;
177.45 + }
177.46 +
177.47 + private static int sumIntArr(int[] arr) {
177.48 + int sum = 0;
177.49 + for (int i = 0; i < arr.length; i++) {
177.50 + sum += arr[i];
177.51 + }
177.52 + return sum;
177.53 + }
177.54 +
177.55 + @Factory
177.56 + public static Object[] create() {
177.57 + return VMTest.create(CompareIntArrayTest.class);
177.58 + }
177.59 +
177.60 + private int[] createArray() {
177.61 + int[] arr = new int[10];
177.62 + arr[5] = 3;
177.63 + arr[7] = 8;
177.64 + return arr;
177.65 + }
177.66 +}
178.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
178.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Mon Oct 07 14:20:58 2013 +0200
178.3 @@ -0,0 +1,174 @@
178.4 +/**
178.5 + * Back 2 Browser Bytecode Translator
178.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
178.7 + *
178.8 + * This program is free software: you can redistribute it and/or modify
178.9 + * it under the terms of the GNU General Public License as published by
178.10 + * the Free Software Foundation, version 2 of the License.
178.11 + *
178.12 + * This program is distributed in the hope that it will be useful,
178.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
178.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
178.15 + * GNU General Public License for more details.
178.16 + *
178.17 + * You should have received a copy of the GNU General Public License
178.18 + * along with this program. Look for COPYING file in the top folder.
178.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
178.20 + */
178.21 +package org.apidesign.bck2brwsr.tck;
178.22 +
178.23 +import java.io.UnsupportedEncodingException;
178.24 +import java.net.MalformedURLException;
178.25 +import java.net.URL;
178.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
178.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
178.28 +import org.testng.annotations.Factory;
178.29 +
178.30 +/**
178.31 + *
178.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
178.33 + */
178.34 +public class CompareStringsTest {
178.35 + @Compare public String firstChar() {
178.36 + return "" + ("Hello".toCharArray()[0]);
178.37 + }
178.38 +
178.39 + @Compare public String classCast() {
178.40 + Object o = firstChar();
178.41 + return String.class.cast(o);
178.42 + }
178.43 +
178.44 + @Compare public String classCastThrown() {
178.45 + Object o = null;
178.46 + return String.class.cast(o);
178.47 + }
178.48 +
178.49 + @Compare public boolean equalToNull() {
178.50 + return "Ahoj".equals(null);
178.51 + }
178.52 +
178.53 + @Compare public int highByteLenght() {
178.54 + byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
178.55 + return new String(arr, 0).length();
178.56 + }
178.57 +
178.58 + @Compare public String highByte() {
178.59 + byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
178.60 + StringBuilder sb = new StringBuilder();
178.61 + sb.append("pref:");
178.62 + sb.append(new String(arr, 0));
178.63 + return sb.toString();
178.64 + }
178.65 +
178.66 + @Compare public static Object compareURLs() throws MalformedURLException {
178.67 + return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
178.68 + }
178.69 +
178.70 + @Compare public String deleteLastTwoCharacters() {
178.71 + StringBuilder sb = new StringBuilder();
178.72 + sb.append("453.0");
178.73 + if (sb.toString().endsWith(".0")) {
178.74 + final int l = sb.length();
178.75 + sb.delete(l - 2, l);
178.76 + }
178.77 + return sb.toString().toString();
178.78 + }
178.79 +
178.80 + @Compare public String nameOfStringClass() throws Exception {
178.81 + return Class.forName("java.lang.String").getName();
178.82 + }
178.83 + @Compare public String nameOfArrayClass() throws Exception {
178.84 + return Class.forName("org.apidesign.bck2brwsr.tck.CompareHashTest").getName();
178.85 + }
178.86 +
178.87 + @Compare public String lowerHello() {
178.88 + return "HeLlO".toLowerCase();
178.89 + }
178.90 +
178.91 + @Compare public String lowerA() {
178.92 + return String.valueOf(Character.toLowerCase('A')).toString();
178.93 + }
178.94 + @Compare public String upperHello() {
178.95 + return "hello".toUpperCase();
178.96 + }
178.97 +
178.98 + @Compare public String upperA() {
178.99 + return String.valueOf(Character.toUpperCase('a')).toString();
178.100 + }
178.101 +
178.102 + @Compare public boolean matchRegExp() throws Exception {
178.103 + return "58038503".matches("\\d*");
178.104 + }
178.105 +
178.106 + @Compare public boolean doesNotMatchRegExp() throws Exception {
178.107 + return "58038503GH".matches("\\d*");
178.108 + }
178.109 +
178.110 + @Compare public boolean doesNotMatchRegExpFully() throws Exception {
178.111 + return "Hello".matches("Hell");
178.112 + }
178.113 +
178.114 + @Compare public String emptyCharArray() {
178.115 + char[] arr = new char[10];
178.116 + return new String(arr);
178.117 + }
178.118 +
178.119 + @Compare public String variousCharacterTests() throws Exception {
178.120 + StringBuilder sb = new StringBuilder();
178.121 +
178.122 + sb.append(Character.isUpperCase('a'));
178.123 + sb.append(Character.isUpperCase('A'));
178.124 + sb.append(Character.isLowerCase('a'));
178.125 + sb.append(Character.isLowerCase('A'));
178.126 +
178.127 + sb.append(Character.isLetter('A'));
178.128 + sb.append(Character.isLetterOrDigit('9'));
178.129 + sb.append(Character.isLetterOrDigit('A'));
178.130 + sb.append(Character.isLetter('0'));
178.131 +
178.132 + return sb.toString().toString();
178.133 + }
178.134 +
178.135 + @Compare
178.136 + public String nullFieldInitialized() {
178.137 + NullField nf = new NullField();
178.138 + return ("" + nf.name).toString();
178.139 + }
178.140 + @Compare
178.141 + public String toUTFString() throws UnsupportedEncodingException {
178.142 + byte[] arr = {
178.143 + (byte) -59, (byte) -67, (byte) 108, (byte) 117, (byte) -59, (byte) -91,
178.144 + (byte) 111, (byte) 117, (byte) -60, (byte) -115, (byte) 107, (byte) -61,
178.145 + (byte) -67, (byte) 32, (byte) 107, (byte) -59, (byte) -81, (byte) -59,
178.146 + (byte) -120
178.147 + };
178.148 + return new String(arr, "utf-8");
178.149 + }
178.150 +
178.151 + @Compare
178.152 + public int stringToBytesLenght() throws UnsupportedEncodingException {
178.153 + return "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("utf8").length;
178.154 + }
178.155 +
178.156 + @Compare public String replaceSeq() {
178.157 + return "Hello World.".replace(".", "!");
178.158 + }
178.159 + @Compare public String replaceSeqAll() {
178.160 + return "Hello World! Hello World.".replace("World", "Jarda");
178.161 + }
178.162 + @Compare public String replaceSeqAA() {
178.163 + String res = "aaa".replace("aa", "b");
178.164 + assert res.equals("ba") : "Expecting ba: " + res;
178.165 + return res;
178.166 + }
178.167 +
178.168 + @Factory
178.169 + public static Object[] create() {
178.170 + return VMTest.create(CompareStringsTest.class);
178.171 + }
178.172 +
178.173 + private static final class NullField {
178.174 +
178.175 + String name;
178.176 + }
178.177 +}
179.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
179.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java Mon Oct 07 14:20:58 2013 +0200
179.3 @@ -0,0 +1,69 @@
179.4 +/**
179.5 + * Back 2 Browser Bytecode Translator
179.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
179.7 + *
179.8 + * This program is free software: you can redistribute it and/or modify
179.9 + * it under the terms of the GNU General Public License as published by
179.10 + * the Free Software Foundation, version 2 of the License.
179.11 + *
179.12 + * This program is distributed in the hope that it will be useful,
179.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
179.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
179.15 + * GNU General Public License for more details.
179.16 + *
179.17 + * You should have received a copy of the GNU General Public License
179.18 + * along with this program. Look for COPYING file in the top folder.
179.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
179.20 + */
179.21 +package org.apidesign.bck2brwsr.tck;
179.22 +
179.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
179.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
179.25 +import org.testng.annotations.Factory;
179.26 +
179.27 +/**
179.28 + *
179.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
179.30 + */
179.31 +public class DoubleTest {
179.32 + @Compare public boolean parsedDoubleIsDouble() {
179.33 + return Double.valueOf("1.1") instanceof Double;
179.34 + }
179.35 +
179.36 + @Compare public String integerToString() {
179.37 + return toStr(1);
179.38 + }
179.39 +
179.40 + @Compare public String integerAndHalfToString() {
179.41 + return toStr(1.5);
179.42 + }
179.43 +
179.44 + @Compare public double longToAndBack() {
179.45 + return Double.parseDouble(toStr(Long.MAX_VALUE / 10));
179.46 + }
179.47 +
179.48 + @Compare public String negativeIntToString() {
179.49 + return toStr(-10);
179.50 + }
179.51 +
179.52 + @Compare public String negativeIntAndHalfToString() {
179.53 + return toStr(-10.5);
179.54 + }
179.55 +
179.56 + @Compare public double negativeLongAndBack() {
179.57 + return Double.parseDouble(toStr(Long.MIN_VALUE / 10));
179.58 + }
179.59 +
179.60 + @Compare public double canParseExp() {
179.61 + return Double.parseDouble(toStr(1.7976931348623157e+308));
179.62 + }
179.63 +
179.64 + private static String toStr(double d) {
179.65 + return Double.toString(d);
179.66 + }
179.67 +
179.68 + @Factory
179.69 + public static Object[] create() {
179.70 + return VMTest.create(DoubleTest.class);
179.71 + }
179.72 +}
180.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
180.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/EnumsTest.java Mon Oct 07 14:20:58 2013 +0200
180.3 @@ -0,0 +1,61 @@
180.4 +package org.apidesign.bck2brwsr.tck;
180.5 +
180.6 +import java.util.EnumMap;
180.7 +import java.util.EnumSet;
180.8 +import org.apidesign.bck2brwsr.vmtest.Compare;
180.9 +import org.apidesign.bck2brwsr.vmtest.VMTest;
180.10 +import org.testng.annotations.Factory;
180.11 +
180.12 +/**
180.13 + *
180.14 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
180.15 + */
180.16 +public class EnumsTest {
180.17 + enum Color {
180.18 + B, W;
180.19 + }
180.20 +
180.21 + /*
180.22 + @Compare public String enumSet() {
180.23 + try { throw new Exception(); } catch (Exception ex) {}
180.24 + EnumSet<Color> c = EnumSet.allOf(Color.class);
180.25 + return c.toString();
180.26 + }
180.27 +
180.28 + @Compare public String enumSetOneByOne() {
180.29 + EnumSet<Color> c = EnumSet.of(Color.B, Color.W);
180.30 + return c.toString();
180.31 + }
180.32 + */
180.33 +
180.34 + @Compare public boolean enumFirstContains() {
180.35 + EnumSet<Color> c = EnumSet.of(Color.B);
180.36 + return c.contains(Color.B);
180.37 + }
180.38 +
180.39 + @Compare public boolean enumFirstDoesNotContains() {
180.40 + EnumSet<Color> c = EnumSet.of(Color.B);
180.41 + return c.contains(Color.W);
180.42 + }
180.43 +
180.44 + @Compare public boolean enumSndContains() {
180.45 + EnumSet<Color> c = EnumSet.of(Color.W);
180.46 + return c.contains(Color.W);
180.47 + }
180.48 +
180.49 + @Compare public boolean enumSecondDoesNotContains() {
180.50 + EnumSet<Color> c = EnumSet.of(Color.W);
180.51 + return c.contains(Color.B);
180.52 + }
180.53 +
180.54 + @Compare public String enumMap() {
180.55 + EnumMap<Color,String> c = new EnumMap(Color.class);
180.56 + c.put(Color.B, "Black");
180.57 + c.put(Color.W, "White");
180.58 + return c.toString();
180.59 + }
180.60 +
180.61 + @Factory public static Object[] create() {
180.62 + return VMTest.create(EnumsTest.class);
180.63 + }
180.64 +}
181.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
181.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java Mon Oct 07 14:20:58 2013 +0200
181.3 @@ -0,0 +1,106 @@
181.4 +/**
181.5 + * Back 2 Browser Bytecode Translator
181.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
181.7 + *
181.8 + * This program is free software: you can redistribute it and/or modify
181.9 + * it under the terms of the GNU General Public License as published by
181.10 + * the Free Software Foundation, version 2 of the License.
181.11 + *
181.12 + * This program is distributed in the hope that it will be useful,
181.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
181.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181.15 + * GNU General Public License for more details.
181.16 + *
181.17 + * You should have received a copy of the GNU General Public License
181.18 + * along with this program. Look for COPYING file in the top folder.
181.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
181.20 + */
181.21 +package org.apidesign.bck2brwsr.tck;
181.22 +
181.23 +import java.io.InputStream;
181.24 +import java.net.URL;
181.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
181.26 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
181.27 +import org.apidesign.bck2brwsr.vmtest.Http;
181.28 +import org.apidesign.bck2brwsr.vmtest.VMTest;
181.29 +import org.testng.annotations.Factory;
181.30 +
181.31 +/**
181.32 + *
181.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
181.34 + */
181.35 +public class HttpResourceTest {
181.36 +
181.37 + @Http({
181.38 + @Http.Resource(path = "/xhr", content = "Hello Brwsr!", mimeType = "text/plain")
181.39 + })
181.40 + @BrwsrTest
181.41 +
181.42 +
181.43 + public String testReadContentViaXHR() throws Exception {
181.44 + String msg = read("/xhr");
181.45 + assert "Hello Brwsr!".equals(msg) : "The message was " + msg;
181.46 + return msg;
181.47 + }
181.48 +
181.49 + @Http({
181.50 + @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain")
181.51 + })
181.52 + @BrwsrTest
181.53 + public String testReadContentViaURL() throws Exception {
181.54 + URL url = new URL("http:/url");
181.55 + String msg = (String) url.getContent();
181.56 + assert "Hello via URL!".equals(msg) : "The message was " + msg;
181.57 + return msg;
181.58 + }
181.59 + @Http({
181.60 + @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain")
181.61 + })
181.62 + @BrwsrTest
181.63 + public String testReadContentViaURLWithStringParam() throws Exception {
181.64 + URL url = new URL("http:/url");
181.65 + String msg = (String) url.getContent(new Class[] { String.class });
181.66 + assert "Hello via URL!".equals(msg) : "The message was " + msg;
181.67 + return msg;
181.68 + }
181.69 +
181.70 + @Http({
181.71 + @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary")
181.72 + })
181.73 + @BrwsrTest
181.74 + public void testReadByte() throws Exception {
181.75 + URL url = new URL("http:/bytes");
181.76 + final Object res = url.getContent(new Class[] { byte[].class });
181.77 + assert res instanceof byte[] : "Expecting byte[]: " + res;
181.78 + byte[] arr = (byte[]) res;
181.79 + assert arr.length == 1 : "One byte " + arr.length;
181.80 + assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]);
181.81 + }
181.82 +
181.83 + @Http({
181.84 + @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary")
181.85 + })
181.86 + @BrwsrTest
181.87 + public void testReadByteViaInputStream() throws Exception {
181.88 + URL url = new URL("http:/bytes");
181.89 + InputStream is = url.openStream();
181.90 + byte[] arr = new byte[10];
181.91 + int len = is.read(arr);
181.92 + assert len == 1 : "One byte " + len;
181.93 + assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]);
181.94 + }
181.95 +
181.96 + @JavaScriptBody(args = { "url" }, body =
181.97 + "var req = new XMLHttpRequest();\n"
181.98 + + "req.open('GET', url, false);\n"
181.99 + + "req.send();\n"
181.100 + + "return req.responseText;"
181.101 + )
181.102 + private static native String read(String url);
181.103 +
181.104 +
181.105 + @Factory
181.106 + public static Object[] create() {
181.107 + return VMTest.create(HttpResourceTest.class);
181.108 + }
181.109 +}
182.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java Mon Oct 07 14:20:58 2013 +0200
182.3 @@ -0,0 +1,34 @@
182.4 +/**
182.5 + * Back 2 Browser Bytecode Translator
182.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
182.7 + *
182.8 + * This program is free software: you can redistribute it and/or modify
182.9 + * it under the terms of the GNU General Public License as published by
182.10 + * the Free Software Foundation, version 2 of the License.
182.11 + *
182.12 + * This program is distributed in the hope that it will be useful,
182.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
182.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
182.15 + * GNU General Public License for more details.
182.16 + *
182.17 + * You should have received a copy of the GNU General Public License
182.18 + * along with this program. Look for COPYING file in the top folder.
182.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
182.20 + */
182.21 +package org.apidesign.bck2brwsr.tck;
182.22 +
182.23 +/**
182.24 + *
182.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
182.26 + */
182.27 +public class InheritanceA {
182.28 + private String name;
182.29 +
182.30 + public void setA(String n) {
182.31 + this.name = n;
182.32 + }
182.33 +
182.34 + public String getA() {
182.35 + return name;
182.36 + }
182.37 +}
183.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
183.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java Mon Oct 07 14:20:58 2013 +0200
183.3 @@ -0,0 +1,34 @@
183.4 +/**
183.5 + * Back 2 Browser Bytecode Translator
183.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
183.7 + *
183.8 + * This program is free software: you can redistribute it and/or modify
183.9 + * it under the terms of the GNU General Public License as published by
183.10 + * the Free Software Foundation, version 2 of the License.
183.11 + *
183.12 + * This program is distributed in the hope that it will be useful,
183.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
183.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183.15 + * GNU General Public License for more details.
183.16 + *
183.17 + * You should have received a copy of the GNU General Public License
183.18 + * along with this program. Look for COPYING file in the top folder.
183.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
183.20 + */
183.21 +package org.apidesign.bck2brwsr.tck;
183.22 +
183.23 +/**
183.24 + *
183.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
183.26 + */
183.27 +public class InheritanceB extends InheritanceA {
183.28 + private String name;
183.29 +
183.30 + public void setB(String n) {
183.31 + this.name = n;
183.32 + }
183.33 +
183.34 + public String getB() {
183.35 + return name;
183.36 + }
183.37 +}
184.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
184.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java Mon Oct 07 14:20:58 2013 +0200
184.3 @@ -0,0 +1,41 @@
184.4 +/**
184.5 + * Back 2 Browser Bytecode Translator
184.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
184.7 + *
184.8 + * This program is free software: you can redistribute it and/or modify
184.9 + * it under the terms of the GNU General Public License as published by
184.10 + * the Free Software Foundation, version 2 of the License.
184.11 + *
184.12 + * This program is distributed in the hope that it will be useful,
184.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
184.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
184.15 + * GNU General Public License for more details.
184.16 + *
184.17 + * You should have received a copy of the GNU General Public License
184.18 + * along with this program. Look for COPYING file in the top folder.
184.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
184.20 + */
184.21 +package org.apidesign.bck2brwsr.tck;
184.22 +
184.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
184.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
184.25 +import org.testng.annotations.Factory;
184.26 +
184.27 +/**
184.28 + *
184.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
184.30 + */
184.31 +public class InheritanceTest {
184.32 +
184.33 + @Compare public String checkFieldsIndependent() throws ClassNotFoundException {
184.34 + InheritanceB ib = new InheritanceB();
184.35 + ib.setA("A");
184.36 + ib.setB("B");
184.37 + return "A: " + ib.getA() + " B: " + ib.getB();
184.38 + }
184.39 +
184.40 + @Factory
184.41 + public static Object[] create() {
184.42 + return VMTest.create(InheritanceTest.class);
184.43 + }
184.44 +}
185.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
185.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Mon Oct 07 14:20:58 2013 +0200
185.3 @@ -0,0 +1,166 @@
185.4 +/**
185.5 + * Back 2 Browser Bytecode Translator
185.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
185.7 + *
185.8 + * This program is free software: you can redistribute it and/or modify
185.9 + * it under the terms of the GNU General Public License as published by
185.10 + * the Free Software Foundation, version 2 of the License.
185.11 + *
185.12 + * This program is distributed in the hope that it will be useful,
185.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
185.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
185.15 + * GNU General Public License for more details.
185.16 + *
185.17 + * You should have received a copy of the GNU General Public License
185.18 + * along with this program. Look for COPYING file in the top folder.
185.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
185.20 + */
185.21 +package org.apidesign.bck2brwsr.tck;
185.22 +
185.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
185.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
185.25 +import org.testng.annotations.Factory;
185.26 +
185.27 +/**
185.28 + *
185.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
185.30 + */
185.31 +public class IntegerArithmeticTest {
185.32 +
185.33 + private static int add(int x, int y) {
185.34 + return x + y;
185.35 + }
185.36 +
185.37 + private static int sub(int x, int y) {
185.38 + return x - y;
185.39 + }
185.40 +
185.41 + private static int mul(int x, int y) {
185.42 + return x * y;
185.43 + }
185.44 +
185.45 + private static int div(int x, int y) {
185.46 + return x / y;
185.47 + }
185.48 +
185.49 + private static int mod(int x, int y) {
185.50 + return x % y;
185.51 + }
185.52 +
185.53 + private static int neg(int x) {
185.54 + return (-x);
185.55 + }
185.56 +
185.57 + private static float fadd(float x, float y) {
185.58 + return x + y;
185.59 + }
185.60 +
185.61 + private static double dadd(double x, double y) {
185.62 + return x + y;
185.63 + }
185.64 +
185.65 + @Compare public int addOverflow() {
185.66 + return add(Integer.MAX_VALUE, 1);
185.67 + }
185.68 +
185.69 + @Compare public int subUnderflow() {
185.70 + return sub(Integer.MIN_VALUE, 1);
185.71 + }
185.72 +
185.73 + @Compare public int addMaxIntAndMaxInt() {
185.74 + return add(Integer.MAX_VALUE, Integer.MAX_VALUE);
185.75 + }
185.76 +
185.77 + @Compare public int subMinIntAndMinInt() {
185.78 + return sub(Integer.MIN_VALUE, Integer.MIN_VALUE);
185.79 + }
185.80 +
185.81 + @Compare public int multiplyMaxInt() {
185.82 + return mul(Integer.MAX_VALUE, 2);
185.83 + }
185.84 +
185.85 + @Compare public int multiplyMaxIntAndMaxInt() {
185.86 + return mul(Integer.MAX_VALUE, Integer.MAX_VALUE);
185.87 + }
185.88 +
185.89 + @Compare public int multiplyMinInt() {
185.90 + return mul(Integer.MIN_VALUE, 2);
185.91 + }
185.92 +
185.93 + @Compare public int multiplyMinIntAndMinInt() {
185.94 + return mul(Integer.MIN_VALUE, Integer.MIN_VALUE);
185.95 + }
185.96 +
185.97 + @Compare public int multiplyPrecision() {
185.98 + return mul(119106029, 1103515245);
185.99 + }
185.100 +
185.101 + @Compare public int division() {
185.102 + return div(1, 2);
185.103 + }
185.104 +
185.105 + @Compare public int divisionReminder() {
185.106 + return mod(1, 2);
185.107 + }
185.108 +
185.109 + @Compare public int negativeDivision() {
185.110 + return div(-7, 3);
185.111 + }
185.112 +
185.113 + @Compare public int negativeDivisionReminder() {
185.114 + return mod(-7, 3);
185.115 + }
185.116 +
185.117 + @Compare public int conversionFromFloat() {
185.118 + return (int) fadd(-2, -0.6f);
185.119 + }
185.120 +
185.121 + @Compare public int conversionFromDouble() {
185.122 + return (int) dadd(-2, -0.6);
185.123 + }
185.124 +
185.125 + @Compare public boolean divByZeroThrowsArithmeticException() {
185.126 + try {
185.127 + div(1, 0);
185.128 + return false;
185.129 + } catch (final ArithmeticException e) {
185.130 + return true;
185.131 + }
185.132 + }
185.133 +
185.134 + @Compare public boolean modByZeroThrowsArithmeticException() {
185.135 + try {
185.136 + mod(1, 0);
185.137 + return false;
185.138 + } catch (final ArithmeticException e) {
185.139 + return true;
185.140 + }
185.141 + }
185.142 +
185.143 + @Compare public int negate() {
185.144 + return neg(123456);
185.145 + }
185.146 +
185.147 + @Compare public int negateMaxInt() {
185.148 + return neg(Integer.MAX_VALUE);
185.149 + }
185.150 +
185.151 + @Compare public int negateMinInt() {
185.152 + return neg(Integer.MIN_VALUE);
185.153 + }
185.154 +
185.155 + @Compare public int sumTwoDimensions() {
185.156 + int[][] matrix = createMatrix(4, 3);
185.157 + matrix[0][0] += 10;
185.158 + return matrix[0][0];
185.159 + }
185.160 +
185.161 + static int[][] createMatrix(int x, int y) {
185.162 + return new int[x][y];
185.163 + }
185.164 +
185.165 + @Factory
185.166 + public static Object[] create() {
185.167 + return VMTest.create(IntegerArithmeticTest.class);
185.168 + }
185.169 +}
186.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
186.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LoggerTest.java Mon Oct 07 14:20:58 2013 +0200
186.3 @@ -0,0 +1,43 @@
186.4 +/**
186.5 + * Back 2 Browser Bytecode Translator
186.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
186.7 + *
186.8 + * This program is free software: you can redistribute it and/or modify
186.9 + * it under the terms of the GNU General Public License as published by
186.10 + * the Free Software Foundation, version 2 of the License.
186.11 + *
186.12 + * This program is distributed in the hope that it will be useful,
186.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
186.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
186.15 + * GNU General Public License for more details.
186.16 + *
186.17 + * You should have received a copy of the GNU General Public License
186.18 + * along with this program. Look for COPYING file in the top folder.
186.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
186.20 + */
186.21 +package org.apidesign.bck2brwsr.tck;
186.22 +
186.23 +import java.util.logging.Logger;
186.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
186.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
186.26 +import org.testng.annotations.Factory;
186.27 +
186.28 +/**
186.29 + *
186.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
186.31 + */
186.32 +public class LoggerTest {
186.33 + @Compare public String parentLogger() {
186.34 + Logger lx = Logger.getLogger("x");
186.35 + assert lx != null;
186.36 + assert lx.getName().equals("x") : "Right name: " + lx.getName();
186.37 + Logger lxyz = Logger.getLogger("x.y.z");
186.38 + assert lxyz != null;
186.39 + assert lxyz.getName().equals("x.y.z") : "xyz name: " + lxyz.getName();
186.40 + return lxyz.getParent().getName();
186.41 + }
186.42 +
186.43 + @Factory public static Object[] create() {
186.44 + return VMTest.create(LoggerTest.class);
186.45 + }
186.46 +}
187.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Mon Oct 07 14:20:58 2013 +0200
187.3 @@ -0,0 +1,376 @@
187.4 +/**
187.5 + * Back 2 Browser Bytecode Translator
187.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
187.7 + *
187.8 + * This program is free software: you can redistribute it and/or modify
187.9 + * it under the terms of the GNU General Public License as published by
187.10 + * the Free Software Foundation, version 2 of the License.
187.11 + *
187.12 + * This program is distributed in the hope that it will be useful,
187.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
187.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
187.15 + * GNU General Public License for more details.
187.16 + *
187.17 + * You should have received a copy of the GNU General Public License
187.18 + * along with this program. Look for COPYING file in the top folder.
187.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
187.20 + */
187.21 +package org.apidesign.bck2brwsr.tck;
187.22 +
187.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
187.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
187.25 +import org.testng.annotations.Factory;
187.26 +
187.27 +/**
187.28 + *
187.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
187.30 + */
187.31 +public class LongArithmeticTest {
187.32 +
187.33 + private static long add(long x, long y) {
187.34 + return (x + y);
187.35 + }
187.36 +
187.37 + private static long sub(long x, long y) {
187.38 + return (x - y);
187.39 + }
187.40 +
187.41 + private static long mul(long x, long y) {
187.42 + return (x * y);
187.43 + }
187.44 +
187.45 + private static long div(long x, long y) {
187.46 + return (x / y);
187.47 + }
187.48 +
187.49 + private static long mod(long x, long y) {
187.50 + return (x % y);
187.51 + }
187.52 +
187.53 + private static long neg(long x) {
187.54 + return (-x);
187.55 + }
187.56 +
187.57 + private static long shl(long x, int b) {
187.58 + return (x << b);
187.59 + }
187.60 +
187.61 + private static long shr(long x, int b) {
187.62 + return (x >> b);
187.63 + }
187.64 +
187.65 + private static long ushr(long x, int b) {
187.66 + return (x >>> b);
187.67 + }
187.68 +
187.69 + private static long and(long x, long y) {
187.70 + return (x & y);
187.71 + }
187.72 +
187.73 + private static long or(long x, long y) {
187.74 + return (x | y);
187.75 + }
187.76 +
187.77 + private static long xor(long x, long y) {
187.78 + return (x ^ y);
187.79 + }
187.80 +
187.81 + private static float fadd(float x, float y) {
187.82 + return x + y;
187.83 + }
187.84 +
187.85 + private static double dadd(double x, double y) {
187.86 + return x + y;
187.87 + }
187.88 +
187.89 + public static int compare(long x, long y, int zero) {
187.90 + final int xyResult = compareL(x, y, zero);
187.91 + final int yxResult = compareL(y, x, zero);
187.92 +
187.93 + return ((xyResult + yxResult) == 0) ? xyResult : -2;
187.94 + }
187.95 +
187.96 + private static int compareL(long x, long y, int zero) {
187.97 + int result = -2;
187.98 + int trueCount = 0;
187.99 +
187.100 + x += zero;
187.101 + if (x == y) {
187.102 + result = 0;
187.103 + ++trueCount;
187.104 + }
187.105 +
187.106 + x += zero;
187.107 + if (x < y) {
187.108 + result = -1;
187.109 + ++trueCount;
187.110 + }
187.111 +
187.112 + x += zero;
187.113 + if (x > y) {
187.114 + result = 1;
187.115 + ++trueCount;
187.116 + }
187.117 +
187.118 + return (trueCount == 1) ? result : -2;
187.119 + }
187.120 +
187.121 + @Compare public long conversion() {
187.122 + return Long.MAX_VALUE;
187.123 + }
187.124 +
187.125 + @Compare public long negate1() {
187.126 + return neg(0x00fa37d7763e0ca1l);
187.127 + }
187.128 +
187.129 + @Compare public long negate2() {
187.130 + return neg(0x80fa37d7763e0ca1l);
187.131 + }
187.132 +
187.133 + @Compare public long negate3() {
187.134 + return neg(0xfffffffffffffeddl);
187.135 + }
187.136 +
187.137 + @Compare public long addOverflow() {
187.138 + return add(Long.MAX_VALUE, 1l);
187.139 + }
187.140 +
187.141 + @Compare public long subUnderflow() {
187.142 + return sub(Long.MIN_VALUE, 1l);
187.143 + }
187.144 +
187.145 + @Compare public long addMaxLongAndMaxLong() {
187.146 + return add(Long.MAX_VALUE, Long.MAX_VALUE);
187.147 + }
187.148 +
187.149 + @Compare public long subMinLongAndMinLong() {
187.150 + return sub(Long.MIN_VALUE, Long.MIN_VALUE);
187.151 + }
187.152 +
187.153 + @Compare public long subMinLongAndMaxLong() {
187.154 + return sub(Long.MIN_VALUE, Long.MAX_VALUE);
187.155 + }
187.156 +
187.157 + @Compare public long multiplyMaxLong() {
187.158 + return mul(Long.MAX_VALUE, 2l);
187.159 + }
187.160 +
187.161 + @Compare public long multiplyMaxLongAndMaxLong() {
187.162 + return mul(Long.MAX_VALUE, Long.MAX_VALUE);
187.163 + }
187.164 +
187.165 + @Compare public long multiplyMinLong() {
187.166 + return mul(Long.MIN_VALUE, 2l);
187.167 + }
187.168 +
187.169 + @Compare public long multiplyMinLongAndMinLong() {
187.170 + return mul(Long.MIN_VALUE, Long.MIN_VALUE);
187.171 + }
187.172 +
187.173 + @Compare public long multiplyPrecision() {
187.174 + return mul(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
187.175 + }
187.176 +
187.177 + @Compare public long divideSmallPositiveNumbers() {
187.178 + return div(0xabcdef, 0x123);
187.179 + }
187.180 +
187.181 + @Compare public long divideSmallNegativeNumbers() {
187.182 + return div(-0xabcdef, -0x123);
187.183 + }
187.184 +
187.185 + @Compare public long divideSmallMixedNumbers() {
187.186 + return div(0xabcdef, -0x123);
187.187 + }
187.188 +
187.189 + @Compare public long dividePositiveNumbersOneDigitDenom() {
187.190 + return div(0xabcdef0102ffffl, 0x654);
187.191 + }
187.192 +
187.193 + @Compare public long divideNegativeNumbersOneDigitDenom() {
187.194 + return div(-0xabcdef0102ffffl, -0x654);
187.195 + }
187.196 +
187.197 + @Compare public long divideMixedNumbersOneDigitDenom() {
187.198 + return div(-0xabcdef0102ffffl, 0x654);
187.199 + }
187.200 +
187.201 + @Compare public long dividePositiveNumbersMultiDigitDenom() {
187.202 + return div(0x7ffefc003322aabbl, 0x89ab1000l);
187.203 + }
187.204 +
187.205 + @Compare public long divideNegativeNumbersMultiDigitDenom() {
187.206 + return div(-0x7ffefc003322aabbl, -0x123489ab1001l);
187.207 + }
187.208 +
187.209 + @Compare public long divideMixedNumbersMultiDigitDenom() {
187.210 + return div(0x7ffefc003322aabbl, -0x38f49b0b7574e36l);
187.211 + }
187.212 +
187.213 + @Compare public long divideWithOverflow() {
187.214 + return div(0x8000fffe0000l, 0x8000ffffl);
187.215 + }
187.216 +
187.217 + @Compare public long divideWithCorrection() {
187.218 + return div(0x7fff800000000000l, 0x800000000001l);
187.219 + }
187.220 +
187.221 + @Compare public long moduloSmallPositiveNumbers() {
187.222 + return mod(0xabcdef, 0x123);
187.223 + }
187.224 +
187.225 + @Compare public long moduloSmallNegativeNumbers() {
187.226 + return mod(-0xabcdef, -0x123);
187.227 + }
187.228 +
187.229 + @Compare public long moduloSmallMixedNumbers() {
187.230 + return mod(0xabcdef, -0x123);
187.231 + }
187.232 +
187.233 + @Compare public long moduloPositiveNumbersOneDigitDenom() {
187.234 + return mod(0xabcdef0102ffffl, 0x654);
187.235 + }
187.236 +
187.237 + @Compare public long moduloNegativeNumbersOneDigitDenom() {
187.238 + return mod(-0xabcdef0102ffffl, -0x654);
187.239 + }
187.240 +
187.241 + @Compare public long moduloMixedNumbersOneDigitDenom() {
187.242 + return mod(-0xabcdef0102ffffl, 0x654);
187.243 + }
187.244 +
187.245 + @Compare public long moduloPositiveNumbersMultiDigitDenom() {
187.246 + return mod(0x7ffefc003322aabbl, 0x89ab1000l);
187.247 + }
187.248 +
187.249 + @Compare public long moduloNegativeNumbersMultiDigitDenom() {
187.250 + return mod(-0x7ffefc003322aabbl, -0x123489ab1001l);
187.251 + }
187.252 +
187.253 + @Compare public long moduloMixedNumbersMultiDigitDenom() {
187.254 + return mod(0x7ffefc003322aabbl, -0x38f49b0b7574e36l);
187.255 + }
187.256 +
187.257 + @Compare public long moduloWithOverflow() {
187.258 + return mod(0x8000fffe0000l, 0x8000ffffl);
187.259 + }
187.260 +
187.261 + @Compare public long moduloWithCorrection() {
187.262 + return mod(0x7fff800000000000l, 0x800000000001l);
187.263 + }
187.264 +
187.265 + @Compare public long conversionFromFloatPositive() {
187.266 + return (long) fadd(2, 0.6f);
187.267 + }
187.268 +
187.269 + @Compare public long conversionFromFloatNegative() {
187.270 + return (long) fadd(-2, -0.6f);
187.271 + }
187.272 +
187.273 + @Compare public long conversionFromDoublePositive() {
187.274 + return (long) dadd(0x20ffff0000L, 0.6);
187.275 + }
187.276 +
187.277 + @Compare public long conversionFromDoubleNegative() {
187.278 + return (long) dadd(-0x20ffff0000L, -0.6);
187.279 + }
187.280 +
187.281 + @Compare public boolean divByZeroThrowsArithmeticException() {
187.282 + try {
187.283 + div(1, 0);
187.284 + return false;
187.285 + } catch (final ArithmeticException e) {
187.286 + return true;
187.287 + }
187.288 + }
187.289 +
187.290 + @Compare public boolean modByZeroThrowsArithmeticException() {
187.291 + try {
187.292 + mod(1, 0);
187.293 + return false;
187.294 + } catch (final ArithmeticException e) {
187.295 + return true;
187.296 + }
187.297 + }
187.298 +
187.299 + @Compare public long shiftL1() {
187.300 + return shl(0x00fa37d7763e0ca1l, 5);
187.301 + }
187.302 +
187.303 + @Compare public long shiftL2() {
187.304 + return shl(0x00fa37d7763e0ca1l, 32);
187.305 + }
187.306 +
187.307 + @Compare public long shiftL3() {
187.308 + return shl(0x00fa37d7763e0ca1l, 45);
187.309 + }
187.310 +
187.311 + @Compare public long shiftR1() {
187.312 + return shr(0x00fa37d7763e0ca1l, 5);
187.313 + }
187.314 +
187.315 + @Compare public long shiftR2() {
187.316 + return shr(0x00fa37d7763e0ca1l, 32);
187.317 + }
187.318 +
187.319 + @Compare public long shiftR3() {
187.320 + return shr(0x00fa37d7763e0ca1l, 45);
187.321 + }
187.322 +
187.323 + @Compare public long uShiftR1() {
187.324 + return ushr(0x00fa37d7763e0ca1l, 5);
187.325 + }
187.326 +
187.327 + @Compare public long uShiftR2() {
187.328 + return ushr(0x00fa37d7763e0ca1l, 45);
187.329 + }
187.330 +
187.331 + @Compare public long uShiftR3() {
187.332 + return ushr(0xf0fa37d7763e0ca1l, 5);
187.333 + }
187.334 +
187.335 + @Compare public long uShiftR4() {
187.336 + return ushr(0xf0fa37d7763e0ca1l, 45);
187.337 + }
187.338 +
187.339 + @Compare public long and1() {
187.340 + return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
187.341 + }
187.342 +
187.343 + @Compare public long or1() {
187.344 + return or(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
187.345 + }
187.346 +
187.347 + @Compare public long xor1() {
187.348 + return xor(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
187.349 + }
187.350 +
187.351 + @Compare public long xor2() {
187.352 + return xor(0x00fa37d7763e0ca1l, 0x00000000ff00123el);
187.353 + }
187.354 +
187.355 + @Compare public long xor3() {
187.356 + return xor(0x00000000763e0ca1l, 0x00000000ff00123el);
187.357 + }
187.358 +
187.359 + @Compare public int compareSameNumbers() {
187.360 + return compare(0x0000000000000000l, 0x0000000000000000l, 0);
187.361 + }
187.362 +
187.363 + @Compare public int comparePositiveNumbers() {
187.364 + return compare(0x0000000000200000l, 0x0000000010000000l, 0);
187.365 + }
187.366 +
187.367 + @Compare public int compareNegativeNumbers() {
187.368 + return compare(0xffffffffffffffffl, 0xffffffff00000000l, 0);
187.369 + }
187.370 +
187.371 + @Compare public int compareMixedNumbers() {
187.372 + return compare(0x8000000000000000l, 0x7fffffffffffffffl, 0);
187.373 + }
187.374 +
187.375 + @Factory
187.376 + public static Object[] create() {
187.377 + return VMTest.create(LongArithmeticTest.class);
187.378 + }
187.379 +}
188.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
188.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/NotifyWaitTest.java Mon Oct 07 14:20:58 2013 +0200
188.3 @@ -0,0 +1,62 @@
188.4 +/**
188.5 + * Back 2 Browser Bytecode Translator
188.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
188.7 + *
188.8 + * This program is free software: you can redistribute it and/or modify
188.9 + * it under the terms of the GNU General Public License as published by
188.10 + * the Free Software Foundation, version 2 of the License.
188.11 + *
188.12 + * This program is distributed in the hope that it will be useful,
188.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
188.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
188.15 + * GNU General Public License for more details.
188.16 + *
188.17 + * You should have received a copy of the GNU General Public License
188.18 + * along with this program. Look for COPYING file in the top folder.
188.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
188.20 + */
188.21 +package org.apidesign.bck2brwsr.tck;
188.22 +
188.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
188.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
188.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
188.26 +import org.testng.annotations.Factory;
188.27 +
188.28 +/**
188.29 + *
188.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
188.31 + */
188.32 +public class NotifyWaitTest {
188.33 +
188.34 + @Compare public synchronized String canCallNotify() throws Exception {
188.35 + notify();
188.36 + return "OK";
188.37 + }
188.38 +
188.39 + @Compare public synchronized String canCallNotifyAll() throws Exception {
188.40 + notifyAll();
188.41 + return "OK";
188.42 + }
188.43 +
188.44 + @BrwsrTest public synchronized String throwsInterruptedException() {
188.45 + try {
188.46 + wait();
188.47 + throw new IllegalStateException();
188.48 + } catch (InterruptedException ex) {
188.49 + return "OK";
188.50 + }
188.51 + }
188.52 +
188.53 + @BrwsrTest public synchronized String waitMsThrowsInterruptedException() {
188.54 + try {
188.55 + wait(32);
188.56 + throw new IllegalStateException();
188.57 + } catch (InterruptedException ex) {
188.58 + return "OK";
188.59 + }
188.60 + }
188.61 +
188.62 + @Factory public static Object[] create() {
188.63 + return VMTest.create(NotifyWaitTest.class);
188.64 + }
188.65 +}
189.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
189.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Mon Oct 07 14:20:58 2013 +0200
189.3 @@ -0,0 +1,161 @@
189.4 +/**
189.5 + * Back 2 Browser Bytecode Translator
189.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
189.7 + *
189.8 + * This program is free software: you can redistribute it and/or modify
189.9 + * it under the terms of the GNU General Public License as published by
189.10 + * the Free Software Foundation, version 2 of the License.
189.11 + *
189.12 + * This program is distributed in the hope that it will be useful,
189.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
189.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
189.15 + * GNU General Public License for more details.
189.16 + *
189.17 + * You should have received a copy of the GNU General Public License
189.18 + * along with this program. Look for COPYING file in the top folder.
189.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
189.20 + */
189.21 +package org.apidesign.bck2brwsr.tck;
189.22 +
189.23 +import java.lang.reflect.Array;
189.24 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
189.25 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
189.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
189.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
189.28 +import org.testng.annotations.Factory;
189.29 +
189.30 +/**
189.31 + *
189.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
189.33 + */
189.34 +public class ReflectionArrayTest {
189.35 + @Compare public int lengthOfStringArray() {
189.36 + String[] arr = (String[]) Array.newInstance(String.class, 10);
189.37 + return arr.length;
189.38 + }
189.39 +
189.40 + @Compare public int reflectiveLengthOfStringArray() {
189.41 + Object arr = Array.newInstance(String.class, 10);
189.42 + return Array.getLength(arr);
189.43 + }
189.44 +
189.45 + @Compare public int reflectiveLengthOneNonArray() {
189.46 + Object arr = "non-array";
189.47 + return Array.getLength(arr);
189.48 + }
189.49 +
189.50 + @Compare public String compTypeOfStringArray() {
189.51 + String[] arr = (String[]) Array.newInstance(String.class, 10);
189.52 + return arr.getClass().getComponentType().getName();
189.53 + }
189.54 +
189.55 + @Compare public Object negativeArrayExcp() {
189.56 + return Array.newInstance(String.class, -5);
189.57 + }
189.58 +
189.59 + @Compare public int lengthOfIntArray() {
189.60 + int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10);
189.61 + return arr.length;
189.62 + }
189.63 +
189.64 + @Compare public int reflectiveLengthOfIntArray() {
189.65 + Object arr = Array.newInstance(Integer.TYPE, 10);
189.66 + return Array.getLength(arr);
189.67 + }
189.68 +
189.69 + @Compare public String compTypeOfIntArray() {
189.70 + int[] arr = (int[]) Array.newInstance(int.class, 10);
189.71 + return arr.getClass().getComponentType().getName();
189.72 + }
189.73 +
189.74 + @Compare public Object intNegativeArrayExcp() {
189.75 + return Array.newInstance(int.class, -5);
189.76 + }
189.77 +
189.78 + @Compare public Integer verifyAutobox() {
189.79 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.80 + return (Integer) Array.get(arr, 0);
189.81 + }
189.82 + @Compare public String verifyObjectArray() {
189.83 + String[] arr = (String[]) Array.newInstance(String.class, 5);
189.84 + Array.set(arr, 0, "Hello");
189.85 + return (String) Array.get(arr, 0);
189.86 + }
189.87 + @Compare public int verifyInt() {
189.88 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.89 + return Array.getInt(arr, 0);
189.90 + }
189.91 + @Compare public long verifyConvertToLong() {
189.92 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.93 + return Array.getLong(arr, 0);
189.94 + }
189.95 +
189.96 + @Compare public Object verifySetIntToObject() {
189.97 + try {
189.98 + Object[] arr = (Object[]) Array.newInstance(Object.class, 5);
189.99 + Array.setInt(arr, 0, 10);
189.100 + return Array.get(arr, 0);
189.101 + } catch (Exception exception) {
189.102 + return exception.getClass().getName();
189.103 + }
189.104 + }
189.105 + @Compare public long verifySetShort() {
189.106 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.107 + Array.setShort(arr, 0, (short)10);
189.108 + return Array.getLong(arr, 0);
189.109 + }
189.110 + @Compare public long verifyCantSetLong() {
189.111 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.112 + Array.setLong(arr, 0, 10);
189.113 + return Array.getLong(arr, 0);
189.114 + }
189.115 + @Compare public float verifyLongToFloat() {
189.116 + Object arr = Array.newInstance(float.class, 5);
189.117 + Array.setLong(arr, 0, 10);
189.118 + return Array.getFloat(arr, 0);
189.119 + }
189.120 +
189.121 + @Compare public double verifyConvertToDouble() {
189.122 + int[] arr = (int[]) Array.newInstance(int.class, 5);
189.123 + return Array.getDouble(arr, 0);
189.124 + }
189.125 +
189.126 + @Compare public int multiIntArray() {
189.127 + int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
189.128 + return arr[0][1][2] + 5 + arr[2][2][0];
189.129 + }
189.130 +
189.131 + @Compare public String multiIntArrayCompType() {
189.132 + return Array.newInstance(int.class, 3, 3, 3).getClass().getName();
189.133 + }
189.134 +
189.135 + @JavaScriptBody(args = {}, body = "return [1, 2];")
189.136 + private static native Object crtarr();
189.137 +
189.138 + @JavaScriptBody(args = {}, body = "return new Object();")
189.139 + private static native Object newobj();
189.140 +
189.141 + @BrwsrTest
189.142 + public static void toStringArray() {
189.143 + final Object arr = crtarr();
189.144 + final Object real = new Object[2];
189.145 + assert arr instanceof Object[] : "Any array is Java array: " + arr;
189.146 + assert arr.getClass() == real.getClass() : "Same classes " + arr + " and " + real.getClass();
189.147 + final String str = arr.toString();
189.148 + assert str != null;
189.149 + assert str.startsWith("[Ljava.lang.Object;@") : str;
189.150 + }
189.151 +
189.152 + @BrwsrTest
189.153 + public static void objectToString() {
189.154 + String s = newobj().toString();
189.155 + assert s != null : "Some string computed";
189.156 + assert s.startsWith("java.lang.Object@") : "Regular object toString(): " + s;
189.157 + }
189.158 +
189.159 +
189.160 + @Factory
189.161 + public static Object[] create() {
189.162 + return VMTest.create(ReflectionArrayTest.class);
189.163 + }
189.164 +}
190.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
190.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Mon Oct 07 14:20:58 2013 +0200
190.3 @@ -0,0 +1,272 @@
190.4 +/**
190.5 + * Back 2 Browser Bytecode Translator
190.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
190.7 + *
190.8 + * This program is free software: you can redistribute it and/or modify
190.9 + * it under the terms of the GNU General Public License as published by
190.10 + * the Free Software Foundation, version 2 of the License.
190.11 + *
190.12 + * This program is distributed in the hope that it will be useful,
190.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
190.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
190.15 + * GNU General Public License for more details.
190.16 + *
190.17 + * You should have received a copy of the GNU General Public License
190.18 + * along with this program. Look for COPYING file in the top folder.
190.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
190.20 + */
190.21 +package org.apidesign.bck2brwsr.tck;
190.22 +
190.23 +import java.lang.annotation.Retention;
190.24 +import java.lang.annotation.RetentionPolicy;
190.25 +import java.lang.reflect.Method;
190.26 +import java.util.Arrays;
190.27 +import java.util.Collections;
190.28 +import java.util.List;
190.29 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
190.30 +import org.apidesign.bck2brwsr.vmtest.Compare;
190.31 +import org.apidesign.bck2brwsr.vmtest.VMTest;
190.32 +import org.testng.annotations.Factory;
190.33 +
190.34 +/**
190.35 + *
190.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
190.37 + */
190.38 +public class ReflectionTest {
190.39 + @Compare public boolean nonNullThis() {
190.40 + return this == null;
190.41 + }
190.42 +
190.43 + @Compare public String intType() {
190.44 + return Integer.TYPE.toString();
190.45 + }
190.46 +
190.47 + @Compare public String voidType() throws Exception {
190.48 + return void.class.toString();
190.49 + }
190.50 +
190.51 + @Compare public String longClass() {
190.52 + return long.class.toString();
190.53 + }
190.54 +
190.55 + @Compare public boolean isRunnableInterface() {
190.56 + return Runnable.class.isInterface();
190.57 + }
190.58 +
190.59 + @Compare public boolean isAssignableToPrimitiveType() {
190.60 + return boolean.class.isAssignableFrom(Runnable.class);
190.61 + }
190.62 +
190.63 + @Compare public boolean isAssignableFromPrimitiveType() {
190.64 + return Runnable.class.isAssignableFrom(boolean.class);
190.65 + }
190.66 +
190.67 + @Compare public boolean isAssignableLongFromInt() {
190.68 + return long.class.isAssignableFrom(int.class);
190.69 + }
190.70 +
190.71 + @Compare public boolean isAssignableIntFromLong() {
190.72 + return int.class.isAssignableFrom(long.class);
190.73 + }
190.74 +
190.75 + @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException {
190.76 + return Runnable.class.getMethod("run").getName();
190.77 + }
190.78 +
190.79 + @Compare public String namesOfMethods() {
190.80 + StringBuilder sb = new StringBuilder();
190.81 + String[] arr = new String[20];
190.82 + int i = 0;
190.83 + for (Method m : StaticUse.class.getMethods()) {
190.84 + arr[i++] = m.getName();
190.85 + }
190.86 + for (String s : sort(arr, i)) {
190.87 + sb.append(s).append("\n");
190.88 + }
190.89 + return sb.toString();
190.90 + }
190.91 +
190.92 + @Compare public String namesOfDeclaringClassesOfMethods() {
190.93 + StringBuilder sb = new StringBuilder();
190.94 + String[] arr = new String[20];
190.95 + int i = 0;
190.96 + for (Method m : StaticUse.class.getMethods()) {
190.97 + arr[i++] = m.getName() + "@" + m.getDeclaringClass().getName();
190.98 + }
190.99 + for (String s : sort(arr, i)) {
190.100 + sb.append(s).append("\n");
190.101 + }
190.102 + return sb.toString();
190.103 + }
190.104 +
190.105 + @Compare public String cannotCallNonStaticMethodWithNull() throws Exception {
190.106 + StaticUse.class.getMethod("instanceMethod").invoke(null);
190.107 + return "should not happen";
190.108 + }
190.109 +
190.110 + @Compare public String classCastException() {
190.111 + try {
190.112 + Integer i = (Integer)StaticUseSub.getNonNull();
190.113 + return "" + i.intValue();
190.114 + } catch (ClassCastException ex) {
190.115 + return ex.getClass().getName();
190.116 + }
190.117 + }
190.118 +
190.119 + @Compare public String methodThatThrowsException() throws Exception {
190.120 + StaticUse.class.getMethod("instanceMethod").invoke(new StaticUse());
190.121 + return "should not happen";
190.122 + }
190.123 +
190.124 + @Compare public Object voidReturnType() throws Exception {
190.125 + return StaticUse.class.getMethod("instanceMethod").getReturnType();
190.126 + }
190.127 +
190.128 + @Retention(RetentionPolicy.RUNTIME)
190.129 + @interface Ann {
190.130 + }
190.131 +
190.132 + @Compare public String annoClass() throws Exception {
190.133 + Retention r = Ann.class.getAnnotation(Retention.class);
190.134 + assert r != null : "Annotation is present";
190.135 + assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value();
190.136 + return r.annotationType().getName();
190.137 + }
190.138 +
190.139 + @Compare public boolean isAnnotation() {
190.140 + return Ann.class.isAnnotation();
190.141 + }
190.142 + @Compare public boolean isNotAnnotation() {
190.143 + return String.class.isAnnotation();
190.144 + }
190.145 + @Compare public boolean isNotAnnotationEnum() {
190.146 + return E.class.isAnnotation();
190.147 + }
190.148 + enum E { A, B };
190.149 + @Compare public boolean isEnum() {
190.150 + return E.A.getClass().isEnum();
190.151 + }
190.152 +
190.153 + @Compare public boolean isNotEnum() {
190.154 + return "".getClass().isEnum();
190.155 + }
190.156 +
190.157 + @Compare public String newInstanceFails() throws InstantiationException {
190.158 + try {
190.159 + return "success: " + StaticUseSub.class.newInstance();
190.160 + } catch (IllegalAccessException ex) {
190.161 + return ex.getClass().getName();
190.162 + }
190.163 + }
190.164 +
190.165 + @Compare public String paramTypes() throws Exception {
190.166 + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE);
190.167 + final Class[] pt = plus.getParameterTypes();
190.168 + return pt[0].getName();
190.169 + }
190.170 + @Compare public String paramTypesNotFound() throws Exception {
190.171 + return StaticUse.class.getMethod("plus", int.class, double.class).toString();
190.172 + }
190.173 + @Compare public int methodWithArgs() throws Exception {
190.174 + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE);
190.175 + return (Integer)plus.invoke(null, 2, 3);
190.176 + }
190.177 +
190.178 + @Compare public String classGetNameForByte() {
190.179 + return byte.class.getName();
190.180 + }
190.181 + @Compare public String classGetNameForBaseObject() {
190.182 + return newObject().getClass().getName();
190.183 + }
190.184 + @Compare public String classGetNameForJavaObject() {
190.185 + return new Object().getClass().getName();
190.186 + }
190.187 + @Compare public String classGetNameForObjectArray() {
190.188 + return (new Object[3]).getClass().getName();
190.189 + }
190.190 + @Compare public String classGetNameForSimpleIntArray() {
190.191 + return (new int[3]).getClass().getName();
190.192 + }
190.193 + @Compare public boolean sameClassGetNameForSimpleCharArray() {
190.194 + return (new char[3]).getClass() == (new char[34]).getClass();
190.195 + }
190.196 + @Compare public String classGetNameForMultiIntArray() {
190.197 + return (new int[3][4][5][6][7][8][9]).getClass().getName();
190.198 + }
190.199 + @Compare public String classGetNameForMultiIntArrayInner() {
190.200 + final int[][][][][][][] arr = new int[3][4][5][6][7][8][9];
190.201 + int[][][][][][] subarr = arr[0];
190.202 + int[][][][][] subsubarr = subarr[0];
190.203 + return subsubarr.getClass().getName();
190.204 + }
190.205 + @Compare public String classGetNameForMultiStringArray() {
190.206 + return (new String[3][4][5][6][7][8][9]).getClass().getName();
190.207 + }
190.208 +
190.209 + @Compare public String classForByte() throws Exception {
190.210 + return Class.forName("[Z").getName();
190.211 + }
190.212 +
190.213 + @Compare public String classForUnknownArray() {
190.214 + try {
190.215 + return Class.forName("[W").getName();
190.216 + } catch (Exception ex) {
190.217 + return ex.getClass().getName();
190.218 + }
190.219 + }
190.220 +
190.221 + @Compare public String classForUnknownDeepArray() {
190.222 + try {
190.223 + return Class.forName("[[[[[W").getName();
190.224 + } catch (Exception ex) {
190.225 + return ex.getClass().getName();
190.226 + }
190.227 + }
190.228 +
190.229 + @Compare public String componentGetNameForObjectArray() {
190.230 + return (new Object[3]).getClass().getComponentType().getName();
190.231 + }
190.232 + @Compare public boolean sameComponentGetNameForObjectArray() {
190.233 + return (new Object[3]).getClass().getComponentType() == Object.class;
190.234 + }
190.235 + @Compare public String componentGetNameForSimpleIntArray() {
190.236 + return (new int[3]).getClass().getComponentType().getName();
190.237 + }
190.238 + @Compare public String componentGetNameForMultiIntArray() {
190.239 + return (new int[3][4][5][6][7][8][9]).getClass().getComponentType().getName();
190.240 + }
190.241 + @Compare public String componentGetNameForMultiStringArray() {
190.242 + Class<?> c = (new String[3][4][5][6][7][8][9]).getClass();
190.243 + StringBuilder sb = new StringBuilder();
190.244 + for (;;) {
190.245 + sb.append(c.getName()).append("\n");
190.246 + c = c.getComponentType();
190.247 + if (c == null) {
190.248 + break;
190.249 + }
190.250 + }
190.251 + return sb.toString();
190.252 + }
190.253 +
190.254 + @Compare public boolean isArray() {
190.255 + return new Object[0].getClass().isArray();
190.256 + }
190.257 +
190.258 + @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;")
190.259 + private static String[] sort(String[] arr, int len) {
190.260 + List<String> list = Arrays.asList(arr).subList(0, len);
190.261 + Collections.sort(list);
190.262 + return list.toArray(new String[0]);
190.263 + }
190.264 +
190.265 + @JavaScriptBody(args = {}, body = "return new Object();")
190.266 + private static Object newObject() {
190.267 + return new Object();
190.268 + }
190.269 +
190.270 + @Factory
190.271 + public static Object[] create() {
190.272 + return VMTest.create(ReflectionTest.class);
190.273 + }
190.274 +
190.275 +}
191.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
191.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpSplitTest.java Mon Oct 07 14:20:58 2013 +0200
191.3 @@ -0,0 +1,50 @@
191.4 +/**
191.5 + * Back 2 Browser Bytecode Translator
191.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
191.7 + *
191.8 + * This program is free software: you can redistribute it and/or modify
191.9 + * it under the terms of the GNU General Public License as published by
191.10 + * the Free Software Foundation, version 2 of the License.
191.11 + *
191.12 + * This program is distributed in the hope that it will be useful,
191.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
191.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
191.15 + * GNU General Public License for more details.
191.16 + *
191.17 + * You should have received a copy of the GNU General Public License
191.18 + * along with this program. Look for COPYING file in the top folder.
191.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
191.20 + */
191.21 +package org.apidesign.bck2brwsr.tck;
191.22 +
191.23 +import java.util.Arrays;
191.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
191.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
191.26 +import org.testng.annotations.Factory;
191.27 +
191.28 +/**
191.29 + *
191.30 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
191.31 + */
191.32 +public class RegExpSplitTest {
191.33 +
191.34 + public @Compare Object splitSpace() {
191.35 + return Arrays.asList("How are you today?".split(" "));
191.36 + }
191.37 +
191.38 + public @Compare Object splitSpaceTrimMinusOne() {
191.39 + return Arrays.asList(" How are you today? ".split(" ", -1));
191.40 + }
191.41 +
191.42 + public @Compare Object splitSpaceTrimZero() {
191.43 + return Arrays.asList(" How are you today? ".split(" ", 0));
191.44 + }
191.45 +
191.46 + public @Compare Object splitSpaceLimit2() {
191.47 + return Arrays.asList("How are you today?".split(" ", 2));
191.48 + }
191.49 +
191.50 + @Factory public static Object[] create() {
191.51 + return VMTest.create(RegExpSplitTest.class);
191.52 + }
191.53 +}
192.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
192.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Mon Oct 07 14:20:58 2013 +0200
192.3 @@ -0,0 +1,45 @@
192.4 +/**
192.5 + * Back 2 Browser Bytecode Translator
192.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
192.7 + *
192.8 + * This program is free software: you can redistribute it and/or modify
192.9 + * it under the terms of the GNU General Public License as published by
192.10 + * the Free Software Foundation, version 2 of the License.
192.11 + *
192.12 + * This program is distributed in the hope that it will be useful,
192.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
192.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192.15 + * GNU General Public License for more details.
192.16 + *
192.17 + * You should have received a copy of the GNU General Public License
192.18 + * along with this program. Look for COPYING file in the top folder.
192.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
192.20 + */
192.21 +package org.apidesign.bck2brwsr.tck;
192.22 +
192.23 +import java.io.InputStream;
192.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
192.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
192.26 +import org.testng.annotations.Factory;
192.27 +
192.28 +/**
192.29 + *
192.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
192.31 + */
192.32 +public class ResourcesTest {
192.33 +
192.34 + @Compare public String readResourceAsStream() throws Exception {
192.35 + InputStream is = getClass().getResourceAsStream("Resources.txt");
192.36 + byte[] b = new byte[30];
192.37 + int len = is.read(b);
192.38 + StringBuilder sb = new StringBuilder();
192.39 + for (int i = 0; i < len; i++) {
192.40 + sb.append((char)b[i]);
192.41 + }
192.42 + return sb.toString();
192.43 + }
192.44 +
192.45 + @Factory public static Object[] create() {
192.46 + return VMTest.create(ResourcesTest.class);
192.47 + }
192.48 +}
193.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
193.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java Mon Oct 07 14:20:58 2013 +0200
193.3 @@ -0,0 +1,102 @@
193.4 +/**
193.5 + * Back 2 Browser Bytecode Translator
193.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
193.7 + *
193.8 + * This program is free software: you can redistribute it and/or modify
193.9 + * it under the terms of the GNU General Public License as published by
193.10 + * the Free Software Foundation, version 2 of the License.
193.11 + *
193.12 + * This program is distributed in the hope that it will be useful,
193.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
193.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
193.15 + * GNU General Public License for more details.
193.16 + *
193.17 + * You should have received a copy of the GNU General Public License
193.18 + * along with this program. Look for COPYING file in the top folder.
193.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
193.20 + */
193.21 +package org.apidesign.bck2brwsr.tck;
193.22 +
193.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
193.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
193.25 +import org.testng.annotations.Factory;
193.26 +
193.27 +/**
193.28 + *
193.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
193.30 + */
193.31 +public class ShortArithmeticTest {
193.32 +
193.33 + private static short add(short x, short y) {
193.34 + return (short)(x + y);
193.35 + }
193.36 +
193.37 + private static short sub(short x, short y) {
193.38 + return (short)(x - y);
193.39 + }
193.40 +
193.41 + private static short mul(short x, short y) {
193.42 + return (short)(x * y);
193.43 + }
193.44 +
193.45 + private static short div(short x, short y) {
193.46 + return (short)(x / y);
193.47 + }
193.48 +
193.49 + private static short mod(short x, short y) {
193.50 + return (short)(x % y);
193.51 + }
193.52 +
193.53 + @Compare public short conversion() {
193.54 + return (short)123456;
193.55 + }
193.56 +
193.57 + @Compare public short addOverflow() {
193.58 + return add(Short.MAX_VALUE, (short)1);
193.59 + }
193.60 +
193.61 + @Compare public short subUnderflow() {
193.62 + return sub(Short.MIN_VALUE, (short)1);
193.63 + }
193.64 +
193.65 + @Compare public short addMaxShortAndMaxShort() {
193.66 + return add(Short.MAX_VALUE, Short.MAX_VALUE);
193.67 + }
193.68 +
193.69 + @Compare public short subMinShortAndMinShort() {
193.70 + return sub(Short.MIN_VALUE, Short.MIN_VALUE);
193.71 + }
193.72 +
193.73 + @Compare public short multiplyMaxShort() {
193.74 + return mul(Short.MAX_VALUE, (short)2);
193.75 + }
193.76 +
193.77 + @Compare public short multiplyMaxShortAndMaxShort() {
193.78 + return mul(Short.MAX_VALUE, Short.MAX_VALUE);
193.79 + }
193.80 +
193.81 + @Compare public short multiplyMinShort() {
193.82 + return mul(Short.MIN_VALUE, (short)2);
193.83 + }
193.84 +
193.85 + @Compare public short multiplyMinShortAndMinShort() {
193.86 + return mul(Short.MIN_VALUE, Short.MIN_VALUE);
193.87 + }
193.88 +
193.89 + @Compare public short multiplyPrecision() {
193.90 + return mul((short)17638, (short)1103);
193.91 + }
193.92 +
193.93 + @Compare public short division() {
193.94 + return div((short)1, (short)2);
193.95 + }
193.96 +
193.97 + @Compare public short divisionReminder() {
193.98 + return mod((short)1, (short)2);
193.99 + }
193.100 +
193.101 + @Factory
193.102 + public static Object[] create() {
193.103 + return VMTest.create(ShortArithmeticTest.class);
193.104 + }
193.105 +}
194.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
194.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Mon Oct 07 14:20:58 2013 +0200
194.3 @@ -0,0 +1,39 @@
194.4 +/**
194.5 + * Back 2 Browser Bytecode Translator
194.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
194.7 + *
194.8 + * This program is free software: you can redistribute it and/or modify
194.9 + * it under the terms of the GNU General Public License as published by
194.10 + * the Free Software Foundation, version 2 of the License.
194.11 + *
194.12 + * This program is distributed in the hope that it will be useful,
194.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
194.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
194.15 + * GNU General Public License for more details.
194.16 + *
194.17 + * You should have received a copy of the GNU General Public License
194.18 + * along with this program. Look for COPYING file in the top folder.
194.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
194.20 + */
194.21 +package org.apidesign.bck2brwsr.tck;
194.22 +
194.23 +class StaticUse {
194.24 + public static final Object NON_NULL = new Object();
194.25 + public static int cnt;
194.26 + static {
194.27 + if (cnt++ != 0) {
194.28 + throw new IllegalStateException("Multiple initialization of a <cinit>");
194.29 + }
194.30 + }
194.31 +
194.32 + StaticUse() {
194.33 + }
194.34 +
194.35 + public void instanceMethod() {
194.36 + throw new IllegalStateException();
194.37 + }
194.38 +
194.39 + public static int plus(int a, int b) {
194.40 + return a + b;
194.41 + }
194.42 +}
195.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
195.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSub.java Mon Oct 07 14:20:58 2013 +0200
195.3 @@ -0,0 +1,30 @@
195.4 +/**
195.5 + * Back 2 Browser Bytecode Translator
195.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
195.7 + *
195.8 + * This program is free software: you can redistribute it and/or modify
195.9 + * it under the terms of the GNU General Public License as published by
195.10 + * the Free Software Foundation, version 2 of the License.
195.11 + *
195.12 + * This program is distributed in the hope that it will be useful,
195.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
195.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
195.15 + * GNU General Public License for more details.
195.16 + *
195.17 + * You should have received a copy of the GNU General Public License
195.18 + * along with this program. Look for COPYING file in the top folder.
195.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
195.20 + */
195.21 +package org.apidesign.bck2brwsr.tck;
195.22 +
195.23 +public class StaticUseSub extends StaticUse {
195.24 + private StaticUseSub() {
195.25 + }
195.26 +
195.27 + public static Object getNonNull() {
195.28 + return NON_NULL;
195.29 + }
195.30 + static Object getNull() {
195.31 + return null;
195.32 + }
195.33 +}
196.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
196.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSubTest.java Mon Oct 07 14:20:58 2013 +0200
196.3 @@ -0,0 +1,45 @@
196.4 +/**
196.5 + * Back 2 Browser Bytecode Translator
196.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
196.7 + *
196.8 + * This program is free software: you can redistribute it and/or modify
196.9 + * it under the terms of the GNU General Public License as published by
196.10 + * the Free Software Foundation, version 2 of the License.
196.11 + *
196.12 + * This program is distributed in the hope that it will be useful,
196.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
196.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
196.15 + * GNU General Public License for more details.
196.16 + *
196.17 + * You should have received a copy of the GNU General Public License
196.18 + * along with this program. Look for COPYING file in the top folder.
196.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
196.20 + */
196.21 +package org.apidesign.bck2brwsr.tck;
196.22 +
196.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
196.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
196.25 +import org.testng.annotations.Factory;
196.26 +
196.27 +/**
196.28 + *
196.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
196.30 + */
196.31 +public class StaticUseSubTest {
196.32 + @Compare public String staticFieldInitializationInSuperClass() throws Exception {
196.33 + Object ret = StaticUseSub.getNonNull();
196.34 + return ret.getClass().getName();
196.35 + }
196.36 +
196.37 + @Compare public String isNullPointerTheSame() throws Exception {
196.38 + try {
196.39 + return StaticUseSub.getNull().getClass().toString();
196.40 + } catch (NullPointerException ex) {
196.41 + return ex.getClass().getName();
196.42 + }
196.43 + }
196.44 +
196.45 + @Factory public static Object[] create() {
196.46 + return VMTest.create(StaticUseSubTest.class);
196.47 + }
196.48 +}
197.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
197.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java Mon Oct 07 14:20:58 2013 +0200
197.3 @@ -0,0 +1,41 @@
197.4 +/**
197.5 + * Back 2 Browser Bytecode Translator
197.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
197.7 + *
197.8 + * This program is free software: you can redistribute it and/or modify
197.9 + * it under the terms of the GNU General Public License as published by
197.10 + * the Free Software Foundation, version 2 of the License.
197.11 + *
197.12 + * This program is distributed in the hope that it will be useful,
197.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
197.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
197.15 + * GNU General Public License for more details.
197.16 + *
197.17 + * You should have received a copy of the GNU General Public License
197.18 + * along with this program. Look for COPYING file in the top folder.
197.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
197.20 + */
197.21 +package org.apidesign.bck2brwsr.vmtest.impl;
197.22 +
197.23 +import java.io.UnsupportedEncodingException;
197.24 +import java.util.zip.CRC32;
197.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
197.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
197.27 +import org.testng.annotations.Factory;
197.28 +
197.29 +/**
197.30 + *
197.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
197.32 + */
197.33 +public class CRC32Test {
197.34 +
197.35 + @Compare public long crc1() throws UnsupportedEncodingException {
197.36 + CRC32 crc = new CRC32();
197.37 + crc.update("Hello World!".getBytes("UTF-8"));
197.38 + return crc.getValue();
197.39 + }
197.40 +
197.41 + @Factory public static Object[] create() {
197.42 + return VMTest.create(CRC32Test.class);
197.43 + }
197.44 +}
198.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
198.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CallMeTwiceTest.java Mon Oct 07 14:20:58 2013 +0200
198.3 @@ -0,0 +1,43 @@
198.4 +/**
198.5 + * Back 2 Browser Bytecode Translator
198.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
198.7 + *
198.8 + * This program is free software: you can redistribute it and/or modify
198.9 + * it under the terms of the GNU General Public License as published by
198.10 + * the Free Software Foundation, version 2 of the License.
198.11 + *
198.12 + * This program is distributed in the hope that it will be useful,
198.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
198.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
198.15 + * GNU General Public License for more details.
198.16 + *
198.17 + * You should have received a copy of the GNU General Public License
198.18 + * along with this program. Look for COPYING file in the top folder.
198.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
198.20 + */
198.21 +package org.apidesign.bck2brwsr.vmtest.impl;
198.22 +
198.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
198.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
198.25 +import org.testng.annotations.Factory;
198.26 +
198.27 +/**
198.28 + *
198.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
198.30 + */
198.31 +public class CallMeTwiceTest {
198.32 + int cnt;
198.33 +
198.34 + @BrwsrTest public void callMeTwice() throws InterruptedException {
198.35 + if (cnt++ == 0) {
198.36 + throw new InterruptedException();
198.37 + }
198.38 + int prevCnt = cnt;
198.39 + cnt = 0;
198.40 + assert prevCnt == 2 : "We need to receive two calls " + prevCnt;
198.41 + }
198.42 +
198.43 + @Factory public static Object[] create() {
198.44 + return VMTest.create(CallMeTwiceTest.class);
198.45 + }
198.46 +}
199.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
199.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/HtmlAnnotations.java Mon Oct 07 14:20:58 2013 +0200
199.3 @@ -0,0 +1,86 @@
199.4 +/**
199.5 + * Back 2 Browser Bytecode Translator
199.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
199.7 + *
199.8 + * This program is free software: you can redistribute it and/or modify
199.9 + * it under the terms of the GNU General Public License as published by
199.10 + * the Free Software Foundation, version 2 of the License.
199.11 + *
199.12 + * This program is distributed in the hope that it will be useful,
199.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
199.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
199.15 + * GNU General Public License for more details.
199.16 + *
199.17 + * You should have received a copy of the GNU General Public License
199.18 + * along with this program. Look for COPYING file in the top folder.
199.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
199.20 + */
199.21 +package org.apidesign.bck2brwsr.vmtest.impl;
199.22 +
199.23 +import net.java.html.js.JavaScriptBody;
199.24 +import net.java.html.js.JavaScriptResource;
199.25 +
199.26 +/**
199.27 + *
199.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
199.29 + */
199.30 +@JavaScriptResource("htmlannotations.js")
199.31 +public class HtmlAnnotations {
199.32 + private Object callback;
199.33 +
199.34 +
199.35 + @JavaScriptBody(args = {}, body = "return 42;")
199.36 + public static int fourtyTwo() {
199.37 + return -1;
199.38 + }
199.39 +
199.40 + @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
199.41 + public static native int useExternalMul(int x, int y);
199.42 +
199.43 + public static int callback() {
199.44 + final int[] arr = { 0 };
199.45 + callback(new Runnable() {
199.46 + @Override
199.47 + public void run() {
199.48 + arr[0]++;
199.49 + }
199.50 + });
199.51 + return arr[0];
199.52 + }
199.53 +
199.54 + @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()()")
199.55 + private static native void callback(Runnable r);
199.56 +
199.57 + @JavaScriptBody(args = { }, javacall = true, body = "return @org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::callback()();")
199.58 + public static native int staticCallback();
199.59 +
199.60 +
199.61 + protected long chooseLong(boolean takeFirst, boolean takeSecond, long first, long second) {
199.62 + long l = 0;
199.63 + if (takeFirst) l += first;
199.64 + if (takeSecond) l += second;
199.65 + return l;
199.66 + }
199.67 +
199.68 + protected void onError(Object obj) throws Exception {
199.69 + callback = obj;
199.70 + }
199.71 +
199.72 + Object getError() {
199.73 + return callback;
199.74 + }
199.75 +
199.76 + public static Object create() {
199.77 + return new HtmlAnnotations();
199.78 + }
199.79 + @JavaScriptBody(args = { "impl", "a", "b" }, javacall = true, body =
199.80 + "return impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::chooseLong(ZZJJ)(true, false, a, b);"
199.81 + )
199.82 + public static native long first(Object impl, long a, long b);
199.83 +
199.84 + @JavaScriptBody(args = { "impl", "d" }, javacall = true, body =
199.85 + "impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::onError(Ljava/lang/Object;)(d);" +
199.86 + "return impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::getError()();"
199.87 + )
199.88 + public static native Double onError(Object impl, Double d);
199.89 +}
200.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
200.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/HtmlAnnotationsTest.java Mon Oct 07 14:20:58 2013 +0200
200.3 @@ -0,0 +1,71 @@
200.4 +/**
200.5 + * Back 2 Browser Bytecode Translator
200.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
200.7 + *
200.8 + * This program is free software: you can redistribute it and/or modify
200.9 + * it under the terms of the GNU General Public License as published by
200.10 + * the Free Software Foundation, version 2 of the License.
200.11 + *
200.12 + * This program is distributed in the hope that it will be useful,
200.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
200.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
200.15 + * GNU General Public License for more details.
200.16 + *
200.17 + * You should have received a copy of the GNU General Public License
200.18 + * along with this program. Look for COPYING file in the top folder.
200.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
200.20 + */
200.21 +package org.apidesign.bck2brwsr.vmtest.impl;
200.22 +
200.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
200.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
200.25 +import org.testng.annotations.Factory;
200.26 +
200.27 +/** Verify cooperation with net.java.html.js annotations.
200.28 + *
200.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
200.30 + */
200.31 +public class HtmlAnnotationsTest {
200.32 + @BrwsrTest public void fourtyTwo() throws Exception {
200.33 + assertEquals(HtmlAnnotations.fourtyTwo(), 42);
200.34 + }
200.35 +
200.36 + @BrwsrTest public void externalMul() throws Exception {
200.37 + assertEquals(HtmlAnnotations.useExternalMul(7, 6), 42);
200.38 + }
200.39 +
200.40 + @BrwsrTest public void callRunnableFromJS() throws Exception {
200.41 + assertEquals(HtmlAnnotations.callback(), 1);
200.42 + }
200.43 +
200.44 + @BrwsrTest public void callStaticMethodFromJS() throws Exception {
200.45 + assertEquals(HtmlAnnotations.staticCallback(), 1);
200.46 + }
200.47 +
200.48 + @BrwsrTest public void callbackWithFourParamsAndReturnType() throws Exception {
200.49 + Object instance = HtmlAnnotations.create();
200.50 + assertNotNull(instance, "Instance created");
200.51 + assertEquals(HtmlAnnotations.first(instance, 42, 31), 42);
200.52 + }
200.53 +
200.54 + @BrwsrTest public void callbackWithObjectParamsAndReturnType() throws Exception {
200.55 + Object instance = HtmlAnnotations.create();
200.56 + assertNotNull(instance, "Instance created");
200.57 + assertEquals(HtmlAnnotations.onError(instance, 42.0), 42.0);
200.58 + }
200.59 +
200.60 + private static void assertEquals(double real, double exp) {
200.61 + if (real - exp < 0.01) {
200.62 + return;
200.63 + }
200.64 + assert false : "Expecting " + exp + " but was " + real;
200.65 + }
200.66 +
200.67 + private static void assertNotNull(Object obj, String msg) {
200.68 + assert obj != null : msg;
200.69 + }
200.70 +
200.71 + @Factory public static Object[] create() {
200.72 + return VMTest.create(HtmlAnnotationsTest.class);
200.73 + }
200.74 +}
201.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
201.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java Mon Oct 07 14:20:58 2013 +0200
201.3 @@ -0,0 +1,67 @@
201.4 +/**
201.5 + * Back 2 Browser Bytecode Translator
201.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
201.7 + *
201.8 + * This program is free software: you can redistribute it and/or modify
201.9 + * it under the terms of the GNU General Public License as published by
201.10 + * the Free Software Foundation, version 2 of the License.
201.11 + *
201.12 + * This program is distributed in the hope that it will be useful,
201.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
201.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
201.15 + * GNU General Public License for more details.
201.16 + *
201.17 + * You should have received a copy of the GNU General Public License
201.18 + * along with this program. Look for COPYING file in the top folder.
201.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
201.20 + */
201.21 +package org.apidesign.bck2brwsr.vmtest.impl;
201.22 +
201.23 +import java.io.ByteArrayInputStream;
201.24 +import java.io.IOException;
201.25 +import java.io.InputStream;
201.26 +import org.apidesign.bck2brwsr.emul.zip.FastJar;
201.27 +import org.testng.annotations.Test;
201.28 +import static org.testng.Assert.*;
201.29 +
201.30 +/**
201.31 + *
201.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
201.33 + */
201.34 +@GenerateZip(name = "five.zip", contents = {
201.35 + "1.txt", "one",
201.36 + "2.txt", "duo",
201.37 + "3.txt", "three",
201.38 + "4.txt", "four",
201.39 + "5.txt", "five"
201.40 +})
201.41 +public class ZipEntryTest {
201.42 + @Test
201.43 + public void readEntriesEffectively() throws IOException {
201.44 + InputStream is = ZipEntryTest.class.getResourceAsStream("five.zip");
201.45 + byte[] arr = new byte[is.available()];
201.46 + int len = is.read(arr);
201.47 + assertEquals(len, arr.length, "Read fully");
201.48 +
201.49 + FastJar fj = new FastJar(arr);
201.50 + FastJar.Entry[] entrs = fj.list();
201.51 +
201.52 + assertEquals(5, entrs.length, "Five entries");
201.53 +
201.54 + for (int i = 1; i <= 5; i++) {
201.55 + FastJar.Entry en = entrs[i - 1];
201.56 + assertEquals(en.name, i + ".txt");
201.57 +// assertEquals(cis.cnt, 0, "Content of the file should be skipped, not read");
201.58 + }
201.59 +
201.60 + assertContent("three", fj.getInputStream(entrs[3 - 1]), "read OK");
201.61 + assertContent("five", fj.getInputStream(entrs[5 - 1]), "read OK");
201.62 + }
201.63 +
201.64 + private static void assertContent(String exp, InputStream is, String msg) throws IOException {
201.65 + byte[] arr = new byte[512];
201.66 + int len = is.read(arr);
201.67 + String s = new String(arr, 0, len);
201.68 + assertEquals(exp, s, msg);
201.69 + }
201.70 +}
202.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
202.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Mon Oct 07 14:20:58 2013 +0200
202.3 @@ -0,0 +1,108 @@
202.4 +/**
202.5 + * Back 2 Browser Bytecode Translator
202.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
202.7 + *
202.8 + * This program is free software: you can redistribute it and/or modify
202.9 + * it under the terms of the GNU General Public License as published by
202.10 + * the Free Software Foundation, version 2 of the License.
202.11 + *
202.12 + * This program is distributed in the hope that it will be useful,
202.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
202.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
202.15 + * GNU General Public License for more details.
202.16 + *
202.17 + * You should have received a copy of the GNU General Public License
202.18 + * along with this program. Look for COPYING file in the top folder.
202.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
202.20 + */
202.21 +package org.apidesign.bck2brwsr.vmtest.impl;
202.22 +
202.23 +import java.io.IOException;
202.24 +import java.io.InputStream;
202.25 +import java.util.Objects;
202.26 +import java.util.zip.ZipEntry;
202.27 +import java.util.zip.ZipInputStream;
202.28 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
202.29 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
202.30 +import org.apidesign.bck2brwsr.vmtest.Compare;
202.31 +import org.apidesign.bck2brwsr.vmtest.Http;
202.32 +import org.apidesign.bck2brwsr.vmtest.VMTest;
202.33 +import org.testng.annotations.Factory;
202.34 +
202.35 +/**
202.36 + *
202.37 + * @author Jaroslav Tulach <jtulach@netbeans.org>
202.38 + */
202.39 +@GenerateZip(name = "readAnEntry.zip", contents = {
202.40 + "my/main/file.txt", "Hello World!"
202.41 +})
202.42 +public class ZipFileTest {
202.43 +
202.44 + @Compare public String readAnEntry() throws IOException {
202.45 + InputStream is = ZipFileTest.class.getResourceAsStream("readAnEntry.zip");
202.46 + ZipInputStream zip = new ZipInputStream(is);
202.47 + ZipEntry entry = zip.getNextEntry();
202.48 + assertEquals(entry.getName(), "my/main/file.txt", "Correct entry");
202.49 +
202.50 + byte[] arr = new byte[4096];
202.51 + int len = zip.read(arr);
202.52 +
202.53 + assertEquals(zip.getNextEntry(), null, "No next entry");
202.54 +
202.55 + final String ret = new String(arr, 0, len, "UTF-8");
202.56 + return ret;
202.57 + }
202.58 +
202.59 + @JavaScriptBody(args = { "res", "path" }, body =
202.60 + "var myvm = bck2brwsr.apply(null, path);\n"
202.61 + + "var cls = myvm.loadClass('java.lang.String');\n"
202.62 + + "return cls.getClass__Ljava_lang_Class_2().getResourceAsStream__Ljava_io_InputStream_2Ljava_lang_String_2(res);\n"
202.63 + )
202.64 + private static native Object loadVMResource(String res, String...path);
202.65 +
202.66 + @Http({
202.67 + @Http.Resource(path = "/readAnEntry.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip")
202.68 + })
202.69 + @BrwsrTest public void canVmLoadResourceFromZip() throws IOException {
202.70 + Object res = loadVMResource("/my/main/file.txt", "/readAnEntry.jar");
202.71 + assert res instanceof InputStream : "Got array of bytes: " + res;
202.72 + InputStream is = (InputStream)res;
202.73 +
202.74 + byte[] arr = new byte[4096];
202.75 + int len = is.read(arr);
202.76 +
202.77 + final String ret = new String(arr, 0, len, "UTF-8");
202.78 +
202.79 + assertEquals(ret, "Hello World!", "Can read the bytes");
202.80 + }
202.81 +
202.82 + @GenerateZip(name = "cpattr.zip", contents = {
202.83 + "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n"
202.84 + + "Created-By: hand\n"
202.85 + + "Class-Path: realJar.jar\n\n\n"
202.86 + })
202.87 + @Http({
202.88 + @Http.Resource(path = "/readComplexEntry.jar", mimeType = "x-application/zip", content = "", resource="cpattr.zip"),
202.89 + @Http.Resource(path = "/realJar.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip"),
202.90 + })
202.91 + @BrwsrTest public void understandsClassPathAttr() throws IOException {
202.92 + Object res = loadVMResource("/my/main/file.txt", "/readComplexEntry.jar");
202.93 + assert res instanceof InputStream : "Got array of bytes: " + res;
202.94 + InputStream is = (InputStream)res;
202.95 +
202.96 + byte[] arr = new byte[4096];
202.97 + int len = is.read(arr);
202.98 +
202.99 + final String ret = new String(arr, 0, len, "UTF-8");
202.100 +
202.101 + assertEquals(ret, "Hello World!", "Can read the bytes from secondary JAR");
202.102 + }
202.103 +
202.104 + private static void assertEquals(Object real, Object exp, String msg) {
202.105 + assert Objects.equals(exp, real) : msg + " exp: " + exp + " real: " + real;
202.106 + }
202.107 +
202.108 + @Factory public static Object[] create() {
202.109 + return VMTest.create(ZipFileTest.class);
202.110 + }
202.111 +}
203.1 Binary file rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-0.3-SNAPSHOT.jar has changed
204.1 Binary file rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-TEST.jar has changed
205.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
205.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe Mon Oct 07 14:20:58 2013 +0200
205.3 @@ -0,0 +1,1 @@
205.4 +þ
205.5 \ No newline at end of file
206.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
206.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt Mon Oct 07 14:20:58 2013 +0200
206.3 @@ -0,0 +1,1 @@
206.4 +Ahoj
207.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
207.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/vmtest/impl/htmlannotations.js Mon Oct 07 14:20:58 2013 +0200
207.3 @@ -0,0 +1,20 @@
207.4 +/*
207.5 + * Back 2 Browser Bytecode Translator
207.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
207.7 + *
207.8 + * This program is free software: you can redistribute it and/or modify
207.9 + * it under the terms of the GNU General Public License as published by
207.10 + * the Free Software Foundation, version 2 of the License.
207.11 + *
207.12 + * This program is distributed in the hope that it will be useful,
207.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
207.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
207.15 + * GNU General Public License for more details.
207.16 + *
207.17 + * You should have received a copy of the GNU General Public License
207.18 + * along with this program. Look for COPYING file in the top folder.
207.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
207.20 + */
207.21 +
207.22 +function mul(x, y) { return x * y; }
207.23 +window.mul = mul;
208.1 --- a/rt/emul/mini/pom.xml Wed Feb 27 17:50:47 2013 +0100
208.2 +++ b/rt/emul/mini/pom.xml Mon Oct 07 14:20:58 2013 +0200
208.3 @@ -1,15 +1,14 @@
208.4 <?xml version="1.0"?>
208.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
208.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
208.7 +<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/xsd/maven-4.0.0.xsd">
208.8 <modelVersion>4.0.0</modelVersion>
208.9 <parent>
208.10 <groupId>org.apidesign.bck2brwsr</groupId>
208.11 <artifactId>emul.pom</artifactId>
208.12 - <version>0.3-SNAPSHOT</version>
208.13 + <version>0.9-SNAPSHOT</version>
208.14 </parent>
208.15 <groupId>org.apidesign.bck2brwsr</groupId>
208.16 <artifactId>emul.mini</artifactId>
208.17 - <version>0.3-SNAPSHOT</version>
208.18 + <version>0.9-SNAPSHOT</version>
208.19 <name>Minimal API Profile</name>
208.20 <url>http://maven.apache.org</url>
208.21 <properties>
208.22 @@ -19,7 +18,7 @@
208.23 <dependency>
208.24 <groupId>org.apidesign.bck2brwsr</groupId>
208.25 <artifactId>core</artifactId>
208.26 - <version>0.3-SNAPSHOT</version>
208.27 + <version>0.9-SNAPSHOT</version>
208.28 <type>jar</type>
208.29 </dependency>
208.30 <dependency>
208.31 @@ -43,6 +42,28 @@
208.32 <target>1.7</target>
208.33 </configuration>
208.34 </plugin>
208.35 + <plugin>
208.36 + <groupId>org.apache.maven.plugins</groupId>
208.37 + <artifactId>maven-javadoc-plugin</artifactId>
208.38 + <configuration>
208.39 + <excludePackageNames>org.apidesign.bck2brwsr.emul.*</excludePackageNames>
208.40 + <skip>false</skip>
208.41 + </configuration>
208.42 + </plugin>
208.43 + <plugin>
208.44 + <groupId>org.apache.maven.plugins</groupId>
208.45 + <artifactId>maven-source-plugin</artifactId>
208.46 + <version>2.2.1</version>
208.47 + <executions>
208.48 + <execution>
208.49 + <id>prepare-sources</id>
208.50 + <goals>
208.51 + <goal>jar</goal>
208.52 + </goals>
208.53 + <phase>package</phase>
208.54 + </execution>
208.55 + </executions>
208.56 + </plugin>
208.57 </plugins>
208.58 </build>
208.59 </project>
209.1 --- a/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Wed Feb 27 17:50:47 2013 +0100
209.2 +++ b/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Mon Oct 07 14:20:58 2013 +0200
209.3 @@ -126,7 +126,7 @@
209.4 throw new OutOfMemoryError();
209.5 newCapacity = Integer.MAX_VALUE;
209.6 }
209.7 - value = copyOf(value, newCapacity);
209.8 + value = System.expandArray(value, newCapacity);
209.9 }
209.10
209.11 /**
210.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
210.2 +++ b/rt/emul/mini/src/main/java/java/lang/ArithmeticException.java Mon Oct 07 14:20:58 2013 +0200
210.3 @@ -0,0 +1,61 @@
210.4 +/*
210.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
210.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
210.7 + *
210.8 + * This code is free software; you can redistribute it and/or modify it
210.9 + * under the terms of the GNU General Public License version 2 only, as
210.10 + * published by the Free Software Foundation. Oracle designates this
210.11 + * particular file as subject to the "Classpath" exception as provided
210.12 + * by Oracle in the LICENSE file that accompanied this code.
210.13 + *
210.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
210.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
210.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
210.17 + * version 2 for more details (a copy is included in the LICENSE file that
210.18 + * accompanied this code).
210.19 + *
210.20 + * You should have received a copy of the GNU General Public License version
210.21 + * 2 along with this work; if not, write to the Free Software Foundation,
210.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
210.23 + *
210.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
210.25 + * or visit www.oracle.com if you need additional information or have any
210.26 + * questions.
210.27 + */
210.28 +
210.29 +package java.lang;
210.30 +
210.31 +/**
210.32 + * Thrown when an exceptional arithmetic condition has occurred. For
210.33 + * example, an integer "divide by zero" throws an
210.34 + * instance of this class.
210.35 + *
210.36 + * {@code ArithmeticException} objects may be constructed by the
210.37 + * virtual machine as if {@linkplain Throwable#Throwable(String,
210.38 + * Throwable, boolean, boolean) suppression were disabled and/or the
210.39 + * stack trace was not writable}.
210.40 + *
210.41 + * @author unascribed
210.42 + * @since JDK1.0
210.43 + */
210.44 +public class ArithmeticException extends RuntimeException {
210.45 + private static final long serialVersionUID = 2256477558314496007L;
210.46 +
210.47 + /**
210.48 + * Constructs an {@code ArithmeticException} with no detail
210.49 + * message.
210.50 + */
210.51 + public ArithmeticException() {
210.52 + super();
210.53 + }
210.54 +
210.55 + /**
210.56 + * Constructs an {@code ArithmeticException} with the specified
210.57 + * detail message.
210.58 + *
210.59 + * @param s the detail message.
210.60 + */
210.61 + public ArithmeticException(String s) {
210.62 + super(s);
210.63 + }
210.64 +}
211.1 --- a/rt/emul/mini/src/main/java/java/lang/Boolean.java Wed Feb 27 17:50:47 2013 +0100
211.2 +++ b/rt/emul/mini/src/main/java/java/lang/Boolean.java Mon Oct 07 14:20:58 2013 +0200
211.3 @@ -25,6 +25,9 @@
211.4
211.5 package java.lang;
211.6
211.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
211.8 +import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
211.9 +
211.10 /**
211.11 * The Boolean class wraps a value of the primitive type
211.12 * {@code boolean} in an object. An object of type
211.13 @@ -40,6 +43,7 @@
211.14 * @author Arthur van Hoff
211.15 * @since JDK1.0
211.16 */
211.17 +@JavaScriptPrototype(container = "Boolean.prototype", prototype = "new Boolean")
211.18 public final class Boolean implements java.io.Serializable,
211.19 Comparable<Boolean>
211.20 {
211.21 @@ -127,6 +131,7 @@
211.22 *
211.23 * @return the primitive {@code boolean} value of this object.
211.24 */
211.25 + @JavaScriptBody(args = {}, body = "return this.valueOf();")
211.26 public boolean booleanValue() {
211.27 return value;
211.28 }
211.29 @@ -279,4 +284,13 @@
211.30 private static boolean toBoolean(String name) {
211.31 return ((name != null) && name.equalsIgnoreCase("true"));
211.32 }
211.33 + static {
211.34 + // as last step of initialization, initialize valueOf method
211.35 + initValueOf();
211.36 + }
211.37 + @JavaScriptBody(args = { }, body =
211.38 + "vm.java_lang_Boolean(false)" +
211.39 + ".valueOf = function() { return this._value() ? true : false; };"
211.40 + )
211.41 + private native static void initValueOf();
211.42 }
212.1 --- a/rt/emul/mini/src/main/java/java/lang/Character.java Wed Feb 27 17:50:47 2013 +0100
212.2 +++ b/rt/emul/mini/src/main/java/java/lang/Character.java Mon Oct 07 14:20:58 2013 +0200
212.3 @@ -2298,6 +2298,10 @@
212.4 */
212.5 @Deprecated
212.6 public static boolean isSpace(char ch) {
212.7 + return isSpaceChar(ch);
212.8 + }
212.9 +
212.10 + public static boolean isSpaceChar(int ch) {
212.11 return (ch <= 0x0020) &&
212.12 (((((1L << 0x0009) |
212.13 (1L << 0x000A) |
212.14 @@ -2307,7 +2311,6 @@
212.15 }
212.16
212.17
212.18 -
212.19 /**
212.20 * Determines if the specified character is white space according to Java.
212.21 * A character is a Java whitespace character if and only if it satisfies
212.22 @@ -2372,7 +2375,14 @@
212.23 * @since 1.5
212.24 */
212.25 public static boolean isWhitespace(int codePoint) {
212.26 - throw new UnsupportedOperationException();
212.27 + if (
212.28 + codePoint == SPACE_SEPARATOR ||
212.29 + codePoint == LINE_SEPARATOR ||
212.30 + codePoint == PARAGRAPH_SEPARATOR
212.31 + ) {
212.32 + return true;
212.33 + }
212.34 + return false;
212.35 }
212.36
212.37 /**
212.38 @@ -2516,4 +2526,14 @@
212.39 return (char) (((ch & 0xFF00) >> 8) | (ch << 8));
212.40 }
212.41
212.42 + static {
212.43 + // as last step of initialization, initialize valueOf method
212.44 + initValueOf();
212.45 + }
212.46 + @JavaScriptBody(args = {}, body =
212.47 + "vm.java_lang_Character(false)." +
212.48 + "valueOf = function() { return this._value(); };"
212.49 + )
212.50 + private native static void initValueOf();
212.51 +
212.52 }
213.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java Wed Feb 27 17:50:47 2013 +0100
213.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Mon Oct 07 14:20:58 2013 +0200
213.3 @@ -155,11 +155,15 @@
213.4 }
213.5 return arrType;
213.6 }
213.7 - Class<?> c = loadCls(className, className.replace('.', '_'));
213.8 - if (c == null) {
213.9 - throw new ClassNotFoundException(className);
213.10 + try {
213.11 + Class<?> c = loadCls(className, className.replace('.', '_'));
213.12 + if (c == null) {
213.13 + throw new ClassNotFoundException(className);
213.14 + }
213.15 + return c;
213.16 + } catch (Throwable ex) {
213.17 + throw new ClassNotFoundException(className, ex);
213.18 }
213.19 - return c;
213.20 }
213.21
213.22
213.23 @@ -402,8 +406,15 @@
213.24 }
213.25 return cmpType != null && getComponentType().isAssignableFrom(cmpType);
213.26 }
213.27 - String prop = "$instOf_" + getName().replace('.', '_');
213.28 - return hasCnstrProperty(cls, prop);
213.29 + if (isPrimitive()) {
213.30 + return false;
213.31 + } else {
213.32 + if (cls.isPrimitive()) {
213.33 + return false;
213.34 + }
213.35 + String prop = "$instOf_" + getName().replace('.', '_');
213.36 + return hasCnstrProperty(cls, prop);
213.37 + }
213.38 }
213.39
213.40 @JavaScriptBody(args = { "who", "prop" }, body =
213.41 @@ -1245,6 +1256,7 @@
213.42 }
213.43
213.44 @JavaScriptBody(args = { "sig" }, body =
213.45 + "if (!sig) sig = '[Ljava/lang/Object;';\n" +
213.46 "var c = Array[sig];\n" +
213.47 "if (c) return c;\n" +
213.48 "c = vm.java_lang_Class(true);\n" +
214.1 --- a/rt/emul/mini/src/main/java/java/lang/Double.java Wed Feb 27 17:50:47 2013 +0100
214.2 +++ b/rt/emul/mini/src/main/java/java/lang/Double.java Mon Oct 07 14:20:58 2013 +0200
214.3 @@ -190,12 +190,12 @@
214.4 * @param d the {@code double} to be converted.
214.5 * @return a string representation of the argument.
214.6 */
214.7 - @JavaScriptBody(args="d", body="var r = d.toString();"
214.8 - + "if (isFinite(d) && (r.indexOf('.') === -1)) r = r + '.0';"
214.9 - + "return r;")
214.10 - public static String toString(double d) {
214.11 - throw new UnsupportedOperationException();
214.12 - }
214.13 + @JavaScriptBody(args="d", body="var f = Math.floor(d);\n" +
214.14 + "var r = d.toString();" +
214.15 + "if (f === d && isFinite(d) && r.indexOf('e') === -1) return r + '.0';\n" +
214.16 + " else return r;"
214.17 + )
214.18 + public static native String toString(double d);
214.19
214.20 /**
214.21 * Returns a hexadecimal string representation of the
214.22 @@ -502,10 +502,8 @@
214.23 * @throws NumberFormatException if the string does not contain a
214.24 * parsable number.
214.25 */
214.26 - @JavaScriptBody(args="s", body="return parseFloat(s);")
214.27 public static Double valueOf(String s) throws NumberFormatException {
214.28 - throw new UnsupportedOperationException();
214.29 -// return new Double(FloatingDecimal.readJavaFormatString(s).doubleValue());
214.30 + return new Double(parseDouble(s));
214.31 }
214.32
214.33 /**
214.34 @@ -810,15 +808,17 @@
214.35 * @return the bits that represent the floating-point number.
214.36 */
214.37 public static long doubleToLongBits(double value) {
214.38 - throw new UnsupportedOperationException();
214.39 -// long result = doubleToRawLongBits(value);
214.40 -// // Check for NaN based on values of bit fields, maximum
214.41 -// // exponent and nonzero significand.
214.42 -// if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
214.43 -// DoubleConsts.EXP_BIT_MASK) &&
214.44 -// (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
214.45 -// result = 0x7ff8000000000000L;
214.46 -// return result;
214.47 + final long EXP_BIT_MASK = 9218868437227405312L;
214.48 + final long SIGNIF_BIT_MASK = 4503599627370495L;
214.49 +
214.50 + long result = doubleToRawLongBits(value);
214.51 + // Check for NaN based on values of bit fields, maximum
214.52 + // exponent and nonzero significand.
214.53 + if ( ((result & EXP_BIT_MASK) ==
214.54 + EXP_BIT_MASK) &&
214.55 + (result & SIGNIF_BIT_MASK) != 0L)
214.56 + result = 0x7ff8000000000000L;
214.57 + return result;
214.58 }
214.59
214.60 /**
214.61 @@ -857,7 +857,21 @@
214.62 * @return the bits that represent the floating-point number.
214.63 * @since 1.3
214.64 */
214.65 - public static native long doubleToRawLongBits(double value);
214.66 + public static long doubleToRawLongBits(double value) {
214.67 + int[] arr = { 0, 0 };
214.68 + doubleToRawLongBits(value, arr);
214.69 + long l = arr[1];
214.70 + return (l << 32) | arr[0];
214.71 + }
214.72 +
214.73 + @JavaScriptBody(args = { "value", "arr" }, body = ""
214.74 + + "var a = new ArrayBuffer(8);"
214.75 + + "new Float64Array(a)[0] = value;"
214.76 + + "var out = new Int32Array(a);"
214.77 + + "arr[0] = out[0];"
214.78 + + "arr[1] = out[1];"
214.79 + )
214.80 + private static native void doubleToRawLongBits(double value, int[] arr);
214.81
214.82 /**
214.83 * Returns the {@code double} value corresponding to a given
215.1 --- a/rt/emul/mini/src/main/java/java/lang/Enum.java Wed Feb 27 17:50:47 2013 +0100
215.2 +++ b/rt/emul/mini/src/main/java/java/lang/Enum.java Mon Oct 07 14:20:58 2013 +0200
215.3 @@ -27,6 +27,7 @@
215.4
215.5 import java.io.Serializable;
215.6 import java.io.IOException;
215.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
215.8
215.9 /**
215.10 * This is the common base class of all Java language enumeration types.
215.11 @@ -225,15 +226,17 @@
215.12 */
215.13 public static <T extends Enum<T>> T valueOf(Class<T> enumType,
215.14 String name) {
215.15 - throw new UnsupportedOperationException();
215.16 -// T result = enumType.enumConstantDirectory().get(name);
215.17 -// if (result != null)
215.18 -// return result;
215.19 -// if (name == null)
215.20 -// throw new NullPointerException("Name is null");
215.21 -// throw new IllegalArgumentException(
215.22 -// "No enum constant " + enumType.getCanonicalName() + "." + name);
215.23 + for (Object o : values(enumType)) {
215.24 + T t = enumType.cast(o);
215.25 + if (name.equals(((Enum)t).name)) {
215.26 + return t;
215.27 + }
215.28 + }
215.29 + throw new IllegalArgumentException();
215.30 }
215.31 +
215.32 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;")
215.33 + private static native Object[] values(Class<?> enumType);
215.34
215.35 /**
215.36 * enum classes cannot have finalize methods.
216.1 --- a/rt/emul/mini/src/main/java/java/lang/Float.java Wed Feb 27 17:50:47 2013 +0100
216.2 +++ b/rt/emul/mini/src/main/java/java/lang/Float.java Mon Oct 07 14:20:58 2013 +0200
216.3 @@ -710,15 +710,17 @@
216.4 * @return the bits that represent the floating-point number.
216.5 */
216.6 public static int floatToIntBits(float value) {
216.7 - throw new UnsupportedOperationException();
216.8 -// int result = floatToRawIntBits(value);
216.9 -// // Check for NaN based on values of bit fields, maximum
216.10 -// // exponent and nonzero significand.
216.11 -// if ( ((result & FloatConsts.EXP_BIT_MASK) ==
216.12 -// FloatConsts.EXP_BIT_MASK) &&
216.13 -// (result & FloatConsts.SIGNIF_BIT_MASK) != 0)
216.14 -// result = 0x7fc00000;
216.15 -// return result;
216.16 + final int EXP_BIT_MASK = 2139095040;
216.17 + final int SIGNIF_BIT_MASK = 8388607;
216.18 +
216.19 + int result = floatToRawIntBits(value);
216.20 + // Check for NaN based on values of bit fields, maximum
216.21 + // exponent and nonzero significand.
216.22 + if ( ((result & EXP_BIT_MASK) ==
216.23 + EXP_BIT_MASK) &&
216.24 + (result & SIGNIF_BIT_MASK) != 0)
216.25 + result = 0x7fc00000;
216.26 + return result;
216.27 }
216.28
216.29 /**
216.30 @@ -756,6 +758,11 @@
216.31 * @return the bits that represent the floating-point number.
216.32 * @since 1.3
216.33 */
216.34 + @JavaScriptBody(args = { "value" }, body = ""
216.35 + + "var a = new ArrayBuffer(4);"
216.36 + + "new Float32Array(a)[0] = value;"
216.37 + + "return new Int32Array(a)[0];"
216.38 + )
216.39 public static native int floatToRawIntBits(float value);
216.40
216.41 /**
217.1 --- a/rt/emul/mini/src/main/java/java/lang/Number.java Wed Feb 27 17:50:47 2013 +0100
217.2 +++ b/rt/emul/mini/src/main/java/java/lang/Number.java Mon Oct 07 14:20:58 2013 +0200
217.3 @@ -27,7 +27,6 @@
217.4
217.5 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
217.6 import org.apidesign.bck2brwsr.core.JavaScriptBody;
217.7 -import org.apidesign.bck2brwsr.core.JavaScriptOnly;
217.8 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
217.9
217.10 /**
218.1 --- a/rt/emul/mini/src/main/java/java/lang/Object.java Wed Feb 27 17:50:47 2013 +0100
218.2 +++ b/rt/emul/mini/src/main/java/java/lang/Object.java Mon Oct 07 14:20:58 2013 +0200
218.3 @@ -42,14 +42,21 @@
218.4 public class Object {
218.5
218.6 private static void registerNatives() {
218.7 - try {
218.8 + boolean assertsOn = false;
218.9 + assert assertsOn = false;
218.10 + if (assertsOn) try {
218.11 Array.get(null, 0);
218.12 } catch (Throwable ex) {
218.13 // ignore
218.14 }
218.15 }
218.16 + @JavaScriptBody(args = {}, body = "var p = vm.java_lang_Object(false);" +
218.17 + "p.toString = function() { return this.toString__Ljava_lang_String_2(); };"
218.18 + )
218.19 + private static native void registerToString();
218.20 static {
218.21 registerNatives();
218.22 + registerToString();
218.23 }
218.24
218.25 /**
218.26 @@ -72,9 +79,17 @@
218.27 * @see Class Literals, section 15.8.2 of
218.28 * <cite>The Java™ Language Specification</cite>.
218.29 */
218.30 - @JavaScriptBody(args={}, body="return this.constructor.$class;")
218.31 - public final native Class<?> getClass();
218.32 + public final Class<?> getClass() {
218.33 + Class<?> c = getClassImpl();
218.34 + return c == null ? Object.class : c;
218.35 + }
218.36
218.37 + @JavaScriptBody(args={}, body=
218.38 + "var c = this.constructor.$class;\n"
218.39 + + "return c ? c : null;\n"
218.40 + )
218.41 + private final native Class<?> getClassImpl();
218.42 +
218.43 /**
218.44 * Returns a hash code value for the object. This method is
218.45 * supported for the benefit of hash tables such as those provided by
218.46 @@ -110,12 +125,15 @@
218.47 * @see java.lang.Object#equals(java.lang.Object)
218.48 * @see java.lang.System#identityHashCode
218.49 */
218.50 + public int hashCode() {
218.51 + return defaultHashCode();
218.52 + }
218.53 @JavaScriptBody(args = {}, body =
218.54 "if (this.$hashCode) return this.$hashCode;\n"
218.55 + "var h = this.computeHashCode__I();\n"
218.56 + "return this.$hashCode = h & h;"
218.57 )
218.58 - public native int hashCode();
218.59 + final native int defaultHashCode();
218.60
218.61 @JavaScriptBody(args = {}, body = "return Math.random() * Math.pow(2, 32);")
218.62 native int computeHashCode();
218.63 @@ -310,7 +328,8 @@
218.64 * @see java.lang.Object#notifyAll()
218.65 * @see java.lang.Object#wait()
218.66 */
218.67 - public final native void notify();
218.68 + public final void notify() {
218.69 + }
218.70
218.71 /**
218.72 * Wakes up all threads that are waiting on this object's monitor. A
218.73 @@ -334,7 +353,8 @@
218.74 * @see java.lang.Object#notify()
218.75 * @see java.lang.Object#wait()
218.76 */
218.77 - public final native void notifyAll();
218.78 + public final void notifyAll() {
218.79 + }
218.80
218.81 /**
218.82 * Causes the current thread to wait until either another thread invokes the
218.83 @@ -421,7 +441,9 @@
218.84 * @see java.lang.Object#notify()
218.85 * @see java.lang.Object#notifyAll()
218.86 */
218.87 - public final native void wait(long timeout) throws InterruptedException;
218.88 + public final void wait(long timeout) throws InterruptedException {
218.89 + throw new InterruptedException();
218.90 + }
218.91
218.92 /**
218.93 * Causes the current thread to wait until another thread invokes the
218.94 @@ -486,20 +508,7 @@
218.95 * this exception is thrown.
218.96 */
218.97 public final void wait(long timeout, int nanos) throws InterruptedException {
218.98 - if (timeout < 0) {
218.99 - throw new IllegalArgumentException("timeout value is negative");
218.100 - }
218.101 -
218.102 - if (nanos < 0 || nanos > 999999) {
218.103 - throw new IllegalArgumentException(
218.104 - "nanosecond timeout value out of range");
218.105 - }
218.106 -
218.107 - if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
218.108 - timeout++;
218.109 - }
218.110 -
218.111 - wait(timeout);
218.112 + throw new InterruptedException();
218.113 }
218.114
218.115 /**
218.116 @@ -541,7 +550,7 @@
218.117 * @see java.lang.Object#notifyAll()
218.118 */
218.119 public final void wait() throws InterruptedException {
218.120 - wait(0);
218.121 + throw new InterruptedException();
218.122 }
218.123
218.124 /**
219.1 --- a/rt/emul/mini/src/main/java/java/lang/String.java Wed Feb 27 17:50:47 2013 +0100
219.2 +++ b/rt/emul/mini/src/main/java/java/lang/String.java Mon Oct 07 14:20:58 2013 +0200
219.3 @@ -115,15 +115,17 @@
219.4
219.5 /** use serialVersionUID from JDK 1.0.2 for interoperability */
219.6 private static final long serialVersionUID = -6849794470754667710L;
219.7 +
219.8 + static {
219.9 + registerToString();
219.10 + }
219.11 + @JavaScriptBody(args = {}, body =
219.12 + "var p = vm.java_lang_String(false);\n"
219.13 + + "p.toString = function() {\nreturn this._r().toString();\n};\n"
219.14 + + "p.valueOf = function() {\nreturn this._r().valueOf();\n}\n"
219.15 + )
219.16 + private static native void registerToString();
219.17
219.18 - @JavaScriptOnly(name="toString", value="String.prototype._r")
219.19 - private static void jsToString() {
219.20 - }
219.21 -
219.22 - @JavaScriptOnly(name="valueOf", value="function() { return this.toString().valueOf(); }")
219.23 - private static void jsValudOf() {
219.24 - }
219.25 -
219.26 /**
219.27 * Class String is special cased within the Serialization Stream Protocol.
219.28 *
219.29 @@ -2218,9 +2220,19 @@
219.30 * <code>replacement</code> is <code>null</code>.
219.31 * @since 1.5
219.32 */
219.33 - public String replace(CharSequence target, CharSequence replacement) {
219.34 - throw new UnsupportedOperationException("This one should be supported, but without dep on rest of regexp");
219.35 - }
219.36 + @JavaScriptBody(args = { "target", "replacement" }, body =
219.37 + "var s = this.toString();\n"
219.38 + + "target = target.toString();\n"
219.39 + + "replacement = replacement.toString();\n"
219.40 + + "for (;;) {\n"
219.41 + + " var ret = s.replace(target, replacement);\n"
219.42 + + " if (ret === s) {\n"
219.43 + + " return ret;\n"
219.44 + + " }\n"
219.45 + + " s = ret;\n"
219.46 + + "}"
219.47 + )
219.48 + public native String replace(CharSequence target, CharSequence replacement);
219.49
219.50 /**
219.51 * Splits this string around matches of the given
219.52 @@ -2303,8 +2315,35 @@
219.53 * @spec JSR-51
219.54 */
219.55 public String[] split(String regex, int limit) {
219.56 - throw new UnsupportedOperationException("Needs regexp");
219.57 + if (limit <= 0) {
219.58 + Object[] arr = splitImpl(this, regex, Integer.MAX_VALUE);
219.59 + int to = arr.length;
219.60 + if (limit == 0) {
219.61 + while (to > 1 && ((String)arr[--to]).isEmpty()) {
219.62 + }
219.63 + to++;
219.64 + }
219.65 + String[] ret = new String[to];
219.66 + System.arraycopy(arr, 0, ret, 0, to);
219.67 + return ret;
219.68 + } else {
219.69 + Object[] arr = splitImpl(this, regex, limit);
219.70 + String[] ret = new String[arr.length];
219.71 + int pos = 0;
219.72 + for (int i = 0; i < arr.length; i++) {
219.73 + final String s = (String)arr[i];
219.74 + ret[i] = s;
219.75 + pos = indexOf(s, pos) + s.length();
219.76 + }
219.77 + ret[arr.length - 1] += substring(pos);
219.78 + return ret;
219.79 + }
219.80 }
219.81 +
219.82 + @JavaScriptBody(args = { "str", "regex", "limit"}, body =
219.83 + "return str.split(new RegExp(regex), limit);"
219.84 + )
219.85 + private static native Object[] splitImpl(String str, String regex, int limit);
219.86
219.87 /**
219.88 * Splits this string around matches of the given <a
220.1 --- a/rt/emul/mini/src/main/java/java/lang/Throwable.java Wed Feb 27 17:50:47 2013 +0100
220.2 +++ b/rt/emul/mini/src/main/java/java/lang/Throwable.java Mon Oct 07 14:20:58 2013 +0200
220.3 @@ -638,10 +638,9 @@
220.4 * ... 2 more
220.5 * </pre>
220.6 */
220.7 -// public void printStackTrace() {
220.8 -// printStackTrace(System.err);
220.9 -// }
220.10 -//
220.11 + @JavaScriptBody(args = { }, body = "console.warn(this.toString());")
220.12 + public native void printStackTrace();
220.13 +
220.14 // /**
220.15 // * Prints this throwable and its backtrace to the specified print stream.
220.16 // *
220.17 @@ -1085,4 +1084,22 @@
220.18 // else
220.19 // return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
220.20 }
220.21 +
220.22 + private static Object bck2BrwsrCnvrt(Object o) {
220.23 + if (o instanceof Throwable) {
220.24 + return o;
220.25 + }
220.26 + final String msg = msg(o);
220.27 + if (msg == null || msg.startsWith("TypeError")) {
220.28 + return new NullPointerException(msg);
220.29 + }
220.30 + return new Throwable(msg);
220.31 + }
220.32 +
220.33 + @JavaScriptBody(args = { "o" }, body = "return o ? o.toString() : null;")
220.34 + private static native String msg(Object o);
220.35 +
220.36 + @JavaScriptOnly(name = "bck2BrwsrCnvrt", value = "c.bck2BrwsrCnvrt__Ljava_lang_Object_2Ljava_lang_Object_2")
220.37 + private static void bck2BrwsrCnvrtVM() {
220.38 + }
220.39 }
221.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Wed Feb 27 17:50:47 2013 +0100
221.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Mon Oct 07 14:20:58 2013 +0200
221.3 @@ -636,9 +636,9 @@
221.4 + "arr.jvmName = sig;\n"
221.5 + "return arr;"
221.6 )
221.7 - private static native Object newArray(boolean primitive, String sig, int length);
221.8 + static native Object newArray(boolean primitive, String sig, int length);
221.9
221.10 - private static Object multiNewArray(String sig, int[] dims, int index)
221.11 + static Object multiNewArray(String sig, int[] dims, int index)
221.12 throws IllegalArgumentException, NegativeArraySizeException {
221.13 if (dims.length == index + 1) {
221.14 return newArray(sig.length() == 2, sig, dims[index]);
222.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Wed Feb 27 17:50:47 2013 +0100
222.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Mon Oct 07 14:20:58 2013 +0200
222.3 @@ -501,8 +501,8 @@
222.4 throws IllegalAccessException, IllegalArgumentException,
222.5 InvocationTargetException
222.6 {
222.7 - final boolean isStatic = (getModifiers() & Modifier.STATIC) == 0;
222.8 - if (isStatic && obj == null) {
222.9 + final boolean nonStatic = (getModifiers() & Modifier.STATIC) == 0;
222.10 + if (nonStatic && obj == null) {
222.11 throw new NullPointerException();
222.12 }
222.13 Class[] types = getParameterTypes();
222.14 @@ -512,12 +512,12 @@
222.15 args = args.clone();
222.16 for (int i = 0; i < types.length; i++) {
222.17 Class c = types[i];
222.18 - if (c.isPrimitive()) {
222.19 - args[i] = toPrimitive(c, args[i]);
222.20 + if (c.isPrimitive() && args[i] != null) {
222.21 + args[i] = toPrimitive(args[i]);
222.22 }
222.23 }
222.24 }
222.25 - Object res = invoke0(isStatic, this, obj, args);
222.26 + Object res = invokeTry(nonStatic, this, obj, args);
222.27 if (getReturnType().isPrimitive()) {
222.28 res = fromPrimitive(getReturnType(), res);
222.29 }
222.30 @@ -536,6 +536,15 @@
222.31 + "return method._data().apply(self, p);\n"
222.32 )
222.33 private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
222.34 +
222.35 + private static Object invokeTry(boolean isStatic, Method m, Object self, Object[] args)
222.36 + throws InvocationTargetException {
222.37 + try {
222.38 + return invoke0(isStatic, m, self, args);
222.39 + } catch (Throwable ex) {
222.40 + throw new InvocationTargetException(ex, ex.getMessage());
222.41 + }
222.42 + }
222.43
222.44 static Object fromPrimitive(Class<?> type, Object o) {
222.45 if (type == Integer.TYPE) {
222.46 @@ -573,41 +582,8 @@
222.47 )
222.48 private static native Integer fromRaw(Class<?> cls, String m, Object o);
222.49
222.50 - private static Object toPrimitive(Class<?> type, Object o) {
222.51 - if (type == Integer.TYPE) {
222.52 - return toRaw("intValue__I", o);
222.53 - }
222.54 - if (type == Long.TYPE) {
222.55 - return toRaw("longValue__J", o);
222.56 - }
222.57 - if (type == Double.TYPE) {
222.58 - return toRaw("doubleValue__D", o);
222.59 - }
222.60 - if (type == Float.TYPE) {
222.61 - return toRaw("floatValue__F", o);
222.62 - }
222.63 - if (type == Byte.TYPE) {
222.64 - return toRaw("byteValue__B", o);
222.65 - }
222.66 - if (type == Boolean.TYPE) {
222.67 - return toRaw("booleanValue__Z", o);
222.68 - }
222.69 - if (type == Short.TYPE) {
222.70 - return toRaw("shortValue__S", o);
222.71 - }
222.72 - if (type == Character.TYPE) {
222.73 - return toRaw("charValue__C", o);
222.74 - }
222.75 - if (type.getName().equals("void")) {
222.76 - return o;
222.77 - }
222.78 - throw new IllegalStateException("Can't convert " + o);
222.79 - }
222.80 -
222.81 - @JavaScriptBody(args = { "m", "o" },
222.82 - body = "return o[m](o);"
222.83 - )
222.84 - private static native Object toRaw(String m, Object o);
222.85 + @JavaScriptBody(args = { "o" }, body = "return o.valueOf();")
222.86 + private static native Object toPrimitive(Object o);
222.87
222.88 /**
222.89 * Returns {@code true} if this method is a bridge
223.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Wed Feb 27 17:50:47 2013 +0100
223.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Mon Oct 07 14:20:58 2013 +0200
223.3 @@ -54,6 +54,11 @@
223.4 )
223.5 public static native byte[] expandArray(byte[] arr, int expectedSize);
223.6
223.7 + @JavaScriptBody(args = { "arr", "expectedSize" }, body =
223.8 + "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;"
223.9 + )
223.10 + public static native char[] expandArray(char[] arr, int expectedSize);
223.11 +
223.12 @JavaScriptBody(args = {}, body = "return new Date().getTime();")
223.13 private static native double currentTimeMillisDouble();
223.14
224.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Wed Feb 27 17:50:47 2013 +0100
224.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Mon Oct 07 14:20:58 2013 +0200
224.3 @@ -1,226 +1,244 @@
224.4 // empty line needed here
224.5 -Number.prototype.add32 = function(x) { return (this + x) | 0; };
224.6 -Number.prototype.sub32 = function(x) { return (this - x) | 0; };
224.7 -Number.prototype.mul32 = function(x) {
224.8 - return (((this * (x >> 16)) << 16) + this * (x & 0xFFFF)) | 0;
224.9 -};
224.10 -Number.prototype.neg32 = function() { return (-this) | 0; };
224.11
224.12 -Number.prototype.toInt8 = function() { return (this << 24) >> 24; };
224.13 -Number.prototype.toInt16 = function() { return (this << 16) >> 16; };
224.14 +(function(numberPrototype) {
224.15 + numberPrototype.add32 = function(x) {
224.16 + return (this + x) | 0;
224.17 + };
224.18 + numberPrototype.sub32 = function(x) {
224.19 + return (this - x) | 0;
224.20 + };
224.21 + numberPrototype.mul32 = function(x) {
224.22 + return (((this * (x >> 16)) << 16) + this * (x & 0xFFFF)) | 0;
224.23 + };
224.24 + numberPrototype.neg32 = function() {
224.25 + return (-this) | 0;
224.26 + };
224.27
224.28 -var __m32 = 0xFFFFFFFF;
224.29 + numberPrototype.toInt8 = function() {
224.30 + return (this << 24) >> 24;
224.31 + };
224.32 + numberPrototype.toInt16 = function() {
224.33 + return (this << 16) >> 16;
224.34 + };
224.35
224.36 -Number.prototype.next32 = function(low) {
224.37 - if (this === 0) {
224.38 - return low;
224.39 - }
224.40 - var l = new Number(low);
224.41 - l.hi = this | 0;
224.42 - return l;
224.43 -};
224.44 + var __m32 = 0xFFFFFFFF;
224.45
224.46 -Number.prototype.high32 = function() {
224.47 - return this.hi ? this.hi : (Math.floor(this / (__m32+1))) | 0;
224.48 -};
224.49 -Number.prototype.toInt32 = function() { return this | 0; };
224.50 -Number.prototype.toFP = function() {
224.51 - return this.hi ? this.hi * (__m32+1) + this : this;
224.52 -};
224.53 -Number.prototype.toLong = function() {
224.54 - var hi = (this / (__m32+1)) | 0;
224.55 - var low = (this % (__m32+1)) | 0;
224.56 - if (low < 0) {
224.57 - low += __m32+1;
224.58 - }
224.59 -
224.60 - if (this < 0) {
224.61 - hi -= 1;
224.62 - }
224.63 + numberPrototype.next32 = function(low) {
224.64 + if (this === 0) {
224.65 + return low;
224.66 + }
224.67 + var l = new Number(low);
224.68 + l.hi = this | 0;
224.69 + return l;
224.70 + };
224.71
224.72 - return hi.next32(low);
224.73 -};
224.74 + numberPrototype.high32 = function() {
224.75 + return this.hi ? this.hi : (Math.floor(this / (__m32 + 1))) | 0;
224.76 + };
224.77 + numberPrototype.toInt32 = function() {
224.78 + return this | 0;
224.79 + };
224.80 + numberPrototype.toFP = function() {
224.81 + return this.hi ? this.hi * (__m32 + 1) + this : this;
224.82 + };
224.83 + numberPrototype.toLong = function() {
224.84 + var hi = (this / (__m32 + 1)) | 0;
224.85 + var low = (this % (__m32 + 1)) | 0;
224.86 + if (low < 0) {
224.87 + low += __m32 + 1;
224.88 + }
224.89
224.90 -Number.prototype.toExactString = function() {
224.91 - if (this.hi) {
224.92 - // check for Long.MIN_VALUE
224.93 - if ((this.hi == (0x80000000 | 0)) && (this == 0)) {
224.94 - return '-9223372036854775808';
224.95 + if (this < 0) {
224.96 + hi -= 1;
224.97 }
224.98 - var res = 0;
224.99 - var a = [ 6,9,2,7,6,9,4,9,2,4 ];
224.100 - var s = '';
224.101 - var digit;
224.102 - var neg = this.hi < 0;
224.103 - if (neg) {
224.104 - var x = this.neg64();
224.105 - var hi = x.hi;
224.106 - var low = x;
224.107 - } else {
224.108 - var hi = this.hi;
224.109 - var low = this;
224.110 - }
224.111 - for (var i = 0; i < a.length; i++) {
224.112 - res += hi * a[i];
224.113 - var low_digit = low % 10;
224.114 - digit = (res % 10) + low_digit;
224.115
224.116 - low = Math.floor(low / 10);
224.117 - res = Math.floor(res / 10);
224.118 -
224.119 - if (digit >= 10) {
224.120 - digit -= 10;
224.121 - res++;
224.122 - }
224.123 - s = String(digit).concat(s);
224.124 - }
224.125 - s = String(res).concat(s).replace(/^0+/, '');
224.126 - return (neg ? '-' : '').concat(s);
224.127 - }
224.128 - return String(this);
224.129 -};
224.130 -
224.131 -Number.prototype.add64 = function(x) {
224.132 - var low = this + x;
224.133 - carry = 0;
224.134 - if (low > __m32) {
224.135 - carry = 1;
224.136 - low -= (__m32+1);
224.137 - }
224.138 - var hi = (this.high32() + x.high32() + carry) | 0;
224.139 - return hi.next32(low);
224.140 -};
224.141 -
224.142 -Number.prototype.sub64 = function(x) {
224.143 - var low = this - x;
224.144 - carry = 0;
224.145 - if (low < 0) {
224.146 - carry = 1;
224.147 - low += (__m32+1);
224.148 - }
224.149 - var hi = (this.high32() - x.high32() - carry) | 0;
224.150 - return hi.next32(low);
224.151 -};
224.152 -
224.153 -Number.prototype.mul64 = function(x) {
224.154 - var low = this.mul32(x);
224.155 - low += (low < 0) ? (__m32+1) : 0;
224.156 - // first count upper 32 bits of (this.low * x.low)
224.157 - var hi_hi = 0;
224.158 - var hi_low = 0;
224.159 - var m = 1;
224.160 - for (var i = 0; i < 32; i++) {
224.161 - if (x & m) {
224.162 - hi_hi += this >>> 16;
224.163 - hi_low += this & 0xFFFF
224.164 - }
224.165 - hi_low >>= 1;
224.166 - hi_low += (hi_hi & 1) ? 0x8000 : 0;
224.167 - hi_hi >>= 1;
224.168 - m <<= 1;
224.169 - }
224.170 - var hi = (hi_hi << 16) + hi_low;
224.171 -
224.172 - var m1 = this.high32().mul32(x);
224.173 - var m2 = this.mul32(x.high32());
224.174 - hi = hi.add32(m1).add32(m2);
224.175 -
224.176 - return hi.next32(low);
224.177 -};
224.178 -
224.179 -Number.prototype.and64 = function(x) {
224.180 - var low = this & x;
224.181 - low += (low < 0) ? (__m32+1) : 0;
224.182 - if (this.hi && x.hi) {
224.183 - var hi = this.hi & x.hi;
224.184 return hi.next32(low);
224.185 };
224.186 - return low;
224.187 -};
224.188
224.189 -Number.prototype.or64 = function(x) {
224.190 - var low = this | x;
224.191 - low += (low < 0) ? (__m32+1) : 0;
224.192 - if (this.hi || x.hi) {
224.193 - var hi = this.hi | x.hi;
224.194 + numberPrototype.toExactString = function() {
224.195 + if (this.hi) {
224.196 + // check for Long.MIN_VALUE
224.197 + if ((this.hi == (0x80000000 | 0)) && (this == 0)) {
224.198 + return '-9223372036854775808';
224.199 + }
224.200 + var res = 0;
224.201 + var a = [6, 9, 2, 7, 6, 9, 4, 9, 2, 4];
224.202 + var s = '';
224.203 + var digit;
224.204 + var neg = this.hi < 0;
224.205 + if (neg) {
224.206 + var x = this.neg64();
224.207 + var hi = x.hi;
224.208 + var low = x;
224.209 + } else {
224.210 + var hi = this.hi;
224.211 + var low = this;
224.212 + }
224.213 + for (var i = 0; i < a.length; i++) {
224.214 + res += hi * a[i];
224.215 + var low_digit = low % 10;
224.216 + digit = (res % 10) + low_digit;
224.217 +
224.218 + low = Math.floor(low / 10);
224.219 + res = Math.floor(res / 10);
224.220 +
224.221 + if (digit >= 10) {
224.222 + digit -= 10;
224.223 + res++;
224.224 + }
224.225 + s = String(digit).concat(s);
224.226 + }
224.227 + s = String(res).concat(s).replace(/^0+/, '');
224.228 + return (neg ? '-' : '').concat(s);
224.229 + }
224.230 + return String(this);
224.231 + };
224.232 +
224.233 + numberPrototype.add64 = function(x) {
224.234 + var low = this + x;
224.235 + carry = 0;
224.236 + if (low > __m32) {
224.237 + carry = 1;
224.238 + low -= (__m32 + 1);
224.239 + }
224.240 + var hi = (this.high32() + x.high32() + carry) | 0;
224.241 return hi.next32(low);
224.242 };
224.243 - return low;
224.244 -};
224.245
224.246 -Number.prototype.xor64 = function(x) {
224.247 - var low = this ^ x;
224.248 - low += (low < 0) ? (__m32+1) : 0;
224.249 - if (this.hi || x.hi) {
224.250 - var hi = this.hi ^ x.hi;
224.251 + numberPrototype.sub64 = function(x) {
224.252 + var low = this - x;
224.253 + carry = 0;
224.254 + if (low < 0) {
224.255 + carry = 1;
224.256 + low += (__m32 + 1);
224.257 + }
224.258 + var hi = (this.high32() - x.high32() - carry) | 0;
224.259 return hi.next32(low);
224.260 };
224.261 - return low;
224.262 -};
224.263
224.264 -Number.prototype.shl64 = function(x) {
224.265 - if (x >= 32) {
224.266 - var hi = this << (x - 32);
224.267 - return hi.next32(0);
224.268 - } else {
224.269 - var hi = this.high32() << x;
224.270 - var low_reminder = this >> (32 - x);
224.271 - hi |= low_reminder;
224.272 - var low = this << x;
224.273 - low += (low < 0) ? (__m32+1) : 0;
224.274 + numberPrototype.mul64 = function(x) {
224.275 + var low = this.mul32(x);
224.276 + low += (low < 0) ? (__m32 + 1) : 0;
224.277 + // first count upper 32 bits of (this.low * x.low)
224.278 + var hi_hi = 0;
224.279 + var hi_low = 0;
224.280 + var m = 1;
224.281 + for (var i = 0; i < 32; i++) {
224.282 + if (x & m) {
224.283 + hi_hi += this >>> 16;
224.284 + hi_low += this & 0xFFFF
224.285 + }
224.286 + hi_low >>= 1;
224.287 + hi_low += (hi_hi & 1) ? 0x8000 : 0;
224.288 + hi_hi >>= 1;
224.289 + m <<= 1;
224.290 + }
224.291 + var hi = (hi_hi << 16) + hi_low;
224.292 +
224.293 + var m1 = this.high32().mul32(x);
224.294 + var m2 = this.mul32(x.high32());
224.295 + hi = hi.add32(m1).add32(m2);
224.296 +
224.297 return hi.next32(low);
224.298 - }
224.299 -};
224.300 + };
224.301
224.302 -Number.prototype.shr64 = function(x) {
224.303 - if (x >= 32) {
224.304 - var low = this.high32() >> (x - 32);
224.305 - low += (low < 0) ? (__m32+1) : 0;
224.306 + numberPrototype.and64 = function(x) {
224.307 + var low = this & x;
224.308 + low += (low < 0) ? (__m32 + 1) : 0;
224.309 + if (this.hi && x.hi) {
224.310 + var hi = this.hi & x.hi;
224.311 + return hi.next32(low);
224.312 + }
224.313 + ;
224.314 return low;
224.315 - } else {
224.316 - var low = this >> x;
224.317 - var hi_reminder = this.high32() << (32 - x);
224.318 - low |= hi_reminder;
224.319 - low += (low < 0) ? (__m32+1) : 0;
224.320 - var hi = this.high32() >> x;
224.321 - return hi.next32(low);
224.322 - }
224.323 -};
224.324 + };
224.325
224.326 -Number.prototype.ushr64 = function(x) {
224.327 - if (x >= 32) {
224.328 - var low = this.high32() >>> (x - 32);
224.329 - low += (low < 0) ? (__m32+1) : 0;
224.330 + numberPrototype.or64 = function(x) {
224.331 + var low = this | x;
224.332 + low += (low < 0) ? (__m32 + 1) : 0;
224.333 + if (this.hi || x.hi) {
224.334 + var hi = this.hi | x.hi;
224.335 + return hi.next32(low);
224.336 + }
224.337 + ;
224.338 return low;
224.339 - } else {
224.340 - var low = this >>> x;
224.341 - var hi_reminder = this.high32() << (32 - x);
224.342 - low |= hi_reminder;
224.343 - low += (low < 0) ? (__m32+1) : 0;
224.344 - var hi = this.high32() >>> x;
224.345 - return hi.next32(low);
224.346 - }
224.347 -};
224.348 + };
224.349
224.350 -Number.prototype.compare64 = function(x) {
224.351 - if (this.high32() === x.high32()) {
224.352 - return (this < x) ? -1 : ((this > x) ? 1 : 0);
224.353 - }
224.354 - return (this.high32() < x.high32()) ? -1 : 1;
224.355 -};
224.356 + numberPrototype.xor64 = function(x) {
224.357 + var low = this ^ x;
224.358 + low += (low < 0) ? (__m32 + 1) : 0;
224.359 + if (this.hi || x.hi) {
224.360 + var hi = this.hi ^ x.hi;
224.361 + return hi.next32(low);
224.362 + }
224.363 + ;
224.364 + return low;
224.365 + };
224.366
224.367 -Number.prototype.neg64 = function() {
224.368 - var hi = this.high32();
224.369 - var low = this;
224.370 - if ((hi === 0) && (low < 0)) { return -low; }
224.371 - hi = ~hi;
224.372 - low = ~low;
224.373 - low += (low < 0) ? (__m32+1) : 0;
224.374 - var ret = hi.next32(low);
224.375 - return ret.add64(1);
224.376 -};
224.377 + numberPrototype.shl64 = function(x) {
224.378 + if (x >= 32) {
224.379 + var hi = this << (x - 32);
224.380 + return hi.next32(0);
224.381 + } else {
224.382 + var hi = this.high32() << x;
224.383 + var low_reminder = this >> (32 - x);
224.384 + hi |= low_reminder;
224.385 + var low = this << x;
224.386 + low += (low < 0) ? (__m32 + 1) : 0;
224.387 + return hi.next32(low);
224.388 + }
224.389 + };
224.390
224.391 -(function(numberPrototype) {
224.392 + numberPrototype.shr64 = function(x) {
224.393 + if (x >= 32) {
224.394 + var low = this.high32() >> (x - 32);
224.395 + low += (low < 0) ? (__m32 + 1) : 0;
224.396 + return low;
224.397 + } else {
224.398 + var low = this >> x;
224.399 + var hi_reminder = this.high32() << (32 - x);
224.400 + low |= hi_reminder;
224.401 + low += (low < 0) ? (__m32 + 1) : 0;
224.402 + var hi = this.high32() >> x;
224.403 + return hi.next32(low);
224.404 + }
224.405 + };
224.406 +
224.407 + numberPrototype.ushr64 = function(x) {
224.408 + if (x >= 32) {
224.409 + var low = this.high32() >>> (x - 32);
224.410 + low += (low < 0) ? (__m32 + 1) : 0;
224.411 + return low;
224.412 + } else {
224.413 + var low = this >>> x;
224.414 + var hi_reminder = this.high32() << (32 - x);
224.415 + low |= hi_reminder;
224.416 + low += (low < 0) ? (__m32 + 1) : 0;
224.417 + var hi = this.high32() >>> x;
224.418 + return hi.next32(low);
224.419 + }
224.420 + };
224.421 +
224.422 + numberPrototype.compare64 = function(x) {
224.423 + if (this.high32() === x.high32()) {
224.424 + return (this < x) ? -1 : ((this > x) ? 1 : 0);
224.425 + }
224.426 + return (this.high32() < x.high32()) ? -1 : 1;
224.427 + };
224.428 +
224.429 + numberPrototype.neg64 = function() {
224.430 + var hi = this.high32();
224.431 + var low = this;
224.432 + if ((hi === 0) && (low < 0)) {
224.433 + return -low;
224.434 + }
224.435 + hi = ~hi;
224.436 + low = ~low;
224.437 + low += (low < 0) ? (__m32 + 1) : 0;
224.438 + var ret = hi.next32(low);
224.439 + return ret.add64(1);
224.440 + };
224.441 +
224.442 function __handleDivByZero() {
224.443 var exception = new vm.java_lang_ArithmeticException;
224.444 vm.java_lang_ArithmeticException(false).constructor
224.445 @@ -551,3 +569,5 @@
224.446 return negateResult ? result.neg64() : result;
224.447 }
224.448 })(Number.prototype);
224.449 +
224.450 +vm.java_lang_Number(false);
225.1 --- a/rt/emul/pom.xml Wed Feb 27 17:50:47 2013 +0100
225.2 +++ b/rt/emul/pom.xml Mon Oct 07 14:20:58 2013 +0200
225.3 @@ -4,15 +4,16 @@
225.4 <parent>
225.5 <groupId>org.apidesign.bck2brwsr</groupId>
225.6 <artifactId>rt</artifactId>
225.7 - <version>0.3-SNAPSHOT</version>
225.8 + <version>0.9-SNAPSHOT</version>
225.9 </parent>
225.10 <groupId>org.apidesign.bck2brwsr</groupId>
225.11 <artifactId>emul.pom</artifactId>
225.12 - <version>0.3-SNAPSHOT</version>
225.13 + <version>0.9-SNAPSHOT</version>
225.14 <packaging>pom</packaging>
225.15 <name>Emulation of Core Libraries</name>
225.16 <modules>
225.17 <module>mini</module>
225.18 <module>compact</module>
225.19 + <module>brwsrtest</module>
225.20 </modules>
225.21 </project>
226.1 --- a/rt/javap/pom.xml Wed Feb 27 17:50:47 2013 +0100
226.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
226.3 @@ -1,41 +0,0 @@
226.4 -<?xml version="1.0"?>
226.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
226.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
226.7 - <modelVersion>4.0.0</modelVersion>
226.8 - <parent>
226.9 - <groupId>org.apidesign.bck2brwsr</groupId>
226.10 - <artifactId>rt</artifactId>
226.11 - <version>0.3-SNAPSHOT</version>
226.12 - </parent>
226.13 - <groupId>org.apidesign.bck2brwsr</groupId>
226.14 - <artifactId>javap</artifactId>
226.15 - <version>0.3-SNAPSHOT</version>
226.16 - <name>ByteCode Parser</name>
226.17 - <url>http://maven.apache.org</url>
226.18 - <properties>
226.19 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
226.20 - </properties>
226.21 - <build>
226.22 - <plugins>
226.23 - <plugin>
226.24 - <groupId>org.apache.maven.plugins</groupId>
226.25 - <artifactId>maven-compiler-plugin</artifactId>
226.26 - <version>2.5.1</version>
226.27 - <configuration>
226.28 - <compilerArguments>
226.29 - <!--<bootclasspath>non-existing</bootclasspath>-->
226.30 - </compilerArguments>
226.31 - <source>1.6</source>
226.32 - <target>1.6</target>
226.33 - </configuration>
226.34 - </plugin>
226.35 - </plugins>
226.36 - </build>
226.37 - <dependencies>
226.38 - <dependency>
226.39 - <groupId>org.apidesign.bck2brwsr</groupId>
226.40 - <artifactId>emul.mini</artifactId>
226.41 - <version>0.3-SNAPSHOT</version>
226.42 - </dependency>
226.43 - </dependencies>
226.44 -</project>
227.1 --- a/rt/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Wed Feb 27 17:50:47 2013 +0100
227.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
227.3 @@ -1,145 +0,0 @@
227.4 -/*
227.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
227.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
227.7 - *
227.8 - * This code is free software; you can redistribute it and/or modify it
227.9 - * under the terms of the GNU General Public License version 2 only, as
227.10 - * published by the Free Software Foundation. Oracle designates this
227.11 - * particular file as subject to the "Classpath" exception as provided
227.12 - * by Oracle in the LICENSE file that accompanied this code.
227.13 - *
227.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
227.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
227.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
227.17 - * version 2 for more details (a copy is included in the LICENSE file that
227.18 - * accompanied this code).
227.19 - *
227.20 - * You should have received a copy of the GNU General Public License version
227.21 - * 2 along with this work; if not, write to the Free Software Foundation,
227.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
227.23 - *
227.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
227.25 - * or visit www.oracle.com if you need additional information or have any
227.26 - * questions.
227.27 - */
227.28 -package org.apidesign.javap;
227.29 -
227.30 -import java.io.ByteArrayInputStream;
227.31 -import java.io.DataInputStream;
227.32 -import java.io.IOException;
227.33 -
227.34 -/** An abstract parser for annotation definitions. Analyses the bytes and
227.35 - * performs some callbacks to the overriden parser methods.
227.36 - *
227.37 - * @author Jaroslav Tulach <jtulach@netbeans.org>
227.38 - */
227.39 -public class AnnotationParser {
227.40 - private final boolean textual;
227.41 - private final boolean iterateArray;
227.42 -
227.43 - protected AnnotationParser(boolean textual, boolean iterateArray) {
227.44 - this.textual = textual;
227.45 - this.iterateArray = iterateArray;
227.46 - }
227.47 -
227.48 - protected void visitAnnotationStart(String type, boolean top) throws IOException {
227.49 - }
227.50 -
227.51 - protected void visitAnnotationEnd(String type, boolean top) throws IOException {
227.52 - }
227.53 -
227.54 - protected void visitValueStart(String attrName, char type) throws IOException {
227.55 - }
227.56 -
227.57 - protected void visitValueEnd(String attrName, char type) throws IOException {
227.58 - }
227.59 -
227.60 -
227.61 - protected void visitAttr(
227.62 - String annoType, String attr, String attrType, String value
227.63 - ) throws IOException {
227.64 - }
227.65 -
227.66 - protected void visitEnumAttr(
227.67 - String annoType, String attr, String attrType, String value
227.68 - ) throws IOException {
227.69 - visitAttr(annoType, attr, attrType, value);
227.70 - }
227.71 -
227.72 - /** Initialize the parsing with constant pool from <code>cd</code>.
227.73 - *
227.74 - * @param attr the attribute defining annotations
227.75 - * @param cd constant pool
227.76 - * @throws IOException in case I/O fails
227.77 - */
227.78 - public final void parse(byte[] attr, ClassData cd) throws IOException {
227.79 - ByteArrayInputStream is = new ByteArrayInputStream(attr);
227.80 - DataInputStream dis = new DataInputStream(is);
227.81 - try {
227.82 - read(dis, cd);
227.83 - } finally {
227.84 - is.close();
227.85 - }
227.86 - }
227.87 -
227.88 - private void read(DataInputStream dis, ClassData cd) throws IOException {
227.89 - int cnt = dis.readUnsignedShort();
227.90 - for (int i = 0; i < cnt; i++) {
227.91 - readAnno(dis, cd, true);
227.92 - }
227.93 - }
227.94 -
227.95 - private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
227.96 - int type = dis.readUnsignedShort();
227.97 - String typeName = cd.StringValue(type);
227.98 - visitAnnotationStart(typeName, top);
227.99 - int cnt = dis.readUnsignedShort();
227.100 - for (int i = 0; i < cnt; i++) {
227.101 - String attrName = cd.StringValue(dis.readUnsignedShort());
227.102 - readValue(dis, cd, typeName, attrName);
227.103 - }
227.104 - visitAnnotationEnd(typeName, top);
227.105 - if (cnt == 0) {
227.106 - visitAttr(typeName, null, null, null);
227.107 - }
227.108 - }
227.109 -
227.110 - private void readValue(
227.111 - DataInputStream dis, ClassData cd, String typeName, String attrName
227.112 - ) throws IOException {
227.113 - char type = (char)dis.readByte();
227.114 - visitValueStart(attrName, type);
227.115 - if (type == '@') {
227.116 - readAnno(dis, cd, false);
227.117 - } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
227.118 - int primitive = dis.readUnsignedShort();
227.119 - String val = cd.stringValue(primitive, textual);
227.120 - String attrType;
227.121 - if (type == 's') {
227.122 - attrType = "Ljava_lang_String_2";
227.123 - if (textual) {
227.124 - val = '"' + val + '"';
227.125 - }
227.126 - } else {
227.127 - attrType = "" + type;
227.128 - }
227.129 - visitAttr(typeName, attrName, attrType, val);
227.130 - } else if (type == 'c') {
227.131 - int cls = dis.readUnsignedShort();
227.132 - } else if (type == '[') {
227.133 - int cnt = dis.readUnsignedShort();
227.134 - for (int i = 0; i < cnt; i++) {
227.135 - readValue(dis, cd, typeName, iterateArray ? attrName : null);
227.136 - }
227.137 - } else if (type == 'e') {
227.138 - int enumT = dis.readUnsignedShort();
227.139 - String attrType = cd.stringValue(enumT, textual);
227.140 - int enumN = dis.readUnsignedShort();
227.141 - String val = cd.stringValue(enumN, textual);
227.142 - visitEnumAttr(typeName, attrName, attrType, val);
227.143 - } else {
227.144 - throw new IOException("Unknown type " + type);
227.145 - }
227.146 - visitValueEnd(attrName, type);
227.147 - }
227.148 -}
228.1 --- a/rt/javap/src/main/java/org/apidesign/javap/AttrData.java Wed Feb 27 17:50:47 2013 +0100
228.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
228.3 @@ -1,77 +0,0 @@
228.4 -/*
228.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
228.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
228.7 - *
228.8 - * This code is free software; you can redistribute it and/or modify it
228.9 - * under the terms of the GNU General Public License version 2 only, as
228.10 - * published by the Free Software Foundation. Oracle designates this
228.11 - * particular file as subject to the "Classpath" exception as provided
228.12 - * by Oracle in the LICENSE file that accompanied this code.
228.13 - *
228.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
228.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
228.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
228.17 - * version 2 for more details (a copy is included in the LICENSE file that
228.18 - * accompanied this code).
228.19 - *
228.20 - * You should have received a copy of the GNU General Public License version
228.21 - * 2 along with this work; if not, write to the Free Software Foundation,
228.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
228.23 - *
228.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
228.25 - * or visit www.oracle.com if you need additional information or have any
228.26 - * questions.
228.27 - */
228.28 -
228.29 -
228.30 -
228.31 -package org.apidesign.javap;
228.32 -
228.33 -import java.io.*;
228.34 -
228.35 -/**
228.36 - * Reads and stores attribute information.
228.37 - *
228.38 - * @author Sucheta Dambalkar (Adopted code from jdis)
228.39 - */
228.40 -class AttrData {
228.41 - ClassData cls;
228.42 - int name_cpx;
228.43 - int datalen;
228.44 - byte data[];
228.45 -
228.46 - public AttrData (ClassData cls) {
228.47 - this.cls=cls;
228.48 - }
228.49 -
228.50 - /**
228.51 - * Reads unknown attribute.
228.52 - */
228.53 - public void read(int name_cpx, DataInputStream in) throws IOException {
228.54 - this.name_cpx=name_cpx;
228.55 - datalen=in.readInt();
228.56 - data=new byte[datalen];
228.57 - in.readFully(data);
228.58 - }
228.59 -
228.60 - /**
228.61 - * Reads just the name of known attribute.
228.62 - */
228.63 - public void read(int name_cpx){
228.64 - this.name_cpx=name_cpx;
228.65 - }
228.66 -
228.67 - /**
228.68 - * Returns attribute name.
228.69 - */
228.70 - public String getAttrName(){
228.71 - return cls.getString(name_cpx);
228.72 - }
228.73 -
228.74 - /**
228.75 - * Returns attribute data.
228.76 - */
228.77 - public byte[] getData(){
228.78 - return data;
228.79 - }
228.80 -}
229.1 --- a/rt/javap/src/main/java/org/apidesign/javap/CPX.java Wed Feb 27 17:50:47 2013 +0100
229.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
229.3 @@ -1,40 +0,0 @@
229.4 -/*
229.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
229.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
229.7 - *
229.8 - * This code is free software; you can redistribute it and/or modify it
229.9 - * under the terms of the GNU General Public License version 2 only, as
229.10 - * published by the Free Software Foundation. Oracle designates this
229.11 - * particular file as subject to the "Classpath" exception as provided
229.12 - * by Oracle in the LICENSE file that accompanied this code.
229.13 - *
229.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
229.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
229.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
229.17 - * version 2 for more details (a copy is included in the LICENSE file that
229.18 - * accompanied this code).
229.19 - *
229.20 - * You should have received a copy of the GNU General Public License version
229.21 - * 2 along with this work; if not, write to the Free Software Foundation,
229.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
229.23 - *
229.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
229.25 - * or visit www.oracle.com if you need additional information or have any
229.26 - * questions.
229.27 - */
229.28 -
229.29 -
229.30 -package org.apidesign.javap;
229.31 -
229.32 -/**
229.33 - * Stores constant pool entry information with one field.
229.34 - *
229.35 - * @author Sucheta Dambalkar (Adopted code from jdis)
229.36 - */
229.37 -class CPX {
229.38 - int cpx;
229.39 -
229.40 - CPX (int cpx) {
229.41 - this.cpx=cpx;
229.42 - }
229.43 -}
230.1 --- a/rt/javap/src/main/java/org/apidesign/javap/CPX2.java Wed Feb 27 17:50:47 2013 +0100
230.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
230.3 @@ -1,41 +0,0 @@
230.4 -/*
230.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
230.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
230.7 - *
230.8 - * This code is free software; you can redistribute it and/or modify it
230.9 - * under the terms of the GNU General Public License version 2 only, as
230.10 - * published by the Free Software Foundation. Oracle designates this
230.11 - * particular file as subject to the "Classpath" exception as provided
230.12 - * by Oracle in the LICENSE file that accompanied this code.
230.13 - *
230.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
230.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
230.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
230.17 - * version 2 for more details (a copy is included in the LICENSE file that
230.18 - * accompanied this code).
230.19 - *
230.20 - * You should have received a copy of the GNU General Public License version
230.21 - * 2 along with this work; if not, write to the Free Software Foundation,
230.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
230.23 - *
230.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
230.25 - * or visit www.oracle.com if you need additional information or have any
230.26 - * questions.
230.27 - */
230.28 -
230.29 -
230.30 -package org.apidesign.javap;
230.31 -
230.32 -/**
230.33 - * Stores constant pool entry information with two fields.
230.34 - *
230.35 - * @author Sucheta Dambalkar (Adopted code from jdis)
230.36 - */
230.37 -class CPX2 {
230.38 - int cpx1,cpx2;
230.39 -
230.40 - CPX2 (int cpx1, int cpx2) {
230.41 - this.cpx1=cpx1;
230.42 - this.cpx2=cpx2;
230.43 - }
230.44 -}
231.1 --- a/rt/javap/src/main/java/org/apidesign/javap/ClassData.java Wed Feb 27 17:50:47 2013 +0100
231.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
231.3 @@ -1,713 +0,0 @@
231.4 -/*
231.5 - * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
231.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
231.7 - *
231.8 - * This code is free software; you can redistribute it and/or modify it
231.9 - * under the terms of the GNU General Public License version 2 only, as
231.10 - * published by the Free Software Foundation. Oracle designates this
231.11 - * particular file as subject to the "Classpath" exception as provided
231.12 - * by Oracle in the LICENSE file that accompanied this code.
231.13 - *
231.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
231.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
231.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
231.17 - * version 2 for more details (a copy is included in the LICENSE file that
231.18 - * accompanied this code).
231.19 - *
231.20 - * You should have received a copy of the GNU General Public License version
231.21 - * 2 along with this work; if not, write to the Free Software Foundation,
231.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
231.23 - *
231.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
231.25 - * or visit www.oracle.com if you need additional information or have any
231.26 - * questions.
231.27 - */
231.28 -
231.29 -
231.30 -package org.apidesign.javap;
231.31 -
231.32 -import java.io.*;
231.33 -
231.34 -/**
231.35 - * Central data repository of the Java Disassembler.
231.36 - * Stores all the information in java class file.
231.37 - *
231.38 - * @author Sucheta Dambalkar (Adopted code from jdis)
231.39 - */
231.40 -public final class ClassData implements RuntimeConstants {
231.41 -
231.42 - private int magic;
231.43 - private int minor_version;
231.44 - private int major_version;
231.45 - private int cpool_count;
231.46 - private Object cpool[];
231.47 - private int access;
231.48 - private int this_class = 0;;
231.49 - private int super_class;
231.50 - private int interfaces_count;
231.51 - private int[] interfaces = new int[0];;
231.52 - private int fields_count;
231.53 - private FieldData[] fields;
231.54 - private int methods_count;
231.55 - private MethodData[] methods;
231.56 - private InnerClassData[] innerClasses;
231.57 - private int attributes_count;
231.58 - private AttrData[] attrs;
231.59 - private String classname;
231.60 - private String superclassname;
231.61 - private int source_cpx=0;
231.62 - private byte tags[];
231.63 - private Hashtable indexHashAscii = new Hashtable();
231.64 - private String pkgPrefix="";
231.65 - private int pkgPrefixLen=0;
231.66 -
231.67 - /**
231.68 - * Read classfile to disassemble.
231.69 - */
231.70 - public ClassData(InputStream infile) throws IOException {
231.71 - this.read(new DataInputStream(infile));
231.72 - }
231.73 -
231.74 - /**
231.75 - * Reads and stores class file information.
231.76 - */
231.77 - public void read(DataInputStream in) throws IOException {
231.78 - // Read the header
231.79 - magic = in.readInt();
231.80 - if (magic != JAVA_MAGIC) {
231.81 - throw new ClassFormatError("wrong magic: " +
231.82 - toHex(magic) + ", expected " +
231.83 - toHex(JAVA_MAGIC));
231.84 - }
231.85 - minor_version = in.readShort();
231.86 - major_version = in.readShort();
231.87 - if (major_version != JAVA_VERSION) {
231.88 - }
231.89 -
231.90 - // Read the constant pool
231.91 - readCP(in);
231.92 - access = in.readUnsignedShort();
231.93 - this_class = in.readUnsignedShort();
231.94 - super_class = in.readUnsignedShort();
231.95 -
231.96 - //Read interfaces.
231.97 - interfaces_count = in.readUnsignedShort();
231.98 - if(interfaces_count > 0){
231.99 - interfaces = new int[interfaces_count];
231.100 - }
231.101 - for (int i = 0; i < interfaces_count; i++) {
231.102 - interfaces[i]=in.readShort();
231.103 - }
231.104 -
231.105 - // Read the fields
231.106 - readFields(in);
231.107 -
231.108 - // Read the methods
231.109 - readMethods(in);
231.110 -
231.111 - // Read the attributes
231.112 - attributes_count = in.readUnsignedShort();
231.113 - attrs=new AttrData[attributes_count];
231.114 - for (int k = 0; k < attributes_count; k++) {
231.115 - int name_cpx=in.readUnsignedShort();
231.116 - if (getTag(name_cpx)==CONSTANT_UTF8
231.117 - && getString(name_cpx).equals("SourceFile")
231.118 - ){ if (in.readInt()!=2)
231.119 - throw new ClassFormatError("invalid attr length");
231.120 - source_cpx=in.readUnsignedShort();
231.121 - AttrData attr=new AttrData(this);
231.122 - attr.read(name_cpx);
231.123 - attrs[k]=attr;
231.124 -
231.125 - } else if (getTag(name_cpx)==CONSTANT_UTF8
231.126 - && getString(name_cpx).equals("InnerClasses")
231.127 - ){ int length=in.readInt();
231.128 - int num=in.readUnsignedShort();
231.129 - if (2+num*8 != length)
231.130 - throw new ClassFormatError("invalid attr length");
231.131 - innerClasses=new InnerClassData[num];
231.132 - for (int j = 0; j < num; j++) {
231.133 - InnerClassData innerClass=new InnerClassData(this);
231.134 - innerClass.read(in);
231.135 - innerClasses[j]=innerClass;
231.136 - }
231.137 - AttrData attr=new AttrData(this);
231.138 - attr.read(name_cpx);
231.139 - attrs[k]=attr;
231.140 - } else {
231.141 - AttrData attr=new AttrData(this);
231.142 - attr.read(name_cpx, in);
231.143 - attrs[k]=attr;
231.144 - }
231.145 - }
231.146 - in.close();
231.147 - } // end ClassData.read()
231.148 -
231.149 - /**
231.150 - * Reads and stores constant pool info.
231.151 - */
231.152 - void readCP(DataInputStream in) throws IOException {
231.153 - cpool_count = in.readUnsignedShort();
231.154 - tags = new byte[cpool_count];
231.155 - cpool = new Object[cpool_count];
231.156 - for (int i = 1; i < cpool_count; i++) {
231.157 - byte tag = in.readByte();
231.158 -
231.159 - switch(tags[i] = tag) {
231.160 - case CONSTANT_UTF8:
231.161 - String str=in.readUTF();
231.162 - indexHashAscii.put(cpool[i] = str, new Integer(i));
231.163 - break;
231.164 - case CONSTANT_INTEGER:
231.165 - cpool[i] = new Integer(in.readInt());
231.166 - break;
231.167 - case CONSTANT_FLOAT:
231.168 - cpool[i] = new Float(in.readFloat());
231.169 - break;
231.170 - case CONSTANT_LONG:
231.171 - cpool[i++] = new Long(in.readLong());
231.172 - break;
231.173 - case CONSTANT_DOUBLE:
231.174 - cpool[i++] = new Double(in.readDouble());
231.175 - break;
231.176 - case CONSTANT_CLASS:
231.177 - case CONSTANT_STRING:
231.178 - cpool[i] = new CPX(in.readUnsignedShort());
231.179 - break;
231.180 -
231.181 - case CONSTANT_FIELD:
231.182 - case CONSTANT_METHOD:
231.183 - case CONSTANT_INTERFACEMETHOD:
231.184 - case CONSTANT_NAMEANDTYPE:
231.185 - cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
231.186 - break;
231.187 -
231.188 - case 0:
231.189 - default:
231.190 - throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
231.191 - }
231.192 - }
231.193 - }
231.194 -
231.195 - /**
231.196 - * Reads and strores field info.
231.197 - */
231.198 - protected void readFields(DataInputStream in) throws IOException {
231.199 - int fields_count = in.readUnsignedShort();
231.200 - fields=new FieldData[fields_count];
231.201 - for (int k = 0; k < fields_count; k++) {
231.202 - FieldData field=new FieldData(this);
231.203 - field.read(in);
231.204 - fields[k]=field;
231.205 - }
231.206 - }
231.207 -
231.208 - /**
231.209 - * Reads and strores Method info.
231.210 - */
231.211 - protected void readMethods(DataInputStream in) throws IOException {
231.212 - int methods_count = in.readUnsignedShort();
231.213 - methods=new MethodData[methods_count];
231.214 - for (int k = 0; k < methods_count ; k++) {
231.215 - MethodData method=new MethodData(this);
231.216 - method.read(in);
231.217 - methods[k]=method;
231.218 - }
231.219 - }
231.220 -
231.221 - /**
231.222 - * get a string
231.223 - */
231.224 - public String getString(int n) {
231.225 - if (n == 0) {
231.226 - return null;
231.227 - } else {
231.228 - return (String)cpool[n];
231.229 - }
231.230 - }
231.231 -
231.232 - /**
231.233 - * get the type of constant given an index
231.234 - */
231.235 - public byte getTag(int n) {
231.236 - try{
231.237 - return tags[n];
231.238 - } catch (ArrayIndexOutOfBoundsException e) {
231.239 - return (byte)100;
231.240 - }
231.241 - }
231.242 -
231.243 - static final String hexString="0123456789ABCDEF";
231.244 -
231.245 - public static char hexTable[]=hexString.toCharArray();
231.246 -
231.247 - static String toHex(long val, int width) {
231.248 - StringBuffer s = new StringBuffer();
231.249 - for (int i=width-1; i>=0; i--)
231.250 - s.append(hexTable[((int)(val>>(4*i)))&0xF]);
231.251 - return "0x"+s.toString();
231.252 - }
231.253 -
231.254 - static String toHex(long val) {
231.255 - int width;
231.256 - for (width=16; width>0; width--) {
231.257 - if ((val>>(width-1)*4)!=0) break;
231.258 - }
231.259 - return toHex(val, width);
231.260 - }
231.261 -
231.262 - static String toHex(int val) {
231.263 - int width;
231.264 - for (width=8; width>0; width--) {
231.265 - if ((val>>(width-1)*4)!=0) break;
231.266 - }
231.267 - return toHex(val, width);
231.268 - }
231.269 -
231.270 - /**
231.271 - * Returns the name of this class.
231.272 - */
231.273 - public String getClassName() {
231.274 - String res=null;
231.275 - if (this_class==0) {
231.276 - return res;
231.277 - }
231.278 - int tcpx;
231.279 - try {
231.280 - if (tags[this_class]!=CONSTANT_CLASS) {
231.281 - return res; //"<CP["+cpx+"] is not a Class> ";
231.282 - }
231.283 - tcpx=((CPX)cpool[this_class]).cpx;
231.284 - } catch (ArrayIndexOutOfBoundsException e) {
231.285 - return res; // "#"+cpx+"// invalid constant pool index";
231.286 - } catch (Throwable e) {
231.287 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.288 - }
231.289 -
231.290 - try {
231.291 - return (String)(cpool[tcpx]);
231.292 - } catch (ArrayIndexOutOfBoundsException e) {
231.293 - return res; // "class #"+scpx+"// invalid constant pool index";
231.294 - } catch (ClassCastException e) {
231.295 - return res; // "class #"+scpx+"// invalid constant pool reference";
231.296 - } catch (Throwable e) {
231.297 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.298 - }
231.299 -
231.300 - }
231.301 -
231.302 - /**
231.303 - * Returns the name of class at perticular index.
231.304 - */
231.305 - public String getClassName(int cpx) {
231.306 - String res="#"+cpx;
231.307 - if (cpx==0) {
231.308 - return res;
231.309 - }
231.310 - int scpx;
231.311 - try {
231.312 - if (tags[cpx]!=CONSTANT_CLASS) {
231.313 - return res; //"<CP["+cpx+"] is not a Class> ";
231.314 - }
231.315 - scpx=((CPX)cpool[cpx]).cpx;
231.316 - } catch (ArrayIndexOutOfBoundsException e) {
231.317 - return res; // "#"+cpx+"// invalid constant pool index";
231.318 - } catch (Throwable e) {
231.319 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.320 - }
231.321 - res="#"+scpx;
231.322 - try {
231.323 - return (String)(cpool[scpx]);
231.324 - } catch (ArrayIndexOutOfBoundsException e) {
231.325 - return res; // "class #"+scpx+"// invalid constant pool index";
231.326 - } catch (ClassCastException e) {
231.327 - return res; // "class #"+scpx+"// invalid constant pool reference";
231.328 - } catch (Throwable e) {
231.329 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.330 - }
231.331 - }
231.332 -
231.333 - public int getAccessFlags() {
231.334 - return access;
231.335 - }
231.336 -
231.337 - /**
231.338 - * Returns true if it is a class
231.339 - */
231.340 - public boolean isClass() {
231.341 - if((access & ACC_INTERFACE) == 0) return true;
231.342 - return false;
231.343 - }
231.344 -
231.345 - /**
231.346 - * Returns true if it is a interface.
231.347 - */
231.348 - public boolean isInterface(){
231.349 - if((access & ACC_INTERFACE) != 0) return true;
231.350 - return false;
231.351 - }
231.352 -
231.353 - /**
231.354 - * Returns true if this member is public, false otherwise.
231.355 - */
231.356 - public boolean isPublic(){
231.357 - return (access & ACC_PUBLIC) != 0;
231.358 - }
231.359 -
231.360 - /**
231.361 - * Returns the access of this class or interface.
231.362 - */
231.363 - public String[] getAccess(){
231.364 - Vector v = new Vector();
231.365 - if ((access & ACC_PUBLIC) !=0) v.addElement("public");
231.366 - if ((access & ACC_FINAL) !=0) v.addElement("final");
231.367 - if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
231.368 - String[] accflags = new String[v.size()];
231.369 - v.copyInto(accflags);
231.370 - return accflags;
231.371 - }
231.372 -
231.373 - /**
231.374 - * Returns list of innerclasses.
231.375 - */
231.376 - public InnerClassData[] getInnerClasses(){
231.377 - return innerClasses;
231.378 - }
231.379 -
231.380 - /**
231.381 - * Returns list of attributes.
231.382 - */
231.383 - final AttrData[] getAttributes(){
231.384 - return attrs;
231.385 - }
231.386 -
231.387 - public byte[] findAnnotationData(boolean classRetention) {
231.388 - String n = classRetention ?
231.389 - "RuntimeInvisibleAnnotations" : // NOI18N
231.390 - "RuntimeVisibleAnnotations"; // NOI18N
231.391 - return findAttr(n, attrs);
231.392 - }
231.393 -
231.394 - /**
231.395 - * Returns true if superbit is set.
231.396 - */
231.397 - public boolean isSuperSet(){
231.398 - if ((access & ACC_SUPER) !=0) return true;
231.399 - return false;
231.400 - }
231.401 -
231.402 - /**
231.403 - * Returns super class name.
231.404 - */
231.405 - public String getSuperClassName(){
231.406 - String res=null;
231.407 - if (super_class==0) {
231.408 - return res;
231.409 - }
231.410 - int scpx;
231.411 - try {
231.412 - if (tags[super_class]!=CONSTANT_CLASS) {
231.413 - return res; //"<CP["+cpx+"] is not a Class> ";
231.414 - }
231.415 - scpx=((CPX)cpool[super_class]).cpx;
231.416 - } catch (ArrayIndexOutOfBoundsException e) {
231.417 - return res; // "#"+cpx+"// invalid constant pool index";
231.418 - } catch (Throwable e) {
231.419 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.420 - }
231.421 -
231.422 - try {
231.423 - return (String)(cpool[scpx]);
231.424 - } catch (ArrayIndexOutOfBoundsException e) {
231.425 - return res; // "class #"+scpx+"// invalid constant pool index";
231.426 - } catch (ClassCastException e) {
231.427 - return res; // "class #"+scpx+"// invalid constant pool reference";
231.428 - } catch (Throwable e) {
231.429 - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
231.430 - }
231.431 - }
231.432 -
231.433 - /**
231.434 - * Returns list of super interfaces.
231.435 - */
231.436 - public String[] getSuperInterfaces(){
231.437 - String interfacenames[] = new String[interfaces.length];
231.438 - int interfacecpx = -1;
231.439 - for(int i = 0; i < interfaces.length; i++){
231.440 - interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
231.441 - interfacenames[i] = (String)(cpool[interfacecpx]);
231.442 - }
231.443 - return interfacenames;
231.444 - }
231.445 -
231.446 - /**
231.447 - * Returns string at prticular constant pool index.
231.448 - */
231.449 - public String getStringValue(int cpoolx) {
231.450 - try {
231.451 - return ((String)cpool[cpoolx]);
231.452 - } catch (ArrayIndexOutOfBoundsException e) {
231.453 - return "//invalid constant pool index:"+cpoolx;
231.454 - } catch (ClassCastException e) {
231.455 - return "//invalid constant pool ref:"+cpoolx;
231.456 - }
231.457 - }
231.458 -
231.459 - /**
231.460 - * Returns list of field info.
231.461 - */
231.462 - public FieldData[] getFields(){
231.463 - return fields;
231.464 - }
231.465 -
231.466 - /**
231.467 - * Returns list of method info.
231.468 - */
231.469 - public MethodData[] getMethods(){
231.470 - return methods;
231.471 - }
231.472 -
231.473 - /**
231.474 - * Returns constant pool entry at that index.
231.475 - */
231.476 - public CPX2 getCpoolEntry(int cpx){
231.477 - return ((CPX2)(cpool[cpx]));
231.478 - }
231.479 -
231.480 - public Object getCpoolEntryobj(int cpx){
231.481 - return (cpool[cpx]);
231.482 - }
231.483 -
231.484 - /**
231.485 - * Returns index of this class.
231.486 - */
231.487 - public int getthis_cpx(){
231.488 - return this_class;
231.489 - }
231.490 -
231.491 - /**
231.492 - * Returns string at that index.
231.493 - */
231.494 - public String StringValue(int cpx) {
231.495 - return stringValue(cpx, false);
231.496 - }
231.497 - public String stringValue(int cpx, boolean textual) {
231.498 - return stringValue(cpx, textual, null);
231.499 - }
231.500 - public String stringValue(int cpx, String[] classRefs) {
231.501 - return stringValue(cpx, true, classRefs);
231.502 - }
231.503 - private String stringValue(int cpx, boolean textual, String[] refs) {
231.504 - if (cpx==0) return "#0";
231.505 - int tag;
231.506 - Object x;
231.507 - String suffix="";
231.508 - try {
231.509 - tag=tags[cpx];
231.510 - x=cpool[cpx];
231.511 - } catch (IndexOutOfBoundsException e) {
231.512 - return "<Incorrect CP index:"+cpx+">";
231.513 - }
231.514 -
231.515 - if (x==null) return "<NULL>";
231.516 - switch (tag) {
231.517 - case CONSTANT_UTF8: {
231.518 - if (!textual) {
231.519 - return (String)x;
231.520 - }
231.521 - StringBuilder sb=new StringBuilder();
231.522 - String s=(String)x;
231.523 - for (int k=0; k<s.length(); k++) {
231.524 - char c=s.charAt(k);
231.525 - switch (c) {
231.526 - case '\\': sb.append('\\').append('\\'); break;
231.527 - case '\t': sb.append('\\').append('t'); break;
231.528 - case '\n': sb.append('\\').append('n'); break;
231.529 - case '\r': sb.append('\\').append('r'); break;
231.530 - case '\"': sb.append('\\').append('\"'); break;
231.531 - default: sb.append(c);
231.532 - }
231.533 - }
231.534 - return sb.toString();
231.535 - }
231.536 - case CONSTANT_DOUBLE: {
231.537 - Double d=(Double)x;
231.538 - String sd=d.toString();
231.539 - if (textual) {
231.540 - return sd;
231.541 - }
231.542 - return sd+"d";
231.543 - }
231.544 - case CONSTANT_FLOAT: {
231.545 - Float f=(Float)x;
231.546 - String sf=(f).toString();
231.547 - if (textual) {
231.548 - return sf;
231.549 - }
231.550 - return sf+"f";
231.551 - }
231.552 - case CONSTANT_LONG: {
231.553 - Long ln = (Long)x;
231.554 - if (textual) {
231.555 - return ln.toString();
231.556 - }
231.557 - return ln.toString()+'l';
231.558 - }
231.559 - case CONSTANT_INTEGER: {
231.560 - Integer in = (Integer)x;
231.561 - return in.toString();
231.562 - }
231.563 - case CONSTANT_CLASS:
231.564 - String jn = getClassName(cpx);
231.565 - if (textual) {
231.566 - if (refs != null) {
231.567 - refs[0] = jn;
231.568 - }
231.569 - return jn;
231.570 - }
231.571 - return javaName(jn);
231.572 - case CONSTANT_STRING:
231.573 - String sv = stringValue(((CPX)x).cpx, textual);
231.574 - if (textual) {
231.575 - return '"' + sv + '"';
231.576 - } else {
231.577 - return sv;
231.578 - }
231.579 - case CONSTANT_FIELD:
231.580 - case CONSTANT_METHOD:
231.581 - case CONSTANT_INTERFACEMETHOD:
231.582 - //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
231.583 - return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
231.584 -
231.585 - case CONSTANT_NAMEANDTYPE:
231.586 - return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
231.587 - default:
231.588 - return "UnknownTag"; //TBD
231.589 - }
231.590 - }
231.591 -
231.592 - /**
231.593 - * Returns resolved java type name.
231.594 - */
231.595 - public String javaName(String name) {
231.596 - if( name==null) return "null";
231.597 - int len=name.length();
231.598 - if (len==0) return "\"\"";
231.599 - int cc='/';
231.600 - fullname: { // xxx/yyy/zzz
231.601 - int cp;
231.602 - for (int k=0; k<len; k += Character.charCount(cp)) {
231.603 - cp=name.codePointAt(k);
231.604 - if (cc=='/') {
231.605 - if (!isJavaIdentifierStart(cp)) break fullname;
231.606 - } else if (cp!='/') {
231.607 - if (!isJavaIdentifierPart(cp)) break fullname;
231.608 - }
231.609 - cc=cp;
231.610 - }
231.611 - return name;
231.612 - }
231.613 - return "\""+name+"\"";
231.614 - }
231.615 -
231.616 - public String getName(int cpx) {
231.617 - String res;
231.618 - try {
231.619 - return javaName((String)cpool[cpx]); //.replace('/','.');
231.620 - } catch (ArrayIndexOutOfBoundsException e) {
231.621 - return "<invalid constant pool index:"+cpx+">";
231.622 - } catch (ClassCastException e) {
231.623 - return "<invalid constant pool ref:"+cpx+">";
231.624 - }
231.625 - }
231.626 -
231.627 - /**
231.628 - * Returns unqualified class name.
231.629 - */
231.630 - public String getShortClassName(int cpx) {
231.631 - String classname=javaName(getClassName(cpx));
231.632 - pkgPrefixLen=classname.lastIndexOf("/")+1;
231.633 - if (pkgPrefixLen!=0) {
231.634 - pkgPrefix=classname.substring(0,pkgPrefixLen);
231.635 - if (classname.startsWith(pkgPrefix)) {
231.636 - return classname.substring(pkgPrefixLen);
231.637 - }
231.638 - }
231.639 - return classname;
231.640 - }
231.641 -
231.642 - /**
231.643 - * Returns source file name.
231.644 - */
231.645 - public String getSourceName(){
231.646 - return getName(source_cpx);
231.647 - }
231.648 -
231.649 - /**
231.650 - * Returns package name.
231.651 - */
231.652 - public String getPkgName(){
231.653 - String classname=getClassName(this_class);
231.654 - pkgPrefixLen=classname.lastIndexOf("/")+1;
231.655 - if (pkgPrefixLen!=0) {
231.656 - pkgPrefix=classname.substring(0,pkgPrefixLen);
231.657 - return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
231.658 - }else return null;
231.659 - }
231.660 -
231.661 - /**
231.662 - * Returns total constant pool entry count.
231.663 - */
231.664 - public int getCpoolCount(){
231.665 - return cpool_count;
231.666 - }
231.667 -
231.668 - /**
231.669 - * Returns minor version of class file.
231.670 - */
231.671 - public int getMinor_version(){
231.672 - return minor_version;
231.673 - }
231.674 -
231.675 - /**
231.676 - * Returns major version of class file.
231.677 - */
231.678 - public int getMajor_version(){
231.679 - return major_version;
231.680 - }
231.681 -
231.682 - private boolean isJavaIdentifierStart(int cp) {
231.683 - return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
231.684 - }
231.685 -
231.686 - private boolean isJavaIdentifierPart(int cp) {
231.687 - return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
231.688 - }
231.689 -
231.690 - public String[] getNameAndType(int indx) {
231.691 - return getNameAndType(indx, 0, new String[2]);
231.692 - }
231.693 -
231.694 - private String[] getNameAndType(int indx, int at, String[] arr) {
231.695 - CPX2 c2 = getCpoolEntry(indx);
231.696 - arr[at] = StringValue(c2.cpx1);
231.697 - arr[at + 1] = StringValue(c2.cpx2);
231.698 - return arr;
231.699 - }
231.700 -
231.701 - public String[] getFieldInfoName(int indx) {
231.702 - CPX2 c2 = getCpoolEntry(indx);
231.703 - String[] arr = new String[3];
231.704 - arr[0] = getClassName(c2.cpx1);
231.705 - return getNameAndType(c2.cpx2, 1, arr);
231.706 - }
231.707 -
231.708 - static byte[] findAttr(String n, AttrData[] attrs) {
231.709 - for (AttrData ad : attrs) {
231.710 - if (n.equals(ad.getAttrName())) {
231.711 - return ad.getData();
231.712 - }
231.713 - }
231.714 - return null;
231.715 - }
231.716 -}
232.1 --- a/rt/javap/src/main/java/org/apidesign/javap/Constants.java Wed Feb 27 17:50:47 2013 +0100
232.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
232.3 @@ -1,372 +0,0 @@
232.4 -/*
232.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
232.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
232.7 - *
232.8 - * This code is free software; you can redistribute it and/or modify it
232.9 - * under the terms of the GNU General Public License version 2 only, as
232.10 - * published by the Free Software Foundation. Oracle designates this
232.11 - * particular file as subject to the "Classpath" exception as provided
232.12 - * by Oracle in the LICENSE file that accompanied this code.
232.13 - *
232.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
232.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
232.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
232.17 - * version 2 for more details (a copy is included in the LICENSE file that
232.18 - * accompanied this code).
232.19 - *
232.20 - * You should have received a copy of the GNU General Public License version
232.21 - * 2 along with this work; if not, write to the Free Software Foundation,
232.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
232.23 - *
232.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
232.25 - * or visit www.oracle.com if you need additional information or have any
232.26 - * questions.
232.27 - */
232.28 -
232.29 -
232.30 -
232.31 -package org.apidesign.javap;
232.32 -
232.33 -/**
232.34 - * This interface defines constant that are used
232.35 - * throughout the compiler. It inherits from RuntimeConstants,
232.36 - * which is an autogenerated class that contains contstants
232.37 - * defined in the interpreter.
232.38 - */
232.39 -
232.40 -public
232.41 -interface Constants extends RuntimeConstants {
232.42 -
232.43 - /**
232.44 - * End of input
232.45 - */
232.46 - public static final int EOF = -1;
232.47 -
232.48 - /*
232.49 - * Flags
232.50 - */
232.51 - public static final int F_VERBOSE = 1 << 0;
232.52 - public static final int F_DUMP = 1 << 1;
232.53 - public static final int F_WARNINGS = 1 << 2;
232.54 - public static final int F_DEBUG = 1 << 3;
232.55 - public static final int F_OPTIMIZE = 1 << 4;
232.56 - public static final int F_DEPENDENCIES = 1 << 5;
232.57 -
232.58 - /*
232.59 - * Type codes
232.60 - */
232.61 - public static final int TC_BOOLEAN = 0;
232.62 - public static final int TC_BYTE = 1;
232.63 - public static final int TC_CHAR = 2;
232.64 - public static final int TC_SHORT = 3;
232.65 - public static final int TC_INT = 4;
232.66 - public static final int TC_LONG = 5;
232.67 - public static final int TC_FLOAT = 6;
232.68 - public static final int TC_DOUBLE = 7;
232.69 - public static final int TC_NULL = 8;
232.70 - public static final int TC_ARRAY = 9;
232.71 - public static final int TC_CLASS = 10;
232.72 - public static final int TC_VOID = 11;
232.73 - public static final int TC_METHOD = 12;
232.74 - public static final int TC_ERROR = 13;
232.75 -
232.76 - /*
232.77 - * Type Masks
232.78 - */
232.79 - public static final int TM_NULL = 1 << TC_NULL;
232.80 - public static final int TM_VOID = 1 << TC_VOID;
232.81 - public static final int TM_BOOLEAN = 1 << TC_BOOLEAN;
232.82 - public static final int TM_BYTE = 1 << TC_BYTE;
232.83 - public static final int TM_CHAR = 1 << TC_CHAR;
232.84 - public static final int TM_SHORT = 1 << TC_SHORT;
232.85 - public static final int TM_INT = 1 << TC_INT;
232.86 - public static final int TM_LONG = 1 << TC_LONG;
232.87 - public static final int TM_FLOAT = 1 << TC_FLOAT;
232.88 - public static final int TM_DOUBLE = 1 << TC_DOUBLE;
232.89 - public static final int TM_ARRAY = 1 << TC_ARRAY;
232.90 - public static final int TM_CLASS = 1 << TC_CLASS;
232.91 - public static final int TM_METHOD = 1 << TC_METHOD;
232.92 - public static final int TM_ERROR = 1 << TC_ERROR;
232.93 -
232.94 - public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT;
232.95 - public static final int TM_NUM32 = TM_INT32 | TM_FLOAT;
232.96 - public static final int TM_NUM64 = TM_LONG | TM_DOUBLE;
232.97 - public static final int TM_INTEGER = TM_INT32 | TM_LONG;
232.98 - public static final int TM_REAL = TM_FLOAT | TM_DOUBLE;
232.99 - public static final int TM_NUMBER = TM_INTEGER | TM_REAL;
232.100 - public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL;
232.101 -
232.102 - /*
232.103 - * Class status
232.104 - */
232.105 - public static final int CS_UNDEFINED = 0;
232.106 - public static final int CS_UNDECIDED = 1;
232.107 - public static final int CS_BINARY = 2;
232.108 - public static final int CS_SOURCE = 3;
232.109 - public static final int CS_PARSED = 4;
232.110 - public static final int CS_COMPILED = 5;
232.111 - public static final int CS_NOTFOUND = 6;
232.112 -
232.113 - /*
232.114 - * Attributes
232.115 - */
232.116 - public static final int ATT_ALL = -1;
232.117 - public static final int ATT_CODE = 1;
232.118 -
232.119 - /*
232.120 - * Number of bits used in file offsets
232.121 - */
232.122 - public static final int OFFSETBITS = 19;
232.123 - public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1;
232.124 - public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1;
232.125 -
232.126 - /*
232.127 - * Operators
232.128 - */
232.129 - public final int COMMA = 0;
232.130 - public final int ASSIGN = 1;
232.131 -
232.132 - public final int ASGMUL = 2;
232.133 - public final int ASGDIV = 3;
232.134 - public final int ASGREM = 4;
232.135 - public final int ASGADD = 5;
232.136 - public final int ASGSUB = 6;
232.137 - public final int ASGLSHIFT = 7;
232.138 - public final int ASGRSHIFT = 8;
232.139 - public final int ASGURSHIFT = 9;
232.140 - public final int ASGBITAND = 10;
232.141 - public final int ASGBITOR = 11;
232.142 - public final int ASGBITXOR = 12;
232.143 -
232.144 - public final int COND = 13;
232.145 - public final int OR = 14;
232.146 - public final int AND = 15;
232.147 - public final int BITOR = 16;
232.148 - public final int BITXOR = 17;
232.149 - public final int BITAND = 18;
232.150 - public final int NE = 19;
232.151 - public final int EQ = 20;
232.152 - public final int GE = 21;
232.153 - public final int GT = 22;
232.154 - public final int LE = 23;
232.155 - public final int LT = 24;
232.156 - public final int INSTANCEOF = 25;
232.157 - public final int LSHIFT = 26;
232.158 - public final int RSHIFT = 27;
232.159 - public final int URSHIFT = 28;
232.160 - public final int ADD = 29;
232.161 - public final int SUB = 30;
232.162 - public final int DIV = 31;
232.163 - public final int REM = 32;
232.164 - public final int MUL = 33;
232.165 - public final int CAST = 34; // (x)y
232.166 - public final int POS = 35; // +x
232.167 - public final int NEG = 36; // -x
232.168 - public final int NOT = 37;
232.169 - public final int BITNOT = 38;
232.170 - public final int PREINC = 39; // ++x
232.171 - public final int PREDEC = 40; // --x
232.172 - public final int NEWARRAY = 41;
232.173 - public final int NEWINSTANCE = 42;
232.174 - public final int NEWFROMNAME = 43;
232.175 - public final int POSTINC = 44; // x++
232.176 - public final int POSTDEC = 45; // x--
232.177 - public final int FIELD = 46;
232.178 - public final int METHOD = 47; // x(y)
232.179 - public final int ARRAYACCESS = 48; // x[y]
232.180 - public final int NEW = 49;
232.181 - public final int INC = 50;
232.182 - public final int DEC = 51;
232.183 -
232.184 - public final int CONVERT = 55; // implicit conversion
232.185 - public final int EXPR = 56; // (x)
232.186 - public final int ARRAY = 57; // {x, y, ...}
232.187 - public final int GOTO = 58;
232.188 -
232.189 - /*
232.190 - * Value tokens
232.191 - */
232.192 - public final int IDENT = 60;
232.193 - public final int BOOLEANVAL = 61;
232.194 - public final int BYTEVAL = 62;
232.195 - public final int CHARVAL = 63;
232.196 - public final int SHORTVAL = 64;
232.197 - public final int INTVAL = 65;
232.198 - public final int LONGVAL = 66;
232.199 - public final int FLOATVAL = 67;
232.200 - public final int DOUBLEVAL = 68;
232.201 - public final int STRINGVAL = 69;
232.202 -
232.203 - /*
232.204 - * Type keywords
232.205 - */
232.206 - public final int BYTE = 70;
232.207 - public final int CHAR = 71;
232.208 - public final int SHORT = 72;
232.209 - public final int INT = 73;
232.210 - public final int LONG = 74;
232.211 - public final int FLOAT = 75;
232.212 - public final int DOUBLE = 76;
232.213 - public final int VOID = 77;
232.214 - public final int BOOLEAN = 78;
232.215 -
232.216 - /*
232.217 - * Expression keywords
232.218 - */
232.219 - public final int TRUE = 80;
232.220 - public final int FALSE = 81;
232.221 - public final int THIS = 82;
232.222 - public final int SUPER = 83;
232.223 - public final int NULL = 84;
232.224 -
232.225 - /*
232.226 - * Statement keywords
232.227 - */
232.228 - public final int IF = 90;
232.229 - public final int ELSE = 91;
232.230 - public final int FOR = 92;
232.231 - public final int WHILE = 93;
232.232 - public final int DO = 94;
232.233 - public final int SWITCH = 95;
232.234 - public final int CASE = 96;
232.235 - public final int DEFAULT = 97;
232.236 - public final int BREAK = 98;
232.237 - public final int CONTINUE = 99;
232.238 - public final int RETURN = 100;
232.239 - public final int TRY = 101;
232.240 - public final int CATCH = 102;
232.241 - public final int FINALLY = 103;
232.242 - public final int THROW = 104;
232.243 - public final int STAT = 105;
232.244 - public final int EXPRESSION = 106;
232.245 - public final int DECLARATION = 107;
232.246 - public final int VARDECLARATION = 108;
232.247 -
232.248 - /*
232.249 - * Declaration keywords
232.250 - */
232.251 - public final int IMPORT = 110;
232.252 - public final int CLASS = 111;
232.253 - public final int EXTENDS = 112;
232.254 - public final int IMPLEMENTS = 113;
232.255 - public final int INTERFACE = 114;
232.256 - public final int PACKAGE = 115;
232.257 -
232.258 - /*
232.259 - * Modifier keywords
232.260 - */
232.261 - public final int PRIVATE = 120;
232.262 - public final int PUBLIC = 121;
232.263 - public final int PROTECTED = 122;
232.264 - public final int CONST = 123;
232.265 - public final int STATIC = 124;
232.266 - public final int TRANSIENT = 125;
232.267 - public final int SYNCHRONIZED = 126;
232.268 - public final int NATIVE = 127;
232.269 - public final int FINAL = 128;
232.270 - public final int VOLATILE = 129;
232.271 - public final int ABSTRACT = 130;
232.272 - public final int STRICT = 165;
232.273 -
232.274 - /*
232.275 - * Punctuation
232.276 - */
232.277 - public final int SEMICOLON = 135;
232.278 - public final int COLON = 136;
232.279 - public final int QUESTIONMARK = 137;
232.280 - public final int LBRACE = 138;
232.281 - public final int RBRACE = 139;
232.282 - public final int LPAREN = 140;
232.283 - public final int RPAREN = 141;
232.284 - public final int LSQBRACKET = 142;
232.285 - public final int RSQBRACKET = 143;
232.286 - public final int THROWS = 144;
232.287 -
232.288 - /*
232.289 - * Special tokens
232.290 - */
232.291 - public final int ERROR = 145; // an error
232.292 - public final int COMMENT = 146; // not used anymore.
232.293 - public final int TYPE = 147;
232.294 - public final int LENGTH = 148;
232.295 - public final int INLINERETURN = 149;
232.296 - public final int INLINEMETHOD = 150;
232.297 - public final int INLINENEWINSTANCE = 151;
232.298 -
232.299 - /*
232.300 - * Added for jasm
232.301 - */
232.302 - public final int METHODREF = 152;
232.303 - public final int FIELDREF = 153;
232.304 - public final int STACK = 154;
232.305 - public final int LOCAL = 155;
232.306 - public final int CPINDEX = 156;
232.307 - public final int CPNAME = 157;
232.308 - public final int SIGN = 158;
232.309 - public final int BITS = 159;
232.310 - public final int INF = 160;
232.311 - public final int NAN = 161;
232.312 - public final int INNERCLASS = 162;
232.313 - public final int OF = 163;
232.314 - public final int SYNTHETIC = 164;
232.315 -// last used=165;
232.316 -
232.317 - /*
232.318 - * Operator precedence
232.319 - */
232.320 - public static final int opPrecedence[] = {
232.321 - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
232.322 - 11, 11, 11, 12, 13, 14, 15, 16, 17, 18,
232.323 - 18, 19, 19, 19, 19, 19, 20, 20, 20, 21,
232.324 - 21, 22, 22, 22, 23, 24, 24, 24, 24, 24,
232.325 - 24, 25, 25, 26, 26, 26, 26, 26, 26
232.326 - };
232.327 -
232.328 - /*
232.329 - * Operator names
232.330 - */
232.331 - public static final String opNames[] = {
232.332 - ",", "=", "*=", "/=", "%=",
232.333 - "+=", "-=", "<<=", ">>=", "<<<=",
232.334 - "&=", "|=", "^=", "?:", "||",
232.335 - "&&", "|", "^", "&", "!=",
232.336 - "==", ">=", ">", "<=", "<",
232.337 - "instanceof", "<<", ">>", "<<<", "+",
232.338 - "-", "/", "%", "*", "cast",
232.339 - "+", "-", "!", "~", "++",
232.340 - "--", "new", "new", "new", "++",
232.341 - "--", "field", "method", "[]", "new",
232.342 - "++", "--", null, null, null,
232.343 -
232.344 - "convert", "expr", "array", "goto", null,
232.345 -
232.346 - "Identifier", "Boolean", "Byte", "Char", "Short",
232.347 - "Integer", "Long", "Float", "Double", "String",
232.348 -
232.349 - "byte", "char", "short", "int", "long",
232.350 - "float", "double", "void", "boolean", null,
232.351 -
232.352 - "true", "false", "this", "super", "null",
232.353 - null, null, null, null, null,
232.354 -
232.355 - "if", "else", "for", "while", "do",
232.356 - "switch", "case", "default", "break", "continue",
232.357 - "return", "try", "catch", "finally", "throw",
232.358 - "stat", "expression", "declaration", "declaration", null,
232.359 -
232.360 - "import", "class", "extends", "implements", "interface",
232.361 - "package", null, null, null, null,
232.362 -
232.363 - "private", "public", "protected", "const", "static",
232.364 - "transient", "synchronized", "native", "final", "volatile",
232.365 - "abstract", null, null, null, null,
232.366 -
232.367 - ";", ":", "?", "{", "}",
232.368 - "(", ")", "[", "]", "throws",
232.369 - "error", "comment", "type", "length", "inline-return",
232.370 - "inline-method", "inline-new",
232.371 - "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN",
232.372 - "bits", "INF", "NaN", "InnerClass", "of", "synthetic"
232.373 - };
232.374 -
232.375 -}
233.1 --- a/rt/javap/src/main/java/org/apidesign/javap/FieldData.java Wed Feb 27 17:50:47 2013 +0100
233.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
233.3 @@ -1,168 +0,0 @@
233.4 -/*
233.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
233.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
233.7 - *
233.8 - * This code is free software; you can redistribute it and/or modify it
233.9 - * under the terms of the GNU General Public License version 2 only, as
233.10 - * published by the Free Software Foundation. Oracle designates this
233.11 - * particular file as subject to the "Classpath" exception as provided
233.12 - * by Oracle in the LICENSE file that accompanied this code.
233.13 - *
233.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
233.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
233.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
233.17 - * version 2 for more details (a copy is included in the LICENSE file that
233.18 - * accompanied this code).
233.19 - *
233.20 - * You should have received a copy of the GNU General Public License version
233.21 - * 2 along with this work; if not, write to the Free Software Foundation,
233.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
233.23 - *
233.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
233.25 - * or visit www.oracle.com if you need additional information or have any
233.26 - * questions.
233.27 - */
233.28 -
233.29 -
233.30 -package org.apidesign.javap;
233.31 -
233.32 -import java.io.*;
233.33 -
233.34 -/**
233.35 - * Strores field data informastion.
233.36 - *
233.37 - * @author Sucheta Dambalkar (Adopted code from jdis)
233.38 - */
233.39 -
233.40 -public class FieldData implements RuntimeConstants {
233.41 -
233.42 - ClassData cls;
233.43 - int access;
233.44 - int name_index;
233.45 - int descriptor_index;
233.46 - int attributes_count;
233.47 - int value_cpx=0;
233.48 - boolean isSynthetic=false;
233.49 - boolean isDeprecated=false;
233.50 - Vector attrs;
233.51 -
233.52 - public FieldData(ClassData cls){
233.53 - this.cls=cls;
233.54 - }
233.55 -
233.56 - /**
233.57 - * Read and store field info.
233.58 - */
233.59 - public void read(DataInputStream in) throws IOException {
233.60 - access = in.readUnsignedShort();
233.61 - name_index = in.readUnsignedShort();
233.62 - descriptor_index = in.readUnsignedShort();
233.63 - // Read the attributes
233.64 - int attributes_count = in.readUnsignedShort();
233.65 - attrs=new Vector(attributes_count);
233.66 - for (int i = 0; i < attributes_count; i++) {
233.67 - int attr_name_index=in.readUnsignedShort();
233.68 - if (cls.getTag(attr_name_index)!=CONSTANT_UTF8) continue;
233.69 - String attr_name=cls.getString(attr_name_index);
233.70 - if (attr_name.equals("ConstantValue")){
233.71 - if (in.readInt()!=2)
233.72 - throw new ClassFormatError("invalid ConstantValue attr length");
233.73 - value_cpx=in.readUnsignedShort();
233.74 - AttrData attr=new AttrData(cls);
233.75 - attr.read(attr_name_index);
233.76 - attrs.addElement(attr);
233.77 - } else if (attr_name.equals("Synthetic")){
233.78 - if (in.readInt()!=0)
233.79 - throw new ClassFormatError("invalid Synthetic attr length");
233.80 - isSynthetic=true;
233.81 - AttrData attr=new AttrData(cls);
233.82 - attr.read(attr_name_index);
233.83 - attrs.addElement(attr);
233.84 - } else if (attr_name.equals("Deprecated")){
233.85 - if (in.readInt()!=0)
233.86 - throw new ClassFormatError("invalid Synthetic attr length");
233.87 - isDeprecated = true;
233.88 - AttrData attr=new AttrData(cls);
233.89 - attr.read(attr_name_index);
233.90 - attrs.addElement(attr);
233.91 - } else {
233.92 - AttrData attr=new AttrData(cls);
233.93 - attr.read(attr_name_index, in);
233.94 - attrs.addElement(attr);
233.95 - }
233.96 - }
233.97 -
233.98 - } // end read
233.99 -
233.100 - public boolean isStatic() {
233.101 - return (access & ACC_STATIC) != 0;
233.102 - }
233.103 -
233.104 - /**
233.105 - * Returns access of a field.
233.106 - */
233.107 - public String[] getAccess(){
233.108 - Vector v = new Vector();
233.109 - if ((access & ACC_PUBLIC) !=0) v.addElement("public");
233.110 - if ((access & ACC_PRIVATE) !=0) v.addElement("private");
233.111 - if ((access & ACC_PROTECTED) !=0) v.addElement("protected");
233.112 - if ((access & ACC_STATIC) !=0) v.addElement("static");
233.113 - if ((access & ACC_FINAL) !=0) v.addElement("final");
233.114 - if ((access & ACC_VOLATILE) !=0) v.addElement("volatile");
233.115 - if ((access & ACC_TRANSIENT) !=0) v.addElement("transient");
233.116 - String[] accflags = new String[v.size()];
233.117 - v.copyInto(accflags);
233.118 - return accflags;
233.119 - }
233.120 -
233.121 - /**
233.122 - * Returns name of a field.
233.123 - */
233.124 - public String getName(){
233.125 - return cls.getStringValue(name_index);
233.126 - }
233.127 -
233.128 - /**
233.129 - * Returns internal signature of a field
233.130 - */
233.131 - public String getInternalSig(){
233.132 - return cls.getStringValue(descriptor_index);
233.133 - }
233.134 -
233.135 - /**
233.136 - * Returns true if field is synthetic.
233.137 - */
233.138 - public boolean isSynthetic(){
233.139 - return isSynthetic;
233.140 - }
233.141 -
233.142 - /**
233.143 - * Returns true if field is deprecated.
233.144 - */
233.145 - public boolean isDeprecated(){
233.146 - return isDeprecated;
233.147 - }
233.148 -
233.149 - /**
233.150 - * Returns index of constant value in cpool.
233.151 - */
233.152 - public int getConstantValueIndex(){
233.153 - return (value_cpx);
233.154 - }
233.155 -
233.156 - /**
233.157 - * Returns list of attributes of field.
233.158 - */
233.159 - public Vector getAttributes(){
233.160 - return attrs;
233.161 - }
233.162 -
233.163 - public byte[] findAnnotationData(boolean classRetention) {
233.164 - String n = classRetention ?
233.165 - "RuntimeInvisibleAnnotations" : // NOI18N
233.166 - "RuntimeVisibleAnnotations"; // NOI18N
233.167 - AttrData[] arr = new AttrData[attrs.size()];
233.168 - attrs.copyInto(arr);
233.169 - return ClassData.findAttr(n, arr);
233.170 - }
233.171 -}
234.1 --- a/rt/javap/src/main/java/org/apidesign/javap/Hashtable.java Wed Feb 27 17:50:47 2013 +0100
234.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
234.3 @@ -1,94 +0,0 @@
234.4 -/**
234.5 - * Back 2 Browser Bytecode Translator
234.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
234.7 - *
234.8 - * This program is free software: you can redistribute it and/or modify
234.9 - * it under the terms of the GNU General Public License as published by
234.10 - * the Free Software Foundation, version 2 of the License.
234.11 - *
234.12 - * This program is distributed in the hope that it will be useful,
234.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
234.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
234.15 - * GNU General Public License for more details.
234.16 - *
234.17 - * You should have received a copy of the GNU General Public License
234.18 - * along with this program. Look for COPYING file in the top folder.
234.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
234.20 - */
234.21 -package org.apidesign.javap;
234.22 -
234.23 -/** A JavaScript optimized replacement for Hashtable.
234.24 - *
234.25 - * @author Jaroslav Tulach <jtulach@netbeans.org>
234.26 - */
234.27 -final class Hashtable {
234.28 - private Object[] keys;
234.29 - private Object[] values;
234.30 -
234.31 - Hashtable(int i) {
234.32 - this();
234.33 - }
234.34 -
234.35 - Hashtable(int i, double d) {
234.36 - this();
234.37 - }
234.38 -
234.39 - Hashtable() {
234.40 - }
234.41 -
234.42 - synchronized void put(Object key, Object val) {
234.43 - int[] where = { -1, -1 };
234.44 - Object found = get(key, where);
234.45 - if (where[0] != -1) {
234.46 - // key exists
234.47 - values[where[0]] = val;
234.48 - } else {
234.49 - if (where[1] != -1) {
234.50 - // null found
234.51 - keys[where[1]] = key;
234.52 - values[where[1]] = val;
234.53 - } else {
234.54 - if (keys == null) {
234.55 - keys = new Object[11];
234.56 - values = new Object[11];
234.57 - keys[0] = key;
234.58 - values[0] = val;
234.59 - } else {
234.60 - Object[] newKeys = new Object[keys.length * 2];
234.61 - Object[] newValues = new Object[values.length * 2];
234.62 - for (int i = 0; i < keys.length; i++) {
234.63 - newKeys[i] = keys[i];
234.64 - newValues[i] = values[i];
234.65 - }
234.66 - newKeys[keys.length] = key;
234.67 - newValues[keys.length] = val;
234.68 - keys = newKeys;
234.69 - values = newValues;
234.70 - }
234.71 - }
234.72 - }
234.73 - }
234.74 -
234.75 - Object get(Object key) {
234.76 - return get(key, null);
234.77 - }
234.78 - private synchronized Object get(Object key, int[] foundAndNull) {
234.79 - if (keys == null) {
234.80 - return null;
234.81 - }
234.82 - for (int i = 0; i < keys.length; i++) {
234.83 - if (keys[i] == null) {
234.84 - if (foundAndNull != null) {
234.85 - foundAndNull[1] = i;
234.86 - }
234.87 - } else if (keys[i].equals(key)) {
234.88 - if (foundAndNull != null) {
234.89 - foundAndNull[0] = i;
234.90 - }
234.91 - return values[i];
234.92 - }
234.93 - }
234.94 - return null;
234.95 - }
234.96 -
234.97 -}
235.1 --- a/rt/javap/src/main/java/org/apidesign/javap/InnerClassData.java Wed Feb 27 17:50:47 2013 +0100
235.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
235.3 @@ -1,75 +0,0 @@
235.4 -/*
235.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
235.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
235.7 - *
235.8 - * This code is free software; you can redistribute it and/or modify it
235.9 - * under the terms of the GNU General Public License version 2 only, as
235.10 - * published by the Free Software Foundation. Oracle designates this
235.11 - * particular file as subject to the "Classpath" exception as provided
235.12 - * by Oracle in the LICENSE file that accompanied this code.
235.13 - *
235.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
235.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
235.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
235.17 - * version 2 for more details (a copy is included in the LICENSE file that
235.18 - * accompanied this code).
235.19 - *
235.20 - * You should have received a copy of the GNU General Public License version
235.21 - * 2 along with this work; if not, write to the Free Software Foundation,
235.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
235.23 - *
235.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
235.25 - * or visit www.oracle.com if you need additional information or have any
235.26 - * questions.
235.27 - */
235.28 -
235.29 -
235.30 -package org.apidesign.javap;
235.31 -
235.32 -import java.io.*;
235.33 -import java.util.*;
235.34 -
235.35 -/**
235.36 - * Strores InnerClass data informastion.
235.37 - *
235.38 - * @author Sucheta Dambalkar (Adopted code from jdis)
235.39 - */
235.40 -class InnerClassData implements RuntimeConstants {
235.41 - ClassData cls;
235.42 -
235.43 -
235.44 - int inner_class_info_index
235.45 - ,outer_class_info_index
235.46 - ,inner_name_index
235.47 - ,access
235.48 - ;
235.49 -
235.50 - public InnerClassData(ClassData cls) {
235.51 - this.cls=cls;
235.52 -
235.53 - }
235.54 -
235.55 - /**
235.56 - * Read Innerclass attribute data.
235.57 - */
235.58 - public void read(DataInputStream in) throws IOException {
235.59 - inner_class_info_index = in.readUnsignedShort();
235.60 - outer_class_info_index = in.readUnsignedShort();
235.61 - inner_name_index = in.readUnsignedShort();
235.62 - access = in.readUnsignedShort();
235.63 - } // end read
235.64 -
235.65 - /**
235.66 - * Returns the access of this class or interface.
235.67 - */
235.68 - public String[] getAccess(){
235.69 - Vector v = new Vector();
235.70 - if ((access & ACC_PUBLIC) !=0) v.addElement("public");
235.71 - if ((access & ACC_FINAL) !=0) v.addElement("final");
235.72 - if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
235.73 - String[] accflags = new String[v.size()];
235.74 - v.copyInto(accflags);
235.75 - return accflags;
235.76 - }
235.77 -
235.78 -} // end InnerClassData
236.1 --- a/rt/javap/src/main/java/org/apidesign/javap/LineNumData.java Wed Feb 27 17:50:47 2013 +0100
236.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
236.3 @@ -1,50 +0,0 @@
236.4 -/*
236.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
236.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
236.7 - *
236.8 - * This code is free software; you can redistribute it and/or modify it
236.9 - * under the terms of the GNU General Public License version 2 only, as
236.10 - * published by the Free Software Foundation. Oracle designates this
236.11 - * particular file as subject to the "Classpath" exception as provided
236.12 - * by Oracle in the LICENSE file that accompanied this code.
236.13 - *
236.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
236.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
236.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
236.17 - * version 2 for more details (a copy is included in the LICENSE file that
236.18 - * accompanied this code).
236.19 - *
236.20 - * You should have received a copy of the GNU General Public License version
236.21 - * 2 along with this work; if not, write to the Free Software Foundation,
236.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
236.23 - *
236.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
236.25 - * or visit www.oracle.com if you need additional information or have any
236.26 - * questions.
236.27 - */
236.28 -
236.29 -
236.30 -package org.apidesign.javap;
236.31 -
236.32 -import java.util.*;
236.33 -import java.io.*;
236.34 -
236.35 -/**
236.36 - * Strores LineNumberTable data information.
236.37 - *
236.38 - * @author Sucheta Dambalkar (Adopted code from jdis)
236.39 - */
236.40 -class LineNumData {
236.41 - short start_pc, line_number;
236.42 -
236.43 - public LineNumData() {}
236.44 -
236.45 - /**
236.46 - * Read LineNumberTable attribute.
236.47 - */
236.48 - public LineNumData(DataInputStream in) throws IOException {
236.49 - start_pc = in.readShort();
236.50 - line_number=in.readShort();
236.51 -
236.52 - }
236.53 -}
237.1 --- a/rt/javap/src/main/java/org/apidesign/javap/LocVarData.java Wed Feb 27 17:50:47 2013 +0100
237.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
237.3 @@ -1,54 +0,0 @@
237.4 -/*
237.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
237.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
237.7 - *
237.8 - * This code is free software; you can redistribute it and/or modify it
237.9 - * under the terms of the GNU General Public License version 2 only, as
237.10 - * published by the Free Software Foundation. Oracle designates this
237.11 - * particular file as subject to the "Classpath" exception as provided
237.12 - * by Oracle in the LICENSE file that accompanied this code.
237.13 - *
237.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
237.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
237.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
237.17 - * version 2 for more details (a copy is included in the LICENSE file that
237.18 - * accompanied this code).
237.19 - *
237.20 - * You should have received a copy of the GNU General Public License version
237.21 - * 2 along with this work; if not, write to the Free Software Foundation,
237.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
237.23 - *
237.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
237.25 - * or visit www.oracle.com if you need additional information or have any
237.26 - * questions.
237.27 - */
237.28 -
237.29 -
237.30 -package org.apidesign.javap;
237.31 -
237.32 -import java.util.*;
237.33 -import java.io.*;
237.34 -
237.35 -/**
237.36 - * Strores LocalVariableTable data information.
237.37 - *
237.38 - * @author Sucheta Dambalkar (Adopted code from jdis)
237.39 - */
237.40 -class LocVarData {
237.41 - short start_pc, length, name_cpx, sig_cpx, slot;
237.42 -
237.43 - public LocVarData() {
237.44 - }
237.45 -
237.46 - /**
237.47 - * Read LocalVariableTable attribute.
237.48 - */
237.49 - public LocVarData(DataInputStream in) throws IOException {
237.50 - start_pc = in.readShort();
237.51 - length=in.readShort();
237.52 - name_cpx=in.readShort();
237.53 - sig_cpx=in.readShort();
237.54 - slot=in.readShort();
237.55 -
237.56 - }
237.57 -}
238.1 --- a/rt/javap/src/main/java/org/apidesign/javap/MethodData.java Wed Feb 27 17:50:47 2013 +0100
238.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
238.3 @@ -1,394 +0,0 @@
238.4 -/*
238.5 - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
238.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
238.7 - *
238.8 - * This code is free software; you can redistribute it and/or modify it
238.9 - * under the terms of the GNU General Public License version 2 only, as
238.10 - * published by the Free Software Foundation. Oracle designates this
238.11 - * particular file as subject to the "Classpath" exception as provided
238.12 - * by Oracle in the LICENSE file that accompanied this code.
238.13 - *
238.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
238.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
238.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
238.17 - * version 2 for more details (a copy is included in the LICENSE file that
238.18 - * accompanied this code).
238.19 - *
238.20 - * You should have received a copy of the GNU General Public License version
238.21 - * 2 along with this work; if not, write to the Free Software Foundation,
238.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
238.23 - *
238.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
238.25 - * or visit www.oracle.com if you need additional information or have any
238.26 - * questions.
238.27 - */
238.28 -
238.29 -package org.apidesign.javap;
238.30 -
238.31 -
238.32 -import java.io.DataInputStream;
238.33 -import java.io.IOException;
238.34 -import static org.apidesign.javap.RuntimeConstants.*;
238.35 -
238.36 -/**
238.37 - * Strores method data informastion.
238.38 - *
238.39 - * @author Sucheta Dambalkar (Adopted code from jdis)
238.40 - */
238.41 -public class MethodData {
238.42 -
238.43 - ClassData cls;
238.44 - int access;
238.45 - int name_index;
238.46 - int descriptor_index;
238.47 - int attributes_count;
238.48 - byte[] code;
238.49 - Vector exception_table = new Vector(0);
238.50 - Vector lin_num_tb = new Vector(0);
238.51 - Vector loc_var_tb = new Vector(0);
238.52 - StackMapTableData[] stackMapTable;
238.53 - StackMapData[] stackMap;
238.54 - int[] exc_index_table=null;
238.55 - Vector attrs=new Vector(0);
238.56 - Vector code_attrs=new Vector(0);
238.57 - int max_stack, max_locals;
238.58 - boolean isSynthetic=false;
238.59 - boolean isDeprecated=false;
238.60 -
238.61 - public MethodData(ClassData cls){
238.62 - this.cls=cls;
238.63 - }
238.64 -
238.65 - /**
238.66 - * Read method info.
238.67 - */
238.68 - public void read(DataInputStream in) throws IOException {
238.69 - access = in.readUnsignedShort();
238.70 - name_index=in.readUnsignedShort();
238.71 - descriptor_index =in.readUnsignedShort();
238.72 - int attributes_count = in.readUnsignedShort();
238.73 - for (int i = 0; i < attributes_count; i++) {
238.74 - int attr_name_index=in.readUnsignedShort();
238.75 -
238.76 - readAttr: {
238.77 - if (cls.getTag(attr_name_index)==CONSTANT_UTF8) {
238.78 - String attr_name=cls.getString(attr_name_index);
238.79 - if ( attr_name.equals("Code")){
238.80 - readCode (in);
238.81 - AttrData attr=new AttrData(cls);
238.82 - attr.read(attr_name_index);
238.83 - attrs.addElement(attr);
238.84 - break readAttr;
238.85 - } else if ( attr_name.equals("Exceptions")){
238.86 - readExceptions(in);
238.87 - AttrData attr=new AttrData(cls);
238.88 - attr.read(attr_name_index);
238.89 - attrs.addElement(attr);
238.90 - break readAttr;
238.91 - } else if (attr_name.equals("Synthetic")){
238.92 - if (in.readInt()!=0)
238.93 - throw new ClassFormatError("invalid Synthetic attr length");
238.94 - isSynthetic=true;
238.95 - AttrData attr=new AttrData(cls);
238.96 - attr.read(attr_name_index);
238.97 - attrs.addElement(attr);
238.98 - break readAttr;
238.99 - } else if (attr_name.equals("Deprecated")){
238.100 - if (in.readInt()!=0)
238.101 - throw new ClassFormatError("invalid Synthetic attr length");
238.102 - isDeprecated = true;
238.103 - AttrData attr=new AttrData(cls);
238.104 - attr.read(attr_name_index);
238.105 - attrs.addElement(attr);
238.106 - break readAttr;
238.107 - }
238.108 - }
238.109 - AttrData attr=new AttrData(cls);
238.110 - attr.read(attr_name_index, in);
238.111 - attrs.addElement(attr);
238.112 - }
238.113 - }
238.114 - }
238.115 -
238.116 - /**
238.117 - * Read code attribute info.
238.118 - */
238.119 - public void readCode(DataInputStream in) throws IOException {
238.120 -
238.121 - int attr_length = in.readInt();
238.122 - max_stack=in.readUnsignedShort();
238.123 - max_locals=in.readUnsignedShort();
238.124 - int codelen=in.readInt();
238.125 -
238.126 - code=new byte[codelen];
238.127 - int totalread = 0;
238.128 - while(totalread < codelen){
238.129 - totalread += in.read(code, totalread, codelen-totalread);
238.130 - }
238.131 - // in.read(code, 0, codelen);
238.132 - int clen = 0;
238.133 - readExceptionTable(in);
238.134 - int code_attributes_count = in.readUnsignedShort();
238.135 -
238.136 - for (int k = 0 ; k < code_attributes_count ; k++) {
238.137 - int table_name_index=in.readUnsignedShort();
238.138 - int table_name_tag=cls.getTag(table_name_index);
238.139 - AttrData attr=new AttrData(cls);
238.140 - if (table_name_tag==CONSTANT_UTF8) {
238.141 - String table_name_tstr=cls.getString(table_name_index);
238.142 - if (table_name_tstr.equals("LineNumberTable")) {
238.143 - readLineNumTable(in);
238.144 - attr.read(table_name_index);
238.145 - } else if (table_name_tstr.equals("LocalVariableTable")) {
238.146 - readLocVarTable(in);
238.147 - attr.read(table_name_index);
238.148 - } else if (table_name_tstr.equals("StackMapTable")) {
238.149 - readStackMapTable(in);
238.150 - attr.read(table_name_index);
238.151 - } else if (table_name_tstr.equals("StackMap")) {
238.152 - readStackMap(in);
238.153 - attr.read(table_name_index);
238.154 - } else {
238.155 - attr.read(table_name_index, in);
238.156 - }
238.157 - code_attrs.addElement(attr);
238.158 - continue;
238.159 - }
238.160 -
238.161 - attr.read(table_name_index, in);
238.162 - code_attrs.addElement(attr);
238.163 - }
238.164 - }
238.165 -
238.166 - /**
238.167 - * Read exception table info.
238.168 - */
238.169 - void readExceptionTable (DataInputStream in) throws IOException {
238.170 - int exception_table_len=in.readUnsignedShort();
238.171 - exception_table=new Vector(exception_table_len);
238.172 - for (int l = 0; l < exception_table_len; l++) {
238.173 - exception_table.addElement(new TrapData(in, l));
238.174 - }
238.175 - }
238.176 -
238.177 - /**
238.178 - * Read LineNumberTable attribute info.
238.179 - */
238.180 - void readLineNumTable (DataInputStream in) throws IOException {
238.181 - int attr_len = in.readInt(); // attr_length
238.182 - int lin_num_tb_len = in.readUnsignedShort();
238.183 - lin_num_tb=new Vector(lin_num_tb_len);
238.184 - for (int l = 0; l < lin_num_tb_len; l++) {
238.185 - lin_num_tb.addElement(new LineNumData(in));
238.186 - }
238.187 - }
238.188 -
238.189 - /**
238.190 - * Read LocalVariableTable attribute info.
238.191 - */
238.192 - void readLocVarTable (DataInputStream in) throws IOException {
238.193 - int attr_len=in.readInt(); // attr_length
238.194 - int loc_var_tb_len = in.readUnsignedShort();
238.195 - loc_var_tb = new Vector(loc_var_tb_len);
238.196 - for (int l = 0; l < loc_var_tb_len; l++) {
238.197 - loc_var_tb.addElement(new LocVarData(in));
238.198 - }
238.199 - }
238.200 -
238.201 - /**
238.202 - * Read Exception attribute info.
238.203 - */
238.204 - public void readExceptions(DataInputStream in) throws IOException {
238.205 - int attr_len=in.readInt(); // attr_length in prog
238.206 - int num_exceptions = in.readUnsignedShort();
238.207 - exc_index_table=new int[num_exceptions];
238.208 - for (int l = 0; l < num_exceptions; l++) {
238.209 - int exc=in.readShort();
238.210 - exc_index_table[l]=exc;
238.211 - }
238.212 - }
238.213 -
238.214 - /**
238.215 - * Read StackMapTable attribute info.
238.216 - */
238.217 - void readStackMapTable(DataInputStream in) throws IOException {
238.218 - int attr_len = in.readInt(); //attr_length
238.219 - int stack_map_tb_len = in.readUnsignedShort();
238.220 - stackMapTable = new StackMapTableData[stack_map_tb_len];
238.221 - for (int i=0; i<stack_map_tb_len; i++) {
238.222 - stackMapTable[i] = StackMapTableData.getInstance(in, this);
238.223 - }
238.224 - }
238.225 -
238.226 - /**
238.227 - * Read StackMap attribute info.
238.228 - */
238.229 - void readStackMap(DataInputStream in) throws IOException {
238.230 - int attr_len = in.readInt(); //attr_length
238.231 - int stack_map_len = in.readUnsignedShort();
238.232 - stackMap = new StackMapData[stack_map_len];
238.233 - for (int i = 0; i<stack_map_len; i++) {
238.234 - stackMap[i] = new StackMapData(in, this);
238.235 - }
238.236 - }
238.237 -
238.238 - /**
238.239 - * Return access of the method.
238.240 - */
238.241 - public int getAccess(){
238.242 - return access;
238.243 - }
238.244 -
238.245 - /**
238.246 - * Return name of the method.
238.247 - */
238.248 - public String getName(){
238.249 - return cls.getStringValue(name_index);
238.250 - }
238.251 -
238.252 - /**
238.253 - * Return internal siganature of the method.
238.254 - */
238.255 - public String getInternalSig(){
238.256 - return cls.getStringValue(descriptor_index);
238.257 - }
238.258 -
238.259 - /**
238.260 - * Return code attribute data of a method.
238.261 - */
238.262 - public byte[] getCode(){
238.263 - return code;
238.264 - }
238.265 -
238.266 - /**
238.267 - * Return LineNumberTable size.
238.268 - */
238.269 - public int getnumlines(){
238.270 - return lin_num_tb.size();
238.271 - }
238.272 -
238.273 - /**
238.274 - * Return LineNumberTable
238.275 - */
238.276 - public Vector getlin_num_tb(){
238.277 - return lin_num_tb;
238.278 - }
238.279 -
238.280 - /**
238.281 - * Return LocalVariableTable size.
238.282 - */
238.283 - public int getloc_var_tbsize(){
238.284 - return loc_var_tb.size();
238.285 - }
238.286 -
238.287 -
238.288 - /**
238.289 - * Return LocalVariableTable.
238.290 - */
238.291 - public Vector getloc_var_tb(){
238.292 - return loc_var_tb;
238.293 - }
238.294 -
238.295 - /**
238.296 - * Return StackMap.
238.297 - */
238.298 - public StackMapData[] getStackMap() {
238.299 - return stackMap;
238.300 - }
238.301 -
238.302 - /**
238.303 - * Return StackMapTable.
238.304 - */
238.305 - public StackMapTableData[] getStackMapTable() {
238.306 - return stackMapTable;
238.307 - }
238.308 -
238.309 - public StackMapIterator createStackMapIterator() {
238.310 - return new StackMapIterator(this);
238.311 - }
238.312 -
238.313 - /**
238.314 - * Return true if method is static
238.315 - */
238.316 - public boolean isStatic(){
238.317 - if ((access & ACC_STATIC) !=0) return true;
238.318 - return false;
238.319 - }
238.320 -
238.321 -
238.322 - /**
238.323 - * Return max depth of operand stack.
238.324 - */
238.325 - public int getMaxStack(){
238.326 - return max_stack;
238.327 - }
238.328 -
238.329 -
238.330 - /**
238.331 - * Return number of local variables.
238.332 - */
238.333 - public int getMaxLocals(){
238.334 - return max_locals;
238.335 - }
238.336 -
238.337 -
238.338 - /**
238.339 - * Return exception index table in Exception attribute.
238.340 - */
238.341 - public int []get_exc_index_table(){
238.342 - return exc_index_table;
238.343 - }
238.344 -
238.345 -
238.346 - /**
238.347 - * Return exception table in code attributre.
238.348 - */
238.349 - public TrapDataIterator getTrapDataIterator(){
238.350 - return new TrapDataIterator(exception_table);
238.351 - }
238.352 -
238.353 -
238.354 - /**
238.355 - * Return method attributes.
238.356 - */
238.357 - public Vector getAttributes(){
238.358 - return attrs;
238.359 - }
238.360 -
238.361 -
238.362 - /**
238.363 - * Return code attributes.
238.364 - */
238.365 - public Vector getCodeAttributes(){
238.366 - return code_attrs;
238.367 - }
238.368 -
238.369 -
238.370 - /**
238.371 - * Return true if method id synthetic.
238.372 - */
238.373 - public boolean isSynthetic(){
238.374 - return isSynthetic;
238.375 - }
238.376 -
238.377 -
238.378 - /**
238.379 - * Return true if method is deprecated.
238.380 - */
238.381 - public boolean isDeprecated(){
238.382 - return isDeprecated;
238.383 - }
238.384 -
238.385 - public byte[] findAnnotationData(boolean classRetention) {
238.386 - String n = classRetention ?
238.387 - "RuntimeInvisibleAnnotations" : // NOI18N
238.388 - "RuntimeVisibleAnnotations"; // NOI18N
238.389 - AttrData[] arr = new AttrData[attrs.size()];
238.390 - attrs.copyInto(arr);
238.391 - return ClassData.findAttr(n, arr);
238.392 - }
238.393 -
238.394 - public boolean isConstructor() {
238.395 - return "<init>".equals(getName());
238.396 - }
238.397 -}
239.1 --- a/rt/javap/src/main/java/org/apidesign/javap/RuntimeConstants.java Wed Feb 27 17:50:47 2013 +0100
239.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
239.3 @@ -1,787 +0,0 @@
239.4 -/*
239.5 - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
239.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
239.7 - *
239.8 - * This code is free software; you can redistribute it and/or modify it
239.9 - * under the terms of the GNU General Public License version 2 only, as
239.10 - * published by the Free Software Foundation. Oracle designates this
239.11 - * particular file as subject to the "Classpath" exception as provided
239.12 - * by Oracle in the LICENSE file that accompanied this code.
239.13 - *
239.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
239.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
239.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
239.17 - * version 2 for more details (a copy is included in the LICENSE file that
239.18 - * accompanied this code).
239.19 - *
239.20 - * You should have received a copy of the GNU General Public License version
239.21 - * 2 along with this work; if not, write to the Free Software Foundation,
239.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
239.23 - *
239.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
239.25 - * or visit www.oracle.com if you need additional information or have any
239.26 - * questions.
239.27 - */
239.28 -
239.29 -
239.30 -package org.apidesign.javap;
239.31 -
239.32 -public interface RuntimeConstants {
239.33 -
239.34 - /* Signature Characters */
239.35 - public static final char SIGC_VOID = 'V';
239.36 - public static final String SIG_VOID = "V";
239.37 - public static final char SIGC_BOOLEAN = 'Z';
239.38 - public static final String SIG_BOOLEAN = "Z";
239.39 - public static final char SIGC_BYTE = 'B';
239.40 - public static final String SIG_BYTE = "B";
239.41 - public static final char SIGC_CHAR = 'C';
239.42 - public static final String SIG_CHAR = "C";
239.43 - public static final char SIGC_SHORT = 'S';
239.44 - public static final String SIG_SHORT = "S";
239.45 - public static final char SIGC_INT = 'I';
239.46 - public static final String SIG_INT = "I";
239.47 - public static final char SIGC_LONG = 'J';
239.48 - public static final String SIG_LONG = "J";
239.49 - public static final char SIGC_FLOAT = 'F';
239.50 - public static final String SIG_FLOAT = "F";
239.51 - public static final char SIGC_DOUBLE = 'D';
239.52 - public static final String SIG_DOUBLE = "D";
239.53 - public static final char SIGC_ARRAY = '[';
239.54 - public static final String SIG_ARRAY = "[";
239.55 - public static final char SIGC_CLASS = 'L';
239.56 - public static final String SIG_CLASS = "L";
239.57 - public static final char SIGC_METHOD = '(';
239.58 - public static final String SIG_METHOD = "(";
239.59 - public static final char SIGC_ENDCLASS = ';';
239.60 - public static final String SIG_ENDCLASS = ";";
239.61 - public static final char SIGC_ENDMETHOD = ')';
239.62 - public static final String SIG_ENDMETHOD = ")";
239.63 - public static final char SIGC_PACKAGE = '/';
239.64 - public static final String SIG_PACKAGE = "/";
239.65 -
239.66 - /* Class File Constants */
239.67 - public static final int JAVA_MAGIC = 0xcafebabe;
239.68 - public static final int JAVA_VERSION = 45;
239.69 - public static final int JAVA_MINOR_VERSION = 3;
239.70 -
239.71 - /* Constant table */
239.72 - public static final int CONSTANT_UTF8 = 1;
239.73 - public static final int CONSTANT_UNICODE = 2;
239.74 - public static final int CONSTANT_INTEGER = 3;
239.75 - public static final int CONSTANT_FLOAT = 4;
239.76 - public static final int CONSTANT_LONG = 5;
239.77 - public static final int CONSTANT_DOUBLE = 6;
239.78 - public static final int CONSTANT_CLASS = 7;
239.79 - public static final int CONSTANT_STRING = 8;
239.80 - public static final int CONSTANT_FIELD = 9;
239.81 - public static final int CONSTANT_METHOD = 10;
239.82 - public static final int CONSTANT_INTERFACEMETHOD = 11;
239.83 - public static final int CONSTANT_NAMEANDTYPE = 12;
239.84 -
239.85 - /* Access Flags */
239.86 - public static final int ACC_PUBLIC = 0x00000001;
239.87 - public static final int ACC_PRIVATE = 0x00000002;
239.88 - public static final int ACC_PROTECTED = 0x00000004;
239.89 - public static final int ACC_STATIC = 0x00000008;
239.90 - public static final int ACC_FINAL = 0x00000010;
239.91 - public static final int ACC_SYNCHRONIZED = 0x00000020;
239.92 - public static final int ACC_SUPER = 0x00000020;
239.93 - public static final int ACC_VOLATILE = 0x00000040;
239.94 - public static final int ACC_TRANSIENT = 0x00000080;
239.95 - public static final int ACC_NATIVE = 0x00000100;
239.96 - public static final int ACC_INTERFACE = 0x00000200;
239.97 - public static final int ACC_ABSTRACT = 0x00000400;
239.98 - public static final int ACC_STRICT = 0x00000800;
239.99 - public static final int ACC_EXPLICIT = 0x00001000;
239.100 - public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
239.101 -
239.102 - /* Type codes */
239.103 - public static final int T_CLASS = 0x00000002;
239.104 - public static final int T_BOOLEAN = 0x00000004;
239.105 - public static final int T_CHAR = 0x00000005;
239.106 - public static final int T_FLOAT = 0x00000006;
239.107 - public static final int T_DOUBLE = 0x00000007;
239.108 - public static final int T_BYTE = 0x00000008;
239.109 - public static final int T_SHORT = 0x00000009;
239.110 - public static final int T_INT = 0x0000000a;
239.111 - public static final int T_LONG = 0x0000000b;
239.112 -
239.113 - /* Type codes for StackMap attribute */
239.114 - public static final int ITEM_Bogus =0; // an unknown or uninitialized value
239.115 - public static final int ITEM_Integer =1; // a 32-bit integer
239.116 - public static final int ITEM_Float =2; // not used
239.117 - public static final int ITEM_Double =3; // not used
239.118 - public static final int ITEM_Long =4; // a 64-bit integer
239.119 - public static final int ITEM_Null =5; // the type of null
239.120 - public static final int ITEM_InitObject =6; // "this" in constructor
239.121 - public static final int ITEM_Object =7; // followed by 2-byte index of class name
239.122 - public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new"
239.123 -
239.124 - /* Constants used in StackMapTable attribute */
239.125 - public static final int SAME_FRAME_BOUND = 64;
239.126 - public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128;
239.127 - public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
239.128 - public static final int SAME_FRAME_EXTENDED = 251;
239.129 - public static final int FULL_FRAME = 255;
239.130 -
239.131 - /* Opcodes */
239.132 - public static final int opc_dead = -2;
239.133 - public static final int opc_label = -1;
239.134 - public static final int opc_nop = 0;
239.135 - public static final int opc_aconst_null = 1;
239.136 - public static final int opc_iconst_m1 = 2;
239.137 - public static final int opc_iconst_0 = 3;
239.138 - public static final int opc_iconst_1 = 4;
239.139 - public static final int opc_iconst_2 = 5;
239.140 - public static final int opc_iconst_3 = 6;
239.141 - public static final int opc_iconst_4 = 7;
239.142 - public static final int opc_iconst_5 = 8;
239.143 - public static final int opc_lconst_0 = 9;
239.144 - public static final int opc_lconst_1 = 10;
239.145 - public static final int opc_fconst_0 = 11;
239.146 - public static final int opc_fconst_1 = 12;
239.147 - public static final int opc_fconst_2 = 13;
239.148 - public static final int opc_dconst_0 = 14;
239.149 - public static final int opc_dconst_1 = 15;
239.150 - public static final int opc_bipush = 16;
239.151 - public static final int opc_sipush = 17;
239.152 - public static final int opc_ldc = 18;
239.153 - public static final int opc_ldc_w = 19;
239.154 - public static final int opc_ldc2_w = 20;
239.155 - public static final int opc_iload = 21;
239.156 - public static final int opc_lload = 22;
239.157 - public static final int opc_fload = 23;
239.158 - public static final int opc_dload = 24;
239.159 - public static final int opc_aload = 25;
239.160 - public static final int opc_iload_0 = 26;
239.161 - public static final int opc_iload_1 = 27;
239.162 - public static final int opc_iload_2 = 28;
239.163 - public static final int opc_iload_3 = 29;
239.164 - public static final int opc_lload_0 = 30;
239.165 - public static final int opc_lload_1 = 31;
239.166 - public static final int opc_lload_2 = 32;
239.167 - public static final int opc_lload_3 = 33;
239.168 - public static final int opc_fload_0 = 34;
239.169 - public static final int opc_fload_1 = 35;
239.170 - public static final int opc_fload_2 = 36;
239.171 - public static final int opc_fload_3 = 37;
239.172 - public static final int opc_dload_0 = 38;
239.173 - public static final int opc_dload_1 = 39;
239.174 - public static final int opc_dload_2 = 40;
239.175 - public static final int opc_dload_3 = 41;
239.176 - public static final int opc_aload_0 = 42;
239.177 - public static final int opc_aload_1 = 43;
239.178 - public static final int opc_aload_2 = 44;
239.179 - public static final int opc_aload_3 = 45;
239.180 - public static final int opc_iaload = 46;
239.181 - public static final int opc_laload = 47;
239.182 - public static final int opc_faload = 48;
239.183 - public static final int opc_daload = 49;
239.184 - public static final int opc_aaload = 50;
239.185 - public static final int opc_baload = 51;
239.186 - public static final int opc_caload = 52;
239.187 - public static final int opc_saload = 53;
239.188 - public static final int opc_istore = 54;
239.189 - public static final int opc_lstore = 55;
239.190 - public static final int opc_fstore = 56;
239.191 - public static final int opc_dstore = 57;
239.192 - public static final int opc_astore = 58;
239.193 - public static final int opc_istore_0 = 59;
239.194 - public static final int opc_istore_1 = 60;
239.195 - public static final int opc_istore_2 = 61;
239.196 - public static final int opc_istore_3 = 62;
239.197 - public static final int opc_lstore_0 = 63;
239.198 - public static final int opc_lstore_1 = 64;
239.199 - public static final int opc_lstore_2 = 65;
239.200 - public static final int opc_lstore_3 = 66;
239.201 - public static final int opc_fstore_0 = 67;
239.202 - public static final int opc_fstore_1 = 68;
239.203 - public static final int opc_fstore_2 = 69;
239.204 - public static final int opc_fstore_3 = 70;
239.205 - public static final int opc_dstore_0 = 71;
239.206 - public static final int opc_dstore_1 = 72;
239.207 - public static final int opc_dstore_2 = 73;
239.208 - public static final int opc_dstore_3 = 74;
239.209 - public static final int opc_astore_0 = 75;
239.210 - public static final int opc_astore_1 = 76;
239.211 - public static final int opc_astore_2 = 77;
239.212 - public static final int opc_astore_3 = 78;
239.213 - public static final int opc_iastore = 79;
239.214 - public static final int opc_lastore = 80;
239.215 - public static final int opc_fastore = 81;
239.216 - public static final int opc_dastore = 82;
239.217 - public static final int opc_aastore = 83;
239.218 - public static final int opc_bastore = 84;
239.219 - public static final int opc_castore = 85;
239.220 - public static final int opc_sastore = 86;
239.221 - public static final int opc_pop = 87;
239.222 - public static final int opc_pop2 = 88;
239.223 - public static final int opc_dup = 89;
239.224 - public static final int opc_dup_x1 = 90;
239.225 - public static final int opc_dup_x2 = 91;
239.226 - public static final int opc_dup2 = 92;
239.227 - public static final int opc_dup2_x1 = 93;
239.228 - public static final int opc_dup2_x2 = 94;
239.229 - public static final int opc_swap = 95;
239.230 - public static final int opc_iadd = 96;
239.231 - public static final int opc_ladd = 97;
239.232 - public static final int opc_fadd = 98;
239.233 - public static final int opc_dadd = 99;
239.234 - public static final int opc_isub = 100;
239.235 - public static final int opc_lsub = 101;
239.236 - public static final int opc_fsub = 102;
239.237 - public static final int opc_dsub = 103;
239.238 - public static final int opc_imul = 104;
239.239 - public static final int opc_lmul = 105;
239.240 - public static final int opc_fmul = 106;
239.241 - public static final int opc_dmul = 107;
239.242 - public static final int opc_idiv = 108;
239.243 - public static final int opc_ldiv = 109;
239.244 - public static final int opc_fdiv = 110;
239.245 - public static final int opc_ddiv = 111;
239.246 - public static final int opc_irem = 112;
239.247 - public static final int opc_lrem = 113;
239.248 - public static final int opc_frem = 114;
239.249 - public static final int opc_drem = 115;
239.250 - public static final int opc_ineg = 116;
239.251 - public static final int opc_lneg = 117;
239.252 - public static final int opc_fneg = 118;
239.253 - public static final int opc_dneg = 119;
239.254 - public static final int opc_ishl = 120;
239.255 - public static final int opc_lshl = 121;
239.256 - public static final int opc_ishr = 122;
239.257 - public static final int opc_lshr = 123;
239.258 - public static final int opc_iushr = 124;
239.259 - public static final int opc_lushr = 125;
239.260 - public static final int opc_iand = 126;
239.261 - public static final int opc_land = 127;
239.262 - public static final int opc_ior = 128;
239.263 - public static final int opc_lor = 129;
239.264 - public static final int opc_ixor = 130;
239.265 - public static final int opc_lxor = 131;
239.266 - public static final int opc_iinc = 132;
239.267 - public static final int opc_i2l = 133;
239.268 - public static final int opc_i2f = 134;
239.269 - public static final int opc_i2d = 135;
239.270 - public static final int opc_l2i = 136;
239.271 - public static final int opc_l2f = 137;
239.272 - public static final int opc_l2d = 138;
239.273 - public static final int opc_f2i = 139;
239.274 - public static final int opc_f2l = 140;
239.275 - public static final int opc_f2d = 141;
239.276 - public static final int opc_d2i = 142;
239.277 - public static final int opc_d2l = 143;
239.278 - public static final int opc_d2f = 144;
239.279 - public static final int opc_i2b = 145;
239.280 - public static final int opc_int2byte = 145;
239.281 - public static final int opc_i2c = 146;
239.282 - public static final int opc_int2char = 146;
239.283 - public static final int opc_i2s = 147;
239.284 - public static final int opc_int2short = 147;
239.285 - public static final int opc_lcmp = 148;
239.286 - public static final int opc_fcmpl = 149;
239.287 - public static final int opc_fcmpg = 150;
239.288 - public static final int opc_dcmpl = 151;
239.289 - public static final int opc_dcmpg = 152;
239.290 - public static final int opc_ifeq = 153;
239.291 - public static final int opc_ifne = 154;
239.292 - public static final int opc_iflt = 155;
239.293 - public static final int opc_ifge = 156;
239.294 - public static final int opc_ifgt = 157;
239.295 - public static final int opc_ifle = 158;
239.296 - public static final int opc_if_icmpeq = 159;
239.297 - public static final int opc_if_icmpne = 160;
239.298 - public static final int opc_if_icmplt = 161;
239.299 - public static final int opc_if_icmpge = 162;
239.300 - public static final int opc_if_icmpgt = 163;
239.301 - public static final int opc_if_icmple = 164;
239.302 - public static final int opc_if_acmpeq = 165;
239.303 - public static final int opc_if_acmpne = 166;
239.304 - public static final int opc_goto = 167;
239.305 - public static final int opc_jsr = 168;
239.306 - public static final int opc_ret = 169;
239.307 - public static final int opc_tableswitch = 170;
239.308 - public static final int opc_lookupswitch = 171;
239.309 - public static final int opc_ireturn = 172;
239.310 - public static final int opc_lreturn = 173;
239.311 - public static final int opc_freturn = 174;
239.312 - public static final int opc_dreturn = 175;
239.313 - public static final int opc_areturn = 176;
239.314 - public static final int opc_return = 177;
239.315 - public static final int opc_getstatic = 178;
239.316 - public static final int opc_putstatic = 179;
239.317 - public static final int opc_getfield = 180;
239.318 - public static final int opc_putfield = 181;
239.319 - public static final int opc_invokevirtual = 182;
239.320 - public static final int opc_invokenonvirtual = 183;
239.321 - public static final int opc_invokespecial = 183;
239.322 - public static final int opc_invokestatic = 184;
239.323 - public static final int opc_invokeinterface = 185;
239.324 -// public static final int opc_xxxunusedxxx = 186;
239.325 - public static final int opc_new = 187;
239.326 - public static final int opc_newarray = 188;
239.327 - public static final int opc_anewarray = 189;
239.328 - public static final int opc_arraylength = 190;
239.329 - public static final int opc_athrow = 191;
239.330 - public static final int opc_checkcast = 192;
239.331 - public static final int opc_instanceof = 193;
239.332 - public static final int opc_monitorenter = 194;
239.333 - public static final int opc_monitorexit = 195;
239.334 - public static final int opc_wide = 196;
239.335 - public static final int opc_multianewarray = 197;
239.336 - public static final int opc_ifnull = 198;
239.337 - public static final int opc_ifnonnull = 199;
239.338 - public static final int opc_goto_w = 200;
239.339 - public static final int opc_jsr_w = 201;
239.340 - /* Pseudo-instructions */
239.341 - public static final int opc_bytecode = 203;
239.342 - public static final int opc_try = 204;
239.343 - public static final int opc_endtry = 205;
239.344 - public static final int opc_catch = 206;
239.345 - public static final int opc_var = 207;
239.346 - public static final int opc_endvar = 208;
239.347 - public static final int opc_localsmap = 209;
239.348 - public static final int opc_stackmap = 210;
239.349 - /* PicoJava prefixes */
239.350 - public static final int opc_nonpriv = 254;
239.351 - public static final int opc_priv = 255;
239.352 -
239.353 - /* Wide instructions */
239.354 - public static final int opc_iload_w = (opc_wide<<8)|opc_iload;
239.355 - public static final int opc_lload_w = (opc_wide<<8)|opc_lload;
239.356 - public static final int opc_fload_w = (opc_wide<<8)|opc_fload;
239.357 - public static final int opc_dload_w = (opc_wide<<8)|opc_dload;
239.358 - public static final int opc_aload_w = (opc_wide<<8)|opc_aload;
239.359 - public static final int opc_istore_w = (opc_wide<<8)|opc_istore;
239.360 - public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore;
239.361 - public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore;
239.362 - public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore;
239.363 - public static final int opc_astore_w = (opc_wide<<8)|opc_astore;
239.364 - public static final int opc_ret_w = (opc_wide<<8)|opc_ret;
239.365 - public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc;
239.366 -
239.367 - /* Opcode Names */
239.368 - public static final String opcNamesTab[] = {
239.369 - "nop",
239.370 - "aconst_null",
239.371 - "iconst_m1",
239.372 - "iconst_0",
239.373 - "iconst_1",
239.374 - "iconst_2",
239.375 - "iconst_3",
239.376 - "iconst_4",
239.377 - "iconst_5",
239.378 - "lconst_0",
239.379 - "lconst_1",
239.380 - "fconst_0",
239.381 - "fconst_1",
239.382 - "fconst_2",
239.383 - "dconst_0",
239.384 - "dconst_1",
239.385 - "bipush",
239.386 - "sipush",
239.387 - "ldc",
239.388 - "ldc_w",
239.389 - "ldc2_w",
239.390 - "iload",
239.391 - "lload",
239.392 - "fload",
239.393 - "dload",
239.394 - "aload",
239.395 - "iload_0",
239.396 - "iload_1",
239.397 - "iload_2",
239.398 - "iload_3",
239.399 - "lload_0",
239.400 - "lload_1",
239.401 - "lload_2",
239.402 - "lload_3",
239.403 - "fload_0",
239.404 - "fload_1",
239.405 - "fload_2",
239.406 - "fload_3",
239.407 - "dload_0",
239.408 - "dload_1",
239.409 - "dload_2",
239.410 - "dload_3",
239.411 - "aload_0",
239.412 - "aload_1",
239.413 - "aload_2",
239.414 - "aload_3",
239.415 - "iaload",
239.416 - "laload",
239.417 - "faload",
239.418 - "daload",
239.419 - "aaload",
239.420 - "baload",
239.421 - "caload",
239.422 - "saload",
239.423 - "istore",
239.424 - "lstore",
239.425 - "fstore",
239.426 - "dstore",
239.427 - "astore",
239.428 - "istore_0",
239.429 - "istore_1",
239.430 - "istore_2",
239.431 - "istore_3",
239.432 - "lstore_0",
239.433 - "lstore_1",
239.434 - "lstore_2",
239.435 - "lstore_3",
239.436 - "fstore_0",
239.437 - "fstore_1",
239.438 - "fstore_2",
239.439 - "fstore_3",
239.440 - "dstore_0",
239.441 - "dstore_1",
239.442 - "dstore_2",
239.443 - "dstore_3",
239.444 - "astore_0",
239.445 - "astore_1",
239.446 - "astore_2",
239.447 - "astore_3",
239.448 - "iastore",
239.449 - "lastore",
239.450 - "fastore",
239.451 - "dastore",
239.452 - "aastore",
239.453 - "bastore",
239.454 - "castore",
239.455 - "sastore",
239.456 - "pop",
239.457 - "pop2",
239.458 - "dup",
239.459 - "dup_x1",
239.460 - "dup_x2",
239.461 - "dup2",
239.462 - "dup2_x1",
239.463 - "dup2_x2",
239.464 - "swap",
239.465 - "iadd",
239.466 - "ladd",
239.467 - "fadd",
239.468 - "dadd",
239.469 - "isub",
239.470 - "lsub",
239.471 - "fsub",
239.472 - "dsub",
239.473 - "imul",
239.474 - "lmul",
239.475 - "fmul",
239.476 - "dmul",
239.477 - "idiv",
239.478 - "ldiv",
239.479 - "fdiv",
239.480 - "ddiv",
239.481 - "irem",
239.482 - "lrem",
239.483 - "frem",
239.484 - "drem",
239.485 - "ineg",
239.486 - "lneg",
239.487 - "fneg",
239.488 - "dneg",
239.489 - "ishl",
239.490 - "lshl",
239.491 - "ishr",
239.492 - "lshr",
239.493 - "iushr",
239.494 - "lushr",
239.495 - "iand",
239.496 - "land",
239.497 - "ior",
239.498 - "lor",
239.499 - "ixor",
239.500 - "lxor",
239.501 - "iinc",
239.502 - "i2l",
239.503 - "i2f",
239.504 - "i2d",
239.505 - "l2i",
239.506 - "l2f",
239.507 - "l2d",
239.508 - "f2i",
239.509 - "f2l",
239.510 - "f2d",
239.511 - "d2i",
239.512 - "d2l",
239.513 - "d2f",
239.514 - "i2b",
239.515 - "i2c",
239.516 - "i2s",
239.517 - "lcmp",
239.518 - "fcmpl",
239.519 - "fcmpg",
239.520 - "dcmpl",
239.521 - "dcmpg",
239.522 - "ifeq",
239.523 - "ifne",
239.524 - "iflt",
239.525 - "ifge",
239.526 - "ifgt",
239.527 - "ifle",
239.528 - "if_icmpeq",
239.529 - "if_icmpne",
239.530 - "if_icmplt",
239.531 - "if_icmpge",
239.532 - "if_icmpgt",
239.533 - "if_icmple",
239.534 - "if_acmpeq",
239.535 - "if_acmpne",
239.536 - "goto",
239.537 - "jsr",
239.538 - "ret",
239.539 - "tableswitch",
239.540 - "lookupswitch",
239.541 - "ireturn",
239.542 - "lreturn",
239.543 - "freturn",
239.544 - "dreturn",
239.545 - "areturn",
239.546 - "return",
239.547 - "getstatic",
239.548 - "putstatic",
239.549 - "getfield",
239.550 - "putfield",
239.551 - "invokevirtual",
239.552 - "invokespecial", // was "invokenonvirtual",
239.553 - "invokestatic",
239.554 - "invokeinterface",
239.555 - "bytecode 186", //"xxxunusedxxx",
239.556 - "new",
239.557 - "newarray",
239.558 - "anewarray",
239.559 - "arraylength",
239.560 - "athrow",
239.561 - "checkcast",
239.562 - "instanceof",
239.563 - "monitorenter",
239.564 - "monitorexit",
239.565 - null, // "wide",
239.566 - "multianewarray",
239.567 - "ifnull",
239.568 - "ifnonnull",
239.569 - "goto_w",
239.570 - "jsr_w",
239.571 - "bytecode 202", // "breakpoint",
239.572 - "bytecode",
239.573 - "try",
239.574 - "endtry",
239.575 - "catch",
239.576 - "var",
239.577 - "endvar",
239.578 - "locals_map",
239.579 - "stack_map"
239.580 - };
239.581 -
239.582 - /* Opcode Lengths */
239.583 - public static final int opcLengthsTab[] = {
239.584 - 1,
239.585 - 1,
239.586 - 1,
239.587 - 1,
239.588 - 1,
239.589 - 1,
239.590 - 1,
239.591 - 1,
239.592 - 1,
239.593 - 1,
239.594 - 1,
239.595 - 1,
239.596 - 1,
239.597 - 1,
239.598 - 1,
239.599 - 1,
239.600 - 2,
239.601 - 3,
239.602 - 2,
239.603 - 3,
239.604 - 3,
239.605 - 2,
239.606 - 2,
239.607 - 2,
239.608 - 2,
239.609 - 2,
239.610 - 1,
239.611 - 1,
239.612 - 1,
239.613 - 1,
239.614 - 1,
239.615 - 1,
239.616 - 1,
239.617 - 1,
239.618 - 1,
239.619 - 1,
239.620 - 1,
239.621 - 1,
239.622 - 1,
239.623 - 1,
239.624 - 1,
239.625 - 1,
239.626 - 1,
239.627 - 1,
239.628 - 1,
239.629 - 1,
239.630 - 1,
239.631 - 1,
239.632 - 1,
239.633 - 1,
239.634 - 1,
239.635 - 1,
239.636 - 1,
239.637 - 1,
239.638 - 2,
239.639 - 2,
239.640 - 2,
239.641 - 2,
239.642 - 2,
239.643 - 1,
239.644 - 1,
239.645 - 1,
239.646 - 1,
239.647 - 1,
239.648 - 1,
239.649 - 1,
239.650 - 1,
239.651 - 1,
239.652 - 1,
239.653 - 1,
239.654 - 1,
239.655 - 1,
239.656 - 1,
239.657 - 1,
239.658 - 1,
239.659 - 1,
239.660 - 1,
239.661 - 1,
239.662 - 1,
239.663 - 1,
239.664 - 1,
239.665 - 1,
239.666 - 1,
239.667 - 1,
239.668 - 1,
239.669 - 1,
239.670 - 1,
239.671 - 1,
239.672 - 1,
239.673 - 1,
239.674 - 1,
239.675 - 1,
239.676 - 1,
239.677 - 1,
239.678 - 1,
239.679 - 1,
239.680 - 1,
239.681 - 1,
239.682 - 1,
239.683 - 1,
239.684 - 1,
239.685 - 1,
239.686 - 1,
239.687 - 1,
239.688 - 1,
239.689 - 1,
239.690 - 1,
239.691 - 1,
239.692 - 1,
239.693 - 1,
239.694 - 1,
239.695 - 1,
239.696 - 1,
239.697 - 1,
239.698 - 1,
239.699 - 1,
239.700 - 1,
239.701 - 1,
239.702 - 1,
239.703 - 1,
239.704 - 1,
239.705 - 1,
239.706 - 1,
239.707 - 1,
239.708 - 1,
239.709 - 1,
239.710 - 1,
239.711 - 1,
239.712 - 1,
239.713 - 1,
239.714 - 1,
239.715 - 1,
239.716 - 3,
239.717 - 1,
239.718 - 1,
239.719 - 1,
239.720 - 1,
239.721 - 1,
239.722 - 1,
239.723 - 1,
239.724 - 1,
239.725 - 1,
239.726 - 1,
239.727 - 1,
239.728 - 1,
239.729 - 1,
239.730 - 1,
239.731 - 1,
239.732 - 1,
239.733 - 1,
239.734 - 1,
239.735 - 1,
239.736 - 1,
239.737 - 3,
239.738 - 3,
239.739 - 3,
239.740 - 3,
239.741 - 3,
239.742 - 3,
239.743 - 3,
239.744 - 3,
239.745 - 3,
239.746 - 3,
239.747 - 3,
239.748 - 3,
239.749 - 3,
239.750 - 3,
239.751 - 3,
239.752 - 3,
239.753 - 2,
239.754 - 99,
239.755 - 99,
239.756 - 1,
239.757 - 1,
239.758 - 1,
239.759 - 1,
239.760 - 1,
239.761 - 1,
239.762 - 3,
239.763 - 3,
239.764 - 3,
239.765 - 3,
239.766 - 3,
239.767 - 3,
239.768 - 3,
239.769 - 5,
239.770 - 0,
239.771 - 3,
239.772 - 2,
239.773 - 3,
239.774 - 1,
239.775 - 1,
239.776 - 3,
239.777 - 3,
239.778 - 1,
239.779 - 1,
239.780 - 0, // wide
239.781 - 4,
239.782 - 3,
239.783 - 3,
239.784 - 5,
239.785 - 5,
239.786 - 1,
239.787 - 1, 0, 0, 0, 0, 0 // pseudo
239.788 - };
239.789 -
239.790 -}
240.1 --- a/rt/javap/src/main/java/org/apidesign/javap/StackMapData.java Wed Feb 27 17:50:47 2013 +0100
240.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
240.3 @@ -1,71 +0,0 @@
240.4 -/*
240.5 - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
240.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
240.7 - *
240.8 - * This code is free software; you can redistribute it and/or modify it
240.9 - * under the terms of the GNU General Public License version 2 only, as
240.10 - * published by the Free Software Foundation. Oracle designates this
240.11 - * particular file as subject to the "Classpath" exception as provided
240.12 - * by Oracle in the LICENSE file that accompanied this code.
240.13 - *
240.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
240.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
240.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
240.17 - * version 2 for more details (a copy is included in the LICENSE file that
240.18 - * accompanied this code).
240.19 - *
240.20 - * You should have received a copy of the GNU General Public License version
240.21 - * 2 along with this work; if not, write to the Free Software Foundation,
240.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
240.23 - *
240.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
240.25 - * or visit www.oracle.com if you need additional information or have any
240.26 - * questions.
240.27 - */
240.28 -
240.29 -
240.30 -package org.apidesign.javap;
240.31 -
240.32 -import java.util.*;
240.33 -import java.io.*;
240.34 -
240.35 -import static org.apidesign.javap.RuntimeConstants.*;
240.36 -
240.37 -/* represents one entry of StackMap attribute
240.38 - */
240.39 -class StackMapData {
240.40 - final int offset;
240.41 - final int[] locals;
240.42 - final int[] stack;
240.43 -
240.44 - StackMapData(int offset, int[] locals, int[] stack) {
240.45 - this.offset = offset;
240.46 - this.locals = locals;
240.47 - this.stack = stack;
240.48 - }
240.49 -
240.50 - StackMapData(DataInputStream in, MethodData method) throws IOException {
240.51 - offset = in.readUnsignedShort();
240.52 - int local_size = in.readUnsignedShort();
240.53 - locals = readTypeArray(in, local_size, method);
240.54 - int stack_size = in.readUnsignedShort();
240.55 - stack = readTypeArray(in, stack_size, method);
240.56 - }
240.57 -
240.58 - static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
240.59 - int[] types = new int[length];
240.60 - for (int i=0; i<length; i++) {
240.61 - types[i] = readType(in, method);
240.62 - }
240.63 - return types;
240.64 - }
240.65 -
240.66 - static final int readType(DataInputStream in, MethodData method) throws IOException {
240.67 - int type = in.readUnsignedByte();
240.68 - if (type == ITEM_Object || type == ITEM_NewObject) {
240.69 - type = type | (in.readUnsignedShort()<<8);
240.70 - }
240.71 - return type;
240.72 - }
240.73 -
240.74 -}
241.1 --- a/rt/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Wed Feb 27 17:50:47 2013 +0100
241.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
241.3 @@ -1,179 +0,0 @@
241.4 -/*
241.5 - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
241.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
241.7 - *
241.8 - * This code is free software; you can redistribute it and/or modify it
241.9 - * under the terms of the GNU General Public License version 2 only, as
241.10 - * published by the Free Software Foundation. Oracle designates this
241.11 - * particular file as subject to the "Classpath" exception as provided
241.12 - * by Oracle in the LICENSE file that accompanied this code.
241.13 - *
241.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
241.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
241.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
241.17 - * version 2 for more details (a copy is included in the LICENSE file that
241.18 - * accompanied this code).
241.19 - *
241.20 - * You should have received a copy of the GNU General Public License version
241.21 - * 2 along with this work; if not, write to the Free Software Foundation,
241.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
241.23 - *
241.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
241.25 - * or visit www.oracle.com if you need additional information or have any
241.26 - * questions.
241.27 - */
241.28 -
241.29 -package org.apidesign.javap;
241.30 -
241.31 -import static org.apidesign.javap.RuntimeConstants.ITEM_Integer;
241.32 -import static org.apidesign.javap.RuntimeConstants.ITEM_Float;
241.33 -import static org.apidesign.javap.RuntimeConstants.ITEM_Double;
241.34 -import static org.apidesign.javap.RuntimeConstants.ITEM_Long;
241.35 -import static org.apidesign.javap.RuntimeConstants.ITEM_Object;
241.36 -
241.37 -public final class StackMapIterator {
241.38 - private final StackMapTableData[] stackMapTable;
241.39 - private final TypeArray argTypes;
241.40 - private final TypeArray localTypes;
241.41 - private final TypeArray stackTypes;
241.42 -
241.43 - private int nextFrameIndex;
241.44 - private int lastFrameByteCodeOffset;
241.45 -
241.46 - private int byteCodeOffset;
241.47 -
241.48 - StackMapIterator(final MethodData methodData) {
241.49 - this(methodData.getStackMapTable(),
241.50 - methodData.getInternalSig(),
241.51 - methodData.isStatic());
241.52 - }
241.53 -
241.54 - StackMapIterator(final StackMapTableData[] stackMapTable,
241.55 - final String methodSignature,
241.56 - final boolean isStaticMethod) {
241.57 - this.stackMapTable = (stackMapTable != null)
241.58 - ? stackMapTable
241.59 - : new StackMapTableData[0];
241.60 -
241.61 - argTypes = getArgTypes(methodSignature, isStaticMethod);
241.62 - localTypes = new TypeArray();
241.63 - stackTypes = new TypeArray();
241.64 -
241.65 - localTypes.addAll(argTypes);
241.66 -
241.67 - lastFrameByteCodeOffset = -1;
241.68 - advanceBy(0);
241.69 - }
241.70 -
241.71 - public String getFrameAsString() {
241.72 - return (nextFrameIndex == 0)
241.73 - ? StackMapTableData.toString("INITIAL", 0, null, null)
241.74 - : stackMapTable[nextFrameIndex - 1].toString();
241.75 - }
241.76 -
241.77 - public int getFrameIndex() {
241.78 - return nextFrameIndex;
241.79 - }
241.80 -
241.81 - public TypeArray getFrameStack() {
241.82 - return stackTypes;
241.83 - }
241.84 -
241.85 - public TypeArray getFrameLocals() {
241.86 - return localTypes;
241.87 - }
241.88 -
241.89 - public TypeArray getArguments() {
241.90 - return argTypes;
241.91 - }
241.92 -
241.93 - public void advanceBy(final int numByteCodes) {
241.94 - if (numByteCodes < 0) {
241.95 - throw new IllegalStateException("Forward only iterator");
241.96 - }
241.97 -
241.98 - byteCodeOffset += numByteCodes;
241.99 - while ((nextFrameIndex < stackMapTable.length)
241.100 - && ((byteCodeOffset - lastFrameByteCodeOffset)
241.101 - >= (stackMapTable[nextFrameIndex].offsetDelta
241.102 - + 1))) {
241.103 - final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
241.104 -
241.105 - lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
241.106 - nextFrame.applyTo(localTypes, stackTypes);
241.107 -
241.108 - ++nextFrameIndex;
241.109 - }
241.110 - }
241.111 -
241.112 - public void advanceTo(final int nextByteCodeOffset) {
241.113 - advanceBy(nextByteCodeOffset - byteCodeOffset);
241.114 - }
241.115 -
241.116 - private static TypeArray getArgTypes(final String methodSignature,
241.117 - final boolean isStaticMethod) {
241.118 - final TypeArray argTypes = new TypeArray();
241.119 -
241.120 - if (!isStaticMethod) {
241.121 - argTypes.add(ITEM_Object);
241.122 - }
241.123 -
241.124 - if (methodSignature.charAt(0) != '(') {
241.125 - throw new IllegalArgumentException("Invalid method signature");
241.126 - }
241.127 -
241.128 - final int length = methodSignature.length();
241.129 - boolean skipType = false;
241.130 - int argType;
241.131 - for (int i = 1; i < length; ++i) {
241.132 - switch (methodSignature.charAt(i)) {
241.133 - case 'B':
241.134 - case 'C':
241.135 - case 'S':
241.136 - case 'Z':
241.137 - case 'I':
241.138 - argType = ITEM_Integer;
241.139 - break;
241.140 - case 'J':
241.141 - argType = ITEM_Long;
241.142 - break;
241.143 - case 'F':
241.144 - argType = ITEM_Float;
241.145 - break;
241.146 - case 'D':
241.147 - argType = ITEM_Double;
241.148 - break;
241.149 - case 'L': {
241.150 - i = methodSignature.indexOf(';', i + 1);
241.151 - if (i == -1) {
241.152 - throw new IllegalArgumentException(
241.153 - "Invalid method signature");
241.154 - }
241.155 - argType = ITEM_Object;
241.156 - break;
241.157 - }
241.158 - case ')':
241.159 - // not interested in the return value type
241.160 - return argTypes;
241.161 - case '[':
241.162 - if (!skipType) {
241.163 - argTypes.add(ITEM_Object);
241.164 - skipType = true;
241.165 - }
241.166 - continue;
241.167 -
241.168 - default:
241.169 - throw new IllegalArgumentException(
241.170 - "Invalid method signature");
241.171 - }
241.172 -
241.173 - if (!skipType) {
241.174 - argTypes.add(argType);
241.175 - } else {
241.176 - skipType = false;
241.177 - }
241.178 - }
241.179 -
241.180 - return argTypes;
241.181 - }
241.182 -}
242.1 --- a/rt/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Wed Feb 27 17:50:47 2013 +0100
242.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
242.3 @@ -1,223 +0,0 @@
242.4 -/*
242.5 - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
242.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
242.7 - *
242.8 - * This code is free software; you can redistribute it and/or modify it
242.9 - * under the terms of the GNU General Public License version 2 only, as
242.10 - * published by the Free Software Foundation. Oracle designates this
242.11 - * particular file as subject to the "Classpath" exception as provided
242.12 - * by Oracle in the LICENSE file that accompanied this code.
242.13 - *
242.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
242.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
242.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
242.17 - * version 2 for more details (a copy is included in the LICENSE file that
242.18 - * accompanied this code).
242.19 - *
242.20 - * You should have received a copy of the GNU General Public License version
242.21 - * 2 along with this work; if not, write to the Free Software Foundation,
242.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
242.23 - *
242.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
242.25 - * or visit www.oracle.com if you need additional information or have any
242.26 - * questions.
242.27 - */
242.28 -
242.29 -
242.30 -package org.apidesign.javap;
242.31 -
242.32 -import java.io.*;
242.33 -
242.34 -import static org.apidesign.javap.RuntimeConstants.*;
242.35 -
242.36 -/* represents one entry of StackMapTable attribute
242.37 - */
242.38 -abstract class StackMapTableData {
242.39 - final int frameType;
242.40 - int offsetDelta;
242.41 -
242.42 - StackMapTableData(int frameType) {
242.43 - this.frameType = frameType;
242.44 - }
242.45 -
242.46 - abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
242.47 -
242.48 - protected static String toString(
242.49 - final String frameType,
242.50 - final int offset,
242.51 - final int[] localTypes,
242.52 - final int[] stackTypes) {
242.53 - final StringBuilder sb = new StringBuilder(frameType);
242.54 -
242.55 - sb.append("(off: +").append(offset);
242.56 - if (localTypes != null) {
242.57 - sb.append(", locals: ");
242.58 - appendTypes(sb, localTypes);
242.59 - }
242.60 - if (stackTypes != null) {
242.61 - sb.append(", stack: ");
242.62 - appendTypes(sb, stackTypes);
242.63 - }
242.64 - sb.append(')');
242.65 -
242.66 - return sb.toString();
242.67 - }
242.68 -
242.69 - private static void appendTypes(final StringBuilder sb, final int[] types) {
242.70 - sb.append('[');
242.71 - if (types.length > 0) {
242.72 - sb.append(TypeArray.typeString(types[0]));
242.73 - for (int i = 1; i < types.length; ++i) {
242.74 - sb.append(", ");
242.75 - sb.append(TypeArray.typeString(types[i]));
242.76 - }
242.77 - }
242.78 - sb.append(']');
242.79 - }
242.80 -
242.81 - static class SameFrame extends StackMapTableData {
242.82 - SameFrame(int frameType, int offsetDelta) {
242.83 - super(frameType);
242.84 - this.offsetDelta = offsetDelta;
242.85 - }
242.86 -
242.87 - @Override
242.88 - void applyTo(TypeArray localTypes, TypeArray stackTypes) {
242.89 - stackTypes.clear();
242.90 - }
242.91 -
242.92 - @Override
242.93 - public String toString() {
242.94 - return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
242.95 - ? "_FRAME_EXTENDED" : ""),
242.96 - offsetDelta,
242.97 - null, null);
242.98 - }
242.99 - }
242.100 -
242.101 - static class SameLocals1StackItem extends StackMapTableData {
242.102 - final int[] stack;
242.103 - SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
242.104 - super(frameType);
242.105 - this.offsetDelta = offsetDelta;
242.106 - this.stack = stack;
242.107 - }
242.108 -
242.109 - @Override
242.110 - void applyTo(TypeArray localTypes, TypeArray stackTypes) {
242.111 - stackTypes.setAll(stack);
242.112 - }
242.113 -
242.114 - @Override
242.115 - public String toString() {
242.116 - return toString(
242.117 - "SAME_LOCALS_1_STACK_ITEM"
242.118 - + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
242.119 - ? "_EXTENDED" : ""),
242.120 - offsetDelta,
242.121 - null, stack);
242.122 - }
242.123 - }
242.124 -
242.125 - static class ChopFrame extends StackMapTableData {
242.126 - ChopFrame(int frameType, int offsetDelta) {
242.127 - super(frameType);
242.128 - this.offsetDelta = offsetDelta;
242.129 - }
242.130 -
242.131 - @Override
242.132 - void applyTo(TypeArray localTypes, TypeArray stackTypes) {
242.133 - localTypes.setSize(localTypes.getSize()
242.134 - - (SAME_FRAME_EXTENDED - frameType));
242.135 - stackTypes.clear();
242.136 - }
242.137 -
242.138 - @Override
242.139 - public String toString() {
242.140 - return toString("CHOP", offsetDelta, null, null);
242.141 - }
242.142 - }
242.143 -
242.144 - static class AppendFrame extends StackMapTableData {
242.145 - final int[] locals;
242.146 - AppendFrame(int frameType, int offsetDelta, int[] locals) {
242.147 - super(frameType);
242.148 - this.offsetDelta = offsetDelta;
242.149 - this.locals = locals;
242.150 - }
242.151 -
242.152 - @Override
242.153 - void applyTo(TypeArray localTypes, TypeArray stackTypes) {
242.154 - localTypes.addAll(locals);
242.155 - stackTypes.clear();
242.156 - }
242.157 -
242.158 - @Override
242.159 - public String toString() {
242.160 - return toString("APPEND", offsetDelta, locals, null);
242.161 - }
242.162 - }
242.163 -
242.164 - static class FullFrame extends StackMapTableData {
242.165 - final int[] locals;
242.166 - final int[] stack;
242.167 - FullFrame(int offsetDelta, int[] locals, int[] stack) {
242.168 - super(FULL_FRAME);
242.169 - this.offsetDelta = offsetDelta;
242.170 - this.locals = locals;
242.171 - this.stack = stack;
242.172 - }
242.173 -
242.174 - @Override
242.175 - void applyTo(TypeArray localTypes, TypeArray stackTypes) {
242.176 - localTypes.setAll(locals);
242.177 - stackTypes.setAll(stack);
242.178 - }
242.179 -
242.180 - @Override
242.181 - public String toString() {
242.182 - return toString("FULL", offsetDelta, locals, stack);
242.183 - }
242.184 - }
242.185 -
242.186 - static StackMapTableData getInstance(DataInputStream in, MethodData method)
242.187 - throws IOException {
242.188 - int frameType = in.readUnsignedByte();
242.189 -
242.190 - if (frameType < SAME_FRAME_BOUND) {
242.191 - // same_frame
242.192 - return new SameFrame(frameType, frameType);
242.193 - } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
242.194 - // same_locals_1_stack_item_frame
242.195 - // read additional single stack element
242.196 - return new SameLocals1StackItem(frameType,
242.197 - (frameType - SAME_FRAME_BOUND),
242.198 - StackMapData.readTypeArray(in, 1, method));
242.199 - } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
242.200 - // same_locals_1_stack_item_extended
242.201 - return new SameLocals1StackItem(frameType,
242.202 - in.readUnsignedShort(),
242.203 - StackMapData.readTypeArray(in, 1, method));
242.204 - } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
242.205 - // chop_frame or same_frame_extended
242.206 - return new ChopFrame(frameType, in.readUnsignedShort());
242.207 - } else if (frameType == SAME_FRAME_EXTENDED) {
242.208 - // chop_frame or same_frame_extended
242.209 - return new SameFrame(frameType, in.readUnsignedShort());
242.210 - } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
242.211 - // append_frame
242.212 - return new AppendFrame(frameType, in.readUnsignedShort(),
242.213 - StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
242.214 - } else if (frameType == FULL_FRAME) {
242.215 - // full_frame
242.216 - int offsetDelta = in.readUnsignedShort();
242.217 - int locals_size = in.readUnsignedShort();
242.218 - int[] locals = StackMapData.readTypeArray(in, locals_size, method);
242.219 - int stack_size = in.readUnsignedShort();
242.220 - int[] stack = StackMapData.readTypeArray(in, stack_size, method);
242.221 - return new FullFrame(offsetDelta, locals, stack);
242.222 - } else {
242.223 - throw new ClassFormatError("unrecognized frame_type in StackMapTable");
242.224 - }
242.225 - }
242.226 -}
243.1 --- a/rt/javap/src/main/java/org/apidesign/javap/TrapData.java Wed Feb 27 17:50:47 2013 +0100
243.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
243.3 @@ -1,62 +0,0 @@
243.4 -/*
243.5 - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
243.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
243.7 - *
243.8 - * This code is free software; you can redistribute it and/or modify it
243.9 - * under the terms of the GNU General Public License version 2 only, as
243.10 - * published by the Free Software Foundation. Oracle designates this
243.11 - * particular file as subject to the "Classpath" exception as provided
243.12 - * by Oracle in the LICENSE file that accompanied this code.
243.13 - *
243.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
243.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
243.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
243.17 - * version 2 for more details (a copy is included in the LICENSE file that
243.18 - * accompanied this code).
243.19 - *
243.20 - * You should have received a copy of the GNU General Public License version
243.21 - * 2 along with this work; if not, write to the Free Software Foundation,
243.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
243.23 - *
243.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
243.25 - * or visit www.oracle.com if you need additional information or have any
243.26 - * questions.
243.27 - */
243.28 -
243.29 -
243.30 -package org.apidesign.javap;
243.31 -
243.32 -import java.io.*;
243.33 -
243.34 -/**
243.35 - * Stores exception table data in code attribute.
243.36 - *
243.37 - * @author Sucheta Dambalkar (Adopted code from jdis)
243.38 - */
243.39 -public final class TrapData {
243.40 - public final short start_pc;
243.41 - public final short end_pc;
243.42 - public final short handler_pc;
243.43 - public final short catch_cpx;
243.44 - final int num;
243.45 -
243.46 -
243.47 - /**
243.48 - * Read and store exception table data in code attribute.
243.49 - */
243.50 - TrapData(DataInputStream in, int num) throws IOException {
243.51 - this.num=num;
243.52 - start_pc = in.readShort();
243.53 - end_pc=in.readShort();
243.54 - handler_pc=in.readShort();
243.55 - catch_cpx=in.readShort();
243.56 - }
243.57 -
243.58 - /**
243.59 - * returns recommended identifier
243.60 - */
243.61 - public String ident() {
243.62 - return "t"+num;
243.63 - }
243.64 -
243.65 -}
244.1 --- a/rt/javap/src/main/java/org/apidesign/javap/TrapDataIterator.java Wed Feb 27 17:50:47 2013 +0100
244.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
244.3 @@ -1,114 +0,0 @@
244.4 -/**
244.5 - * Back 2 Browser Bytecode Translator
244.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
244.7 - *
244.8 - * This program is free software: you can redistribute it and/or modify
244.9 - * it under the terms of the GNU General Public License as published by
244.10 - * the Free Software Foundation, version 2 of the License.
244.11 - *
244.12 - * This program is distributed in the hope that it will be useful,
244.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
244.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
244.15 - * GNU General Public License for more details.
244.16 - *
244.17 - * You should have received a copy of the GNU General Public License
244.18 - * along with this program. Look for COPYING file in the top folder.
244.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
244.20 - */
244.21 -package org.apidesign.javap;
244.22 -
244.23 -/**
244.24 - *
244.25 - * @author Jaroslav Tulach <jtulach@netbeans.org>
244.26 - */
244.27 -public final class TrapDataIterator {
244.28 - private final Hashtable exStart = new Hashtable();
244.29 - private final Hashtable exStop = new Hashtable();
244.30 - private TrapData[] current = new TrapData[10];
244.31 - private int currentCount;
244.32 -
244.33 - TrapDataIterator(Vector exceptionTable) {
244.34 - for (int i=0 ; i < exceptionTable.size(); i++) {
244.35 - final TrapData td = (TrapData)exceptionTable.elementAt(i);
244.36 - put(exStart, td.start_pc, td);
244.37 - put(exStop, td.end_pc, td);
244.38 - }
244.39 - }
244.40 -
244.41 - private static void put(Hashtable h, short key, TrapData td) {
244.42 - Short s = Short.valueOf((short)key);
244.43 - Vector v = (Vector) h.get(s);
244.44 - if (v == null) {
244.45 - v = new Vector(1);
244.46 - h.put(s, v);
244.47 - }
244.48 - v.add(td);
244.49 - }
244.50 -
244.51 - private boolean processAll(Hashtable h, Short key, boolean add) {
244.52 - boolean change = false;
244.53 - Vector v = (Vector)h.get(key);
244.54 - if (v != null) {
244.55 - int s = v.size();
244.56 - for (int i = 0; i < s; i++) {
244.57 - TrapData td = (TrapData)v.elementAt(i);
244.58 - if (add) {
244.59 - add(td);
244.60 - change = true;
244.61 - } else {
244.62 - remove(td);
244.63 - change = true;
244.64 - }
244.65 - }
244.66 - }
244.67 - return change;
244.68 - }
244.69 -
244.70 - public boolean advanceTo(int i) {
244.71 - Short s = Short.valueOf((short)i);
244.72 - boolean ch1 = processAll(exStart, s, true);
244.73 - boolean ch2 = processAll(exStop, s, false);
244.74 - return ch1 || ch2;
244.75 - }
244.76 -
244.77 - public boolean useTry() {
244.78 - return currentCount > 0;
244.79 - }
244.80 -
244.81 - public TrapData[] current() {
244.82 - TrapData[] copy = new TrapData[currentCount];
244.83 - for (int i = 0; i < currentCount; i++) {
244.84 - copy[i] = current[i];
244.85 - }
244.86 - return copy;
244.87 - }
244.88 -
244.89 - private void add(TrapData e) {
244.90 - if (currentCount == current.length) {
244.91 - TrapData[] data = new TrapData[currentCount * 2];
244.92 - for (int i = 0; i < currentCount; i++) {
244.93 - data[i] = current[i];
244.94 - }
244.95 - current = data;
244.96 - }
244.97 - current[currentCount++] = e;
244.98 - }
244.99 -
244.100 - private void remove(TrapData e) {
244.101 - if (currentCount == 0) {
244.102 - return;
244.103 - }
244.104 - int from = 0;
244.105 - while (from < currentCount) {
244.106 - if (e == current[from++]) {
244.107 - break;
244.108 - }
244.109 - }
244.110 - while (from < currentCount) {
244.111 - current[from - 1] = current[from];
244.112 - current[from] = null;
244.113 - from++;
244.114 - }
244.115 - currentCount--;
244.116 - }
244.117 -}
245.1 --- a/rt/javap/src/main/java/org/apidesign/javap/TypeArray.java Wed Feb 27 17:50:47 2013 +0100
245.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
245.3 @@ -1,186 +0,0 @@
245.4 -/*
245.5 - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
245.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
245.7 - *
245.8 - * This code is free software; you can redistribute it and/or modify it
245.9 - * under the terms of the GNU General Public License version 2 only, as
245.10 - * published by the Free Software Foundation. Oracle designates this
245.11 - * particular file as subject to the "Classpath" exception as provided
245.12 - * by Oracle in the LICENSE file that accompanied this code.
245.13 - *
245.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
245.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
245.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
245.17 - * version 2 for more details (a copy is included in the LICENSE file that
245.18 - * accompanied this code).
245.19 - *
245.20 - * You should have received a copy of the GNU General Public License version
245.21 - * 2 along with this work; if not, write to the Free Software Foundation,
245.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
245.23 - *
245.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
245.25 - * or visit www.oracle.com if you need additional information or have any
245.26 - * questions.
245.27 - */
245.28 -
245.29 -package org.apidesign.javap;
245.30 -
245.31 -import static org.apidesign.javap.RuntimeConstants.ITEM_Bogus;
245.32 -import static org.apidesign.javap.RuntimeConstants.ITEM_Integer;
245.33 -import static org.apidesign.javap.RuntimeConstants.ITEM_Float;
245.34 -import static org.apidesign.javap.RuntimeConstants.ITEM_Double;
245.35 -import static org.apidesign.javap.RuntimeConstants.ITEM_Long;
245.36 -import static org.apidesign.javap.RuntimeConstants.ITEM_Null;
245.37 -import static org.apidesign.javap.RuntimeConstants.ITEM_InitObject;
245.38 -import static org.apidesign.javap.RuntimeConstants.ITEM_Object;
245.39 -import static org.apidesign.javap.RuntimeConstants.ITEM_NewObject;
245.40 -
245.41 -public final class TypeArray {
245.42 - private static final int CAPACITY_INCREMENT = 16;
245.43 -
245.44 - private int[] types;
245.45 - private int size;
245.46 -
245.47 - public TypeArray() {
245.48 - }
245.49 -
245.50 - public TypeArray(final TypeArray initialTypes) {
245.51 - setAll(initialTypes);
245.52 - }
245.53 -
245.54 - public void add(final int newType) {
245.55 - ensureCapacity(size + 1);
245.56 - types[size++] = newType;
245.57 - }
245.58 -
245.59 - public void addAll(final TypeArray newTypes) {
245.60 - addAll(newTypes.types, 0, newTypes.size);
245.61 - }
245.62 -
245.63 - public void addAll(final int[] newTypes) {
245.64 - addAll(newTypes, 0, newTypes.length);
245.65 - }
245.66 -
245.67 - public void addAll(final int[] newTypes,
245.68 - final int offset,
245.69 - final int count) {
245.70 - if (count > 0) {
245.71 - ensureCapacity(size + count);
245.72 - arraycopy(newTypes, offset, types, size, count);
245.73 - size += count;
245.74 - }
245.75 - }
245.76 -
245.77 - public void set(final int index, final int newType) {
245.78 - types[index] = newType;
245.79 - }
245.80 -
245.81 - public void setAll(final TypeArray newTypes) {
245.82 - setAll(newTypes.types, 0, newTypes.size);
245.83 - }
245.84 -
245.85 - public void setAll(final int[] newTypes) {
245.86 - setAll(newTypes, 0, newTypes.length);
245.87 - }
245.88 -
245.89 - public void setAll(final int[] newTypes,
245.90 - final int offset,
245.91 - final int count) {
245.92 - if (count > 0) {
245.93 - ensureCapacity(count);
245.94 - arraycopy(newTypes, offset, types, 0, count);
245.95 - size = count;
245.96 - } else {
245.97 - clear();
245.98 - }
245.99 - }
245.100 -
245.101 - public void setSize(final int newSize) {
245.102 - if (size != newSize) {
245.103 - ensureCapacity(newSize);
245.104 -
245.105 - for (int i = size; i < newSize; ++i) {
245.106 - types[i] = 0;
245.107 - }
245.108 - size = newSize;
245.109 - }
245.110 - }
245.111 -
245.112 - public void clear() {
245.113 - size = 0;
245.114 - }
245.115 -
245.116 - public int getSize() {
245.117 - return size;
245.118 - }
245.119 -
245.120 - public int get(final int index) {
245.121 - return types[index];
245.122 - }
245.123 -
245.124 - public static String typeString(final int type) {
245.125 - switch (type & 0xff) {
245.126 - case ITEM_Bogus:
245.127 - return "_top_";
245.128 - case ITEM_Integer:
245.129 - return "_int_";
245.130 - case ITEM_Float:
245.131 - return "_float_";
245.132 - case ITEM_Double:
245.133 - return "_double_";
245.134 - case ITEM_Long:
245.135 - return "_long_";
245.136 - case ITEM_Null:
245.137 - return "_null_";
245.138 - case ITEM_InitObject: // UninitializedThis
245.139 - return "_init_";
245.140 - case ITEM_Object:
245.141 - return "_object_";
245.142 - case ITEM_NewObject: // Uninitialized
245.143 - return "_new_";
245.144 - default:
245.145 - throw new IllegalArgumentException("Unknown type");
245.146 - }
245.147 - }
245.148 -
245.149 - @Override
245.150 - public String toString() {
245.151 - final StringBuilder sb = new StringBuilder("[");
245.152 - if (size > 0) {
245.153 - sb.append(typeString(types[0]));
245.154 - for (int i = 1; i < size; ++i) {
245.155 - sb.append(", ");
245.156 - sb.append(typeString(types[i]));
245.157 - }
245.158 - }
245.159 -
245.160 - return sb.append(']').toString();
245.161 - }
245.162 -
245.163 - private void ensureCapacity(final int minCapacity) {
245.164 - if ((minCapacity == 0)
245.165 - || (types != null) && (minCapacity <= types.length)) {
245.166 - return;
245.167 - }
245.168 -
245.169 - final int newCapacity =
245.170 - ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
245.171 - * CAPACITY_INCREMENT;
245.172 - final int[] newTypes = new int[newCapacity];
245.173 -
245.174 - if (size > 0) {
245.175 - arraycopy(types, 0, newTypes, 0, size);
245.176 - }
245.177 -
245.178 - types = newTypes;
245.179 - }
245.180 -
245.181 - // no System.arraycopy
245.182 - private void arraycopy(final int[] src, final int srcPos,
245.183 - final int[] dest, final int destPos,
245.184 - final int length) {
245.185 - for (int i = 0; i < length; ++i) {
245.186 - dest[destPos + i] = src[srcPos + i];
245.187 - }
245.188 - }
245.189 -}
246.1 --- a/rt/javap/src/main/java/org/apidesign/javap/Vector.java Wed Feb 27 17:50:47 2013 +0100
246.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
246.3 @@ -1,89 +0,0 @@
246.4 -/**
246.5 - * Back 2 Browser Bytecode Translator
246.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
246.7 - *
246.8 - * This program is free software: you can redistribute it and/or modify
246.9 - * it under the terms of the GNU General Public License as published by
246.10 - * the Free Software Foundation, version 2 of the License.
246.11 - *
246.12 - * This program is distributed in the hope that it will be useful,
246.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
246.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
246.15 - * GNU General Public License for more details.
246.16 - *
246.17 - * You should have received a copy of the GNU General Public License
246.18 - * along with this program. Look for COPYING file in the top folder.
246.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
246.20 - */
246.21 -package org.apidesign.javap;
246.22 -
246.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
246.24 -import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
246.25 -
246.26 -/** A JavaScript ready replacement for java.util.Vector
246.27 - *
246.28 - * @author Jaroslav Tulach <jtulach@netbeans.org>
246.29 - */
246.30 -@JavaScriptPrototype(prototype = "new Array" )
246.31 -final class Vector {
246.32 - private Object[] arr;
246.33 -
246.34 - Vector() {
246.35 - }
246.36 -
246.37 - Vector(int i) {
246.38 - }
246.39 -
246.40 - void add(Object objectType) {
246.41 - addElement(objectType);
246.42 - }
246.43 - @JavaScriptBody(args = { "obj" }, body =
246.44 - "this.push(obj);"
246.45 - )
246.46 - void addElement(Object obj) {
246.47 - final int s = size();
246.48 - setSize(s + 1);
246.49 - setElementAt(obj, s);
246.50 - }
246.51 -
246.52 - @JavaScriptBody(args = { }, body =
246.53 - "return this.length;"
246.54 - )
246.55 - int size() {
246.56 - return arr == null ? 0 : arr.length;
246.57 - }
246.58 -
246.59 - @JavaScriptBody(args = { "newArr" }, body =
246.60 - "for (var i = 0; i < this.length; i++) {\n"
246.61 - + " newArr[i] = this[i];\n"
246.62 - + "}\n")
246.63 - void copyInto(Object[] newArr) {
246.64 - if (arr == null) {
246.65 - return;
246.66 - }
246.67 - int min = Math.min(newArr.length, arr.length);
246.68 - for (int i = 0; i < min; i++) {
246.69 - newArr[i] = arr[i];
246.70 - }
246.71 - }
246.72 -
246.73 - @JavaScriptBody(args = { "index" }, body =
246.74 - "return this[index];"
246.75 - )
246.76 - Object elementAt(int index) {
246.77 - return arr[index];
246.78 - }
246.79 -
246.80 - private void setSize(int len) {
246.81 - Object[] newArr = new Object[len];
246.82 - copyInto(newArr);
246.83 - arr = newArr;
246.84 - }
246.85 -
246.86 - @JavaScriptBody(args = { "val", "index" }, body =
246.87 - "this[index] = val;"
246.88 - )
246.89 - void setElementAt(Object val, int index) {
246.90 - arr[index] = val;
246.91 - }
246.92 -}
247.1 --- a/rt/launcher/pom.xml Wed Feb 27 17:50:47 2013 +0100
247.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
247.3 @@ -1,57 +0,0 @@
247.4 -<?xml version="1.0"?>
247.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
247.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
247.7 - <modelVersion>4.0.0</modelVersion>
247.8 - <parent>
247.9 - <groupId>org.apidesign.bck2brwsr</groupId>
247.10 - <artifactId>rt</artifactId>
247.11 - <version>0.3-SNAPSHOT</version>
247.12 - </parent>
247.13 - <groupId>org.apidesign.bck2brwsr</groupId>
247.14 - <artifactId>launcher</artifactId>
247.15 - <version>0.3-SNAPSHOT</version>
247.16 - <name>Bck2Brwsr Launcher</name>
247.17 - <url>http://maven.apache.org</url>
247.18 - <build>
247.19 - <plugins>
247.20 - <plugin>
247.21 - <groupId>org.apache.maven.plugins</groupId>
247.22 - <artifactId>maven-compiler-plugin</artifactId>
247.23 - <version>2.3.2</version>
247.24 - <configuration>
247.25 - <source>1.7</source>
247.26 - <target>1.7</target>
247.27 - </configuration>
247.28 - </plugin>
247.29 - <plugin>
247.30 - <groupId>org.apache.maven.plugins</groupId>
247.31 - <artifactId>maven-javadoc-plugin</artifactId>
247.32 - <version>2.8.1</version>
247.33 - <configuration>
247.34 - <excludePackageNames>org.apidesign.bck2brwsr.launcher.impl</excludePackageNames>
247.35 - </configuration>
247.36 - </plugin>
247.37 - </plugins>
247.38 - </build>
247.39 - <properties>
247.40 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
247.41 - </properties>
247.42 - <dependencies>
247.43 - <dependency>
247.44 - <groupId>junit</groupId>
247.45 - <artifactId>junit</artifactId>
247.46 - <version>3.8.1</version>
247.47 - <scope>test</scope>
247.48 - </dependency>
247.49 - <dependency>
247.50 - <groupId>org.glassfish.grizzly</groupId>
247.51 - <artifactId>grizzly-http-server</artifactId>
247.52 - <version>2.2.19</version>
247.53 - </dependency>
247.54 - <dependency>
247.55 - <groupId>${project.groupId}</groupId>
247.56 - <artifactId>vm4brwsr</artifactId>
247.57 - <version>${project.version}</version>
247.58 - </dependency>
247.59 - </dependencies>
247.60 -</project>
248.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Wed Feb 27 17:50:47 2013 +0100
248.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
248.3 @@ -1,559 +0,0 @@
248.4 -/**
248.5 - * Back 2 Browser Bytecode Translator
248.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
248.7 - *
248.8 - * This program is free software: you can redistribute it and/or modify
248.9 - * it under the terms of the GNU General Public License as published by
248.10 - * the Free Software Foundation, version 2 of the License.
248.11 - *
248.12 - * This program is distributed in the hope that it will be useful,
248.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
248.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
248.15 - * GNU General Public License for more details.
248.16 - *
248.17 - * You should have received a copy of the GNU General Public License
248.18 - * along with this program. Look for COPYING file in the top folder.
248.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
248.20 - */
248.21 -package org.apidesign.bck2brwsr.launcher;
248.22 -
248.23 -import java.io.Closeable;
248.24 -import java.io.File;
248.25 -import java.io.IOException;
248.26 -import java.io.InputStream;
248.27 -import java.io.InterruptedIOException;
248.28 -import java.io.OutputStream;
248.29 -import java.io.Writer;
248.30 -import java.net.URI;
248.31 -import java.net.URISyntaxException;
248.32 -import java.net.URL;
248.33 -import java.util.ArrayList;
248.34 -import java.util.Arrays;
248.35 -import java.util.Enumeration;
248.36 -import java.util.LinkedHashSet;
248.37 -import java.util.List;
248.38 -import java.util.Set;
248.39 -import java.util.concurrent.BlockingQueue;
248.40 -import java.util.concurrent.CountDownLatch;
248.41 -import java.util.concurrent.LinkedBlockingQueue;
248.42 -import java.util.concurrent.TimeUnit;
248.43 -import java.util.logging.Level;
248.44 -import java.util.logging.Logger;
248.45 -import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource;
248.46 -import org.apidesign.vm4brwsr.Bck2Brwsr;
248.47 -import org.glassfish.grizzly.PortRange;
248.48 -import org.glassfish.grizzly.http.server.HttpHandler;
248.49 -import org.glassfish.grizzly.http.server.HttpServer;
248.50 -import org.glassfish.grizzly.http.server.NetworkListener;
248.51 -import org.glassfish.grizzly.http.server.Request;
248.52 -import org.glassfish.grizzly.http.server.Response;
248.53 -import org.glassfish.grizzly.http.server.ServerConfiguration;
248.54 -import org.glassfish.grizzly.http.util.HttpStatus;
248.55 -
248.56 -/**
248.57 - * Lightweight server to launch Bck2Brwsr applications and tests.
248.58 - * Supports execution in native browser as well as Java's internal
248.59 - * execution engine.
248.60 - */
248.61 -final class Bck2BrwsrLauncher extends Launcher implements Closeable {
248.62 - private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
248.63 - private static final InvocationContext END = new InvocationContext(null, null, null);
248.64 - private final Set<ClassLoader> loaders = new LinkedHashSet<>();
248.65 - private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<>();
248.66 - private long timeOut;
248.67 - private final Res resources = new Res();
248.68 - private final String cmd;
248.69 - private Object[] brwsr;
248.70 - private HttpServer server;
248.71 - private CountDownLatch wait;
248.72 -
248.73 - public Bck2BrwsrLauncher(String cmd) {
248.74 - this.cmd = cmd;
248.75 - }
248.76 -
248.77 - @Override
248.78 - InvocationContext runMethod(InvocationContext c) throws IOException {
248.79 - loaders.add(c.clazz.getClassLoader());
248.80 - methods.add(c);
248.81 - try {
248.82 - c.await(timeOut);
248.83 - } catch (InterruptedException ex) {
248.84 - throw new IOException(ex);
248.85 - }
248.86 - return c;
248.87 - }
248.88 -
248.89 - public void setTimeout(long ms) {
248.90 - timeOut = ms;
248.91 - }
248.92 -
248.93 - public void addClassLoader(ClassLoader url) {
248.94 - this.loaders.add(url);
248.95 - }
248.96 -
248.97 - public void showURL(String startpage) throws IOException {
248.98 - if (!startpage.startsWith("/")) {
248.99 - startpage = "/" + startpage;
248.100 - }
248.101 - HttpServer s = initServer(".", true);
248.102 - int last = startpage.lastIndexOf('/');
248.103 - String simpleName = startpage.substring(last);
248.104 - s.getServerConfiguration().addHttpHandler(new Page(resources, startpage), simpleName);
248.105 - s.getServerConfiguration().addHttpHandler(new Page(resources, null), "/");
248.106 - try {
248.107 - launchServerAndBrwsr(s, simpleName);
248.108 - } catch (URISyntaxException | InterruptedException ex) {
248.109 - throw new IOException(ex);
248.110 - }
248.111 - }
248.112 -
248.113 - void showDirectory(File dir, String startpage) throws IOException {
248.114 - if (!startpage.startsWith("/")) {
248.115 - startpage = "/" + startpage;
248.116 - }
248.117 - HttpServer s = initServer(dir.getPath(), false);
248.118 - try {
248.119 - launchServerAndBrwsr(s, startpage);
248.120 - } catch (URISyntaxException | InterruptedException ex) {
248.121 - throw new IOException(ex);
248.122 - }
248.123 - }
248.124 -
248.125 - @Override
248.126 - public void initialize() throws IOException {
248.127 - try {
248.128 - executeInBrowser();
248.129 - } catch (InterruptedException ex) {
248.130 - final InterruptedIOException iio = new InterruptedIOException(ex.getMessage());
248.131 - iio.initCause(ex);
248.132 - throw iio;
248.133 - } catch (Exception ex) {
248.134 - if (ex instanceof IOException) {
248.135 - throw (IOException)ex;
248.136 - }
248.137 - if (ex instanceof RuntimeException) {
248.138 - throw (RuntimeException)ex;
248.139 - }
248.140 - throw new IOException(ex);
248.141 - }
248.142 - }
248.143 -
248.144 - private HttpServer initServer(String path, boolean addClasses) throws IOException {
248.145 - HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535));
248.146 -
248.147 - final ServerConfiguration conf = s.getServerConfiguration();
248.148 - if (addClasses) {
248.149 - conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
248.150 - conf.addHttpHandler(new Classes(resources), "/classes/");
248.151 - }
248.152 - return s;
248.153 - }
248.154 -
248.155 - private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
248.156 - wait = new CountDownLatch(1);
248.157 - server = initServer(".", true);
248.158 - final ServerConfiguration conf = server.getServerConfiguration();
248.159 -
248.160 - class DynamicResourceHandler extends HttpHandler {
248.161 - private final InvocationContext ic;
248.162 - public DynamicResourceHandler(InvocationContext ic) {
248.163 - if (ic == null || ic.resources.isEmpty()) {
248.164 - throw new NullPointerException();
248.165 - }
248.166 - this.ic = ic;
248.167 - for (Resource r : ic.resources) {
248.168 - conf.addHttpHandler(this, r.httpPath);
248.169 - }
248.170 - }
248.171 -
248.172 - public void close() {
248.173 - conf.removeHttpHandler(this);
248.174 - }
248.175 -
248.176 - @Override
248.177 - public void service(Request request, Response response) throws Exception {
248.178 - for (Resource r : ic.resources) {
248.179 - if (r.httpPath.equals(request.getRequestURI())) {
248.180 - LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI());
248.181 - response.setContentType(r.httpType);
248.182 - copyStream(r.httpContent, response.getOutputStream(), null);
248.183 - }
248.184 - }
248.185 - }
248.186 - }
248.187 -
248.188 - conf.addHttpHandler(new Page(resources,
248.189 - "org/apidesign/bck2brwsr/launcher/harness.xhtml"
248.190 - ), "/execute");
248.191 -
248.192 - conf.addHttpHandler(new HttpHandler() {
248.193 - int cnt;
248.194 - List<InvocationContext> cases = new ArrayList<>();
248.195 - DynamicResourceHandler prev;
248.196 - @Override
248.197 - public void service(Request request, Response response) throws Exception {
248.198 - String id = request.getParameter("request");
248.199 - String value = request.getParameter("result");
248.200 -
248.201 -
248.202 - InvocationContext mi = null;
248.203 - int caseNmbr = -1;
248.204 -
248.205 - if (id != null && value != null) {
248.206 - LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value});
248.207 - value = decodeURL(value);
248.208 - int indx = Integer.parseInt(id);
248.209 - cases.get(indx).result(value, null);
248.210 - if (++indx < cases.size()) {
248.211 - mi = cases.get(indx);
248.212 - LOG.log(Level.INFO, "Re-executing case {0}", indx);
248.213 - caseNmbr = indx;
248.214 - }
248.215 - } else {
248.216 - if (!cases.isEmpty()) {
248.217 - LOG.info("Re-executing test cases");
248.218 - mi = cases.get(0);
248.219 - caseNmbr = 0;
248.220 - }
248.221 - }
248.222 -
248.223 - if (prev != null) {
248.224 - prev.close();
248.225 - prev = null;
248.226 - }
248.227 -
248.228 - if (mi == null) {
248.229 - mi = methods.take();
248.230 - caseNmbr = cnt++;
248.231 - }
248.232 - if (mi == END) {
248.233 - response.getWriter().write("");
248.234 - wait.countDown();
248.235 - cnt = 0;
248.236 - LOG.log(Level.INFO, "End of data reached. Exiting.");
248.237 - return;
248.238 - }
248.239 -
248.240 - if (!mi.resources.isEmpty()) {
248.241 - prev = new DynamicResourceHandler(mi);
248.242 - }
248.243 -
248.244 - cases.add(mi);
248.245 - final String cn = mi.clazz.getName();
248.246 - final String mn = mi.methodName;
248.247 - LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn});
248.248 - response.getWriter().write("{"
248.249 - + "className: '" + cn + "', "
248.250 - + "methodName: '" + mn + "', "
248.251 - + "request: " + caseNmbr
248.252 - );
248.253 - if (mi.html != null) {
248.254 - response.getWriter().write(", html: '");
248.255 - response.getWriter().write(encodeJSON(mi.html));
248.256 - response.getWriter().write("'");
248.257 - }
248.258 - response.getWriter().write("}");
248.259 - }
248.260 - }, "/data");
248.261 -
248.262 - this.brwsr = launchServerAndBrwsr(server, "/execute");
248.263 - }
248.264 -
248.265 - private static String encodeJSON(String in) {
248.266 - StringBuilder sb = new StringBuilder();
248.267 - for (int i = 0; i < in.length(); i++) {
248.268 - char ch = in.charAt(i);
248.269 - if (ch < 32 || ch == '\'' || ch == '"') {
248.270 - sb.append("\\u");
248.271 - String hs = "0000" + Integer.toHexString(ch);
248.272 - hs = hs.substring(hs.length() - 4);
248.273 - sb.append(hs);
248.274 - } else {
248.275 - sb.append(ch);
248.276 - }
248.277 - }
248.278 - return sb.toString();
248.279 - }
248.280 -
248.281 - @Override
248.282 - public void shutdown() throws IOException {
248.283 - methods.offer(END);
248.284 - for (;;) {
248.285 - int prev = methods.size();
248.286 - try {
248.287 - if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) {
248.288 - break;
248.289 - }
248.290 - } catch (InterruptedException ex) {
248.291 - throw new IOException(ex);
248.292 - }
248.293 - if (prev == methods.size()) {
248.294 - LOG.log(
248.295 - Level.WARNING,
248.296 - "Timeout and no test has been executed meanwhile (at {0}). Giving up.",
248.297 - methods.size()
248.298 - );
248.299 - break;
248.300 - }
248.301 - LOG.log(Level.INFO,
248.302 - "Timeout, but tests got from {0} to {1}. Trying again.",
248.303 - new Object[]{prev, methods.size()}
248.304 - );
248.305 - }
248.306 - stopServerAndBrwsr(server, brwsr);
248.307 - }
248.308 -
248.309 - static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
248.310 - for (;;) {
248.311 - int ch = is.read();
248.312 - if (ch == -1) {
248.313 - break;
248.314 - }
248.315 - if (ch == '$' && params.length > 0) {
248.316 - int cnt = is.read() - '0';
248.317 - if (cnt == 'U' - '0') {
248.318 - os.write(baseURL.getBytes("UTF-8"));
248.319 - }
248.320 - if (cnt >= 0 && cnt < params.length) {
248.321 - os.write(params[cnt].getBytes("UTF-8"));
248.322 - }
248.323 - } else {
248.324 - os.write(ch);
248.325 - }
248.326 - }
248.327 - }
248.328 -
248.329 - private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
248.330 - server.start();
248.331 - NetworkListener listener = server.getListeners().iterator().next();
248.332 - int port = listener.getPort();
248.333 -
248.334 - URI uri = new URI("http://localhost:" + port + page);
248.335 - LOG.log(Level.INFO, "Showing {0}", uri);
248.336 - if (cmd == null) {
248.337 - try {
248.338 - LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
248.339 - System.getProperty("java.vm.name"),
248.340 - System.getProperty("java.vm.vendor"),
248.341 - System.getProperty("java.vm.version"),
248.342 - });
248.343 - java.awt.Desktop.getDesktop().browse(uri);
248.344 - LOG.log(Level.INFO, "Desktop.browse successfully finished");
248.345 - return null;
248.346 - } catch (UnsupportedOperationException ex) {
248.347 - LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
248.348 - LOG.log(Level.FINE, null, ex);
248.349 - }
248.350 - }
248.351 - {
248.352 - String cmdName = cmd == null ? "xdg-open" : cmd;
248.353 - String[] cmdArr = {
248.354 - cmdName, uri.toString()
248.355 - };
248.356 - LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
248.357 - final Process process = Runtime.getRuntime().exec(cmdArr);
248.358 - return new Object[] { process, null };
248.359 - }
248.360 - }
248.361 -
248.362 - private static String decodeURL(String s) {
248.363 - for (;;) {
248.364 - int pos = s.indexOf('%');
248.365 - if (pos == -1) {
248.366 - return s;
248.367 - }
248.368 - int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16);
248.369 - s = s.substring(0, pos) + (char)i + s.substring(pos + 2);
248.370 - }
248.371 - }
248.372 -
248.373 - private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException {
248.374 - if (brwsr == null) {
248.375 - return;
248.376 - }
248.377 - Process process = (Process)brwsr[0];
248.378 -
248.379 - server.stop();
248.380 - InputStream stdout = process.getInputStream();
248.381 - InputStream stderr = process.getErrorStream();
248.382 - drain("StdOut", stdout);
248.383 - drain("StdErr", stderr);
248.384 - process.destroy();
248.385 - int res;
248.386 - try {
248.387 - res = process.waitFor();
248.388 - } catch (InterruptedException ex) {
248.389 - throw new IOException(ex);
248.390 - }
248.391 - LOG.log(Level.INFO, "Exit code: {0}", res);
248.392 -
248.393 - deleteTree((File)brwsr[1]);
248.394 - }
248.395 -
248.396 - private static void drain(String name, InputStream is) throws IOException {
248.397 - int av = is.available();
248.398 - if (av > 0) {
248.399 - StringBuilder sb = new StringBuilder();
248.400 - sb.append("v== ").append(name).append(" ==v\n");
248.401 - while (av-- > 0) {
248.402 - sb.append((char)is.read());
248.403 - }
248.404 - sb.append("\n^== ").append(name).append(" ==^");
248.405 - LOG.log(Level.INFO, sb.toString());
248.406 - }
248.407 - }
248.408 -
248.409 - private void deleteTree(File file) {
248.410 - if (file == null) {
248.411 - return;
248.412 - }
248.413 - File[] arr = file.listFiles();
248.414 - if (arr != null) {
248.415 - for (File s : arr) {
248.416 - deleteTree(s);
248.417 - }
248.418 - }
248.419 - file.delete();
248.420 - }
248.421 -
248.422 - @Override
248.423 - public void close() throws IOException {
248.424 - shutdown();
248.425 - }
248.426 -
248.427 - private class Res implements Bck2Brwsr.Resources {
248.428 - @Override
248.429 - public InputStream get(String resource) throws IOException {
248.430 - for (ClassLoader l : loaders) {
248.431 - URL u = null;
248.432 - Enumeration<URL> en = l.getResources(resource);
248.433 - while (en.hasMoreElements()) {
248.434 - u = en.nextElement();
248.435 - }
248.436 - if (u != null) {
248.437 - return u.openStream();
248.438 - }
248.439 - }
248.440 - throw new IOException("Can't find " + resource);
248.441 - }
248.442 - }
248.443 -
248.444 - private static class Page extends HttpHandler {
248.445 - private final String resource;
248.446 - private final String[] args;
248.447 - private final Res res;
248.448 -
248.449 - public Page(Res res, String resource, String... args) {
248.450 - this.res = res;
248.451 - this.resource = resource;
248.452 - this.args = args.length == 0 ? new String[] { "$0" } : args;
248.453 - }
248.454 -
248.455 - @Override
248.456 - public void service(Request request, Response response) throws Exception {
248.457 - String r = resource;
248.458 - if (r == null) {
248.459 - r = request.getHttpHandlerPath();
248.460 - }
248.461 - if (r.startsWith("/")) {
248.462 - r = r.substring(1);
248.463 - }
248.464 - String[] replace = {};
248.465 - if (r.endsWith(".html")) {
248.466 - response.setContentType("text/html");
248.467 - LOG.info("Content type text/html");
248.468 - replace = args;
248.469 - }
248.470 - if (r.endsWith(".xhtml")) {
248.471 - response.setContentType("application/xhtml+xml");
248.472 - LOG.info("Content type application/xhtml+xml");
248.473 - replace = args;
248.474 - }
248.475 - OutputStream os = response.getOutputStream();
248.476 - try (InputStream is = res.get(r)) {
248.477 - copyStream(is, os, request.getRequestURL().toString(), replace);
248.478 - } catch (IOException ex) {
248.479 - response.setDetailMessage(ex.getLocalizedMessage());
248.480 - response.setError();
248.481 - response.setStatus(404);
248.482 - }
248.483 - }
248.484 - }
248.485 -
248.486 - private static class VM extends HttpHandler {
248.487 - private final String bck2brwsr;
248.488 -
248.489 - public VM(Res loader) throws IOException {
248.490 - StringBuilder sb = new StringBuilder();
248.491 - Bck2Brwsr.generate(sb, loader);
248.492 - sb.append(
248.493 - "(function WrapperVM(global) {"
248.494 - + " function ldCls(res) {\n"
248.495 - + " var request = new XMLHttpRequest();\n"
248.496 - + " request.open('GET', '/classes/' + res, false);\n"
248.497 - + " request.send();\n"
248.498 - + " if (request.status !== 200) return null;\n"
248.499 - + " var arr = eval('(' + request.responseText + ')');\n"
248.500 - + " return arr;\n"
248.501 - + " }\n"
248.502 - + " var prevvm = global.bck2brwsr;\n"
248.503 - + " global.bck2brwsr = function() {\n"
248.504 - + " var args = Array.prototype.slice.apply(arguments);\n"
248.505 - + " args.unshift(ldCls);\n"
248.506 - + " return prevvm.apply(null, args);\n"
248.507 - + " };\n"
248.508 - + "})(this);\n"
248.509 - );
248.510 - this.bck2brwsr = sb.toString();
248.511 - }
248.512 -
248.513 - @Override
248.514 - public void service(Request request, Response response) throws Exception {
248.515 - response.setCharacterEncoding("UTF-8");
248.516 - response.setContentType("text/javascript");
248.517 - response.getWriter().write(bck2brwsr);
248.518 - }
248.519 - }
248.520 -
248.521 - private static class Classes extends HttpHandler {
248.522 - private final Res loader;
248.523 -
248.524 - public Classes(Res loader) {
248.525 - this.loader = loader;
248.526 - }
248.527 -
248.528 - @Override
248.529 - public void service(Request request, Response response) throws Exception {
248.530 - String res = request.getHttpHandlerPath();
248.531 - if (res.startsWith("/")) {
248.532 - res = res.substring(1);
248.533 - }
248.534 - try (InputStream is = loader.get(res)) {
248.535 - response.setContentType("text/javascript");
248.536 - Writer w = response.getWriter();
248.537 - w.append("[");
248.538 - for (int i = 0;; i++) {
248.539 - int b = is.read();
248.540 - if (b == -1) {
248.541 - break;
248.542 - }
248.543 - if (i > 0) {
248.544 - w.append(", ");
248.545 - }
248.546 - if (i % 20 == 0) {
248.547 - w.write("\n");
248.548 - }
248.549 - if (b > 127) {
248.550 - b = b - 256;
248.551 - }
248.552 - w.append(Integer.toString(b));
248.553 - }
248.554 - w.append("\n]");
248.555 - } catch (IOException ex) {
248.556 - response.setStatus(HttpStatus.NOT_FOUND_404);
248.557 - response.setError();
248.558 - response.setDetailMessage(ex.getMessage());
248.559 - }
248.560 - }
248.561 - }
248.562 -}
249.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Wed Feb 27 17:50:47 2013 +0100
249.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
249.3 @@ -1,110 +0,0 @@
249.4 -/**
249.5 - * Back 2 Browser Bytecode Translator
249.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
249.7 - *
249.8 - * This program is free software: you can redistribute it and/or modify
249.9 - * it under the terms of the GNU General Public License as published by
249.10 - * the Free Software Foundation, version 2 of the License.
249.11 - *
249.12 - * This program is distributed in the hope that it will be useful,
249.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
249.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
249.15 - * GNU General Public License for more details.
249.16 - *
249.17 - * You should have received a copy of the GNU General Public License
249.18 - * along with this program. Look for COPYING file in the top folder.
249.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
249.20 - */
249.21 -package org.apidesign.bck2brwsr.launcher;
249.22 -
249.23 -import java.io.IOException;
249.24 -import java.io.InputStream;
249.25 -import java.util.ArrayList;
249.26 -import java.util.List;
249.27 -import java.util.concurrent.CountDownLatch;
249.28 -import java.util.concurrent.TimeUnit;
249.29 -
249.30 -/** Represents individual method invocation, its context and its result.
249.31 - *
249.32 - * @author Jaroslav Tulach <jtulach@netbeans.org>
249.33 - */
249.34 -public final class InvocationContext {
249.35 - final CountDownLatch wait = new CountDownLatch(1);
249.36 - final Class<?> clazz;
249.37 - final String methodName;
249.38 - private final Launcher launcher;
249.39 - private String result;
249.40 - private Throwable exception;
249.41 - String html;
249.42 - final List<Resource> resources = new ArrayList<>();
249.43 -
249.44 - InvocationContext(Launcher launcher, Class<?> clazz, String methodName) {
249.45 - this.launcher = launcher;
249.46 - this.clazz = clazz;
249.47 - this.methodName = methodName;
249.48 - }
249.49 -
249.50 - /** An HTML fragment to be available for the execution. Useful primarily when
249.51 - * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}.
249.52 - * @param html the html fragment
249.53 - */
249.54 - public void setHtmlFragment(String html) {
249.55 - this.html = html;
249.56 - }
249.57 -
249.58 - /** HTTP resource to be available during execution. An invocation may
249.59 - * perform an HTTP query and obtain a resource relative to the page.
249.60 - */
249.61 - public void addHttpResource(String relativePath, String mimeType, InputStream content) {
249.62 - if (relativePath == null || mimeType == null || content == null) {
249.63 - throw new NullPointerException();
249.64 - }
249.65 - resources.add(new Resource(content, mimeType, relativePath));
249.66 - }
249.67 -
249.68 - /** Invokes the associated method.
249.69 - * @return the textual result of the invocation
249.70 - */
249.71 - public String invoke() throws IOException {
249.72 - launcher.runMethod(this);
249.73 - return toString();
249.74 - }
249.75 -
249.76 - /** Obtains textual result of the invocation.
249.77 - * @return text representing the exception or result value
249.78 - */
249.79 - @Override
249.80 - public String toString() {
249.81 - if (exception != null) {
249.82 - return exception.toString();
249.83 - }
249.84 - return result;
249.85 - }
249.86 -
249.87 - /**
249.88 - * @param timeOut
249.89 - * @throws InterruptedException
249.90 - */
249.91 - void await(long timeOut) throws InterruptedException {
249.92 - wait.await(timeOut, TimeUnit.MILLISECONDS);
249.93 - }
249.94 -
249.95 - void result(String r, Throwable e) {
249.96 - this.result = r;
249.97 - this.exception = e;
249.98 - wait.countDown();
249.99 - }
249.100 -
249.101 -
249.102 - static final class Resource {
249.103 - final InputStream httpContent;
249.104 - final String httpType;
249.105 - final String httpPath;
249.106 -
249.107 - Resource(InputStream httpContent, String httpType, String httpPath) {
249.108 - this.httpContent = httpContent;
249.109 - this.httpType = httpType;
249.110 - this.httpPath = httpPath;
249.111 - }
249.112 - }
249.113 -}
250.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Wed Feb 27 17:50:47 2013 +0100
250.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
250.3 @@ -1,132 +0,0 @@
250.4 -/**
250.5 - * Back 2 Browser Bytecode Translator
250.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
250.7 - *
250.8 - * This program is free software: you can redistribute it and/or modify
250.9 - * it under the terms of the GNU General Public License as published by
250.10 - * the Free Software Foundation, version 2 of the License.
250.11 - *
250.12 - * This program is distributed in the hope that it will be useful,
250.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
250.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
250.15 - * GNU General Public License for more details.
250.16 - *
250.17 - * You should have received a copy of the GNU General Public License
250.18 - * along with this program. Look for COPYING file in the top folder.
250.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
250.20 - */
250.21 -package org.apidesign.bck2brwsr.launcher;
250.22 -
250.23 -import org.apidesign.bck2brwsr.launcher.impl.Console;
250.24 -import java.io.IOException;
250.25 -import java.io.InputStream;
250.26 -import java.net.URL;
250.27 -import java.util.Enumeration;
250.28 -import java.util.LinkedHashSet;
250.29 -import java.util.Set;
250.30 -import java.util.logging.Level;
250.31 -import java.util.logging.Logger;
250.32 -import javax.script.Invocable;
250.33 -import javax.script.ScriptEngine;
250.34 -import javax.script.ScriptEngineManager;
250.35 -import javax.script.ScriptException;
250.36 -import org.apidesign.vm4brwsr.Bck2Brwsr;
250.37 -
250.38 -/**
250.39 - * Tests execution in Java's internal scripting engine.
250.40 - */
250.41 -final class JSLauncher extends Launcher {
250.42 - private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName());
250.43 - private Set<ClassLoader> loaders = new LinkedHashSet<>();
250.44 - private final Res resources = new Res();
250.45 - private Invocable code;
250.46 - private StringBuilder codeSeq;
250.47 - private Object console;
250.48 -
250.49 -
250.50 - @Override InvocationContext runMethod(InvocationContext mi) {
250.51 - loaders.add(mi.clazz.getClassLoader());
250.52 - try {
250.53 - long time = System.currentTimeMillis();
250.54 - LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName});
250.55 - String res = code.invokeMethod(
250.56 - console,
250.57 - "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
250.58 - mi.clazz.getName(), mi.methodName).toString();
250.59 - time = System.currentTimeMillis() - time;
250.60 - LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time});
250.61 - mi.result(res, null);
250.62 - } catch (ScriptException | NoSuchMethodException ex) {
250.63 - mi.result(null, ex);
250.64 - }
250.65 - return mi;
250.66 - }
250.67 -
250.68 - public void addClassLoader(ClassLoader url) {
250.69 - this.loaders.add(url);
250.70 - }
250.71 -
250.72 - @Override
250.73 - public void initialize() throws IOException {
250.74 - try {
250.75 - initRhino();
250.76 - } catch (Exception ex) {
250.77 - if (ex instanceof IOException) {
250.78 - throw (IOException)ex;
250.79 - }
250.80 - if (ex instanceof RuntimeException) {
250.81 - throw (RuntimeException)ex;
250.82 - }
250.83 - throw new IOException(ex);
250.84 - }
250.85 - }
250.86 -
250.87 - private void initRhino() throws IOException, ScriptException, NoSuchMethodException {
250.88 - StringBuilder sb = new StringBuilder();
250.89 - Bck2Brwsr.generate(sb, new Res());
250.90 -
250.91 - ScriptEngineManager sem = new ScriptEngineManager();
250.92 - ScriptEngine mach = sem.getEngineByExtension("js");
250.93 -
250.94 - sb.append(
250.95 - "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);"
250.96 - + "\nfunction initVM() { return vm; };"
250.97 - + "\n");
250.98 -
250.99 - Object res = mach.eval(sb.toString());
250.100 - if (!(mach instanceof Invocable)) {
250.101 - throw new IOException("It is invocable object: " + res);
250.102 - }
250.103 - code = (Invocable) mach;
250.104 - codeSeq = sb;
250.105 -
250.106 - Object vm = code.invokeFunction("initVM");
250.107 - console = code.invokeMethod(vm, "loadClass", Console.class.getName());
250.108 - }
250.109 -
250.110 - @Override
250.111 - public void shutdown() throws IOException {
250.112 - }
250.113 -
250.114 - @Override
250.115 - public String toString() {
250.116 - return codeSeq.toString();
250.117 - }
250.118 -
250.119 - private class Res implements Bck2Brwsr.Resources {
250.120 - @Override
250.121 - public InputStream get(String resource) throws IOException {
250.122 - for (ClassLoader l : loaders) {
250.123 - URL u = null;
250.124 - Enumeration<URL> en = l.getResources(resource);
250.125 - while (en.hasMoreElements()) {
250.126 - u = en.nextElement();
250.127 - }
250.128 - if (u != null) {
250.129 - return u.openStream();
250.130 - }
250.131 - }
250.132 - throw new IOException("Can't find " + resource);
250.133 - }
250.134 - }
250.135 -}
251.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Wed Feb 27 17:50:47 2013 +0100
251.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
251.3 @@ -1,115 +0,0 @@
251.4 -/**
251.5 - * Back 2 Browser Bytecode Translator
251.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
251.7 - *
251.8 - * This program is free software: you can redistribute it and/or modify
251.9 - * it under the terms of the GNU General Public License as published by
251.10 - * the Free Software Foundation, version 2 of the License.
251.11 - *
251.12 - * This program is distributed in the hope that it will be useful,
251.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
251.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
251.15 - * GNU General Public License for more details.
251.16 - *
251.17 - * You should have received a copy of the GNU General Public License
251.18 - * along with this program. Look for COPYING file in the top folder.
251.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
251.20 - */
251.21 -package org.apidesign.bck2brwsr.launcher;
251.22 -
251.23 -import java.io.Closeable;
251.24 -import java.io.File;
251.25 -import java.io.IOException;
251.26 -import java.net.URLClassLoader;
251.27 -import org.apidesign.vm4brwsr.Bck2Brwsr;
251.28 -
251.29 -/** An abstraction for executing tests in a Bck2Brwsr virtual machine.
251.30 - * Either in {@linkm Launcher#createJavaScript JavaScript engine},
251.31 - * or in {@linkm Launcher#createBrowser external browser}.
251.32 - *
251.33 - * @author Jaroslav Tulach <jtulach@netbeans.org>
251.34 - */
251.35 -public abstract class Launcher {
251.36 -
251.37 - Launcher() {
251.38 - }
251.39 -
251.40 - /** Initializes the launcher. This may mean starting a web browser or
251.41 - * initializing execution engine.
251.42 - * @throws IOException if something goes wrong
251.43 - */
251.44 - public abstract void initialize() throws IOException;
251.45 -
251.46 - /** Shuts down the launcher.
251.47 - * @throws IOException if something goes wrong
251.48 - */
251.49 - public abstract void shutdown() throws IOException;
251.50 -
251.51 -
251.52 - /** Builds an invocation context. The context can later be customized
251.53 - * and {@link InvocationContext#invoke() invoked}.
251.54 - *
251.55 - * @param clazz the class to execute method from
251.56 - * @param method the method to execute
251.57 - * @return the context pointing to the selected method
251.58 - */
251.59 - public InvocationContext createInvocation(Class<?> clazz, String method) {
251.60 - return new InvocationContext(this, clazz, method);
251.61 - }
251.62 -
251.63 -
251.64 - /** Creates launcher that uses internal JavaScript engine (Rhino).
251.65 - * @return the launcher
251.66 - */
251.67 - public static Launcher createJavaScript() {
251.68 - final JSLauncher l = new JSLauncher();
251.69 - l.addClassLoader(Bck2Brwsr.class.getClassLoader());
251.70 - return l;
251.71 - }
251.72 -
251.73 - /** Creates launcher that is using external browser.
251.74 - *
251.75 - * @param cmd <code>null</code> to use <code>java.awt.Desktop</code> to show the launcher
251.76 - * or a string to execute in an external process (with a parameter to the URL)
251.77 - * @return launcher executing in external browser.
251.78 - */
251.79 - public static Launcher createBrowser(String cmd) {
251.80 - final Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(cmd);
251.81 - l.addClassLoader(Bck2Brwsr.class.getClassLoader());
251.82 - l.setTimeout(180000);
251.83 - return l;
251.84 - }
251.85 -
251.86 - /** Starts an HTTP server which provides access to classes and resources
251.87 - * available in the <code>classes</code> URL and shows a start page
251.88 - * available as {@link ClassLoader#getResource(java.lang.String)} from the
251.89 - * provide classloader. Opens a browser with URL showing the start page.
251.90 - *
251.91 - * @param classes classloader offering access to classes and resources
251.92 - * @param startpage page to show in the browser
251.93 - * @return interface that allows one to stop the server
251.94 - * @throws IOException if something goes wrong
251.95 - */
251.96 - public static Closeable showURL(URLClassLoader classes, String startpage) throws IOException {
251.97 - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
251.98 - l.addClassLoader(classes);
251.99 - l.showURL(startpage);
251.100 - return l;
251.101 - }
251.102 - /** Starts an HTTP server which provides access to certain directory.
251.103 - * The <code>startpage</code> should be relative location inside the root
251.104 - * driecotry
251.105 - * Opens a browser with URL showing the start page.
251.106 - *
251.107 - * @param directory the root directory on disk
251.108 - * @praam startpage relative path from the root to the page
251.109 - * @exception IOException if something goes wrong.
251.110 - */
251.111 - public static Closeable showDir(File directory, String startpage) throws IOException {
251.112 - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
251.113 - l.showDirectory(directory, startpage);
251.114 - return l;
251.115 - }
251.116 -
251.117 - abstract InvocationContext runMethod(InvocationContext c) throws IOException;
251.118 -}
252.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Wed Feb 27 17:50:47 2013 +0100
252.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
252.3 @@ -1,255 +0,0 @@
252.4 -/**
252.5 - * Back 2 Browser Bytecode Translator
252.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
252.7 - *
252.8 - * This program is free software: you can redistribute it and/or modify
252.9 - * it under the terms of the GNU General Public License as published by
252.10 - * the Free Software Foundation, version 2 of the License.
252.11 - *
252.12 - * This program is distributed in the hope that it will be useful,
252.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
252.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
252.15 - * GNU General Public License for more details.
252.16 - *
252.17 - * You should have received a copy of the GNU General Public License
252.18 - * along with this program. Look for COPYING file in the top folder.
252.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
252.20 - */
252.21 -package org.apidesign.bck2brwsr.launcher.impl;
252.22 -
252.23 -import java.io.IOException;
252.24 -import java.io.InputStream;
252.25 -import java.lang.reflect.InvocationTargetException;
252.26 -import java.lang.reflect.Method;
252.27 -import java.lang.reflect.Modifier;
252.28 -import java.net.URL;
252.29 -import java.util.Enumeration;
252.30 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
252.31 -
252.32 -/**
252.33 - *
252.34 - * @author Jaroslav Tulach <jtulach@netbeans.org>
252.35 - */
252.36 -public class Console {
252.37 - private Console() {
252.38 - }
252.39 - static {
252.40 - turnAssetionStatusOn();
252.41 - }
252.42 -
252.43 - @JavaScriptBody(args = {"id", "attr"}, body =
252.44 - "return window.document.getElementById(id)[attr].toString();")
252.45 - private static native Object getAttr(String id, String attr);
252.46 -
252.47 - @JavaScriptBody(args = {"id", "attr", "value"}, body =
252.48 - "window.document.getElementById(id)[attr] = value;")
252.49 - private static native void setAttr(String id, String attr, Object value);
252.50 -
252.51 - @JavaScriptBody(args = {}, body = "return; window.close();")
252.52 - private static native void closeWindow();
252.53 -
252.54 - private static void log(String newText) {
252.55 - String id = "bck2brwsr.result";
252.56 - String attr = "value";
252.57 - setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
252.58 - setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
252.59 - }
252.60 -
252.61 - public static void execute() throws Exception {
252.62 - String clazz = (String) getAttr("clazz", "value");
252.63 - String method = (String) getAttr("method", "value");
252.64 - Object res = invokeMethod(clazz, method);
252.65 - setAttr("bck2brwsr.result", "value", res);
252.66 - }
252.67 -
252.68 - @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
252.69 - + "var request = new XMLHttpRequest();\n"
252.70 - + "request.open('GET', url, true);\n"
252.71 - + "request.onreadystatechange = function() {\n"
252.72 - + " if (this.readyState!==4) return;\n"
252.73 - + " arr[0] = this.responseText;\n"
252.74 - + " callback.run__V();\n"
252.75 - + "};"
252.76 - + "request.send();"
252.77 - )
252.78 - private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
252.79 -
252.80 - public static void harness(String url) throws IOException {
252.81 - log("Connecting to " + url);
252.82 - Request r = new Request(url);
252.83 - }
252.84 -
252.85 - private static class Request implements Runnable {
252.86 - private final String[] arr = { null };
252.87 - private final String url;
252.88 -
252.89 - private Request(String url) throws IOException {
252.90 - this.url = url;
252.91 - loadText(url, this, arr);
252.92 - }
252.93 -
252.94 - @Override
252.95 - public void run() {
252.96 - try {
252.97 - String data = arr[0];
252.98 - log("\nGot \"" + data + "\"");
252.99 -
252.100 - if (data == null) {
252.101 - log("Some error exiting");
252.102 - closeWindow();
252.103 - return;
252.104 - }
252.105 -
252.106 - if (data.isEmpty()) {
252.107 - log("No data, exiting");
252.108 - closeWindow();
252.109 - return;
252.110 - }
252.111 -
252.112 - Case c = Case.parseData(data);
252.113 - if (c.getHtmlFragment() != null) {
252.114 - setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment());
252.115 - }
252.116 - log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
252.117 -
252.118 - Object result = invokeMethod(c.getClassName(), c.getMethodName());
252.119 -
252.120 - setAttr("bck2brwsr.fragment", "innerHTML", "");
252.121 - log("Result: " + result);
252.122 -
252.123 - result = encodeURL("" + result);
252.124 -
252.125 - log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result);
252.126 - String u = url + "?request=" + c.getRequestId() + "&result=" + result;
252.127 -
252.128 - loadText(u, this, arr);
252.129 -
252.130 - } catch (Exception ex) {
252.131 - log(ex.getClass().getName() + ":" + ex.getMessage());
252.132 - }
252.133 - }
252.134 - }
252.135 -
252.136 - private static String encodeURL(String r) {
252.137 - StringBuilder sb = new StringBuilder();
252.138 - for (int i = 0; i < r.length(); i++) {
252.139 - int ch = r.charAt(i);
252.140 - if (ch < 32 || ch == '%' || ch == '+') {
252.141 - sb.append("%").append(("0" + Integer.toHexString(ch)).substring(0, 2));
252.142 - } else {
252.143 - if (ch == 32) {
252.144 - sb.append("+");
252.145 - } else {
252.146 - sb.append((char)ch);
252.147 - }
252.148 - }
252.149 - }
252.150 - return sb.toString();
252.151 - }
252.152 -
252.153 - static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
252.154 - final Object r = invokeMethod(clazz, method);
252.155 - return r == null ? "null" : r.toString().toString();
252.156 - }
252.157 -
252.158 - /** Helper method that inspects the classpath and loads given resource
252.159 - * (usually a class file). Used while running tests in Rhino.
252.160 - *
252.161 - * @param name resource name to find
252.162 - * @return the array of bytes in the given resource
252.163 - * @throws IOException I/O in case something goes wrong
252.164 - */
252.165 - public static byte[] read(String name) throws IOException {
252.166 - URL u = null;
252.167 - Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
252.168 - while (en.hasMoreElements()) {
252.169 - u = en.nextElement();
252.170 - }
252.171 - if (u == null) {
252.172 - throw new IOException("Can't find " + name);
252.173 - }
252.174 - try (InputStream is = u.openStream()) {
252.175 - byte[] arr;
252.176 - arr = new byte[is.available()];
252.177 - int offset = 0;
252.178 - while (offset < arr.length) {
252.179 - int len = is.read(arr, offset, arr.length - offset);
252.180 - if (len == -1) {
252.181 - throw new IOException("Can't read " + name);
252.182 - }
252.183 - offset += len;
252.184 - }
252.185 - return arr;
252.186 - }
252.187 - }
252.188 -
252.189 - private static Object invokeMethod(String clazz, String method)
252.190 - throws ClassNotFoundException, InvocationTargetException,
252.191 - SecurityException, IllegalAccessException, IllegalArgumentException,
252.192 - InstantiationException {
252.193 - Method found = null;
252.194 - Class<?> c = Class.forName(clazz);
252.195 - for (Method m : c.getMethods()) {
252.196 - if (m.getName().equals(method)) {
252.197 - found = m;
252.198 - }
252.199 - }
252.200 - Object res;
252.201 - if (found != null) {
252.202 - try {
252.203 - if ((found.getModifiers() & Modifier.STATIC) != 0) {
252.204 - res = found.invoke(null);
252.205 - } else {
252.206 - res = found.invoke(c.newInstance());
252.207 - }
252.208 - } catch (Throwable ex) {
252.209 - res = ex.getClass().getName() + ":" + ex.getMessage();
252.210 - }
252.211 - } else {
252.212 - res = "Can't find method " + method + " in " + clazz;
252.213 - }
252.214 - return res;
252.215 - }
252.216 -
252.217 - @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
252.218 - private static void turnAssetionStatusOn() {
252.219 - }
252.220 -
252.221 - private static final class Case {
252.222 - private final Object data;
252.223 -
252.224 - private Case(Object data) {
252.225 - this.data = data;
252.226 - }
252.227 -
252.228 - public static Case parseData(String s) {
252.229 - return new Case(toJSON(s));
252.230 - }
252.231 -
252.232 - public String getMethodName() {
252.233 - return value("methodName", data);
252.234 - }
252.235 -
252.236 - public String getClassName() {
252.237 - return value("className", data);
252.238 - }
252.239 -
252.240 - public String getRequestId() {
252.241 - return value("request", data);
252.242 - }
252.243 -
252.244 - public String getHtmlFragment() {
252.245 - return value("html", data);
252.246 - }
252.247 -
252.248 - @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
252.249 - private static native Object toJSON(String s);
252.250 -
252.251 - @JavaScriptBody(args = {"p", "d"}, body =
252.252 - "var v = d[p];\n"
252.253 - + "if (typeof v === 'undefined') return null;\n"
252.254 - + "return v.toString();"
252.255 - )
252.256 - private static native String value(String p, Object d);
252.257 - }
252.258 -}
253.1 --- a/rt/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Wed Feb 27 17:50:47 2013 +0100
253.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
253.3 @@ -1,43 +0,0 @@
253.4 -<?xml version="1.0" encoding="UTF-8"?>
253.5 -<!--
253.6 -
253.7 - Back 2 Browser Bytecode Translator
253.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
253.9 -
253.10 - This program is free software: you can redistribute it and/or modify
253.11 - it under the terms of the GNU General Public License as published by
253.12 - the Free Software Foundation, version 2 of the License.
253.13 -
253.14 - This program is distributed in the hope that it will be useful,
253.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
253.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
253.17 - GNU General Public License for more details.
253.18 -
253.19 - You should have received a copy of the GNU General Public License
253.20 - along with this program. Look for COPYING file in the top folder.
253.21 - If not, see http://opensource.org/licenses/GPL-2.0.
253.22 -
253.23 --->
253.24 -<!DOCTYPE html>
253.25 -<html xmlns="http://www.w3.org/1999/xhtml">
253.26 - <head>
253.27 - <title>Bck2Brwsr Harness</title>
253.28 - </head>
253.29 - <body>
253.30 - <script src="/bck2brwsr.js"></script>
253.31 - <script>
253.32 - var vm = bck2brwsr();
253.33 - </script>
253.34 -
253.35 - <h1>Bck2Brwsr Execution Harness</h1>
253.36 -
253.37 - <textarea id="bck2brwsr.result" rows="25" style="width: 100%;" disabled="">
253.38 - </textarea>
253.39 -
253.40 - <div id="bck2brwsr.fragment"/>
253.41 -
253.42 - <script type="text/javascript">
253.43 - vm.loadClass('org.apidesign.bck2brwsr.launcher.impl.Console').harness__VLjava_lang_String_2('$U/../data');
253.44 - </script>
253.45 - </body>
253.46 -</html>
254.1 --- a/rt/mojo/pom.xml Wed Feb 27 17:50:47 2013 +0100
254.2 +++ b/rt/mojo/pom.xml Mon Oct 07 14:20:58 2013 +0200
254.3 @@ -1,18 +1,17 @@
254.4 <?xml version="1.0"?>
254.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
254.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
254.7 +<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/xsd/maven-4.0.0.xsd">
254.8 <modelVersion>4.0.0</modelVersion>
254.9 <parent>
254.10 <groupId>org.apidesign.bck2brwsr</groupId>
254.11 <artifactId>rt</artifactId>
254.12 - <version>0.3-SNAPSHOT</version>
254.13 + <version>0.9-SNAPSHOT</version>
254.14 </parent>
254.15 <groupId>org.apidesign.bck2brwsr</groupId>
254.16 - <artifactId>mojo</artifactId>
254.17 - <version>0.3-SNAPSHOT</version>
254.18 + <artifactId>bck2brwsr-maven-plugin</artifactId>
254.19 + <version>0.9-SNAPSHOT</version>
254.20 <packaging>maven-plugin</packaging>
254.21 - <name>Bck2Brwsr Maven Project</name>
254.22 - <url>http://maven.apache.org</url>
254.23 + <name>Bck2Brwsr Maven Plugin</name>
254.24 + <url>http://bck2brwsr.apidesign.org/</url>
254.25 <build>
254.26 <plugins>
254.27 <plugin>
254.28 @@ -63,7 +62,7 @@
254.29 <dependency>
254.30 <groupId>${project.groupId}</groupId>
254.31 <artifactId>vm4brwsr</artifactId>
254.32 - <version>0.3-SNAPSHOT</version>
254.33 + <version>${project.version}</version>
254.34 <exclusions>
254.35 <exclusion>
254.36 <artifactId>emul.mini</artifactId>
254.37 @@ -82,5 +81,15 @@
254.38 <artifactId>launcher</artifactId>
254.39 <version>${project.version}</version>
254.40 </dependency>
254.41 + <dependency>
254.42 + <groupId>${project.groupId}</groupId>
254.43 + <artifactId>launcher.http</artifactId>
254.44 + <version>${project.version}</version>
254.45 + </dependency>
254.46 + <dependency>
254.47 + <groupId>${project.groupId}</groupId>
254.48 + <artifactId>launcher.fx</artifactId>
254.49 + <version>${project.version}</version>
254.50 + </dependency>
254.51 </dependencies>
254.52 </project>
255.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java Wed Feb 27 17:50:47 2013 +0100
255.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
255.3 @@ -1,99 +0,0 @@
255.4 -/**
255.5 - * Back 2 Browser Bytecode Translator
255.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
255.7 - *
255.8 - * This program is free software: you can redistribute it and/or modify
255.9 - * it under the terms of the GNU General Public License as published by
255.10 - * the Free Software Foundation, version 2 of the License.
255.11 - *
255.12 - * This program is distributed in the hope that it will be useful,
255.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
255.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255.15 - * GNU General Public License for more details.
255.16 - *
255.17 - * You should have received a copy of the GNU General Public License
255.18 - * along with this program. Look for COPYING file in the top folder.
255.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
255.20 - */
255.21 -package org.apidesign.bck2brwsr.mojo;
255.22 -
255.23 -import java.io.Closeable;
255.24 -import org.apache.maven.plugin.AbstractMojo;
255.25 -
255.26 -import java.io.File;
255.27 -import java.io.IOException;
255.28 -import java.net.MalformedURLException;
255.29 -import java.net.URL;
255.30 -import java.net.URLClassLoader;
255.31 -import java.util.ArrayList;
255.32 -import java.util.Collection;
255.33 -import java.util.List;
255.34 -import org.apache.maven.artifact.Artifact;
255.35 -import org.apache.maven.plugin.MojoExecutionException;
255.36 -import org.apache.maven.plugins.annotations.LifecyclePhase;
255.37 -import org.apache.maven.plugins.annotations.Mojo;
255.38 -import org.apache.maven.plugins.annotations.Parameter;
255.39 -import org.apache.maven.project.MavenProject;
255.40 -import org.apidesign.bck2brwsr.launcher.Launcher;
255.41 -
255.42 -/** Executes given HTML page in a browser. */
255.43 -@Mojo(name="brwsr", defaultPhase=LifecyclePhase.NONE)
255.44 -public class BrswrMojo extends AbstractMojo {
255.45 - public BrswrMojo() {
255.46 - }
255.47 - /** Resource to show as initial page */
255.48 - @Parameter
255.49 - private String startpage;
255.50 -
255.51 - @Parameter(defaultValue="${project}")
255.52 - private MavenProject prj;
255.53 -
255.54 - /** Root of the class files */
255.55 - @Parameter(defaultValue="${project.build.directory}/classes")
255.56 - private File classes;
255.57 -
255.58 - /** Root of all pages, and files, etc. */
255.59 - @Parameter
255.60 - private File directory;
255.61 -
255.62 - @Override
255.63 - public void execute() throws MojoExecutionException {
255.64 - if (startpage == null) {
255.65 - throw new MojoExecutionException("You have to provide a start page");
255.66 - }
255.67 -
255.68 - try {
255.69 - Closeable httpServer;
255.70 - if (directory != null) {
255.71 - httpServer = Launcher.showDir(directory, startpage);
255.72 - } else {
255.73 - URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
255.74 - try {
255.75 - httpServer = Launcher.showURL(url, startpage());
255.76 - } catch (Exception ex) {
255.77 - throw new MojoExecutionException("Can't open " + startpage(), ex);
255.78 - }
255.79 - }
255.80 - System.in.read();
255.81 - httpServer.close();
255.82 - } catch (IOException ex) {
255.83 - throw new MojoExecutionException("Can't show the browser", ex);
255.84 - }
255.85 - }
255.86 -
255.87 - private String startpage() {
255.88 - return startpage;
255.89 - }
255.90 -
255.91 - private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
255.92 - List<URL> arr = new ArrayList<URL>();
255.93 - arr.add(root.toURI().toURL());
255.94 - for (Artifact a : deps) {
255.95 - final File f = a.getFile();
255.96 - if (f != null) {
255.97 - arr.add(f.toURI().toURL());
255.98 - }
255.99 - }
255.100 - return new URLClassLoader(arr.toArray(new URL[0]), BrswrMojo.class.getClassLoader());
255.101 - }
255.102 -}
256.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
256.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java Mon Oct 07 14:20:58 2013 +0200
256.3 @@ -0,0 +1,121 @@
256.4 +/**
256.5 + * Back 2 Browser Bytecode Translator
256.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
256.7 + *
256.8 + * This program is free software: you can redistribute it and/or modify
256.9 + * it under the terms of the GNU General Public License as published by
256.10 + * the Free Software Foundation, version 2 of the License.
256.11 + *
256.12 + * This program is distributed in the hope that it will be useful,
256.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
256.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
256.15 + * GNU General Public License for more details.
256.16 + *
256.17 + * You should have received a copy of the GNU General Public License
256.18 + * along with this program. Look for COPYING file in the top folder.
256.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
256.20 + */
256.21 +package org.apidesign.bck2brwsr.mojo;
256.22 +
256.23 +import java.io.Closeable;
256.24 +import org.apache.maven.plugin.AbstractMojo;
256.25 +
256.26 +import java.io.File;
256.27 +import java.io.IOException;
256.28 +import java.net.MalformedURLException;
256.29 +import java.net.URL;
256.30 +import java.net.URLClassLoader;
256.31 +import java.util.ArrayList;
256.32 +import java.util.Collection;
256.33 +import java.util.List;
256.34 +import org.apache.maven.artifact.Artifact;
256.35 +import org.apache.maven.model.Resource;
256.36 +import org.apache.maven.plugin.MojoExecutionException;
256.37 +import org.apache.maven.plugins.annotations.LifecyclePhase;
256.38 +import org.apache.maven.plugins.annotations.Mojo;
256.39 +import org.apache.maven.plugins.annotations.Parameter;
256.40 +import org.apache.maven.plugins.annotations.ResolutionScope;
256.41 +import org.apache.maven.project.MavenProject;
256.42 +import org.apidesign.bck2brwsr.launcher.Launcher;
256.43 +
256.44 +/** Executes given HTML page in a browser. */
256.45 +@Mojo(
256.46 + name="brwsr",
256.47 + requiresDependencyResolution = ResolutionScope.RUNTIME,
256.48 + defaultPhase=LifecyclePhase.NONE
256.49 +)
256.50 +public class BrwsrMojo extends AbstractMojo {
256.51 + public BrwsrMojo() {
256.52 + }
256.53 +
256.54 + /** The identification of a launcher to use. Known values <code>fxbrwsr</code>,
256.55 + * <code>bck2brwsr</code>, or
256.56 + * name of an external process to execute.
256.57 + */
256.58 + @Parameter
256.59 + private String launcher;
256.60 +
256.61 +
256.62 + /** Resource to show as initial page */
256.63 + @Parameter
256.64 + private String startpage;
256.65 +
256.66 + @Parameter(defaultValue="${project}")
256.67 + private MavenProject prj;
256.68 +
256.69 + /** Root of the class files */
256.70 + @Parameter(defaultValue="${project.build.directory}/classes")
256.71 + private File classes;
256.72 +
256.73 + /** Root of all pages, and files, etc. */
256.74 + @Parameter
256.75 + private File directory;
256.76 +
256.77 + @Override
256.78 + public void execute() throws MojoExecutionException {
256.79 + if (startpage == null) {
256.80 + throw new MojoExecutionException("You have to provide a start page");
256.81 + }
256.82 + try {
256.83 + Closeable httpServer;
256.84 + if (directory != null) {
256.85 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
256.86 + httpServer = Launcher.showDir(launcher, directory, url, startpage);
256.87 + } else {
256.88 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
256.89 + try {
256.90 + for (Resource r : prj.getResources()) {
256.91 + File f = new File(r.getDirectory(), startpage().replace('/', File.separatorChar));
256.92 + if (f.exists()) {
256.93 + System.setProperty("startpage.file", f.getPath());
256.94 + }
256.95 + }
256.96 +
256.97 + httpServer = Launcher.showURL(launcher, url, startpage());
256.98 + } catch (Exception ex) {
256.99 + throw new MojoExecutionException("Can't open " + startpage(), ex);
256.100 + }
256.101 + }
256.102 + System.in.read();
256.103 + httpServer.close();
256.104 + } catch (IOException ex) {
256.105 + throw new MojoExecutionException("Can't show the browser", ex);
256.106 + }
256.107 + }
256.108 +
256.109 + private String startpage() {
256.110 + return startpage;
256.111 + }
256.112 +
256.113 + private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
256.114 + List<URL> arr = new ArrayList<URL>();
256.115 + arr.add(root.toURI().toURL());
256.116 + for (Artifact a : deps) {
256.117 + final File f = a.getFile();
256.118 + if (f != null) {
256.119 + arr.add(f.toURI().toURL());
256.120 + }
256.121 + }
256.122 + return new URLClassLoader(arr.toArray(new URL[0]), BrwsrMojo.class.getClassLoader());
256.123 + }
256.124 +}
257.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Wed Feb 27 17:50:47 2013 +0100
257.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Mon Oct 07 14:20:58 2013 +0200
257.3 @@ -33,26 +33,43 @@
257.4 import org.apache.maven.plugins.annotations.LifecyclePhase;
257.5 import org.apache.maven.plugins.annotations.Mojo;
257.6 import org.apache.maven.plugins.annotations.Parameter;
257.7 +import org.apache.maven.plugins.annotations.ResolutionScope;
257.8 import org.apache.maven.project.MavenProject;
257.9 import org.apidesign.vm4brwsr.Bck2Brwsr;
257.10 +import org.apidesign.vm4brwsr.ObfuscationLevel;
257.11
257.12 /** Compiles classes into JavaScript. */
257.13 -@Mojo(name="j2js", defaultPhase=LifecyclePhase.PROCESS_CLASSES)
257.14 +@Mojo(name="j2js",
257.15 + requiresDependencyResolution = ResolutionScope.COMPILE,
257.16 + defaultPhase=LifecyclePhase.PROCESS_CLASSES
257.17 +)
257.18 public class Java2JavaScript extends AbstractMojo {
257.19 public Java2JavaScript() {
257.20 }
257.21 /** Root of the class files */
257.22 @Parameter(defaultValue="${project.build.directory}/classes")
257.23 private File classes;
257.24 - /** File to generate. Defaults bootjava.js in the first non-empty
257.25 - package under the classes directory */
257.26 + /** JavaScript file to generate */
257.27 @Parameter
257.28 private File javascript;
257.29 +
257.30 + /** Additional classes that should be pre-compiled into the javascript
257.31 + * file. By default compiles all classes found under <code>classes</code>
257.32 + * directory and their transitive closure.
257.33 + */
257.34 + @Parameter
257.35 + private List<String> compileclasses;
257.36
257.37 @Parameter(defaultValue="${project}")
257.38 private MavenProject prj;
257.39 -
257.40 -
257.41 +
257.42 + /**
257.43 + * The obfuscation level for the generated JavaScript file.
257.44 + *
257.45 + * @since 0.5
257.46 + */
257.47 + @Parameter(defaultValue="NONE")
257.48 + private ObfuscationLevel obfuscation;
257.49
257.50 @Override
257.51 public void execute() throws MojoExecutionException {
257.52 @@ -60,38 +77,32 @@
257.53 throw new MojoExecutionException("Can't find " + classes);
257.54 }
257.55
257.56 - if (javascript == null) {
257.57 - javascript = new File(findNonEmptyFolder(classes), "bootjava.js");
257.58 - }
257.59 -
257.60 List<String> arr = new ArrayList<String>();
257.61 long newest = collectAllClasses("", classes, arr);
257.62
257.63 + if (compileclasses != null) {
257.64 + arr.retainAll(compileclasses);
257.65 + arr.addAll(compileclasses);
257.66 + }
257.67 +
257.68 if (javascript.lastModified() > newest) {
257.69 return;
257.70 }
257.71
257.72 try {
257.73 - URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
257.74 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
257.75 FileWriter w = new FileWriter(javascript);
257.76 - Bck2Brwsr.generate(w, url, arr.toArray(new String[0]));
257.77 + Bck2Brwsr.newCompiler().
257.78 + obfuscation(obfuscation).
257.79 + resources(url).
257.80 + addRootClasses(arr.toArray(new String[0])).
257.81 + generate(w);
257.82 w.close();
257.83 } catch (IOException ex) {
257.84 throw new MojoExecutionException("Can't compile", ex);
257.85 }
257.86 }
257.87
257.88 - private static File findNonEmptyFolder(File dir) throws MojoExecutionException {
257.89 - if (!dir.isDirectory()) {
257.90 - throw new MojoExecutionException("Not a directory " + dir);
257.91 - }
257.92 - File[] arr = dir.listFiles();
257.93 - if (arr.length == 1 && arr[0].isDirectory()) {
257.94 - return findNonEmptyFolder(arr[0]);
257.95 - }
257.96 - return dir;
257.97 - }
257.98 -
257.99 private static long collectAllClasses(String prefix, File toCheck, List<String> arr) {
257.100 File[] files = toCheck.listFiles();
257.101 if (files != null) {
257.102 @@ -104,7 +115,8 @@
257.103 }
257.104 return newest;
257.105 } else if (toCheck.getName().endsWith(".class")) {
257.106 - arr.add(prefix.substring(0, prefix.length() - 7));
257.107 + final String cls = prefix.substring(0, prefix.length() - 7);
257.108 + arr.add(cls);
257.109 return toCheck.lastModified();
257.110 } else {
257.111 return 0L;
257.112 @@ -115,7 +127,9 @@
257.113 List<URL> arr = new ArrayList<URL>();
257.114 arr.add(root.toURI().toURL());
257.115 for (Artifact a : deps) {
257.116 - arr.add(a.getFile().toURI().toURL());
257.117 + if (a.getFile() != null) {
257.118 + arr.add(a.getFile().toURI().toURL());
257.119 + }
257.120 }
257.121 return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
257.122 }
258.1 --- a/rt/mojo/src/main/resources/META-INF/maven/archetype-metadata.xml Wed Feb 27 17:50:47 2013 +0100
258.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
258.3 @@ -1,55 +0,0 @@
258.4 -<?xml version="1.0" encoding="UTF-8"?>
258.5 -<!--
258.6 -
258.7 - Back 2 Browser Bytecode Translator
258.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
258.9 -
258.10 - This program is free software: you can redistribute it and/or modify
258.11 - it under the terms of the GNU General Public License as published by
258.12 - the Free Software Foundation, version 2 of the License.
258.13 -
258.14 - This program is distributed in the hope that it will be useful,
258.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
258.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
258.17 - GNU General Public License for more details.
258.18 -
258.19 - You should have received a copy of the GNU General Public License
258.20 - along with this program. Look for COPYING file in the top folder.
258.21 - If not, see http://opensource.org/licenses/GPL-2.0.
258.22 -
258.23 --->
258.24 -<archetype-descriptor name="bck2brwsr">
258.25 - <fileSets>
258.26 - <fileSet filtered="true" packaged="true">
258.27 - <directory>src/main/java</directory>
258.28 - <includes>
258.29 - <include>**/App.java</include>
258.30 - </includes>
258.31 - </fileSet>
258.32 - <fileSet filtered="true" packaged="true">
258.33 - <directory>src/main/resources</directory>
258.34 - <includes>
258.35 - <include>**/*.xhtml</include>
258.36 - <include>**/*.html</include>
258.37 - </includes>
258.38 - </fileSet>
258.39 - <fileSet filtered="true" packaged="true">
258.40 - <directory>src/test/java</directory>
258.41 - <includes>
258.42 - <include>**/*Test.java</include>
258.43 - </includes>
258.44 - </fileSet>
258.45 - <fileSet filtered="false" packaged="false">
258.46 - <directory></directory>
258.47 - <includes>
258.48 - <include>nbactions.xml</include>
258.49 - </includes>
258.50 - </fileSet>
258.51 - <fileSet filtered="true" packaged="false">
258.52 - <directory></directory>
258.53 - <includes>
258.54 - <include>bck2brwsr-assembly.xml</include>
258.55 - </includes>
258.56 - </fileSet>
258.57 - </fileSets>
258.58 -</archetype-descriptor>
258.59 \ No newline at end of file
259.1 --- a/rt/mojo/src/main/resources/archetype-resources/bck2brwsr-assembly.xml Wed Feb 27 17:50:47 2013 +0100
259.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
259.3 @@ -1,61 +0,0 @@
259.4 -<?xml version="1.0"?>
259.5 -<!--
259.6 -
259.7 - Back 2 Browser Bytecode Translator
259.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
259.9 -
259.10 - This program is free software: you can redistribute it and/or modify
259.11 - it under the terms of the GNU General Public License as published by
259.12 - the Free Software Foundation, version 2 of the License.
259.13 -
259.14 - This program is distributed in the hope that it will be useful,
259.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
259.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259.17 - GNU General Public License for more details.
259.18 -
259.19 - You should have received a copy of the GNU General Public License
259.20 - along with this program. Look for COPYING file in the top folder.
259.21 - If not, see http://opensource.org/licenses/GPL-2.0.
259.22 -
259.23 --->
259.24 -<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
259.25 - xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
259.26 -
259.27 - <id>bck2brwsr</id>
259.28 - <formats>
259.29 - <format>zip</format>
259.30 - </formats>
259.31 - <baseDirectory>public_html</baseDirectory>
259.32 - <dependencySets>
259.33 - <dependencySet>
259.34 - <useProjectArtifact>false</useProjectArtifact>
259.35 - <scope>runtime</scope>
259.36 - <outputDirectory>lib</outputDirectory>
259.37 - <includes>
259.38 - <include>*:jar</include>
259.39 - <include>*:rt</include>
259.40 - </includes>
259.41 - </dependencySet>
259.42 - <dependencySet>
259.43 - <useProjectArtifact>false</useProjectArtifact>
259.44 - <scope>provided</scope>
259.45 - <includes>
259.46 - <include>*:js</include>
259.47 - </includes>
259.48 - <unpack>true</unpack>
259.49 - <outputDirectory>/</outputDirectory>
259.50 - </dependencySet>
259.51 - </dependencySets>
259.52 - <files>
259.53 - <file>
259.54 - <source>${project.build.directory}/${project.build.finalName}.jar</source>
259.55 - <outputDirectory>/</outputDirectory>
259.56 - </file>
259.57 - <file>
259.58 - <source>${project.build.directory}/classes/${package.replace('.','/')}/index.html</source>
259.59 - <outputDirectory>/</outputDirectory>
259.60 - <destName>index.html</destName>
259.61 - </file>
259.62 - </files>
259.63 -
259.64 -</assembly>
259.65 \ No newline at end of file
260.1 --- a/rt/mojo/src/main/resources/archetype-resources/nbactions.xml Wed Feb 27 17:50:47 2013 +0100
260.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
260.3 @@ -1,10 +0,0 @@
260.4 -<?xml version="1.0" encoding="UTF-8"?>
260.5 -<actions>
260.6 - <action>
260.7 - <actionName>run</actionName>
260.8 - <goals>
260.9 - <goal>process-classes</goal>
260.10 - <goal>org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr</goal>
260.11 - </goals>
260.12 - </action>
260.13 -</actions>
261.1 --- a/rt/mojo/src/main/resources/archetype-resources/pom.xml Wed Feb 27 17:50:47 2013 +0100
261.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
261.3 @@ -1,135 +0,0 @@
261.4 -<?xml version="1.0"?>
261.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
261.6 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
261.7 - <modelVersion>4.0.0</modelVersion>
261.8 -
261.9 - <groupId>${groupId}</groupId>
261.10 - <artifactId>${artifactId}</artifactId>
261.11 - <version>${version}</version>
261.12 - <packaging>jar</packaging>
261.13 -
261.14 - <name>${artifactId}</name>
261.15 -
261.16 - <repositories>
261.17 - <repository>
261.18 - <id>java.net</id>
261.19 - <name>Java.net</name>
261.20 - <url>https://maven.java.net/content/repositories/snapshots/</url>
261.21 - <snapshots>
261.22 - <enabled>true</enabled>
261.23 - </snapshots>
261.24 - </repository>
261.25 - <repository>
261.26 - <id>netbeans</id>
261.27 - <name>NetBeans</name>
261.28 - <url>http://bits.netbeans.org/maven2/</url>
261.29 - </repository>
261.30 - </repositories>
261.31 - <pluginRepositories>
261.32 - <pluginRepository>
261.33 - <id>java.net</id>
261.34 - <name>Local Maven repository of releases</name>
261.35 - <url>https://maven.java.net/content/repositories/snapshots/</url>
261.36 - <snapshots>
261.37 - <enabled>true</enabled>
261.38 - </snapshots>
261.39 - </pluginRepository>
261.40 - </pluginRepositories>
261.41 -
261.42 - <properties>
261.43 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
261.44 - </properties>
261.45 - <build>
261.46 - <plugins>
261.47 - <plugin>
261.48 - <groupId>org.apidesign.bck2brwsr</groupId>
261.49 - <artifactId>mojo</artifactId>
261.50 - <version>0.3-SNAPSHOT</version>
261.51 - <executions>
261.52 - <execution>
261.53 - <goals>
261.54 - <goal>brwsr</goal>
261.55 - </goals>
261.56 - </execution>
261.57 - </executions>
261.58 - <configuration>
261.59 - <startpage>${package.replace('.','/')}/index.html</startpage>
261.60 - </configuration>
261.61 - </plugin>
261.62 - <plugin>
261.63 - <groupId>org.apache.maven.plugins</groupId>
261.64 - <artifactId>maven-compiler-plugin</artifactId>
261.65 - <version>2.3.2</version>
261.66 - <configuration>
261.67 - <source>1.7</source>
261.68 - <target>1.7</target>
261.69 - </configuration>
261.70 - </plugin>
261.71 - <plugin>
261.72 - <groupId>org.apache.maven.plugins</groupId>
261.73 - <artifactId>maven-jar-plugin</artifactId>
261.74 - <version>2.4</version>
261.75 - <configuration>
261.76 - <archive>
261.77 - <manifest>
261.78 - <addClasspath>true</addClasspath>
261.79 - <classpathPrefix>lib/</classpathPrefix>
261.80 - </manifest>
261.81 - </archive>
261.82 - </configuration>
261.83 - </plugin>
261.84 - <plugin>
261.85 - <artifactId>maven-assembly-plugin</artifactId>
261.86 - <version>2.4</version>
261.87 - <executions>
261.88 - <execution>
261.89 - <id>distro-assembly</id>
261.90 - <phase>package</phase>
261.91 - <goals>
261.92 - <goal>single</goal>
261.93 - </goals>
261.94 - <configuration>
261.95 - <descriptors>
261.96 - <descriptor>bck2brwsr-assembly.xml</descriptor>
261.97 - </descriptors>
261.98 - </configuration>
261.99 - </execution>
261.100 - </executions>
261.101 - </plugin>
261.102 - </plugins>
261.103 - </build>
261.104 -
261.105 - <dependencies>
261.106 - <dependency>
261.107 - <groupId>org.apidesign.bck2brwsr</groupId>
261.108 - <artifactId>emul</artifactId>
261.109 - <version>0.3-SNAPSHOT</version>
261.110 - <classifier>rt</classifier>
261.111 - </dependency>
261.112 - <dependency>
261.113 - <groupId>org.apidesign.bck2brwsr</groupId>
261.114 - <artifactId>javaquery.api</artifactId>
261.115 - <version>0.3-SNAPSHOT</version>
261.116 - </dependency>
261.117 - <dependency>
261.118 - <groupId>org.testng</groupId>
261.119 - <artifactId>testng</artifactId>
261.120 - <version>6.5.2</version>
261.121 - <scope>test</scope>
261.122 - </dependency>
261.123 - <dependency>
261.124 - <groupId>org.apidesign.bck2brwsr</groupId>
261.125 - <artifactId>vm4brwsr</artifactId>
261.126 - <classifier>js</classifier>
261.127 - <type>zip</type>
261.128 - <version>0.3-SNAPSHOT</version>
261.129 - <scope>provided</scope>
261.130 - </dependency>
261.131 - <dependency>
261.132 - <groupId>org.apidesign.bck2brwsr</groupId>
261.133 - <artifactId>vmtest</artifactId>
261.134 - <version>0.3-SNAPSHOT</version>
261.135 - <scope>test</scope>
261.136 - </dependency>
261.137 - </dependencies>
261.138 -</project>
262.1 --- a/rt/mojo/src/main/resources/archetype-resources/src/main/java/App.java Wed Feb 27 17:50:47 2013 +0100
262.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
262.3 @@ -1,34 +0,0 @@
262.4 -package ${package};
262.5 -
262.6 -import org.apidesign.bck2brwsr.htmlpage.api.*;
262.7 -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
262.8 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
262.9 -import org.apidesign.bck2brwsr.htmlpage.api.Property;
262.10 -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
262.11 -
262.12 -/** Edit the index.xhtml file. Use 'id' to name certain HTML elements.
262.13 - * Use this class to define behavior of the elements.
262.14 - */
262.15 -@Page(xhtml="index.html", className="Index", properties={
262.16 - @Property(name="name", type=String.class)
262.17 -})
262.18 -public class App {
262.19 - static {
262.20 - Index model = new Index();
262.21 - model.setName("World");
262.22 - model.applyBindings();
262.23 - }
262.24 -
262.25 - @On(event = CLICK, id="hello")
262.26 - static void hello(Index m) {
262.27 - GraphicsContext g = m.CANVAS.getContext();
262.28 - g.clearRect(0, 0, 1000, 1000);
262.29 - g.setFont("italic 40px Calibri");
262.30 - g.fillText(m.getHelloMessage(), 10, 40);
262.31 - }
262.32 -
262.33 - @ComputedProperty
262.34 - static String helloMessage(String name) {
262.35 - return "Hello " + name + "!";
262.36 - }
262.37 -}
263.1 --- a/rt/mojo/src/main/resources/archetype-resources/src/main/resources/index.html Wed Feb 27 17:50:47 2013 +0100
263.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
263.3 @@ -1,22 +0,0 @@
263.4 -<?xml version="1.0" encoding="UTF-8"?>
263.5 -<!DOCTYPE html>
263.6 -<html xmlns="http://www.w3.org/1999/xhtml">
263.7 - <head>
263.8 - <title>Bck2Brwsr's Hello World</title>
263.9 - </head>
263.10 - <body>
263.11 - <h1 data-bind="text: helloMessage">Loading Bck2Brwsr's Hello World...</h1>
263.12 - Your name: <input id='input' data-bind="value: name, valueUpdate: 'afterkeydown'"></input>
263.13 - <button id="hello">Say Hello!</button>
263.14 - <p>
263.15 - <canvas id="canvas" width="300" height="50">
263.16 - </canvas>
263.17 - </p>
263.18 -
263.19 - <script src="bck2brwsr.js"></script>
263.20 - <script type="text/javascript">
263.21 - var vm = bck2brwsr('${artifactId}-${version}.jar');
263.22 - vm.loadClass('${package}.App');
263.23 - </script>
263.24 - </body>
263.25 -</html>
264.1 --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java Wed Feb 27 17:50:47 2013 +0100
264.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
264.3 @@ -1,26 +0,0 @@
264.4 -package ${package};
264.5 -
264.6 -import static org.testng.Assert.*;
264.7 -import org.testng.annotations.BeforeMethod;
264.8 -import org.testng.annotations.Test;
264.9 -
264.10 -/** Demonstrating POJO testing of HTML page model. Runs in good old HotSpot
264.11 - * as it does not reference any HTML elements or browser functionality. Just
264.12 - * operates on the page model.
264.13 - *
264.14 - * @author Jaroslav Tulach <jtulach@netbeans.org>
264.15 - */
264.16 -public class AppTest {
264.17 - private Index model;
264.18 -
264.19 -
264.20 - @BeforeMethod
264.21 - public void initModel() {
264.22 - model = new Index().applyBindings();
264.23 - }
264.24 -
264.25 - @Test public void testHelloMessage() {
264.26 - model.setName("Joe");
264.27 - assertEquals(model.getHelloMessage(), "Hello Joe!", "Cleared after pressing +");
264.28 - }
264.29 -}
265.1 --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Wed Feb 27 17:50:47 2013 +0100
265.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
265.3 @@ -1,40 +0,0 @@
265.4 -package ${package};
265.5 -
265.6 -import org.apidesign.bck2brwsr.vmtest.Compare;
265.7 -import org.apidesign.bck2brwsr.vmtest.VMTest;
265.8 -import org.testng.annotations.Factory;
265.9 -
265.10 -/** Bck2brwsr cares about compatibility with real Java. Whatever API is
265.11 - * supported by bck2brwsr, it needs to behave the same way as when running
265.12 - * in HotSpot VM.
265.13 - * <p>
265.14 - * There can be bugs, however. To help us fix them, we kindly ask you to
265.15 - * write an "inconsistency" test. A test that compares behavior of the API
265.16 - * between real VM and bck2brwsr VM. This class is skeleton of such test.
265.17 - *
265.18 - * @author Jaroslav Tulach <jtulach@netbeans.org>
265.19 - */
265.20 -public class InconsistencyTest {
265.21 - /** A method to demonstrate inconsistency between bck2brwsr and HotSpot.
265.22 - * Make calls to an API that behaves strangely, return some result at
265.23 - * the end. No need to use any <code>assert</code>.
265.24 - *
265.25 - * @return value to compare between HotSpot and bck2brwsr
265.26 - */
265.27 - @Compare
265.28 - public int checkStringHashCode() throws Exception {
265.29 - return "Is string hashCode the same?".hashCode();
265.30 - }
265.31 -
265.32 - /** Factory method that creates a three tests for each method annotated with
265.33 - * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in
265.34 - * HotSpot, one in Rhino and the last one compares the results.
265.35 - *
265.36 - * @see org.apidesign.bck2brwsr.vmtest.VMTest
265.37 - */
265.38 - @Factory
265.39 - public static Object[] create() {
265.40 - return VMTest.create(InconsistencyTest.class);
265.41 - }
265.42 -
265.43 -}
266.1 --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Wed Feb 27 17:50:47 2013 +0100
266.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
266.3 @@ -1,46 +0,0 @@
266.4 -package ${package};
266.5 -
266.6 -import org.apidesign.bck2brwsr.htmlpage.api.OnEvent;
266.7 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
266.8 -import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
266.9 -import org.apidesign.bck2brwsr.vmtest.VMTest;
266.10 -import org.testng.annotations.Factory;
266.11 -
266.12 -/** Sometimes it is useful to run tests inside of the real browser.
266.13 - * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest}
266.14 - * and that is it. If your code references elements on the HTML page,
266.15 - * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which
266.16 - * will be made available on the page before your test starts.
266.17 - *
266.18 - * @author Jaroslav Tulach <jtulach@netbeans.org>
266.19 - */
266.20 -public class IntegrationTest {
266.21 -
266.22 - /** Write to testing code here. Use <code>assert</code> (but not TestNG's
266.23 - * Assert, as TestNG is not compiled with target 1.6 yet).
266.24 - */
266.25 - @HtmlFragment(
266.26 - "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
266.27 - "Your name: <input id='input' data-bind=\"value: name, valueUpdate: 'afterkeydown'\"></input>\n" +
266.28 - "<button id=\"hello\">Say Hello!</button>\n" +
266.29 - "<p>\n" +
266.30 - " <canvas id=\"canvas\" width=\"300\" height=\"50\"></canvas>\n" +
266.31 - "</p>\n"
266.32 - )
266.33 - @BrwsrTest
266.34 - public void modifyValueAssertChangeInModel() {
266.35 - Index m = new Index();
266.36 - m.setName("Joe Hacker");
266.37 - m.applyBindings();
266.38 - assert "Joe Hacker".equals(m.INPUT.getValue()) : "Value is really Joe Hacker: " + m.INPUT.getValue();
266.39 - m.INPUT.setValue("Happy Joe");
266.40 - m.triggerEvent(m.INPUT, OnEvent.CHANGE);
266.41 - assert "Happy Joe".equals(m.getName()) : "Name property updated to Happy Joe: " + m.getName();
266.42 - }
266.43 -
266.44 - @Factory
266.45 - public static Object[] create() {
266.46 - return VMTest.create(IntegrationTest.class);
266.47 - }
266.48 -
266.49 -}
267.1 --- a/rt/pom.xml Wed Feb 27 17:50:47 2013 +0100
267.2 +++ b/rt/pom.xml Mon Oct 07 14:20:58 2013 +0200
267.3 @@ -3,21 +3,19 @@
267.4 <modelVersion>4.0.0</modelVersion>
267.5 <groupId>org.apidesign.bck2brwsr</groupId>
267.6 <artifactId>rt</artifactId>
267.7 - <version>0.3-SNAPSHOT</version>
267.8 + <version>0.9-SNAPSHOT</version>
267.9 <packaging>pom</packaging>
267.10 - <name>Bck3Brwsr Runtime</name>
267.11 + <name>Bck2Brwsr Runtime</name>
267.12 <parent>
267.13 <groupId>org.apidesign</groupId>
267.14 <artifactId>bck2brwsr</artifactId>
267.15 - <version>0.3-SNAPSHOT</version>
267.16 + <version>0.9-SNAPSHOT</version>
267.17 </parent>
267.18 <modules>
267.19 <module>core</module>
267.20 <module>emul</module>
267.21 - <module>javap</module>
267.22 - <module>launcher</module>
267.23 <module>mojo</module>
267.24 <module>vm</module>
267.25 <module>vmtest</module>
267.26 </modules>
267.27 -</project>
267.28 \ No newline at end of file
267.29 +</project>
268.1 --- a/rt/vm/pom.xml Wed Feb 27 17:50:47 2013 +0100
268.2 +++ b/rt/vm/pom.xml Mon Oct 07 14:20:58 2013 +0200
268.3 @@ -1,15 +1,14 @@
268.4 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
268.5 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
268.6 +<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/xsd/maven-4.0.0.xsd">
268.7 <modelVersion>4.0.0</modelVersion>
268.8 <parent>
268.9 <groupId>org.apidesign.bck2brwsr</groupId>
268.10 <artifactId>rt</artifactId>
268.11 - <version>0.3-SNAPSHOT</version>
268.12 + <version>0.9-SNAPSHOT</version>
268.13 </parent>
268.14
268.15 <groupId>org.apidesign.bck2brwsr</groupId>
268.16 <artifactId>vm4brwsr</artifactId>
268.17 - <version>0.3-SNAPSHOT</version>
268.18 + <version>0.9-SNAPSHOT</version>
268.19 <packaging>jar</packaging>
268.20
268.21 <name>Virtual Machine for Browser</name>
268.22 @@ -44,6 +43,7 @@
268.23 <scm>
268.24 <connection>scm:hg:http://source.apidesign.org/hg/bck2brwsr</connection>
268.25 <url>http://source.apidesign.org/hg/bck2brwsr</url>
268.26 + <tag>HEAD</tag>
268.27 </scm>
268.28 <build>
268.29 <plugins>
268.30 @@ -69,6 +69,13 @@
268.31 </configuration>
268.32 </plugin>
268.33 <plugin>
268.34 + <groupId>org.apache.maven.plugins</groupId>
268.35 + <artifactId>maven-javadoc-plugin</artifactId>
268.36 + <configuration>
268.37 + <skip>false</skip>
268.38 + </configuration>
268.39 + </plugin>
268.40 + <plugin>
268.41 <groupId>org.codehaus.mojo</groupId>
268.42 <artifactId>exec-maven-plugin</artifactId>
268.43 <version>1.2.1</version>
268.44 @@ -76,18 +83,24 @@
268.45 <execution>
268.46 <id>generate-js</id>
268.47 <phase>process-classes</phase>
268.48 + <configuration>
268.49 + <executable>java</executable>
268.50 + <arguments>
268.51 + <argument>-Dskip.if.exists=true</argument>
268.52 + <argument>-cp</argument>
268.53 + <classpath />
268.54 + <argument>org.apidesign.vm4brwsr.Main</argument>
268.55 + <argument>--obfuscatelevel</argument>
268.56 + <argument>MINIMAL</argument>
268.57 + <argument>${project.build.directory}/bck2brwsr.js</argument>
268.58 + <argument>org/apidesign/vm4brwsr/Bck2Brwsr</argument>
268.59 + </arguments>
268.60 + </configuration>
268.61 <goals>
268.62 - <goal>java</goal>
268.63 + <goal>exec</goal>
268.64 </goals>
268.65 </execution>
268.66 </executions>
268.67 - <configuration>
268.68 - <mainClass>org.apidesign.vm4brwsr.Main</mainClass>
268.69 - <arguments>
268.70 - <argument>${project.build.directory}/bck2brwsr.js</argument>
268.71 - <argument>org/apidesign/vm4brwsr/Bck2Brwsr</argument>
268.72 - </arguments>
268.73 - </configuration>
268.74 </plugin>
268.75 <plugin>
268.76 <artifactId>maven-assembly-plugin</artifactId>
268.77 @@ -134,10 +147,16 @@
268.78 <scope>compile</scope>
268.79 </dependency>
268.80 <dependency>
268.81 - <groupId>${project.groupId}</groupId>
268.82 - <artifactId>javap</artifactId>
268.83 - <version>${project.version}</version>
268.84 + <groupId>com.google.javascript</groupId>
268.85 + <artifactId>closure-compiler</artifactId>
268.86 + <version>r2388</version>
268.87 <scope>compile</scope>
268.88 </dependency>
268.89 + <dependency>
268.90 + <groupId>org.apidesign.html</groupId>
268.91 + <artifactId>net.java.html.boot</artifactId>
268.92 + <scope>test</scope>
268.93 + <version>${net.java.html.version}</version>
268.94 + </dependency>
268.95 </dependencies>
268.96 </project>
269.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Wed Feb 27 17:50:47 2013 +0100
269.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Mon Oct 07 14:20:58 2013 +0200
269.3 @@ -54,46 +54,127 @@
269.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
269.5 */
269.6 public final class Bck2Brwsr {
269.7 - private Bck2Brwsr() {
269.8 + private final ObfuscationLevel level;
269.9 + private final StringArray classes;
269.10 + private final Resources res;
269.11 +
269.12 + private Bck2Brwsr(ObfuscationLevel level, StringArray classes, Resources resources) {
269.13 + this.level = level;
269.14 + this.classes = classes;
269.15 + this.res = resources;
269.16 }
269.17
269.18 - /** Generates virtual machine from bytes served by a <code>resources</code>
269.19 + /** Helper method to generate virtual machine from bytes served by a <code>resources</code>
269.20 * provider.
269.21 - *
269.22 + *
269.23 * @param out the output to write the generated JavaScript to
269.24 * @param resources provider of class files to use
269.25 * @param classes additional classes to include in the generated script
269.26 * @throws IOException I/O exception can be thrown when something goes wrong
269.27 */
269.28 public static void generate(Appendable out, Resources resources, String... classes) throws IOException {
269.29 - StringArray arr = StringArray.asList(classes);
269.30 - arr.add(VM.class.getName().replace('.', '/'));
269.31 - VM.compile(resources, out, arr);
269.32 + newCompiler().resources(resources).addRootClasses(classes).generate(out);
269.33 }
269.34 -
269.35 - /** Generates virtual machine from bytes served by a class loader.
269.36 - *
269.37 +
269.38 + /** Helper method to generate virtual machine from bytes served by a class loader.
269.39 + *
269.40 * @param out the output to write the generated JavaScript to
269.41 * @param loader class loader to load needed classes from
269.42 * @param classes additional classes to include in the generated script
269.43 * @throws IOException I/O exception can be thrown when something goes wrong
269.44 */
269.45 - public static void generate(Appendable out, final ClassLoader loader, String... classes) throws IOException {
269.46 - class R implements Resources {
269.47 - @Override
269.48 - public InputStream get(String name) throws IOException {
269.49 - Enumeration<URL> en = loader.getResources(name);
269.50 - URL u = null;
269.51 - while (en.hasMoreElements()) {
269.52 - u = en.nextElement();
269.53 - }
269.54 - if (u == null) {
269.55 - throw new IOException("Can't find " + name);
269.56 - }
269.57 - return u.openStream();
269.58 + public static void generate(Appendable out, ClassLoader loader, String... classes) throws IOException {
269.59 + newCompiler().resources(loader).addRootClasses(classes).generate(out);
269.60 + }
269.61 +
269.62 + /** Creates new instance of Bck2Brwsr compiler which is ready to generate
269.63 + * empty Bck2Brwsr virtual machine. The instance can be further
269.64 + * configured by calling chain of methods. For example:
269.65 + * <pre>
269.66 + * {@link #createCompiler()}.{@link #resources(org.apidesign.vm4brwsr.Bck2Brwsr.Resources) resources(loader)}.{@link #addRootClasses(java.lang.String[]) addRootClasses("your/Clazz")}.{@link #generate(java.lang.Appendable) generate(out)};
269.67 + * </pre>
269.68 + *
269.69 + * @return new instance of the Bck2Brwsr compiler
269.70 + * @since 0.5
269.71 + */
269.72 + public static Bck2Brwsr newCompiler() {
269.73 + StringArray arr = StringArray.asList(VM.class.getName().replace('.', '/'));
269.74 + return new Bck2Brwsr(ObfuscationLevel.NONE, arr, null);
269.75 + }
269.76 +
269.77 + /** Creates new instance of the Bck2Brwsr compiler which inherits
269.78 + * all values from <code>this</code> instance and adds additional classes
269.79 + * to the list of those that should be compiled by the {@link #generate(java.lang.Appendable)}
269.80 + * method.
269.81 + *
269.82 + * @param classes the classes to add to the compilation
269.83 + * @return new instance of the compiler
269.84 + */
269.85 + public Bck2Brwsr addRootClasses(String... classes) {
269.86 + if (classes.length == 0) {
269.87 + return this;
269.88 + } else {
269.89 + return new Bck2Brwsr(level, this.classes.addAndNew(classes), res);
269.90 + }
269.91 + }
269.92 +
269.93 + /** Changes the obfuscation level for the compiler by creating new instance
269.94 + * which inherits all values from <code>this</code> and adjust the level
269.95 + * of obfuscation.
269.96 + *
269.97 + * @param level the new level of obfuscation
269.98 + * @return new instance of the compiler with changed level of obfuscation
269.99 + * @since 0.5
269.100 + */
269.101 + public Bck2Brwsr obfuscation(ObfuscationLevel level) {
269.102 + return new Bck2Brwsr(level, classes, res);
269.103 + }
269.104 +
269.105 + /** A way to change the provider of additional resources (classes) for the
269.106 + * compiler.
269.107 + *
269.108 + * @param res the implementation of resources provider
269.109 + * @return new instance of the compiler with all values remaining the same, just
269.110 + * with different resources provider
269.111 + * @since 0.5
269.112 + */
269.113 + public Bck2Brwsr resources(Resources res) {
269.114 + return new Bck2Brwsr(level, classes, res);
269.115 + }
269.116 +
269.117 + /** A way to change the provider of additional resources (classes) for the
269.118 + * compiler by specifying classloader to use for loading them.
269.119 + *
269.120 + * @param loader class loader to load the resources from
269.121 + * @return new instance of the compiler with all values being the same, just
269.122 + * different resources provider
269.123 + * @since 0.5
269.124 + */
269.125 + public Bck2Brwsr resources(final ClassLoader loader) {
269.126 + return resources(new LdrRsrcs(loader));
269.127 + }
269.128 +
269.129 + /** Generates virtual machine based on previous configuration of the
269.130 + * compiler.
269.131 + *
269.132 + * @param out the output to write the generated JavaScript to
269.133 + * @since 0.5
269.134 + */
269.135 + public void generate(Appendable out) throws IOException {
269.136 + Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader());
269.137 + if (level != ObfuscationLevel.NONE) {
269.138 + try {
269.139 + ClosureWrapper.produceTo(out, level, r, classes);
269.140 + return;
269.141 + } catch (IOException ex) {
269.142 + throw ex;
269.143 + } catch (Throwable ex) {
269.144 + out.append("/* Failed to obfuscate: " + ex.getMessage()
269.145 + + " */\n");
269.146 }
269.147 }
269.148 - generate(out, new R(), classes);
269.149 +
269.150 + VM.compile(r, out, classes);
269.151 }
269.152
269.153 /** Provider of resources (classes and other files). The
270.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Mon Oct 07 14:20:58 2013 +0200
270.3 @@ -0,0 +1,3461 @@
270.4 +/*
270.5 + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
270.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
270.7 + *
270.8 + * This code is free software; you can redistribute it and/or modify it
270.9 + * under the terms of the GNU General Public License version 2 only, as
270.10 + * published by the Free Software Foundation. Oracle designates this
270.11 + * particular file as subject to the "Classpath" exception as provided
270.12 + * by Oracle in the LICENSE file that accompanied this code.
270.13 + *
270.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
270.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
270.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
270.17 + * version 2 for more details (a copy is included in the LICENSE file that
270.18 + * accompanied this code).
270.19 + *
270.20 + * You should have received a copy of the GNU General Public License version
270.21 + * 2 along with this work; if not, write to the Free Software Foundation,
270.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
270.23 + *
270.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
270.25 + * or visit www.oracle.com if you need additional information or have any
270.26 + * questions.
270.27 + */
270.28 +package org.apidesign.vm4brwsr;
270.29 +
270.30 +import java.io.ByteArrayInputStream;
270.31 +import java.io.DataInputStream;
270.32 +import java.io.IOException;
270.33 +import java.io.InputStream;
270.34 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
270.35 +import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
270.36 +
270.37 +/** This is a byte code parser heavily based on original code of JavaP utility.
270.38 + * As such I decided to keep the original Oracle's GPLv2 header.
270.39 + *
270.40 + * @author Jaroslav Tulach <jtulach@netbeans.org>
270.41 + */
270.42 +final class ByteCodeParser {
270.43 + private ByteCodeParser() {
270.44 + }
270.45 + /* Signature Characters */
270.46 + public static final char SIGC_VOID = 'V';
270.47 + public static final String SIG_VOID = "V";
270.48 + public static final char SIGC_BOOLEAN = 'Z';
270.49 + public static final String SIG_BOOLEAN = "Z";
270.50 + public static final char SIGC_BYTE = 'B';
270.51 + public static final String SIG_BYTE = "B";
270.52 + public static final char SIGC_CHAR = 'C';
270.53 + public static final String SIG_CHAR = "C";
270.54 + public static final char SIGC_SHORT = 'S';
270.55 + public static final String SIG_SHORT = "S";
270.56 + public static final char SIGC_INT = 'I';
270.57 + public static final String SIG_INT = "I";
270.58 + public static final char SIGC_LONG = 'J';
270.59 + public static final String SIG_LONG = "J";
270.60 + public static final char SIGC_FLOAT = 'F';
270.61 + public static final String SIG_FLOAT = "F";
270.62 + public static final char SIGC_DOUBLE = 'D';
270.63 + public static final String SIG_DOUBLE = "D";
270.64 + public static final char SIGC_ARRAY = '[';
270.65 + public static final String SIG_ARRAY = "[";
270.66 + public static final char SIGC_CLASS = 'L';
270.67 + public static final String SIG_CLASS = "L";
270.68 + public static final char SIGC_METHOD = '(';
270.69 + public static final String SIG_METHOD = "(";
270.70 + public static final char SIGC_ENDCLASS = ';';
270.71 + public static final String SIG_ENDCLASS = ";";
270.72 + public static final char SIGC_ENDMETHOD = ')';
270.73 + public static final String SIG_ENDMETHOD = ")";
270.74 + public static final char SIGC_PACKAGE = '/';
270.75 + public static final String SIG_PACKAGE = "/";
270.76 +
270.77 + /* Class File Constants */
270.78 + public static final int JAVA_MAGIC = 0xcafebabe;
270.79 + public static final int JAVA_VERSION = 45;
270.80 + public static final int JAVA_MINOR_VERSION = 3;
270.81 +
270.82 + /* Constant table */
270.83 + public static final int CONSTANT_UTF8 = 1;
270.84 + public static final int CONSTANT_UNICODE = 2;
270.85 + public static final int CONSTANT_INTEGER = 3;
270.86 + public static final int CONSTANT_FLOAT = 4;
270.87 + public static final int CONSTANT_LONG = 5;
270.88 + public static final int CONSTANT_DOUBLE = 6;
270.89 + public static final int CONSTANT_CLASS = 7;
270.90 + public static final int CONSTANT_STRING = 8;
270.91 + public static final int CONSTANT_FIELD = 9;
270.92 + public static final int CONSTANT_METHOD = 10;
270.93 + public static final int CONSTANT_INTERFACEMETHOD = 11;
270.94 + public static final int CONSTANT_NAMEANDTYPE = 12;
270.95 +
270.96 + /* Access Flags */
270.97 + public static final int ACC_PUBLIC = 0x00000001;
270.98 + public static final int ACC_PRIVATE = 0x00000002;
270.99 + public static final int ACC_PROTECTED = 0x00000004;
270.100 + public static final int ACC_STATIC = 0x00000008;
270.101 + public static final int ACC_FINAL = 0x00000010;
270.102 + public static final int ACC_SYNCHRONIZED = 0x00000020;
270.103 + public static final int ACC_SUPER = 0x00000020;
270.104 + public static final int ACC_VOLATILE = 0x00000040;
270.105 + public static final int ACC_TRANSIENT = 0x00000080;
270.106 + public static final int ACC_NATIVE = 0x00000100;
270.107 + public static final int ACC_INTERFACE = 0x00000200;
270.108 + public static final int ACC_ABSTRACT = 0x00000400;
270.109 + public static final int ACC_STRICT = 0x00000800;
270.110 + public static final int ACC_EXPLICIT = 0x00001000;
270.111 + public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
270.112 +
270.113 + /* Type codes */
270.114 + public static final int T_CLASS = 0x00000002;
270.115 + public static final int T_BOOLEAN = 0x00000004;
270.116 + public static final int T_CHAR = 0x00000005;
270.117 + public static final int T_FLOAT = 0x00000006;
270.118 + public static final int T_DOUBLE = 0x00000007;
270.119 + public static final int T_BYTE = 0x00000008;
270.120 + public static final int T_SHORT = 0x00000009;
270.121 + public static final int T_INT = 0x0000000a;
270.122 + public static final int T_LONG = 0x0000000b;
270.123 +
270.124 + /* Type codes for StackMap attribute */
270.125 + public static final int ITEM_Bogus =0; // an unknown or uninitialized value
270.126 + public static final int ITEM_Integer =1; // a 32-bit integer
270.127 + public static final int ITEM_Float =2; // not used
270.128 + public static final int ITEM_Double =3; // not used
270.129 + public static final int ITEM_Long =4; // a 64-bit integer
270.130 + public static final int ITEM_Null =5; // the type of null
270.131 + public static final int ITEM_InitObject =6; // "this" in constructor
270.132 + public static final int ITEM_Object =7; // followed by 2-byte index of class name
270.133 + public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new"
270.134 +
270.135 + /* Constants used in StackMapTable attribute */
270.136 + public static final int SAME_FRAME_BOUND = 64;
270.137 + public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128;
270.138 + public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
270.139 + public static final int SAME_FRAME_EXTENDED = 251;
270.140 + public static final int FULL_FRAME = 255;
270.141 +
270.142 + /* Opcodes */
270.143 + public static final int opc_dead = -2;
270.144 + public static final int opc_label = -1;
270.145 + public static final int opc_nop = 0;
270.146 + public static final int opc_aconst_null = 1;
270.147 + public static final int opc_iconst_m1 = 2;
270.148 + public static final int opc_iconst_0 = 3;
270.149 + public static final int opc_iconst_1 = 4;
270.150 + public static final int opc_iconst_2 = 5;
270.151 + public static final int opc_iconst_3 = 6;
270.152 + public static final int opc_iconst_4 = 7;
270.153 + public static final int opc_iconst_5 = 8;
270.154 + public static final int opc_lconst_0 = 9;
270.155 + public static final int opc_lconst_1 = 10;
270.156 + public static final int opc_fconst_0 = 11;
270.157 + public static final int opc_fconst_1 = 12;
270.158 + public static final int opc_fconst_2 = 13;
270.159 + public static final int opc_dconst_0 = 14;
270.160 + public static final int opc_dconst_1 = 15;
270.161 + public static final int opc_bipush = 16;
270.162 + public static final int opc_sipush = 17;
270.163 + public static final int opc_ldc = 18;
270.164 + public static final int opc_ldc_w = 19;
270.165 + public static final int opc_ldc2_w = 20;
270.166 + public static final int opc_iload = 21;
270.167 + public static final int opc_lload = 22;
270.168 + public static final int opc_fload = 23;
270.169 + public static final int opc_dload = 24;
270.170 + public static final int opc_aload = 25;
270.171 + public static final int opc_iload_0 = 26;
270.172 + public static final int opc_iload_1 = 27;
270.173 + public static final int opc_iload_2 = 28;
270.174 + public static final int opc_iload_3 = 29;
270.175 + public static final int opc_lload_0 = 30;
270.176 + public static final int opc_lload_1 = 31;
270.177 + public static final int opc_lload_2 = 32;
270.178 + public static final int opc_lload_3 = 33;
270.179 + public static final int opc_fload_0 = 34;
270.180 + public static final int opc_fload_1 = 35;
270.181 + public static final int opc_fload_2 = 36;
270.182 + public static final int opc_fload_3 = 37;
270.183 + public static final int opc_dload_0 = 38;
270.184 + public static final int opc_dload_1 = 39;
270.185 + public static final int opc_dload_2 = 40;
270.186 + public static final int opc_dload_3 = 41;
270.187 + public static final int opc_aload_0 = 42;
270.188 + public static final int opc_aload_1 = 43;
270.189 + public static final int opc_aload_2 = 44;
270.190 + public static final int opc_aload_3 = 45;
270.191 + public static final int opc_iaload = 46;
270.192 + public static final int opc_laload = 47;
270.193 + public static final int opc_faload = 48;
270.194 + public static final int opc_daload = 49;
270.195 + public static final int opc_aaload = 50;
270.196 + public static final int opc_baload = 51;
270.197 + public static final int opc_caload = 52;
270.198 + public static final int opc_saload = 53;
270.199 + public static final int opc_istore = 54;
270.200 + public static final int opc_lstore = 55;
270.201 + public static final int opc_fstore = 56;
270.202 + public static final int opc_dstore = 57;
270.203 + public static final int opc_astore = 58;
270.204 + public static final int opc_istore_0 = 59;
270.205 + public static final int opc_istore_1 = 60;
270.206 + public static final int opc_istore_2 = 61;
270.207 + public static final int opc_istore_3 = 62;
270.208 + public static final int opc_lstore_0 = 63;
270.209 + public static final int opc_lstore_1 = 64;
270.210 + public static final int opc_lstore_2 = 65;
270.211 + public static final int opc_lstore_3 = 66;
270.212 + public static final int opc_fstore_0 = 67;
270.213 + public static final int opc_fstore_1 = 68;
270.214 + public static final int opc_fstore_2 = 69;
270.215 + public static final int opc_fstore_3 = 70;
270.216 + public static final int opc_dstore_0 = 71;
270.217 + public static final int opc_dstore_1 = 72;
270.218 + public static final int opc_dstore_2 = 73;
270.219 + public static final int opc_dstore_3 = 74;
270.220 + public static final int opc_astore_0 = 75;
270.221 + public static final int opc_astore_1 = 76;
270.222 + public static final int opc_astore_2 = 77;
270.223 + public static final int opc_astore_3 = 78;
270.224 + public static final int opc_iastore = 79;
270.225 + public static final int opc_lastore = 80;
270.226 + public static final int opc_fastore = 81;
270.227 + public static final int opc_dastore = 82;
270.228 + public static final int opc_aastore = 83;
270.229 + public static final int opc_bastore = 84;
270.230 + public static final int opc_castore = 85;
270.231 + public static final int opc_sastore = 86;
270.232 + public static final int opc_pop = 87;
270.233 + public static final int opc_pop2 = 88;
270.234 + public static final int opc_dup = 89;
270.235 + public static final int opc_dup_x1 = 90;
270.236 + public static final int opc_dup_x2 = 91;
270.237 + public static final int opc_dup2 = 92;
270.238 + public static final int opc_dup2_x1 = 93;
270.239 + public static final int opc_dup2_x2 = 94;
270.240 + public static final int opc_swap = 95;
270.241 + public static final int opc_iadd = 96;
270.242 + public static final int opc_ladd = 97;
270.243 + public static final int opc_fadd = 98;
270.244 + public static final int opc_dadd = 99;
270.245 + public static final int opc_isub = 100;
270.246 + public static final int opc_lsub = 101;
270.247 + public static final int opc_fsub = 102;
270.248 + public static final int opc_dsub = 103;
270.249 + public static final int opc_imul = 104;
270.250 + public static final int opc_lmul = 105;
270.251 + public static final int opc_fmul = 106;
270.252 + public static final int opc_dmul = 107;
270.253 + public static final int opc_idiv = 108;
270.254 + public static final int opc_ldiv = 109;
270.255 + public static final int opc_fdiv = 110;
270.256 + public static final int opc_ddiv = 111;
270.257 + public static final int opc_irem = 112;
270.258 + public static final int opc_lrem = 113;
270.259 + public static final int opc_frem = 114;
270.260 + public static final int opc_drem = 115;
270.261 + public static final int opc_ineg = 116;
270.262 + public static final int opc_lneg = 117;
270.263 + public static final int opc_fneg = 118;
270.264 + public static final int opc_dneg = 119;
270.265 + public static final int opc_ishl = 120;
270.266 + public static final int opc_lshl = 121;
270.267 + public static final int opc_ishr = 122;
270.268 + public static final int opc_lshr = 123;
270.269 + public static final int opc_iushr = 124;
270.270 + public static final int opc_lushr = 125;
270.271 + public static final int opc_iand = 126;
270.272 + public static final int opc_land = 127;
270.273 + public static final int opc_ior = 128;
270.274 + public static final int opc_lor = 129;
270.275 + public static final int opc_ixor = 130;
270.276 + public static final int opc_lxor = 131;
270.277 + public static final int opc_iinc = 132;
270.278 + public static final int opc_i2l = 133;
270.279 + public static final int opc_i2f = 134;
270.280 + public static final int opc_i2d = 135;
270.281 + public static final int opc_l2i = 136;
270.282 + public static final int opc_l2f = 137;
270.283 + public static final int opc_l2d = 138;
270.284 + public static final int opc_f2i = 139;
270.285 + public static final int opc_f2l = 140;
270.286 + public static final int opc_f2d = 141;
270.287 + public static final int opc_d2i = 142;
270.288 + public static final int opc_d2l = 143;
270.289 + public static final int opc_d2f = 144;
270.290 + public static final int opc_i2b = 145;
270.291 + public static final int opc_int2byte = 145;
270.292 + public static final int opc_i2c = 146;
270.293 + public static final int opc_int2char = 146;
270.294 + public static final int opc_i2s = 147;
270.295 + public static final int opc_int2short = 147;
270.296 + public static final int opc_lcmp = 148;
270.297 + public static final int opc_fcmpl = 149;
270.298 + public static final int opc_fcmpg = 150;
270.299 + public static final int opc_dcmpl = 151;
270.300 + public static final int opc_dcmpg = 152;
270.301 + public static final int opc_ifeq = 153;
270.302 + public static final int opc_ifne = 154;
270.303 + public static final int opc_iflt = 155;
270.304 + public static final int opc_ifge = 156;
270.305 + public static final int opc_ifgt = 157;
270.306 + public static final int opc_ifle = 158;
270.307 + public static final int opc_if_icmpeq = 159;
270.308 + public static final int opc_if_icmpne = 160;
270.309 + public static final int opc_if_icmplt = 161;
270.310 + public static final int opc_if_icmpge = 162;
270.311 + public static final int opc_if_icmpgt = 163;
270.312 + public static final int opc_if_icmple = 164;
270.313 + public static final int opc_if_acmpeq = 165;
270.314 + public static final int opc_if_acmpne = 166;
270.315 + public static final int opc_goto = 167;
270.316 + public static final int opc_jsr = 168;
270.317 + public static final int opc_ret = 169;
270.318 + public static final int opc_tableswitch = 170;
270.319 + public static final int opc_lookupswitch = 171;
270.320 + public static final int opc_ireturn = 172;
270.321 + public static final int opc_lreturn = 173;
270.322 + public static final int opc_freturn = 174;
270.323 + public static final int opc_dreturn = 175;
270.324 + public static final int opc_areturn = 176;
270.325 + public static final int opc_return = 177;
270.326 + public static final int opc_getstatic = 178;
270.327 + public static final int opc_putstatic = 179;
270.328 + public static final int opc_getfield = 180;
270.329 + public static final int opc_putfield = 181;
270.330 + public static final int opc_invokevirtual = 182;
270.331 + public static final int opc_invokenonvirtual = 183;
270.332 + public static final int opc_invokespecial = 183;
270.333 + public static final int opc_invokestatic = 184;
270.334 + public static final int opc_invokeinterface = 185;
270.335 +// public static final int opc_xxxunusedxxx = 186;
270.336 + public static final int opc_new = 187;
270.337 + public static final int opc_newarray = 188;
270.338 + public static final int opc_anewarray = 189;
270.339 + public static final int opc_arraylength = 190;
270.340 + public static final int opc_athrow = 191;
270.341 + public static final int opc_checkcast = 192;
270.342 + public static final int opc_instanceof = 193;
270.343 + public static final int opc_monitorenter = 194;
270.344 + public static final int opc_monitorexit = 195;
270.345 + public static final int opc_wide = 196;
270.346 + public static final int opc_multianewarray = 197;
270.347 + public static final int opc_ifnull = 198;
270.348 + public static final int opc_ifnonnull = 199;
270.349 + public static final int opc_goto_w = 200;
270.350 + public static final int opc_jsr_w = 201;
270.351 + /* Pseudo-instructions */
270.352 + public static final int opc_bytecode = 203;
270.353 + public static final int opc_try = 204;
270.354 + public static final int opc_endtry = 205;
270.355 + public static final int opc_catch = 206;
270.356 + public static final int opc_var = 207;
270.357 + public static final int opc_endvar = 208;
270.358 + public static final int opc_localsmap = 209;
270.359 + public static final int opc_stackmap = 210;
270.360 + /* PicoJava prefixes */
270.361 + public static final int opc_nonpriv = 254;
270.362 + public static final int opc_priv = 255;
270.363 +
270.364 + /* Wide instructions */
270.365 + public static final int opc_iload_w = (opc_wide<<8)|opc_iload;
270.366 + public static final int opc_lload_w = (opc_wide<<8)|opc_lload;
270.367 + public static final int opc_fload_w = (opc_wide<<8)|opc_fload;
270.368 + public static final int opc_dload_w = (opc_wide<<8)|opc_dload;
270.369 + public static final int opc_aload_w = (opc_wide<<8)|opc_aload;
270.370 + public static final int opc_istore_w = (opc_wide<<8)|opc_istore;
270.371 + public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore;
270.372 + public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore;
270.373 + public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore;
270.374 + public static final int opc_astore_w = (opc_wide<<8)|opc_astore;
270.375 + public static final int opc_ret_w = (opc_wide<<8)|opc_ret;
270.376 + public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc;
270.377 +
270.378 + /* Opcode Names */
270.379 + public static final String opcNamesTab[] = {
270.380 + "nop",
270.381 + "aconst_null",
270.382 + "iconst_m1",
270.383 + "iconst_0",
270.384 + "iconst_1",
270.385 + "iconst_2",
270.386 + "iconst_3",
270.387 + "iconst_4",
270.388 + "iconst_5",
270.389 + "lconst_0",
270.390 + "lconst_1",
270.391 + "fconst_0",
270.392 + "fconst_1",
270.393 + "fconst_2",
270.394 + "dconst_0",
270.395 + "dconst_1",
270.396 + "bipush",
270.397 + "sipush",
270.398 + "ldc",
270.399 + "ldc_w",
270.400 + "ldc2_w",
270.401 + "iload",
270.402 + "lload",
270.403 + "fload",
270.404 + "dload",
270.405 + "aload",
270.406 + "iload_0",
270.407 + "iload_1",
270.408 + "iload_2",
270.409 + "iload_3",
270.410 + "lload_0",
270.411 + "lload_1",
270.412 + "lload_2",
270.413 + "lload_3",
270.414 + "fload_0",
270.415 + "fload_1",
270.416 + "fload_2",
270.417 + "fload_3",
270.418 + "dload_0",
270.419 + "dload_1",
270.420 + "dload_2",
270.421 + "dload_3",
270.422 + "aload_0",
270.423 + "aload_1",
270.424 + "aload_2",
270.425 + "aload_3",
270.426 + "iaload",
270.427 + "laload",
270.428 + "faload",
270.429 + "daload",
270.430 + "aaload",
270.431 + "baload",
270.432 + "caload",
270.433 + "saload",
270.434 + "istore",
270.435 + "lstore",
270.436 + "fstore",
270.437 + "dstore",
270.438 + "astore",
270.439 + "istore_0",
270.440 + "istore_1",
270.441 + "istore_2",
270.442 + "istore_3",
270.443 + "lstore_0",
270.444 + "lstore_1",
270.445 + "lstore_2",
270.446 + "lstore_3",
270.447 + "fstore_0",
270.448 + "fstore_1",
270.449 + "fstore_2",
270.450 + "fstore_3",
270.451 + "dstore_0",
270.452 + "dstore_1",
270.453 + "dstore_2",
270.454 + "dstore_3",
270.455 + "astore_0",
270.456 + "astore_1",
270.457 + "astore_2",
270.458 + "astore_3",
270.459 + "iastore",
270.460 + "lastore",
270.461 + "fastore",
270.462 + "dastore",
270.463 + "aastore",
270.464 + "bastore",
270.465 + "castore",
270.466 + "sastore",
270.467 + "pop",
270.468 + "pop2",
270.469 + "dup",
270.470 + "dup_x1",
270.471 + "dup_x2",
270.472 + "dup2",
270.473 + "dup2_x1",
270.474 + "dup2_x2",
270.475 + "swap",
270.476 + "iadd",
270.477 + "ladd",
270.478 + "fadd",
270.479 + "dadd",
270.480 + "isub",
270.481 + "lsub",
270.482 + "fsub",
270.483 + "dsub",
270.484 + "imul",
270.485 + "lmul",
270.486 + "fmul",
270.487 + "dmul",
270.488 + "idiv",
270.489 + "ldiv",
270.490 + "fdiv",
270.491 + "ddiv",
270.492 + "irem",
270.493 + "lrem",
270.494 + "frem",
270.495 + "drem",
270.496 + "ineg",
270.497 + "lneg",
270.498 + "fneg",
270.499 + "dneg",
270.500 + "ishl",
270.501 + "lshl",
270.502 + "ishr",
270.503 + "lshr",
270.504 + "iushr",
270.505 + "lushr",
270.506 + "iand",
270.507 + "land",
270.508 + "ior",
270.509 + "lor",
270.510 + "ixor",
270.511 + "lxor",
270.512 + "iinc",
270.513 + "i2l",
270.514 + "i2f",
270.515 + "i2d",
270.516 + "l2i",
270.517 + "l2f",
270.518 + "l2d",
270.519 + "f2i",
270.520 + "f2l",
270.521 + "f2d",
270.522 + "d2i",
270.523 + "d2l",
270.524 + "d2f",
270.525 + "i2b",
270.526 + "i2c",
270.527 + "i2s",
270.528 + "lcmp",
270.529 + "fcmpl",
270.530 + "fcmpg",
270.531 + "dcmpl",
270.532 + "dcmpg",
270.533 + "ifeq",
270.534 + "ifne",
270.535 + "iflt",
270.536 + "ifge",
270.537 + "ifgt",
270.538 + "ifle",
270.539 + "if_icmpeq",
270.540 + "if_icmpne",
270.541 + "if_icmplt",
270.542 + "if_icmpge",
270.543 + "if_icmpgt",
270.544 + "if_icmple",
270.545 + "if_acmpeq",
270.546 + "if_acmpne",
270.547 + "goto",
270.548 + "jsr",
270.549 + "ret",
270.550 + "tableswitch",
270.551 + "lookupswitch",
270.552 + "ireturn",
270.553 + "lreturn",
270.554 + "freturn",
270.555 + "dreturn",
270.556 + "areturn",
270.557 + "return",
270.558 + "getstatic",
270.559 + "putstatic",
270.560 + "getfield",
270.561 + "putfield",
270.562 + "invokevirtual",
270.563 + "invokespecial", // was "invokenonvirtual",
270.564 + "invokestatic",
270.565 + "invokeinterface",
270.566 + "bytecode 186", //"xxxunusedxxx",
270.567 + "new",
270.568 + "newarray",
270.569 + "anewarray",
270.570 + "arraylength",
270.571 + "athrow",
270.572 + "checkcast",
270.573 + "instanceof",
270.574 + "monitorenter",
270.575 + "monitorexit",
270.576 + null, // "wide",
270.577 + "multianewarray",
270.578 + "ifnull",
270.579 + "ifnonnull",
270.580 + "goto_w",
270.581 + "jsr_w",
270.582 + "bytecode 202", // "breakpoint",
270.583 + "bytecode",
270.584 + "try",
270.585 + "endtry",
270.586 + "catch",
270.587 + "var",
270.588 + "endvar",
270.589 + "locals_map",
270.590 + "stack_map"
270.591 + };
270.592 +
270.593 + /* Opcode Lengths */
270.594 + public static final int opcLengthsTab[] = {
270.595 + 1,
270.596 + 1,
270.597 + 1,
270.598 + 1,
270.599 + 1,
270.600 + 1,
270.601 + 1,
270.602 + 1,
270.603 + 1,
270.604 + 1,
270.605 + 1,
270.606 + 1,
270.607 + 1,
270.608 + 1,
270.609 + 1,
270.610 + 1,
270.611 + 2,
270.612 + 3,
270.613 + 2,
270.614 + 3,
270.615 + 3,
270.616 + 2,
270.617 + 2,
270.618 + 2,
270.619 + 2,
270.620 + 2,
270.621 + 1,
270.622 + 1,
270.623 + 1,
270.624 + 1,
270.625 + 1,
270.626 + 1,
270.627 + 1,
270.628 + 1,
270.629 + 1,
270.630 + 1,
270.631 + 1,
270.632 + 1,
270.633 + 1,
270.634 + 1,
270.635 + 1,
270.636 + 1,
270.637 + 1,
270.638 + 1,
270.639 + 1,
270.640 + 1,
270.641 + 1,
270.642 + 1,
270.643 + 1,
270.644 + 1,
270.645 + 1,
270.646 + 1,
270.647 + 1,
270.648 + 1,
270.649 + 2,
270.650 + 2,
270.651 + 2,
270.652 + 2,
270.653 + 2,
270.654 + 1,
270.655 + 1,
270.656 + 1,
270.657 + 1,
270.658 + 1,
270.659 + 1,
270.660 + 1,
270.661 + 1,
270.662 + 1,
270.663 + 1,
270.664 + 1,
270.665 + 1,
270.666 + 1,
270.667 + 1,
270.668 + 1,
270.669 + 1,
270.670 + 1,
270.671 + 1,
270.672 + 1,
270.673 + 1,
270.674 + 1,
270.675 + 1,
270.676 + 1,
270.677 + 1,
270.678 + 1,
270.679 + 1,
270.680 + 1,
270.681 + 1,
270.682 + 1,
270.683 + 1,
270.684 + 1,
270.685 + 1,
270.686 + 1,
270.687 + 1,
270.688 + 1,
270.689 + 1,
270.690 + 1,
270.691 + 1,
270.692 + 1,
270.693 + 1,
270.694 + 1,
270.695 + 1,
270.696 + 1,
270.697 + 1,
270.698 + 1,
270.699 + 1,
270.700 + 1,
270.701 + 1,
270.702 + 1,
270.703 + 1,
270.704 + 1,
270.705 + 1,
270.706 + 1,
270.707 + 1,
270.708 + 1,
270.709 + 1,
270.710 + 1,
270.711 + 1,
270.712 + 1,
270.713 + 1,
270.714 + 1,
270.715 + 1,
270.716 + 1,
270.717 + 1,
270.718 + 1,
270.719 + 1,
270.720 + 1,
270.721 + 1,
270.722 + 1,
270.723 + 1,
270.724 + 1,
270.725 + 1,
270.726 + 1,
270.727 + 3,
270.728 + 1,
270.729 + 1,
270.730 + 1,
270.731 + 1,
270.732 + 1,
270.733 + 1,
270.734 + 1,
270.735 + 1,
270.736 + 1,
270.737 + 1,
270.738 + 1,
270.739 + 1,
270.740 + 1,
270.741 + 1,
270.742 + 1,
270.743 + 1,
270.744 + 1,
270.745 + 1,
270.746 + 1,
270.747 + 1,
270.748 + 3,
270.749 + 3,
270.750 + 3,
270.751 + 3,
270.752 + 3,
270.753 + 3,
270.754 + 3,
270.755 + 3,
270.756 + 3,
270.757 + 3,
270.758 + 3,
270.759 + 3,
270.760 + 3,
270.761 + 3,
270.762 + 3,
270.763 + 3,
270.764 + 2,
270.765 + 99,
270.766 + 99,
270.767 + 1,
270.768 + 1,
270.769 + 1,
270.770 + 1,
270.771 + 1,
270.772 + 1,
270.773 + 3,
270.774 + 3,
270.775 + 3,
270.776 + 3,
270.777 + 3,
270.778 + 3,
270.779 + 3,
270.780 + 5,
270.781 + 0,
270.782 + 3,
270.783 + 2,
270.784 + 3,
270.785 + 1,
270.786 + 1,
270.787 + 3,
270.788 + 3,
270.789 + 1,
270.790 + 1,
270.791 + 0, // wide
270.792 + 4,
270.793 + 3,
270.794 + 3,
270.795 + 5,
270.796 + 5,
270.797 + 1,
270.798 + 1, 0, 0, 0, 0, 0 // pseudo
270.799 + };
270.800 +
270.801 + /**
270.802 + * End of input
270.803 + */
270.804 + public static final int EOF = -1;
270.805 +
270.806 + /*
270.807 + * Flags
270.808 + */
270.809 + public static final int F_VERBOSE = 1 << 0;
270.810 + public static final int F_DUMP = 1 << 1;
270.811 + public static final int F_WARNINGS = 1 << 2;
270.812 + public static final int F_DEBUG = 1 << 3;
270.813 + public static final int F_OPTIMIZE = 1 << 4;
270.814 + public static final int F_DEPENDENCIES = 1 << 5;
270.815 +
270.816 + /*
270.817 + * Type codes
270.818 + */
270.819 + public static final int TC_BOOLEAN = 0;
270.820 + public static final int TC_BYTE = 1;
270.821 + public static final int TC_CHAR = 2;
270.822 + public static final int TC_SHORT = 3;
270.823 + public static final int TC_INT = 4;
270.824 + public static final int TC_LONG = 5;
270.825 + public static final int TC_FLOAT = 6;
270.826 + public static final int TC_DOUBLE = 7;
270.827 + public static final int TC_NULL = 8;
270.828 + public static final int TC_ARRAY = 9;
270.829 + public static final int TC_CLASS = 10;
270.830 + public static final int TC_VOID = 11;
270.831 + public static final int TC_METHOD = 12;
270.832 + public static final int TC_ERROR = 13;
270.833 +
270.834 + /*
270.835 + * Type Masks
270.836 + */
270.837 + public static final int TM_NULL = 1 << TC_NULL;
270.838 + public static final int TM_VOID = 1 << TC_VOID;
270.839 + public static final int TM_BOOLEAN = 1 << TC_BOOLEAN;
270.840 + public static final int TM_BYTE = 1 << TC_BYTE;
270.841 + public static final int TM_CHAR = 1 << TC_CHAR;
270.842 + public static final int TM_SHORT = 1 << TC_SHORT;
270.843 + public static final int TM_INT = 1 << TC_INT;
270.844 + public static final int TM_LONG = 1 << TC_LONG;
270.845 + public static final int TM_FLOAT = 1 << TC_FLOAT;
270.846 + public static final int TM_DOUBLE = 1 << TC_DOUBLE;
270.847 + public static final int TM_ARRAY = 1 << TC_ARRAY;
270.848 + public static final int TM_CLASS = 1 << TC_CLASS;
270.849 + public static final int TM_METHOD = 1 << TC_METHOD;
270.850 + public static final int TM_ERROR = 1 << TC_ERROR;
270.851 +
270.852 + public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT;
270.853 + public static final int TM_NUM32 = TM_INT32 | TM_FLOAT;
270.854 + public static final int TM_NUM64 = TM_LONG | TM_DOUBLE;
270.855 + public static final int TM_INTEGER = TM_INT32 | TM_LONG;
270.856 + public static final int TM_REAL = TM_FLOAT | TM_DOUBLE;
270.857 + public static final int TM_NUMBER = TM_INTEGER | TM_REAL;
270.858 + public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL;
270.859 +
270.860 + /*
270.861 + * Class status
270.862 + */
270.863 + public static final int CS_UNDEFINED = 0;
270.864 + public static final int CS_UNDECIDED = 1;
270.865 + public static final int CS_BINARY = 2;
270.866 + public static final int CS_SOURCE = 3;
270.867 + public static final int CS_PARSED = 4;
270.868 + public static final int CS_COMPILED = 5;
270.869 + public static final int CS_NOTFOUND = 6;
270.870 +
270.871 + /*
270.872 + * Attributes
270.873 + */
270.874 + public static final int ATT_ALL = -1;
270.875 + public static final int ATT_CODE = 1;
270.876 +
270.877 + /*
270.878 + * Number of bits used in file offsets
270.879 + */
270.880 + public static final int OFFSETBITS = 19;
270.881 + public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1;
270.882 + public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1;
270.883 +
270.884 + /*
270.885 + * Operators
270.886 + */
270.887 + public final int COMMA = 0;
270.888 + public final int ASSIGN = 1;
270.889 +
270.890 + public final int ASGMUL = 2;
270.891 + public final int ASGDIV = 3;
270.892 + public final int ASGREM = 4;
270.893 + public final int ASGADD = 5;
270.894 + public final int ASGSUB = 6;
270.895 + public final int ASGLSHIFT = 7;
270.896 + public final int ASGRSHIFT = 8;
270.897 + public final int ASGURSHIFT = 9;
270.898 + public final int ASGBITAND = 10;
270.899 + public final int ASGBITOR = 11;
270.900 + public final int ASGBITXOR = 12;
270.901 +
270.902 + public final int COND = 13;
270.903 + public final int OR = 14;
270.904 + public final int AND = 15;
270.905 + public final int BITOR = 16;
270.906 + public final int BITXOR = 17;
270.907 + public final int BITAND = 18;
270.908 + public final int NE = 19;
270.909 + public final int EQ = 20;
270.910 + public final int GE = 21;
270.911 + public final int GT = 22;
270.912 + public final int LE = 23;
270.913 + public final int LT = 24;
270.914 + public final int INSTANCEOF = 25;
270.915 + public final int LSHIFT = 26;
270.916 + public final int RSHIFT = 27;
270.917 + public final int URSHIFT = 28;
270.918 + public final int ADD = 29;
270.919 + public final int SUB = 30;
270.920 + public final int DIV = 31;
270.921 + public final int REM = 32;
270.922 + public final int MUL = 33;
270.923 + public final int CAST = 34; // (x)y
270.924 + public final int POS = 35; // +x
270.925 + public final int NEG = 36; // -x
270.926 + public final int NOT = 37;
270.927 + public final int BITNOT = 38;
270.928 + public final int PREINC = 39; // ++x
270.929 + public final int PREDEC = 40; // --x
270.930 + public final int NEWARRAY = 41;
270.931 + public final int NEWINSTANCE = 42;
270.932 + public final int NEWFROMNAME = 43;
270.933 + public final int POSTINC = 44; // x++
270.934 + public final int POSTDEC = 45; // x--
270.935 + public final int FIELD = 46;
270.936 + public final int METHOD = 47; // x(y)
270.937 + public final int ARRAYACCESS = 48; // x[y]
270.938 + public final int NEW = 49;
270.939 + public final int INC = 50;
270.940 + public final int DEC = 51;
270.941 +
270.942 + public final int CONVERT = 55; // implicit conversion
270.943 + public final int EXPR = 56; // (x)
270.944 + public final int ARRAY = 57; // {x, y, ...}
270.945 + public final int GOTO = 58;
270.946 +
270.947 + /*
270.948 + * Value tokens
270.949 + */
270.950 + public final int IDENT = 60;
270.951 + public final int BOOLEANVAL = 61;
270.952 + public final int BYTEVAL = 62;
270.953 + public final int CHARVAL = 63;
270.954 + public final int SHORTVAL = 64;
270.955 + public final int INTVAL = 65;
270.956 + public final int LONGVAL = 66;
270.957 + public final int FLOATVAL = 67;
270.958 + public final int DOUBLEVAL = 68;
270.959 + public final int STRINGVAL = 69;
270.960 +
270.961 + /*
270.962 + * Type keywords
270.963 + */
270.964 + public final int BYTE = 70;
270.965 + public final int CHAR = 71;
270.966 + public final int SHORT = 72;
270.967 + public final int INT = 73;
270.968 + public final int LONG = 74;
270.969 + public final int FLOAT = 75;
270.970 + public final int DOUBLE = 76;
270.971 + public final int VOID = 77;
270.972 + public final int BOOLEAN = 78;
270.973 +
270.974 + /*
270.975 + * Expression keywords
270.976 + */
270.977 + public final int TRUE = 80;
270.978 + public final int FALSE = 81;
270.979 + public final int THIS = 82;
270.980 + public final int SUPER = 83;
270.981 + public final int NULL = 84;
270.982 +
270.983 + /*
270.984 + * Statement keywords
270.985 + */
270.986 + public final int IF = 90;
270.987 + public final int ELSE = 91;
270.988 + public final int FOR = 92;
270.989 + public final int WHILE = 93;
270.990 + public final int DO = 94;
270.991 + public final int SWITCH = 95;
270.992 + public final int CASE = 96;
270.993 + public final int DEFAULT = 97;
270.994 + public final int BREAK = 98;
270.995 + public final int CONTINUE = 99;
270.996 + public final int RETURN = 100;
270.997 + public final int TRY = 101;
270.998 + public final int CATCH = 102;
270.999 + public final int FINALLY = 103;
270.1000 + public final int THROW = 104;
270.1001 + public final int STAT = 105;
270.1002 + public final int EXPRESSION = 106;
270.1003 + public final int DECLARATION = 107;
270.1004 + public final int VARDECLARATION = 108;
270.1005 +
270.1006 + /*
270.1007 + * Declaration keywords
270.1008 + */
270.1009 + public final int IMPORT = 110;
270.1010 + public final int CLASS = 111;
270.1011 + public final int EXTENDS = 112;
270.1012 + public final int IMPLEMENTS = 113;
270.1013 + public final int INTERFACE = 114;
270.1014 + public final int PACKAGE = 115;
270.1015 +
270.1016 + /*
270.1017 + * Modifier keywords
270.1018 + */
270.1019 + public final int PRIVATE = 120;
270.1020 + public final int PUBLIC = 121;
270.1021 + public final int PROTECTED = 122;
270.1022 + public final int CONST = 123;
270.1023 + public final int STATIC = 124;
270.1024 + public final int TRANSIENT = 125;
270.1025 + public final int SYNCHRONIZED = 126;
270.1026 + public final int NATIVE = 127;
270.1027 + public final int FINAL = 128;
270.1028 + public final int VOLATILE = 129;
270.1029 + public final int ABSTRACT = 130;
270.1030 + public final int STRICT = 165;
270.1031 +
270.1032 + /*
270.1033 + * Punctuation
270.1034 + */
270.1035 + public final int SEMICOLON = 135;
270.1036 + public final int COLON = 136;
270.1037 + public final int QUESTIONMARK = 137;
270.1038 + public final int LBRACE = 138;
270.1039 + public final int RBRACE = 139;
270.1040 + public final int LPAREN = 140;
270.1041 + public final int RPAREN = 141;
270.1042 + public final int LSQBRACKET = 142;
270.1043 + public final int RSQBRACKET = 143;
270.1044 + public final int THROWS = 144;
270.1045 +
270.1046 + /*
270.1047 + * Special tokens
270.1048 + */
270.1049 + public final int ERROR = 145; // an error
270.1050 + public final int COMMENT = 146; // not used anymore.
270.1051 + public final int TYPE = 147;
270.1052 + public final int LENGTH = 148;
270.1053 + public final int INLINERETURN = 149;
270.1054 + public final int INLINEMETHOD = 150;
270.1055 + public final int INLINENEWINSTANCE = 151;
270.1056 +
270.1057 + /*
270.1058 + * Added for jasm
270.1059 + */
270.1060 + public final int METHODREF = 152;
270.1061 + public final int FIELDREF = 153;
270.1062 + public final int STACK = 154;
270.1063 + public final int LOCAL = 155;
270.1064 + public final int CPINDEX = 156;
270.1065 + public final int CPNAME = 157;
270.1066 + public final int SIGN = 158;
270.1067 + public final int BITS = 159;
270.1068 + public final int INF = 160;
270.1069 + public final int NAN = 161;
270.1070 + public final int INNERCLASS = 162;
270.1071 + public final int OF = 163;
270.1072 + public final int SYNTHETIC = 164;
270.1073 +// last used=165;
270.1074 +
270.1075 + /*
270.1076 + * Operator precedence
270.1077 + */
270.1078 + public static final int opPrecedence[] = {
270.1079 + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
270.1080 + 11, 11, 11, 12, 13, 14, 15, 16, 17, 18,
270.1081 + 18, 19, 19, 19, 19, 19, 20, 20, 20, 21,
270.1082 + 21, 22, 22, 22, 23, 24, 24, 24, 24, 24,
270.1083 + 24, 25, 25, 26, 26, 26, 26, 26, 26
270.1084 + };
270.1085 +
270.1086 + /*
270.1087 + * Operator names
270.1088 + */
270.1089 + public static final String opNames[] = {
270.1090 + ",", "=", "*=", "/=", "%=",
270.1091 + "+=", "-=", "<<=", ">>=", "<<<=",
270.1092 + "&=", "|=", "^=", "?:", "||",
270.1093 + "&&", "|", "^", "&", "!=",
270.1094 + "==", ">=", ">", "<=", "<",
270.1095 + "instanceof", "<<", ">>", "<<<", "+",
270.1096 + "-", "/", "%", "*", "cast",
270.1097 + "+", "-", "!", "~", "++",
270.1098 + "--", "new", "new", "new", "++",
270.1099 + "--", "field", "method", "[]", "new",
270.1100 + "++", "--", null, null, null,
270.1101 +
270.1102 + "convert", "expr", "array", "goto", null,
270.1103 +
270.1104 + "Identifier", "Boolean", "Byte", "Char", "Short",
270.1105 + "Integer", "Long", "Float", "Double", "String",
270.1106 +
270.1107 + "byte", "char", "short", "int", "long",
270.1108 + "float", "double", "void", "boolean", null,
270.1109 +
270.1110 + "true", "false", "this", "super", "null",
270.1111 + null, null, null, null, null,
270.1112 +
270.1113 + "if", "else", "for", "while", "do",
270.1114 + "switch", "case", "default", "break", "continue",
270.1115 + "return", "try", "catch", "finally", "throw",
270.1116 + "stat", "expression", "declaration", "declaration", null,
270.1117 +
270.1118 + "import", "class", "extends", "implements", "interface",
270.1119 + "package", null, null, null, null,
270.1120 +
270.1121 + "private", "public", "protected", "const", "static",
270.1122 + "transient", "synchronized", "native", "final", "volatile",
270.1123 + "abstract", null, null, null, null,
270.1124 +
270.1125 + ";", ":", "?", "{", "}",
270.1126 + "(", ")", "[", "]", "throws",
270.1127 + "error", "comment", "type", "length", "inline-return",
270.1128 + "inline-method", "inline-new",
270.1129 + "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN",
270.1130 + "bits", "INF", "NaN", "InnerClass", "of", "synthetic"
270.1131 + };
270.1132 +
270.1133 + static class AnnotationParser {
270.1134 +
270.1135 + private final boolean textual;
270.1136 + private final boolean iterateArray;
270.1137 +
270.1138 + protected AnnotationParser(boolean textual, boolean iterateArray) {
270.1139 + this.textual = textual;
270.1140 + this.iterateArray = iterateArray;
270.1141 + }
270.1142 +
270.1143 + protected void visitAnnotationStart(String type, boolean top) throws IOException {
270.1144 + }
270.1145 +
270.1146 + protected void visitAnnotationEnd(String type, boolean top) throws IOException {
270.1147 + }
270.1148 +
270.1149 + protected void visitValueStart(String attrName, char type) throws IOException {
270.1150 + }
270.1151 +
270.1152 + protected void visitValueEnd(String attrName, char type) throws IOException {
270.1153 + }
270.1154 +
270.1155 + protected void visitAttr(
270.1156 + String annoType, String attr, String attrType, String value) throws IOException {
270.1157 + }
270.1158 +
270.1159 + protected void visitEnumAttr(
270.1160 + String annoType, String attr, String attrType, String value) throws IOException {
270.1161 + visitAttr(annoType, attr, attrType, value);
270.1162 + }
270.1163 +
270.1164 + /**
270.1165 + * Initialize the parsing with constant pool from
270.1166 + * <code>cd</code>.
270.1167 + *
270.1168 + * @param attr the attribute defining annotations
270.1169 + * @param cd constant pool
270.1170 + * @throws IOException in case I/O fails
270.1171 + */
270.1172 + public final void parse(byte[] attr, ClassData cd) throws IOException {
270.1173 + ByteArrayInputStream is = new ByteArrayInputStream(attr);
270.1174 + DataInputStream dis = new DataInputStream(is);
270.1175 + try {
270.1176 + read(dis, cd);
270.1177 + } finally {
270.1178 + is.close();
270.1179 + }
270.1180 + }
270.1181 +
270.1182 + private void read(DataInputStream dis, ClassData cd) throws IOException {
270.1183 + int cnt = dis.readUnsignedShort();
270.1184 + for (int i = 0; i < cnt; i++) {
270.1185 + readAnno(dis, cd, true);
270.1186 + }
270.1187 + }
270.1188 +
270.1189 + private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
270.1190 + int type = dis.readUnsignedShort();
270.1191 + String typeName = cd.StringValue(type);
270.1192 + visitAnnotationStart(typeName, top);
270.1193 + int cnt = dis.readUnsignedShort();
270.1194 + for (int i = 0; i < cnt; i++) {
270.1195 + String attrName = cd.StringValue(dis.readUnsignedShort());
270.1196 + readValue(dis, cd, typeName, attrName);
270.1197 + }
270.1198 + visitAnnotationEnd(typeName, top);
270.1199 + if (cnt == 0) {
270.1200 + visitAttr(typeName, null, null, null);
270.1201 + }
270.1202 + }
270.1203 +
270.1204 + private void readValue(
270.1205 + DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
270.1206 + char type = (char) dis.readByte();
270.1207 + visitValueStart(attrName, type);
270.1208 + if (type == '@') {
270.1209 + readAnno(dis, cd, false);
270.1210 + } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
270.1211 + int primitive = dis.readUnsignedShort();
270.1212 + String val = cd.stringValue(primitive, textual);
270.1213 + String attrType;
270.1214 + if (type == 's') {
270.1215 + attrType = "Ljava_lang_String_2";
270.1216 + if (textual) {
270.1217 + val = '"' + val + '"';
270.1218 + }
270.1219 + } else {
270.1220 + attrType = "" + type;
270.1221 + }
270.1222 + visitAttr(typeName, attrName, attrType, val);
270.1223 + } else if (type == 'c') {
270.1224 + int cls = dis.readUnsignedShort();
270.1225 + } else if (type == '[') {
270.1226 + int cnt = dis.readUnsignedShort();
270.1227 + for (int i = 0; i < cnt; i++) {
270.1228 + readValue(dis, cd, typeName, iterateArray ? attrName : null);
270.1229 + }
270.1230 + } else if (type == 'e') {
270.1231 + int enumT = dis.readUnsignedShort();
270.1232 + String attrType = cd.stringValue(enumT, textual);
270.1233 + int enumN = dis.readUnsignedShort();
270.1234 + String val = cd.stringValue(enumN, textual);
270.1235 + visitEnumAttr(typeName, attrName, attrType, val);
270.1236 + } else {
270.1237 + throw new IOException("Unknown type " + type);
270.1238 + }
270.1239 + visitValueEnd(attrName, type);
270.1240 + }
270.1241 + }
270.1242 +
270.1243 + /**
270.1244 + * Reads and stores attribute information.
270.1245 + *
270.1246 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.1247 + */
270.1248 + private static class AttrData {
270.1249 +
270.1250 + ClassData cls;
270.1251 + int name_cpx;
270.1252 + int datalen;
270.1253 + byte data[];
270.1254 +
270.1255 + public AttrData(ClassData cls) {
270.1256 + this.cls = cls;
270.1257 + }
270.1258 +
270.1259 + /**
270.1260 + * Reads unknown attribute.
270.1261 + */
270.1262 + public void read(int name_cpx, DataInputStream in) throws IOException {
270.1263 + this.name_cpx = name_cpx;
270.1264 + datalen = in.readInt();
270.1265 + data = new byte[datalen];
270.1266 + in.readFully(data);
270.1267 + }
270.1268 +
270.1269 + /**
270.1270 + * Reads just the name of known attribute.
270.1271 + */
270.1272 + public void read(int name_cpx) {
270.1273 + this.name_cpx = name_cpx;
270.1274 + }
270.1275 +
270.1276 + /**
270.1277 + * Returns attribute name.
270.1278 + */
270.1279 + public String getAttrName() {
270.1280 + return cls.getString(name_cpx);
270.1281 + }
270.1282 +
270.1283 + /**
270.1284 + * Returns attribute data.
270.1285 + */
270.1286 + public byte[] getData() {
270.1287 + return data;
270.1288 + }
270.1289 + }
270.1290 +
270.1291 + /**
270.1292 + * Stores constant pool entry information with one field.
270.1293 + *
270.1294 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.1295 + */
270.1296 + private static class CPX {
270.1297 +
270.1298 + int cpx;
270.1299 +
270.1300 + CPX(int cpx) {
270.1301 + this.cpx = cpx;
270.1302 + }
270.1303 + }
270.1304 +
270.1305 + /**
270.1306 + * Stores constant pool entry information with two fields.
270.1307 + *
270.1308 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.1309 + */
270.1310 + private static class CPX2 {
270.1311 +
270.1312 + int cpx1, cpx2;
270.1313 +
270.1314 + CPX2(int cpx1, int cpx2) {
270.1315 + this.cpx1 = cpx1;
270.1316 + this.cpx2 = cpx2;
270.1317 + }
270.1318 + }
270.1319 +
270.1320 + /**
270.1321 + * Central data repository of the Java Disassembler. Stores all the
270.1322 + * information in java class file.
270.1323 + *
270.1324 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.1325 + */
270.1326 + static final class ClassData {
270.1327 +
270.1328 + private int magic;
270.1329 + private int minor_version;
270.1330 + private int major_version;
270.1331 + private int cpool_count;
270.1332 + private Object cpool[];
270.1333 + private int access;
270.1334 + private int this_class = 0;
270.1335 + private int super_class;
270.1336 + private int interfaces_count;
270.1337 + private int[] interfaces = new int[0];
270.1338 + private int fields_count;
270.1339 + private FieldData[] fields;
270.1340 + private int methods_count;
270.1341 + private MethodData[] methods;
270.1342 + private InnerClassData[] innerClasses;
270.1343 + private int attributes_count;
270.1344 + private AttrData[] attrs;
270.1345 + private String classname;
270.1346 + private String superclassname;
270.1347 + private int source_cpx = 0;
270.1348 + private byte tags[];
270.1349 + private Hashtable indexHashAscii = new Hashtable();
270.1350 + private String pkgPrefix = "";
270.1351 + private int pkgPrefixLen = 0;
270.1352 +
270.1353 + /**
270.1354 + * Read classfile to disassemble.
270.1355 + */
270.1356 + public ClassData(InputStream infile) throws IOException {
270.1357 + this.read(new DataInputStream(infile));
270.1358 + }
270.1359 +
270.1360 + /**
270.1361 + * Reads and stores class file information.
270.1362 + */
270.1363 + public void read(DataInputStream in) throws IOException {
270.1364 + // Read the header
270.1365 + magic = in.readInt();
270.1366 + if (magic != JAVA_MAGIC) {
270.1367 + throw new ClassFormatError("wrong magic: "
270.1368 + + toHex(magic) + ", expected "
270.1369 + + toHex(JAVA_MAGIC));
270.1370 + }
270.1371 + minor_version = in.readShort();
270.1372 + major_version = in.readShort();
270.1373 + if (major_version != JAVA_VERSION) {
270.1374 + }
270.1375 +
270.1376 + // Read the constant pool
270.1377 + readCP(in);
270.1378 + access = in.readUnsignedShort();
270.1379 + this_class = in.readUnsignedShort();
270.1380 + super_class = in.readUnsignedShort();
270.1381 +
270.1382 + //Read interfaces.
270.1383 + interfaces_count = in.readUnsignedShort();
270.1384 + if (interfaces_count > 0) {
270.1385 + interfaces = new int[interfaces_count];
270.1386 + }
270.1387 + for (int i = 0; i < interfaces_count; i++) {
270.1388 + interfaces[i] = in.readShort();
270.1389 + }
270.1390 +
270.1391 + // Read the fields
270.1392 + readFields(in);
270.1393 +
270.1394 + // Read the methods
270.1395 + readMethods(in);
270.1396 +
270.1397 + // Read the attributes
270.1398 + attributes_count = in.readUnsignedShort();
270.1399 + attrs = new AttrData[attributes_count];
270.1400 + for (int k = 0; k < attributes_count; k++) {
270.1401 + int name_cpx = in.readUnsignedShort();
270.1402 + if (getTag(name_cpx) == CONSTANT_UTF8
270.1403 + && getString(name_cpx).equals("SourceFile")) {
270.1404 + if (in.readInt() != 2) {
270.1405 + throw new ClassFormatError("invalid attr length");
270.1406 + }
270.1407 + source_cpx = in.readUnsignedShort();
270.1408 + AttrData attr = new AttrData(this);
270.1409 + attr.read(name_cpx);
270.1410 + attrs[k] = attr;
270.1411 +
270.1412 + } else if (getTag(name_cpx) == CONSTANT_UTF8
270.1413 + && getString(name_cpx).equals("InnerClasses")) {
270.1414 + int length = in.readInt();
270.1415 + int num = in.readUnsignedShort();
270.1416 + if (2 + num * 8 != length) {
270.1417 + throw new ClassFormatError("invalid attr length");
270.1418 + }
270.1419 + innerClasses = new InnerClassData[num];
270.1420 + for (int j = 0; j < num; j++) {
270.1421 + InnerClassData innerClass = new InnerClassData(this);
270.1422 + innerClass.read(in);
270.1423 + innerClasses[j] = innerClass;
270.1424 + }
270.1425 + AttrData attr = new AttrData(this);
270.1426 + attr.read(name_cpx);
270.1427 + attrs[k] = attr;
270.1428 + } else {
270.1429 + AttrData attr = new AttrData(this);
270.1430 + attr.read(name_cpx, in);
270.1431 + attrs[k] = attr;
270.1432 + }
270.1433 + }
270.1434 + in.close();
270.1435 + } // end ClassData.read()
270.1436 +
270.1437 + /**
270.1438 + * Reads and stores constant pool info.
270.1439 + */
270.1440 + void readCP(DataInputStream in) throws IOException {
270.1441 + cpool_count = in.readUnsignedShort();
270.1442 + tags = new byte[cpool_count];
270.1443 + cpool = new Object[cpool_count];
270.1444 + for (int i = 1; i < cpool_count; i++) {
270.1445 + byte tag = in.readByte();
270.1446 +
270.1447 + switch (tags[i] = tag) {
270.1448 + case CONSTANT_UTF8:
270.1449 + String str = in.readUTF();
270.1450 + indexHashAscii.put(cpool[i] = str, new Integer(i));
270.1451 + break;
270.1452 + case CONSTANT_INTEGER:
270.1453 + cpool[i] = new Integer(in.readInt());
270.1454 + break;
270.1455 + case CONSTANT_FLOAT:
270.1456 + cpool[i] = new Float(in.readFloat());
270.1457 + break;
270.1458 + case CONSTANT_LONG:
270.1459 + cpool[i++] = new Long(in.readLong());
270.1460 + break;
270.1461 + case CONSTANT_DOUBLE:
270.1462 + cpool[i++] = new Double(in.readDouble());
270.1463 + break;
270.1464 + case CONSTANT_CLASS:
270.1465 + case CONSTANT_STRING:
270.1466 + cpool[i] = new CPX(in.readUnsignedShort());
270.1467 + break;
270.1468 +
270.1469 + case CONSTANT_FIELD:
270.1470 + case CONSTANT_METHOD:
270.1471 + case CONSTANT_INTERFACEMETHOD:
270.1472 + case CONSTANT_NAMEANDTYPE:
270.1473 + cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
270.1474 + break;
270.1475 +
270.1476 + case 0:
270.1477 + default:
270.1478 + throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
270.1479 + }
270.1480 + }
270.1481 + }
270.1482 +
270.1483 + /**
270.1484 + * Reads and strores field info.
270.1485 + */
270.1486 + protected void readFields(DataInputStream in) throws IOException {
270.1487 + int fields_count = in.readUnsignedShort();
270.1488 + fields = new FieldData[fields_count];
270.1489 + for (int k = 0; k < fields_count; k++) {
270.1490 + FieldData field = new FieldData(this);
270.1491 + field.read(in);
270.1492 + fields[k] = field;
270.1493 + }
270.1494 + }
270.1495 +
270.1496 + /**
270.1497 + * Reads and strores Method info.
270.1498 + */
270.1499 + protected void readMethods(DataInputStream in) throws IOException {
270.1500 + int methods_count = in.readUnsignedShort();
270.1501 + methods = new MethodData[methods_count];
270.1502 + for (int k = 0; k < methods_count; k++) {
270.1503 + MethodData method = new MethodData(this);
270.1504 + method.read(in);
270.1505 + methods[k] = method;
270.1506 + }
270.1507 + }
270.1508 +
270.1509 + /**
270.1510 + * get a string
270.1511 + */
270.1512 + public String getString(int n) {
270.1513 + if (n == 0) {
270.1514 + return null;
270.1515 + } else {
270.1516 + return (String) cpool[n];
270.1517 + }
270.1518 + }
270.1519 +
270.1520 + /**
270.1521 + * get the type of constant given an index
270.1522 + */
270.1523 + public byte getTag(int n) {
270.1524 + try {
270.1525 + return tags[n];
270.1526 + } catch (ArrayIndexOutOfBoundsException e) {
270.1527 + return (byte) 100;
270.1528 + }
270.1529 + }
270.1530 + static final String hexString = "0123456789ABCDEF";
270.1531 + public static char hexTable[] = hexString.toCharArray();
270.1532 +
270.1533 + static String toHex(long val, int width) {
270.1534 + StringBuffer s = new StringBuffer();
270.1535 + for (int i = width - 1; i >= 0; i--) {
270.1536 + s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
270.1537 + }
270.1538 + return "0x" + s.toString();
270.1539 + }
270.1540 +
270.1541 + static String toHex(long val) {
270.1542 + int width;
270.1543 + for (width = 16; width > 0; width--) {
270.1544 + if ((val >> (width - 1) * 4) != 0) {
270.1545 + break;
270.1546 + }
270.1547 + }
270.1548 + return toHex(val, width);
270.1549 + }
270.1550 +
270.1551 + static String toHex(int val) {
270.1552 + int width;
270.1553 + for (width = 8; width > 0; width--) {
270.1554 + if ((val >> (width - 1) * 4) != 0) {
270.1555 + break;
270.1556 + }
270.1557 + }
270.1558 + return toHex(val, width);
270.1559 + }
270.1560 +
270.1561 + /**
270.1562 + * Returns the name of this class.
270.1563 + */
270.1564 + public String getClassName() {
270.1565 + String res = null;
270.1566 + if (this_class == 0) {
270.1567 + return res;
270.1568 + }
270.1569 + int tcpx;
270.1570 + try {
270.1571 + if (tags[this_class] != CONSTANT_CLASS) {
270.1572 + return res; //"<CP["+cpx+"] is not a Class> ";
270.1573 + }
270.1574 + tcpx = ((CPX) cpool[this_class]).cpx;
270.1575 + } catch (ArrayIndexOutOfBoundsException e) {
270.1576 + return res; // "#"+cpx+"// invalid constant pool index";
270.1577 + } catch (Throwable e) {
270.1578 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1579 + }
270.1580 +
270.1581 + try {
270.1582 + return (String) (cpool[tcpx]);
270.1583 + } catch (ArrayIndexOutOfBoundsException e) {
270.1584 + return res; // "class #"+scpx+"// invalid constant pool index";
270.1585 + } catch (ClassCastException e) {
270.1586 + return res; // "class #"+scpx+"// invalid constant pool reference";
270.1587 + } catch (Throwable e) {
270.1588 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1589 + }
270.1590 +
270.1591 + }
270.1592 +
270.1593 + /**
270.1594 + * Returns the name of class at perticular index.
270.1595 + */
270.1596 + public String getClassName(int cpx) {
270.1597 + String res = "#" + cpx;
270.1598 + if (cpx == 0) {
270.1599 + return res;
270.1600 + }
270.1601 + int scpx;
270.1602 + try {
270.1603 + if (tags[cpx] != CONSTANT_CLASS) {
270.1604 + return res; //"<CP["+cpx+"] is not a Class> ";
270.1605 + }
270.1606 + scpx = ((CPX) cpool[cpx]).cpx;
270.1607 + } catch (ArrayIndexOutOfBoundsException e) {
270.1608 + return res; // "#"+cpx+"// invalid constant pool index";
270.1609 + } catch (Throwable e) {
270.1610 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1611 + }
270.1612 + res = "#" + scpx;
270.1613 + try {
270.1614 + return (String) (cpool[scpx]);
270.1615 + } catch (ArrayIndexOutOfBoundsException e) {
270.1616 + return res; // "class #"+scpx+"// invalid constant pool index";
270.1617 + } catch (ClassCastException e) {
270.1618 + return res; // "class #"+scpx+"// invalid constant pool reference";
270.1619 + } catch (Throwable e) {
270.1620 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1621 + }
270.1622 + }
270.1623 +
270.1624 + public int getAccessFlags() {
270.1625 + return access;
270.1626 + }
270.1627 +
270.1628 + /**
270.1629 + * Returns true if it is a class
270.1630 + */
270.1631 + public boolean isClass() {
270.1632 + if ((access & ACC_INTERFACE) == 0) {
270.1633 + return true;
270.1634 + }
270.1635 + return false;
270.1636 + }
270.1637 +
270.1638 + /**
270.1639 + * Returns true if it is a interface.
270.1640 + */
270.1641 + public boolean isInterface() {
270.1642 + if ((access & ACC_INTERFACE) != 0) {
270.1643 + return true;
270.1644 + }
270.1645 + return false;
270.1646 + }
270.1647 +
270.1648 + /**
270.1649 + * Returns true if this member is public, false otherwise.
270.1650 + */
270.1651 + public boolean isPublic() {
270.1652 + return (access & ACC_PUBLIC) != 0;
270.1653 + }
270.1654 +
270.1655 + /**
270.1656 + * Returns the access of this class or interface.
270.1657 + */
270.1658 + public String[] getAccess() {
270.1659 + Vector v = new Vector();
270.1660 + if ((access & ACC_PUBLIC) != 0) {
270.1661 + v.addElement("public");
270.1662 + }
270.1663 + if ((access & ACC_FINAL) != 0) {
270.1664 + v.addElement("final");
270.1665 + }
270.1666 + if ((access & ACC_ABSTRACT) != 0) {
270.1667 + v.addElement("abstract");
270.1668 + }
270.1669 + String[] accflags = new String[v.size()];
270.1670 + v.copyInto(accflags);
270.1671 + return accflags;
270.1672 + }
270.1673 +
270.1674 + /**
270.1675 + * Returns list of innerclasses.
270.1676 + */
270.1677 + public InnerClassData[] getInnerClasses() {
270.1678 + return innerClasses;
270.1679 + }
270.1680 +
270.1681 + /**
270.1682 + * Returns list of attributes.
270.1683 + */
270.1684 + final AttrData[] getAttributes() {
270.1685 + return attrs;
270.1686 + }
270.1687 +
270.1688 + public byte[] findAnnotationData(boolean classRetention) {
270.1689 + String n = classRetention
270.1690 + ? "RuntimeInvisibleAnnotations" : // NOI18N
270.1691 + "RuntimeVisibleAnnotations"; // NOI18N
270.1692 + return findAttr(n, attrs);
270.1693 + }
270.1694 +
270.1695 + /**
270.1696 + * Returns true if superbit is set.
270.1697 + */
270.1698 + public boolean isSuperSet() {
270.1699 + if ((access & ACC_SUPER) != 0) {
270.1700 + return true;
270.1701 + }
270.1702 + return false;
270.1703 + }
270.1704 +
270.1705 + /**
270.1706 + * Returns super class name.
270.1707 + */
270.1708 + public String getSuperClassName() {
270.1709 + String res = null;
270.1710 + if (super_class == 0) {
270.1711 + return res;
270.1712 + }
270.1713 + int scpx;
270.1714 + try {
270.1715 + if (tags[super_class] != CONSTANT_CLASS) {
270.1716 + return res; //"<CP["+cpx+"] is not a Class> ";
270.1717 + }
270.1718 + scpx = ((CPX) cpool[super_class]).cpx;
270.1719 + } catch (ArrayIndexOutOfBoundsException e) {
270.1720 + return res; // "#"+cpx+"// invalid constant pool index";
270.1721 + } catch (Throwable e) {
270.1722 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1723 + }
270.1724 +
270.1725 + try {
270.1726 + return (String) (cpool[scpx]);
270.1727 + } catch (ArrayIndexOutOfBoundsException e) {
270.1728 + return res; // "class #"+scpx+"// invalid constant pool index";
270.1729 + } catch (ClassCastException e) {
270.1730 + return res; // "class #"+scpx+"// invalid constant pool reference";
270.1731 + } catch (Throwable e) {
270.1732 + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
270.1733 + }
270.1734 + }
270.1735 +
270.1736 + /**
270.1737 + * Returns list of super interfaces.
270.1738 + */
270.1739 + public String[] getSuperInterfaces() {
270.1740 + String interfacenames[] = new String[interfaces.length];
270.1741 + int interfacecpx = -1;
270.1742 + for (int i = 0; i < interfaces.length; i++) {
270.1743 + interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
270.1744 + interfacenames[i] = (String) (cpool[interfacecpx]);
270.1745 + }
270.1746 + return interfacenames;
270.1747 + }
270.1748 +
270.1749 + /**
270.1750 + * Returns string at prticular constant pool index.
270.1751 + */
270.1752 + public String getStringValue(int cpoolx) {
270.1753 + try {
270.1754 + return ((String) cpool[cpoolx]);
270.1755 + } catch (ArrayIndexOutOfBoundsException e) {
270.1756 + return "//invalid constant pool index:" + cpoolx;
270.1757 + } catch (ClassCastException e) {
270.1758 + return "//invalid constant pool ref:" + cpoolx;
270.1759 + }
270.1760 + }
270.1761 +
270.1762 + /**
270.1763 + * Returns list of field info.
270.1764 + */
270.1765 + public FieldData[] getFields() {
270.1766 + return fields;
270.1767 + }
270.1768 +
270.1769 + /**
270.1770 + * Returns list of method info.
270.1771 + */
270.1772 + public MethodData[] getMethods() {
270.1773 + return methods;
270.1774 + }
270.1775 +
270.1776 + /**
270.1777 + * Returns constant pool entry at that index.
270.1778 + */
270.1779 + public CPX2 getCpoolEntry(int cpx) {
270.1780 + return ((CPX2) (cpool[cpx]));
270.1781 + }
270.1782 +
270.1783 + public Object getCpoolEntryobj(int cpx) {
270.1784 + return (cpool[cpx]);
270.1785 + }
270.1786 +
270.1787 + /**
270.1788 + * Returns index of this class.
270.1789 + */
270.1790 + public int getthis_cpx() {
270.1791 + return this_class;
270.1792 + }
270.1793 +
270.1794 + /**
270.1795 + * Returns string at that index.
270.1796 + */
270.1797 + public String StringValue(int cpx) {
270.1798 + return stringValue(cpx, false);
270.1799 + }
270.1800 +
270.1801 + public String stringValue(int cpx, boolean textual) {
270.1802 + return stringValue(cpx, textual, null);
270.1803 + }
270.1804 +
270.1805 + public String stringValue(int cpx, String[] classRefs) {
270.1806 + return stringValue(cpx, true, classRefs);
270.1807 + }
270.1808 +
270.1809 + private String stringValue(int cpx, boolean textual, String[] refs) {
270.1810 + if (cpx == 0) {
270.1811 + return "#0";
270.1812 + }
270.1813 + int tag;
270.1814 + Object x;
270.1815 + String suffix = "";
270.1816 + try {
270.1817 + tag = tags[cpx];
270.1818 + x = cpool[cpx];
270.1819 + } catch (IndexOutOfBoundsException e) {
270.1820 + return "<Incorrect CP index:" + cpx + ">";
270.1821 + }
270.1822 +
270.1823 + if (x == null) {
270.1824 + return "<NULL>";
270.1825 + }
270.1826 + switch (tag) {
270.1827 + case CONSTANT_UTF8: {
270.1828 + if (!textual) {
270.1829 + return (String) x;
270.1830 + }
270.1831 + StringBuilder sb = new StringBuilder();
270.1832 + String s = (String) x;
270.1833 + for (int k = 0; k < s.length(); k++) {
270.1834 + char c = s.charAt(k);
270.1835 + switch (c) {
270.1836 + case '\\':
270.1837 + sb.append('\\').append('\\');
270.1838 + break;
270.1839 + case '\t':
270.1840 + sb.append('\\').append('t');
270.1841 + break;
270.1842 + case '\n':
270.1843 + sb.append('\\').append('n');
270.1844 + break;
270.1845 + case '\r':
270.1846 + sb.append('\\').append('r');
270.1847 + break;
270.1848 + case '\"':
270.1849 + sb.append('\\').append('\"');
270.1850 + break;
270.1851 + default:
270.1852 + sb.append(c);
270.1853 + }
270.1854 + }
270.1855 + return sb.toString();
270.1856 + }
270.1857 + case CONSTANT_DOUBLE: {
270.1858 + Double d = (Double) x;
270.1859 + String sd = d.toString();
270.1860 + if (textual) {
270.1861 + return sd;
270.1862 + }
270.1863 + return sd + "d";
270.1864 + }
270.1865 + case CONSTANT_FLOAT: {
270.1866 + Float f = (Float) x;
270.1867 + String sf = (f).toString();
270.1868 + if (textual) {
270.1869 + return sf;
270.1870 + }
270.1871 + return sf + "f";
270.1872 + }
270.1873 + case CONSTANT_LONG: {
270.1874 + Long ln = (Long) x;
270.1875 + if (textual) {
270.1876 + return ln.toString();
270.1877 + }
270.1878 + return ln.toString() + 'l';
270.1879 + }
270.1880 + case CONSTANT_INTEGER: {
270.1881 + Integer in = (Integer) x;
270.1882 + return in.toString();
270.1883 + }
270.1884 + case CONSTANT_CLASS:
270.1885 + String jn = getClassName(cpx);
270.1886 + if (textual) {
270.1887 + if (refs != null) {
270.1888 + refs[0] = jn;
270.1889 + }
270.1890 + return jn;
270.1891 + }
270.1892 + return javaName(jn);
270.1893 + case CONSTANT_STRING:
270.1894 + String sv = stringValue(((CPX) x).cpx, textual);
270.1895 + if (textual) {
270.1896 + return '"' + sv + '"';
270.1897 + } else {
270.1898 + return sv;
270.1899 + }
270.1900 + case CONSTANT_FIELD:
270.1901 + case CONSTANT_METHOD:
270.1902 + case CONSTANT_INTERFACEMETHOD:
270.1903 + //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
270.1904 + return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
270.1905 +
270.1906 + case CONSTANT_NAMEANDTYPE:
270.1907 + return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
270.1908 + default:
270.1909 + return "UnknownTag"; //TBD
270.1910 + }
270.1911 + }
270.1912 +
270.1913 + /**
270.1914 + * Returns resolved java type name.
270.1915 + */
270.1916 + public String javaName(String name) {
270.1917 + if (name == null) {
270.1918 + return "null";
270.1919 + }
270.1920 + int len = name.length();
270.1921 + if (len == 0) {
270.1922 + return "\"\"";
270.1923 + }
270.1924 + int cc = '/';
270.1925 + fullname:
270.1926 + { // xxx/yyy/zzz
270.1927 + int cp;
270.1928 + for (int k = 0; k < len; k += Character.charCount(cp)) {
270.1929 + cp = name.codePointAt(k);
270.1930 + if (cc == '/') {
270.1931 + if (!isJavaIdentifierStart(cp)) {
270.1932 + break fullname;
270.1933 + }
270.1934 + } else if (cp != '/') {
270.1935 + if (!isJavaIdentifierPart(cp)) {
270.1936 + break fullname;
270.1937 + }
270.1938 + }
270.1939 + cc = cp;
270.1940 + }
270.1941 + return name;
270.1942 + }
270.1943 + return "\"" + name + "\"";
270.1944 + }
270.1945 +
270.1946 + public String getName(int cpx) {
270.1947 + String res;
270.1948 + try {
270.1949 + return javaName((String) cpool[cpx]); //.replace('/','.');
270.1950 + } catch (ArrayIndexOutOfBoundsException e) {
270.1951 + return "<invalid constant pool index:" + cpx + ">";
270.1952 + } catch (ClassCastException e) {
270.1953 + return "<invalid constant pool ref:" + cpx + ">";
270.1954 + }
270.1955 + }
270.1956 +
270.1957 + /**
270.1958 + * Returns unqualified class name.
270.1959 + */
270.1960 + public String getShortClassName(int cpx) {
270.1961 + String classname = javaName(getClassName(cpx));
270.1962 + pkgPrefixLen = classname.lastIndexOf("/") + 1;
270.1963 + if (pkgPrefixLen != 0) {
270.1964 + pkgPrefix = classname.substring(0, pkgPrefixLen);
270.1965 + if (classname.startsWith(pkgPrefix)) {
270.1966 + return classname.substring(pkgPrefixLen);
270.1967 + }
270.1968 + }
270.1969 + return classname;
270.1970 + }
270.1971 +
270.1972 + /**
270.1973 + * Returns source file name.
270.1974 + */
270.1975 + public String getSourceName() {
270.1976 + return getName(source_cpx);
270.1977 + }
270.1978 +
270.1979 + /**
270.1980 + * Returns package name.
270.1981 + */
270.1982 + public String getPkgName() {
270.1983 + String classname = getClassName(this_class);
270.1984 + pkgPrefixLen = classname.lastIndexOf("/") + 1;
270.1985 + if (pkgPrefixLen != 0) {
270.1986 + pkgPrefix = classname.substring(0, pkgPrefixLen);
270.1987 + return ("package " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
270.1988 + } else {
270.1989 + return null;
270.1990 + }
270.1991 + }
270.1992 +
270.1993 + /**
270.1994 + * Returns total constant pool entry count.
270.1995 + */
270.1996 + public int getCpoolCount() {
270.1997 + return cpool_count;
270.1998 + }
270.1999 +
270.2000 + /**
270.2001 + * Returns minor version of class file.
270.2002 + */
270.2003 + public int getMinor_version() {
270.2004 + return minor_version;
270.2005 + }
270.2006 +
270.2007 + /**
270.2008 + * Returns major version of class file.
270.2009 + */
270.2010 + public int getMajor_version() {
270.2011 + return major_version;
270.2012 + }
270.2013 +
270.2014 + private boolean isJavaIdentifierStart(int cp) {
270.2015 + return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
270.2016 + }
270.2017 +
270.2018 + private boolean isJavaIdentifierPart(int cp) {
270.2019 + return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
270.2020 + }
270.2021 +
270.2022 + public String[] getNameAndType(int indx) {
270.2023 + return getNameAndType(indx, 0, new String[2]);
270.2024 + }
270.2025 +
270.2026 + private String[] getNameAndType(int indx, int at, String[] arr) {
270.2027 + CPX2 c2 = getCpoolEntry(indx);
270.2028 + arr[at] = StringValue(c2.cpx1);
270.2029 + arr[at + 1] = StringValue(c2.cpx2);
270.2030 + return arr;
270.2031 + }
270.2032 +
270.2033 + public String[] getFieldInfoName(int indx) {
270.2034 + CPX2 c2 = getCpoolEntry(indx);
270.2035 + String[] arr = new String[3];
270.2036 + arr[0] = getClassName(c2.cpx1);
270.2037 + return getNameAndType(c2.cpx2, 1, arr);
270.2038 + }
270.2039 +
270.2040 + static byte[] findAttr(String n, AttrData[] attrs) {
270.2041 + for (AttrData ad : attrs) {
270.2042 + if (n.equals(ad.getAttrName())) {
270.2043 + return ad.getData();
270.2044 + }
270.2045 + }
270.2046 + return null;
270.2047 + }
270.2048 + }
270.2049 +
270.2050 + /**
270.2051 + * Strores field data informastion.
270.2052 + *
270.2053 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.2054 + */
270.2055 + static class FieldData {
270.2056 +
270.2057 + ClassData cls;
270.2058 + int access;
270.2059 + int name_index;
270.2060 + int descriptor_index;
270.2061 + int attributes_count;
270.2062 + int value_cpx = 0;
270.2063 + boolean isSynthetic = false;
270.2064 + boolean isDeprecated = false;
270.2065 + Vector attrs;
270.2066 +
270.2067 + public FieldData(ClassData cls) {
270.2068 + this.cls = cls;
270.2069 + }
270.2070 +
270.2071 + /**
270.2072 + * Read and store field info.
270.2073 + */
270.2074 + public void read(DataInputStream in) throws IOException {
270.2075 + access = in.readUnsignedShort();
270.2076 + name_index = in.readUnsignedShort();
270.2077 + descriptor_index = in.readUnsignedShort();
270.2078 + // Read the attributes
270.2079 + int attributes_count = in.readUnsignedShort();
270.2080 + attrs = new Vector(attributes_count);
270.2081 + for (int i = 0; i < attributes_count; i++) {
270.2082 + int attr_name_index = in.readUnsignedShort();
270.2083 + if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
270.2084 + continue;
270.2085 + }
270.2086 + String attr_name = cls.getString(attr_name_index);
270.2087 + if (attr_name.equals("ConstantValue")) {
270.2088 + if (in.readInt() != 2) {
270.2089 + throw new ClassFormatError("invalid ConstantValue attr length");
270.2090 + }
270.2091 + value_cpx = in.readUnsignedShort();
270.2092 + AttrData attr = new AttrData(cls);
270.2093 + attr.read(attr_name_index);
270.2094 + attrs.addElement(attr);
270.2095 + } else if (attr_name.equals("Synthetic")) {
270.2096 + if (in.readInt() != 0) {
270.2097 + throw new ClassFormatError("invalid Synthetic attr length");
270.2098 + }
270.2099 + isSynthetic = true;
270.2100 + AttrData attr = new AttrData(cls);
270.2101 + attr.read(attr_name_index);
270.2102 + attrs.addElement(attr);
270.2103 + } else if (attr_name.equals("Deprecated")) {
270.2104 + if (in.readInt() != 0) {
270.2105 + throw new ClassFormatError("invalid Synthetic attr length");
270.2106 + }
270.2107 + isDeprecated = true;
270.2108 + AttrData attr = new AttrData(cls);
270.2109 + attr.read(attr_name_index);
270.2110 + attrs.addElement(attr);
270.2111 + } else {
270.2112 + AttrData attr = new AttrData(cls);
270.2113 + attr.read(attr_name_index, in);
270.2114 + attrs.addElement(attr);
270.2115 + }
270.2116 + }
270.2117 +
270.2118 + } // end read
270.2119 +
270.2120 + public boolean isStatic() {
270.2121 + return (access & ACC_STATIC) != 0;
270.2122 + }
270.2123 +
270.2124 + /**
270.2125 + * Returns access of a field.
270.2126 + */
270.2127 + public String[] getAccess() {
270.2128 + Vector v = new Vector();
270.2129 + if ((access & ACC_PUBLIC) != 0) {
270.2130 + v.addElement("public");
270.2131 + }
270.2132 + if ((access & ACC_PRIVATE) != 0) {
270.2133 + v.addElement("private");
270.2134 + }
270.2135 + if ((access & ACC_PROTECTED) != 0) {
270.2136 + v.addElement("protected");
270.2137 + }
270.2138 + if ((access & ACC_STATIC) != 0) {
270.2139 + v.addElement("static");
270.2140 + }
270.2141 + if ((access & ACC_FINAL) != 0) {
270.2142 + v.addElement("final");
270.2143 + }
270.2144 + if ((access & ACC_VOLATILE) != 0) {
270.2145 + v.addElement("volatile");
270.2146 + }
270.2147 + if ((access & ACC_TRANSIENT) != 0) {
270.2148 + v.addElement("transient");
270.2149 + }
270.2150 + String[] accflags = new String[v.size()];
270.2151 + v.copyInto(accflags);
270.2152 + return accflags;
270.2153 + }
270.2154 +
270.2155 + /**
270.2156 + * Returns name of a field.
270.2157 + */
270.2158 + public String getName() {
270.2159 + return cls.getStringValue(name_index);
270.2160 + }
270.2161 +
270.2162 + /**
270.2163 + * Returns internal signature of a field
270.2164 + */
270.2165 + public String getInternalSig() {
270.2166 + return cls.getStringValue(descriptor_index);
270.2167 + }
270.2168 +
270.2169 + /**
270.2170 + * Returns true if field is synthetic.
270.2171 + */
270.2172 + public boolean isSynthetic() {
270.2173 + return isSynthetic;
270.2174 + }
270.2175 +
270.2176 + /**
270.2177 + * Returns true if field is deprecated.
270.2178 + */
270.2179 + public boolean isDeprecated() {
270.2180 + return isDeprecated;
270.2181 + }
270.2182 +
270.2183 + /**
270.2184 + * Returns index of constant value in cpool.
270.2185 + */
270.2186 + public int getConstantValueIndex() {
270.2187 + return (value_cpx);
270.2188 + }
270.2189 +
270.2190 + /**
270.2191 + * Returns list of attributes of field.
270.2192 + */
270.2193 + public Vector getAttributes() {
270.2194 + return attrs;
270.2195 + }
270.2196 +
270.2197 + public byte[] findAnnotationData(boolean classRetention) {
270.2198 + String n = classRetention
270.2199 + ? "RuntimeInvisibleAnnotations" : // NOI18N
270.2200 + "RuntimeVisibleAnnotations"; // NOI18N
270.2201 + AttrData[] arr = new AttrData[attrs.size()];
270.2202 + attrs.copyInto(arr);
270.2203 + return ClassData.findAttr(n, arr);
270.2204 + }
270.2205 + }
270.2206 +
270.2207 + /**
270.2208 + * A JavaScript optimized replacement for Hashtable.
270.2209 + *
270.2210 + * @author Jaroslav Tulach <jtulach@netbeans.org>
270.2211 + */
270.2212 + private static final class Hashtable {
270.2213 +
270.2214 + private Object[] keys;
270.2215 + private Object[] values;
270.2216 +
270.2217 + Hashtable(int i) {
270.2218 + this();
270.2219 + }
270.2220 +
270.2221 + Hashtable(int i, double d) {
270.2222 + this();
270.2223 + }
270.2224 +
270.2225 + Hashtable() {
270.2226 + }
270.2227 +
270.2228 + synchronized void put(Object key, Object val) {
270.2229 + int[] where = {-1, -1};
270.2230 + Object found = get(key, where);
270.2231 + if (where[0] != -1) {
270.2232 + // key exists
270.2233 + values[where[0]] = val;
270.2234 + } else {
270.2235 + if (where[1] != -1) {
270.2236 + // null found
270.2237 + keys[where[1]] = key;
270.2238 + values[where[1]] = val;
270.2239 + } else {
270.2240 + if (keys == null) {
270.2241 + keys = new Object[11];
270.2242 + values = new Object[11];
270.2243 + keys[0] = key;
270.2244 + values[0] = val;
270.2245 + } else {
270.2246 + Object[] newKeys = new Object[keys.length * 2];
270.2247 + Object[] newValues = new Object[values.length * 2];
270.2248 + for (int i = 0; i < keys.length; i++) {
270.2249 + newKeys[i] = keys[i];
270.2250 + newValues[i] = values[i];
270.2251 + }
270.2252 + newKeys[keys.length] = key;
270.2253 + newValues[keys.length] = val;
270.2254 + keys = newKeys;
270.2255 + values = newValues;
270.2256 + }
270.2257 + }
270.2258 + }
270.2259 + }
270.2260 +
270.2261 + Object get(Object key) {
270.2262 + return get(key, null);
270.2263 + }
270.2264 +
270.2265 + private synchronized Object get(Object key, int[] foundAndNull) {
270.2266 + if (keys == null) {
270.2267 + return null;
270.2268 + }
270.2269 + for (int i = 0; i < keys.length; i++) {
270.2270 + if (keys[i] == null) {
270.2271 + if (foundAndNull != null) {
270.2272 + foundAndNull[1] = i;
270.2273 + }
270.2274 + } else if (keys[i].equals(key)) {
270.2275 + if (foundAndNull != null) {
270.2276 + foundAndNull[0] = i;
270.2277 + }
270.2278 + return values[i];
270.2279 + }
270.2280 + }
270.2281 + return null;
270.2282 + }
270.2283 + }
270.2284 +
270.2285 + /**
270.2286 + * Strores InnerClass data informastion.
270.2287 + *
270.2288 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.2289 + */
270.2290 + private static class InnerClassData {
270.2291 +
270.2292 + ClassData cls;
270.2293 + int inner_class_info_index, outer_class_info_index, inner_name_index, access;
270.2294 +
270.2295 + public InnerClassData(ClassData cls) {
270.2296 + this.cls = cls;
270.2297 +
270.2298 + }
270.2299 +
270.2300 + /**
270.2301 + * Read Innerclass attribute data.
270.2302 + */
270.2303 + public void read(DataInputStream in) throws IOException {
270.2304 + inner_class_info_index = in.readUnsignedShort();
270.2305 + outer_class_info_index = in.readUnsignedShort();
270.2306 + inner_name_index = in.readUnsignedShort();
270.2307 + access = in.readUnsignedShort();
270.2308 + } // end read
270.2309 +
270.2310 + /**
270.2311 + * Returns the access of this class or interface.
270.2312 + */
270.2313 + public String[] getAccess() {
270.2314 + Vector v = new Vector();
270.2315 + if ((access & ACC_PUBLIC) != 0) {
270.2316 + v.addElement("public");
270.2317 + }
270.2318 + if ((access & ACC_FINAL) != 0) {
270.2319 + v.addElement("final");
270.2320 + }
270.2321 + if ((access & ACC_ABSTRACT) != 0) {
270.2322 + v.addElement("abstract");
270.2323 + }
270.2324 + String[] accflags = new String[v.size()];
270.2325 + v.copyInto(accflags);
270.2326 + return accflags;
270.2327 + }
270.2328 + } // end InnerClassData
270.2329 +
270.2330 + /**
270.2331 + * Strores LineNumberTable data information.
270.2332 + *
270.2333 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.2334 + */
270.2335 + private static class LineNumData {
270.2336 +
270.2337 + short start_pc, line_number;
270.2338 +
270.2339 + public LineNumData() {
270.2340 + }
270.2341 +
270.2342 + /**
270.2343 + * Read LineNumberTable attribute.
270.2344 + */
270.2345 + public LineNumData(DataInputStream in) throws IOException {
270.2346 + start_pc = in.readShort();
270.2347 + line_number = in.readShort();
270.2348 +
270.2349 + }
270.2350 + }
270.2351 +
270.2352 + /**
270.2353 + * Strores LocalVariableTable data information.
270.2354 + *
270.2355 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.2356 + */
270.2357 + private static class LocVarData {
270.2358 +
270.2359 + short start_pc, length, name_cpx, sig_cpx, slot;
270.2360 +
270.2361 + public LocVarData() {
270.2362 + }
270.2363 +
270.2364 + /**
270.2365 + * Read LocalVariableTable attribute.
270.2366 + */
270.2367 + public LocVarData(DataInputStream in) throws IOException {
270.2368 + start_pc = in.readShort();
270.2369 + length = in.readShort();
270.2370 + name_cpx = in.readShort();
270.2371 + sig_cpx = in.readShort();
270.2372 + slot = in.readShort();
270.2373 +
270.2374 + }
270.2375 + }
270.2376 + /**
270.2377 + * Strores method data informastion.
270.2378 + *
270.2379 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.2380 + */
270.2381 + static class MethodData {
270.2382 +
270.2383 + ClassData cls;
270.2384 + int access;
270.2385 + int name_index;
270.2386 + int descriptor_index;
270.2387 + int attributes_count;
270.2388 + byte[] code;
270.2389 + Vector exception_table = new Vector(0);
270.2390 + Vector lin_num_tb = new Vector(0);
270.2391 + Vector loc_var_tb = new Vector(0);
270.2392 + StackMapTableData[] stackMapTable;
270.2393 + StackMapData[] stackMap;
270.2394 + int[] exc_index_table = null;
270.2395 + Vector attrs = new Vector(0);
270.2396 + Vector code_attrs = new Vector(0);
270.2397 + int max_stack, max_locals;
270.2398 + boolean isSynthetic = false;
270.2399 + boolean isDeprecated = false;
270.2400 +
270.2401 + public MethodData(ClassData cls) {
270.2402 + this.cls = cls;
270.2403 + }
270.2404 +
270.2405 + /**
270.2406 + * Read method info.
270.2407 + */
270.2408 + public void read(DataInputStream in) throws IOException {
270.2409 + access = in.readUnsignedShort();
270.2410 + name_index = in.readUnsignedShort();
270.2411 + descriptor_index = in.readUnsignedShort();
270.2412 + int attributes_count = in.readUnsignedShort();
270.2413 + for (int i = 0; i < attributes_count; i++) {
270.2414 + int attr_name_index = in.readUnsignedShort();
270.2415 +
270.2416 + readAttr:
270.2417 + {
270.2418 + if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
270.2419 + String attr_name = cls.getString(attr_name_index);
270.2420 + if (attr_name.equals("Code")) {
270.2421 + readCode(in);
270.2422 + AttrData attr = new AttrData(cls);
270.2423 + attr.read(attr_name_index);
270.2424 + attrs.addElement(attr);
270.2425 + break readAttr;
270.2426 + } else if (attr_name.equals("Exceptions")) {
270.2427 + readExceptions(in);
270.2428 + AttrData attr = new AttrData(cls);
270.2429 + attr.read(attr_name_index);
270.2430 + attrs.addElement(attr);
270.2431 + break readAttr;
270.2432 + } else if (attr_name.equals("Synthetic")) {
270.2433 + if (in.readInt() != 0) {
270.2434 + throw new ClassFormatError("invalid Synthetic attr length");
270.2435 + }
270.2436 + isSynthetic = true;
270.2437 + AttrData attr = new AttrData(cls);
270.2438 + attr.read(attr_name_index);
270.2439 + attrs.addElement(attr);
270.2440 + break readAttr;
270.2441 + } else if (attr_name.equals("Deprecated")) {
270.2442 + if (in.readInt() != 0) {
270.2443 + throw new ClassFormatError("invalid Synthetic attr length");
270.2444 + }
270.2445 + isDeprecated = true;
270.2446 + AttrData attr = new AttrData(cls);
270.2447 + attr.read(attr_name_index);
270.2448 + attrs.addElement(attr);
270.2449 + break readAttr;
270.2450 + }
270.2451 + }
270.2452 + AttrData attr = new AttrData(cls);
270.2453 + attr.read(attr_name_index, in);
270.2454 + attrs.addElement(attr);
270.2455 + }
270.2456 + }
270.2457 + }
270.2458 +
270.2459 + /**
270.2460 + * Read code attribute info.
270.2461 + */
270.2462 + public void readCode(DataInputStream in) throws IOException {
270.2463 +
270.2464 + int attr_length = in.readInt();
270.2465 + max_stack = in.readUnsignedShort();
270.2466 + max_locals = in.readUnsignedShort();
270.2467 + int codelen = in.readInt();
270.2468 +
270.2469 + code = new byte[codelen];
270.2470 + int totalread = 0;
270.2471 + while (totalread < codelen) {
270.2472 + totalread += in.read(code, totalread, codelen - totalread);
270.2473 + }
270.2474 + // in.read(code, 0, codelen);
270.2475 + int clen = 0;
270.2476 + readExceptionTable(in);
270.2477 + int code_attributes_count = in.readUnsignedShort();
270.2478 +
270.2479 + for (int k = 0; k < code_attributes_count; k++) {
270.2480 + int table_name_index = in.readUnsignedShort();
270.2481 + int table_name_tag = cls.getTag(table_name_index);
270.2482 + AttrData attr = new AttrData(cls);
270.2483 + if (table_name_tag == CONSTANT_UTF8) {
270.2484 + String table_name_tstr = cls.getString(table_name_index);
270.2485 + if (table_name_tstr.equals("LineNumberTable")) {
270.2486 + readLineNumTable(in);
270.2487 + attr.read(table_name_index);
270.2488 + } else if (table_name_tstr.equals("LocalVariableTable")) {
270.2489 + readLocVarTable(in);
270.2490 + attr.read(table_name_index);
270.2491 + } else if (table_name_tstr.equals("StackMapTable")) {
270.2492 + readStackMapTable(in);
270.2493 + attr.read(table_name_index);
270.2494 + } else if (table_name_tstr.equals("StackMap")) {
270.2495 + readStackMap(in);
270.2496 + attr.read(table_name_index);
270.2497 + } else {
270.2498 + attr.read(table_name_index, in);
270.2499 + }
270.2500 + code_attrs.addElement(attr);
270.2501 + continue;
270.2502 + }
270.2503 +
270.2504 + attr.read(table_name_index, in);
270.2505 + code_attrs.addElement(attr);
270.2506 + }
270.2507 + }
270.2508 +
270.2509 + /**
270.2510 + * Read exception table info.
270.2511 + */
270.2512 + void readExceptionTable(DataInputStream in) throws IOException {
270.2513 + int exception_table_len = in.readUnsignedShort();
270.2514 + exception_table = new Vector(exception_table_len);
270.2515 + for (int l = 0; l < exception_table_len; l++) {
270.2516 + exception_table.addElement(new TrapData(in, l));
270.2517 + }
270.2518 + }
270.2519 +
270.2520 + /**
270.2521 + * Read LineNumberTable attribute info.
270.2522 + */
270.2523 + void readLineNumTable(DataInputStream in) throws IOException {
270.2524 + int attr_len = in.readInt(); // attr_length
270.2525 + int lin_num_tb_len = in.readUnsignedShort();
270.2526 + lin_num_tb = new Vector(lin_num_tb_len);
270.2527 + for (int l = 0; l < lin_num_tb_len; l++) {
270.2528 + lin_num_tb.addElement(new LineNumData(in));
270.2529 + }
270.2530 + }
270.2531 +
270.2532 + /**
270.2533 + * Read LocalVariableTable attribute info.
270.2534 + */
270.2535 + void readLocVarTable(DataInputStream in) throws IOException {
270.2536 + int attr_len = in.readInt(); // attr_length
270.2537 + int loc_var_tb_len = in.readUnsignedShort();
270.2538 + loc_var_tb = new Vector(loc_var_tb_len);
270.2539 + for (int l = 0; l < loc_var_tb_len; l++) {
270.2540 + loc_var_tb.addElement(new LocVarData(in));
270.2541 + }
270.2542 + }
270.2543 +
270.2544 + /**
270.2545 + * Read Exception attribute info.
270.2546 + */
270.2547 + public void readExceptions(DataInputStream in) throws IOException {
270.2548 + int attr_len = in.readInt(); // attr_length in prog
270.2549 + int num_exceptions = in.readUnsignedShort();
270.2550 + exc_index_table = new int[num_exceptions];
270.2551 + for (int l = 0; l < num_exceptions; l++) {
270.2552 + int exc = in.readShort();
270.2553 + exc_index_table[l] = exc;
270.2554 + }
270.2555 + }
270.2556 +
270.2557 + /**
270.2558 + * Read StackMapTable attribute info.
270.2559 + */
270.2560 + void readStackMapTable(DataInputStream in) throws IOException {
270.2561 + int attr_len = in.readInt(); //attr_length
270.2562 + int stack_map_tb_len = in.readUnsignedShort();
270.2563 + stackMapTable = new StackMapTableData[stack_map_tb_len];
270.2564 + for (int i = 0; i < stack_map_tb_len; i++) {
270.2565 + stackMapTable[i] = StackMapTableData.getInstance(in, this);
270.2566 + }
270.2567 + }
270.2568 +
270.2569 + /**
270.2570 + * Read StackMap attribute info.
270.2571 + */
270.2572 + void readStackMap(DataInputStream in) throws IOException {
270.2573 + int attr_len = in.readInt(); //attr_length
270.2574 + int stack_map_len = in.readUnsignedShort();
270.2575 + stackMap = new StackMapData[stack_map_len];
270.2576 + for (int i = 0; i < stack_map_len; i++) {
270.2577 + stackMap[i] = new StackMapData(in, this);
270.2578 + }
270.2579 + }
270.2580 +
270.2581 + /**
270.2582 + * Return access of the method.
270.2583 + */
270.2584 + public int getAccess() {
270.2585 + return access;
270.2586 + }
270.2587 +
270.2588 + /**
270.2589 + * Return name of the method.
270.2590 + */
270.2591 + public String getName() {
270.2592 + return cls.getStringValue(name_index);
270.2593 + }
270.2594 +
270.2595 + /**
270.2596 + * Return internal siganature of the method.
270.2597 + */
270.2598 + public String getInternalSig() {
270.2599 + return cls.getStringValue(descriptor_index);
270.2600 + }
270.2601 +
270.2602 + /**
270.2603 + * Return code attribute data of a method.
270.2604 + */
270.2605 + public byte[] getCode() {
270.2606 + return code;
270.2607 + }
270.2608 +
270.2609 + /**
270.2610 + * Return LineNumberTable size.
270.2611 + */
270.2612 + public int getnumlines() {
270.2613 + return lin_num_tb.size();
270.2614 + }
270.2615 +
270.2616 + /**
270.2617 + * Return LineNumberTable
270.2618 + */
270.2619 + public Vector getlin_num_tb() {
270.2620 + return lin_num_tb;
270.2621 + }
270.2622 +
270.2623 + /**
270.2624 + * Return LocalVariableTable size.
270.2625 + */
270.2626 + public int getloc_var_tbsize() {
270.2627 + return loc_var_tb.size();
270.2628 + }
270.2629 +
270.2630 + /**
270.2631 + * Return LocalVariableTable.
270.2632 + */
270.2633 + public Vector getloc_var_tb() {
270.2634 + return loc_var_tb;
270.2635 + }
270.2636 +
270.2637 + /**
270.2638 + * Return StackMap.
270.2639 + */
270.2640 + public StackMapData[] getStackMap() {
270.2641 + return stackMap;
270.2642 + }
270.2643 +
270.2644 + /**
270.2645 + * Return StackMapTable.
270.2646 + */
270.2647 + public StackMapTableData[] getStackMapTable() {
270.2648 + return stackMapTable;
270.2649 + }
270.2650 +
270.2651 + public StackMapIterator createStackMapIterator() {
270.2652 + return new StackMapIterator(this);
270.2653 + }
270.2654 +
270.2655 + /**
270.2656 + * Return true if method is static
270.2657 + */
270.2658 + public boolean isStatic() {
270.2659 + if ((access & ACC_STATIC) != 0) {
270.2660 + return true;
270.2661 + }
270.2662 + return false;
270.2663 + }
270.2664 +
270.2665 + /**
270.2666 + * Return max depth of operand stack.
270.2667 + */
270.2668 + public int getMaxStack() {
270.2669 + return max_stack;
270.2670 + }
270.2671 +
270.2672 + /**
270.2673 + * Return number of local variables.
270.2674 + */
270.2675 + public int getMaxLocals() {
270.2676 + return max_locals;
270.2677 + }
270.2678 +
270.2679 + /**
270.2680 + * Return exception index table in Exception attribute.
270.2681 + */
270.2682 + public int[] get_exc_index_table() {
270.2683 + return exc_index_table;
270.2684 + }
270.2685 +
270.2686 + /**
270.2687 + * Return exception table in code attributre.
270.2688 + */
270.2689 + public TrapDataIterator getTrapDataIterator() {
270.2690 + return new TrapDataIterator(exception_table);
270.2691 + }
270.2692 +
270.2693 + /**
270.2694 + * Return method attributes.
270.2695 + */
270.2696 + public Vector getAttributes() {
270.2697 + return attrs;
270.2698 + }
270.2699 +
270.2700 + /**
270.2701 + * Return code attributes.
270.2702 + */
270.2703 + public Vector getCodeAttributes() {
270.2704 + return code_attrs;
270.2705 + }
270.2706 +
270.2707 + /**
270.2708 + * Return true if method id synthetic.
270.2709 + */
270.2710 + public boolean isSynthetic() {
270.2711 + return isSynthetic;
270.2712 + }
270.2713 +
270.2714 + /**
270.2715 + * Return true if method is deprecated.
270.2716 + */
270.2717 + public boolean isDeprecated() {
270.2718 + return isDeprecated;
270.2719 + }
270.2720 +
270.2721 + public byte[] findAnnotationData(boolean classRetention) {
270.2722 + String n = classRetention
270.2723 + ? "RuntimeInvisibleAnnotations" : // NOI18N
270.2724 + "RuntimeVisibleAnnotations"; // NOI18N
270.2725 + AttrData[] arr = new AttrData[attrs.size()];
270.2726 + attrs.copyInto(arr);
270.2727 + return ClassData.findAttr(n, arr);
270.2728 + }
270.2729 +
270.2730 + public boolean isConstructor() {
270.2731 + return "<init>".equals(getName());
270.2732 + }
270.2733 + }
270.2734 +
270.2735 + /* represents one entry of StackMap attribute
270.2736 + */
270.2737 + private static class StackMapData {
270.2738 +
270.2739 + final int offset;
270.2740 + final int[] locals;
270.2741 + final int[] stack;
270.2742 +
270.2743 + StackMapData(int offset, int[] locals, int[] stack) {
270.2744 + this.offset = offset;
270.2745 + this.locals = locals;
270.2746 + this.stack = stack;
270.2747 + }
270.2748 +
270.2749 + StackMapData(DataInputStream in, MethodData method) throws IOException {
270.2750 + offset = in.readUnsignedShort();
270.2751 + int local_size = in.readUnsignedShort();
270.2752 + locals = readTypeArray(in, local_size, method);
270.2753 + int stack_size = in.readUnsignedShort();
270.2754 + stack = readTypeArray(in, stack_size, method);
270.2755 + }
270.2756 +
270.2757 + static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
270.2758 + int[] types = new int[length];
270.2759 + for (int i = 0; i < length; i++) {
270.2760 + types[i] = readType(in, method);
270.2761 + }
270.2762 + return types;
270.2763 + }
270.2764 +
270.2765 + static final int readType(DataInputStream in, MethodData method) throws IOException {
270.2766 + int type = in.readUnsignedByte();
270.2767 + if (type == ITEM_Object || type == ITEM_NewObject) {
270.2768 + type = type | (in.readUnsignedShort() << 8);
270.2769 + }
270.2770 + return type;
270.2771 + }
270.2772 + }
270.2773 +
270.2774 + static final class StackMapIterator {
270.2775 +
270.2776 + private final StackMapTableData[] stackMapTable;
270.2777 + private final TypeArray argTypes;
270.2778 + private final TypeArray localTypes;
270.2779 + private final TypeArray stackTypes;
270.2780 + private int nextFrameIndex;
270.2781 + private int lastFrameByteCodeOffset;
270.2782 + private int byteCodeOffset;
270.2783 +
270.2784 + StackMapIterator(final MethodData methodData) {
270.2785 + this(methodData.getStackMapTable(),
270.2786 + methodData.getInternalSig(),
270.2787 + methodData.isStatic());
270.2788 + }
270.2789 +
270.2790 + StackMapIterator(final StackMapTableData[] stackMapTable,
270.2791 + final String methodSignature,
270.2792 + final boolean isStaticMethod) {
270.2793 + this.stackMapTable = (stackMapTable != null)
270.2794 + ? stackMapTable
270.2795 + : new StackMapTableData[0];
270.2796 +
270.2797 + argTypes = getArgTypes(methodSignature, isStaticMethod);
270.2798 + localTypes = new TypeArray();
270.2799 + stackTypes = new TypeArray();
270.2800 +
270.2801 + localTypes.addAll(argTypes);
270.2802 +
270.2803 + lastFrameByteCodeOffset = -1;
270.2804 + advanceBy(0);
270.2805 + }
270.2806 +
270.2807 + public String getFrameAsString() {
270.2808 + return (nextFrameIndex == 0)
270.2809 + ? StackMapTableData.toString("INITIAL", 0, null, null)
270.2810 + : stackMapTable[nextFrameIndex - 1].toString();
270.2811 + }
270.2812 +
270.2813 + public int getFrameIndex() {
270.2814 + return nextFrameIndex;
270.2815 + }
270.2816 +
270.2817 + public TypeArray getFrameStack() {
270.2818 + return stackTypes;
270.2819 + }
270.2820 +
270.2821 + public TypeArray getFrameLocals() {
270.2822 + return localTypes;
270.2823 + }
270.2824 +
270.2825 + public TypeArray getArguments() {
270.2826 + return argTypes;
270.2827 + }
270.2828 +
270.2829 + public void advanceBy(final int numByteCodes) {
270.2830 + if (numByteCodes < 0) {
270.2831 + throw new IllegalStateException("Forward only iterator");
270.2832 + }
270.2833 +
270.2834 + byteCodeOffset += numByteCodes;
270.2835 + while ((nextFrameIndex < stackMapTable.length)
270.2836 + && ((byteCodeOffset - lastFrameByteCodeOffset)
270.2837 + >= (stackMapTable[nextFrameIndex].offsetDelta
270.2838 + + 1))) {
270.2839 + final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
270.2840 +
270.2841 + lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
270.2842 + nextFrame.applyTo(localTypes, stackTypes);
270.2843 +
270.2844 + ++nextFrameIndex;
270.2845 + }
270.2846 + }
270.2847 +
270.2848 + public void advanceTo(final int nextByteCodeOffset) {
270.2849 + advanceBy(nextByteCodeOffset - byteCodeOffset);
270.2850 + }
270.2851 +
270.2852 + private static TypeArray getArgTypes(final String methodSignature,
270.2853 + final boolean isStaticMethod) {
270.2854 + final TypeArray argTypes = new TypeArray();
270.2855 +
270.2856 + if (!isStaticMethod) {
270.2857 + argTypes.add(ITEM_Object);
270.2858 + }
270.2859 +
270.2860 + if (methodSignature.charAt(0) != '(') {
270.2861 + throw new IllegalArgumentException("Invalid method signature");
270.2862 + }
270.2863 +
270.2864 + final int length = methodSignature.length();
270.2865 + boolean skipType = false;
270.2866 + int argType;
270.2867 + for (int i = 1; i < length; ++i) {
270.2868 + switch (methodSignature.charAt(i)) {
270.2869 + case 'B':
270.2870 + case 'C':
270.2871 + case 'S':
270.2872 + case 'Z':
270.2873 + case 'I':
270.2874 + argType = ITEM_Integer;
270.2875 + break;
270.2876 + case 'J':
270.2877 + argType = ITEM_Long;
270.2878 + break;
270.2879 + case 'F':
270.2880 + argType = ITEM_Float;
270.2881 + break;
270.2882 + case 'D':
270.2883 + argType = ITEM_Double;
270.2884 + break;
270.2885 + case 'L': {
270.2886 + i = methodSignature.indexOf(';', i + 1);
270.2887 + if (i == -1) {
270.2888 + throw new IllegalArgumentException(
270.2889 + "Invalid method signature");
270.2890 + }
270.2891 + argType = ITEM_Object;
270.2892 + break;
270.2893 + }
270.2894 + case ')':
270.2895 + // not interested in the return value type
270.2896 + return argTypes;
270.2897 + case '[':
270.2898 + if (!skipType) {
270.2899 + argTypes.add(ITEM_Object);
270.2900 + skipType = true;
270.2901 + }
270.2902 + continue;
270.2903 +
270.2904 + default:
270.2905 + throw new IllegalArgumentException(
270.2906 + "Invalid method signature");
270.2907 + }
270.2908 +
270.2909 + if (!skipType) {
270.2910 + argTypes.add(argType);
270.2911 + } else {
270.2912 + skipType = false;
270.2913 + }
270.2914 + }
270.2915 +
270.2916 + return argTypes;
270.2917 + }
270.2918 + }
270.2919 + /* represents one entry of StackMapTable attribute
270.2920 + */
270.2921 +
270.2922 + private static abstract class StackMapTableData {
270.2923 +
270.2924 + final int frameType;
270.2925 + int offsetDelta;
270.2926 +
270.2927 + StackMapTableData(int frameType) {
270.2928 + this.frameType = frameType;
270.2929 + }
270.2930 +
270.2931 + abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
270.2932 +
270.2933 + protected static String toString(
270.2934 + final String frameType,
270.2935 + final int offset,
270.2936 + final int[] localTypes,
270.2937 + final int[] stackTypes) {
270.2938 + final StringBuilder sb = new StringBuilder(frameType);
270.2939 +
270.2940 + sb.append("(off: +").append(offset);
270.2941 + if (localTypes != null) {
270.2942 + sb.append(", locals: ");
270.2943 + appendTypes(sb, localTypes);
270.2944 + }
270.2945 + if (stackTypes != null) {
270.2946 + sb.append(", stack: ");
270.2947 + appendTypes(sb, stackTypes);
270.2948 + }
270.2949 + sb.append(')');
270.2950 +
270.2951 + return sb.toString();
270.2952 + }
270.2953 +
270.2954 + private static void appendTypes(final StringBuilder sb, final int[] types) {
270.2955 + sb.append('[');
270.2956 + if (types.length > 0) {
270.2957 + sb.append(TypeArray.typeString(types[0]));
270.2958 + for (int i = 1; i < types.length; ++i) {
270.2959 + sb.append(", ");
270.2960 + sb.append(TypeArray.typeString(types[i]));
270.2961 + }
270.2962 + }
270.2963 + sb.append(']');
270.2964 + }
270.2965 +
270.2966 + private static class SameFrame extends StackMapTableData {
270.2967 +
270.2968 + SameFrame(int frameType, int offsetDelta) {
270.2969 + super(frameType);
270.2970 + this.offsetDelta = offsetDelta;
270.2971 + }
270.2972 +
270.2973 + @Override
270.2974 + void applyTo(TypeArray localTypes, TypeArray stackTypes) {
270.2975 + stackTypes.clear();
270.2976 + }
270.2977 +
270.2978 + @Override
270.2979 + public String toString() {
270.2980 + return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
270.2981 + ? "_FRAME_EXTENDED" : ""),
270.2982 + offsetDelta,
270.2983 + null, null);
270.2984 + }
270.2985 + }
270.2986 +
270.2987 + private static class SameLocals1StackItem extends StackMapTableData {
270.2988 +
270.2989 + final int[] stack;
270.2990 +
270.2991 + SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
270.2992 + super(frameType);
270.2993 + this.offsetDelta = offsetDelta;
270.2994 + this.stack = stack;
270.2995 + }
270.2996 +
270.2997 + @Override
270.2998 + void applyTo(TypeArray localTypes, TypeArray stackTypes) {
270.2999 + stackTypes.setAll(stack);
270.3000 + }
270.3001 +
270.3002 + @Override
270.3003 + public String toString() {
270.3004 + return toString(
270.3005 + "SAME_LOCALS_1_STACK_ITEM"
270.3006 + + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
270.3007 + ? "_EXTENDED" : ""),
270.3008 + offsetDelta,
270.3009 + null, stack);
270.3010 + }
270.3011 + }
270.3012 +
270.3013 + private static class ChopFrame extends StackMapTableData {
270.3014 +
270.3015 + ChopFrame(int frameType, int offsetDelta) {
270.3016 + super(frameType);
270.3017 + this.offsetDelta = offsetDelta;
270.3018 + }
270.3019 +
270.3020 + @Override
270.3021 + void applyTo(TypeArray localTypes, TypeArray stackTypes) {
270.3022 + localTypes.setSize(localTypes.getSize()
270.3023 + - (SAME_FRAME_EXTENDED - frameType));
270.3024 + stackTypes.clear();
270.3025 + }
270.3026 +
270.3027 + @Override
270.3028 + public String toString() {
270.3029 + return toString("CHOP", offsetDelta, null, null);
270.3030 + }
270.3031 + }
270.3032 +
270.3033 + private static class AppendFrame extends StackMapTableData {
270.3034 +
270.3035 + final int[] locals;
270.3036 +
270.3037 + AppendFrame(int frameType, int offsetDelta, int[] locals) {
270.3038 + super(frameType);
270.3039 + this.offsetDelta = offsetDelta;
270.3040 + this.locals = locals;
270.3041 + }
270.3042 +
270.3043 + @Override
270.3044 + void applyTo(TypeArray localTypes, TypeArray stackTypes) {
270.3045 + localTypes.addAll(locals);
270.3046 + stackTypes.clear();
270.3047 + }
270.3048 +
270.3049 + @Override
270.3050 + public String toString() {
270.3051 + return toString("APPEND", offsetDelta, locals, null);
270.3052 + }
270.3053 + }
270.3054 +
270.3055 + private static class FullFrame extends StackMapTableData {
270.3056 +
270.3057 + final int[] locals;
270.3058 + final int[] stack;
270.3059 +
270.3060 + FullFrame(int offsetDelta, int[] locals, int[] stack) {
270.3061 + super(FULL_FRAME);
270.3062 + this.offsetDelta = offsetDelta;
270.3063 + this.locals = locals;
270.3064 + this.stack = stack;
270.3065 + }
270.3066 +
270.3067 + @Override
270.3068 + void applyTo(TypeArray localTypes, TypeArray stackTypes) {
270.3069 + localTypes.setAll(locals);
270.3070 + stackTypes.setAll(stack);
270.3071 + }
270.3072 +
270.3073 + @Override
270.3074 + public String toString() {
270.3075 + return toString("FULL", offsetDelta, locals, stack);
270.3076 + }
270.3077 + }
270.3078 +
270.3079 + static StackMapTableData getInstance(DataInputStream in, MethodData method)
270.3080 + throws IOException {
270.3081 + int frameType = in.readUnsignedByte();
270.3082 +
270.3083 + if (frameType < SAME_FRAME_BOUND) {
270.3084 + // same_frame
270.3085 + return new SameFrame(frameType, frameType);
270.3086 + } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
270.3087 + // same_locals_1_stack_item_frame
270.3088 + // read additional single stack element
270.3089 + return new SameLocals1StackItem(frameType,
270.3090 + (frameType - SAME_FRAME_BOUND),
270.3091 + StackMapData.readTypeArray(in, 1, method));
270.3092 + } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
270.3093 + // same_locals_1_stack_item_extended
270.3094 + return new SameLocals1StackItem(frameType,
270.3095 + in.readUnsignedShort(),
270.3096 + StackMapData.readTypeArray(in, 1, method));
270.3097 + } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
270.3098 + // chop_frame or same_frame_extended
270.3099 + return new ChopFrame(frameType, in.readUnsignedShort());
270.3100 + } else if (frameType == SAME_FRAME_EXTENDED) {
270.3101 + // chop_frame or same_frame_extended
270.3102 + return new SameFrame(frameType, in.readUnsignedShort());
270.3103 + } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
270.3104 + // append_frame
270.3105 + return new AppendFrame(frameType, in.readUnsignedShort(),
270.3106 + StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
270.3107 + } else if (frameType == FULL_FRAME) {
270.3108 + // full_frame
270.3109 + int offsetDelta = in.readUnsignedShort();
270.3110 + int locals_size = in.readUnsignedShort();
270.3111 + int[] locals = StackMapData.readTypeArray(in, locals_size, method);
270.3112 + int stack_size = in.readUnsignedShort();
270.3113 + int[] stack = StackMapData.readTypeArray(in, stack_size, method);
270.3114 + return new FullFrame(offsetDelta, locals, stack);
270.3115 + } else {
270.3116 + throw new ClassFormatError("unrecognized frame_type in StackMapTable");
270.3117 + }
270.3118 + }
270.3119 + }
270.3120 +
270.3121 + /**
270.3122 + * Stores exception table data in code attribute.
270.3123 + *
270.3124 + * @author Sucheta Dambalkar (Adopted code from jdis)
270.3125 + */
270.3126 + static final class TrapData {
270.3127 +
270.3128 + public final short start_pc;
270.3129 + public final short end_pc;
270.3130 + public final short handler_pc;
270.3131 + public final short catch_cpx;
270.3132 + final int num;
270.3133 +
270.3134 + /**
270.3135 + * Read and store exception table data in code attribute.
270.3136 + */
270.3137 + TrapData(DataInputStream in, int num) throws IOException {
270.3138 + this.num = num;
270.3139 + start_pc = in.readShort();
270.3140 + end_pc = in.readShort();
270.3141 + handler_pc = in.readShort();
270.3142 + catch_cpx = in.readShort();
270.3143 + }
270.3144 +
270.3145 + /**
270.3146 + * returns recommended identifier
270.3147 + */
270.3148 + public String ident() {
270.3149 + return "t" + num;
270.3150 + }
270.3151 + }
270.3152 + /**
270.3153 + *
270.3154 + * @author Jaroslav Tulach <jtulach@netbeans.org>
270.3155 + */
270.3156 + static final class TrapDataIterator {
270.3157 +
270.3158 + private final Hashtable exStart = new Hashtable();
270.3159 + private final Hashtable exStop = new Hashtable();
270.3160 + private TrapData[] current = new TrapData[10];
270.3161 + private int currentCount;
270.3162 +
270.3163 + TrapDataIterator(Vector exceptionTable) {
270.3164 + for (int i = 0; i < exceptionTable.size(); i++) {
270.3165 + final TrapData td = (TrapData) exceptionTable.elementAt(i);
270.3166 + put(exStart, td.start_pc, td);
270.3167 + put(exStop, td.end_pc, td);
270.3168 + }
270.3169 + }
270.3170 +
270.3171 + private static void put(Hashtable h, short key, TrapData td) {
270.3172 + Short s = Short.valueOf((short) key);
270.3173 + Vector v = (Vector) h.get(s);
270.3174 + if (v == null) {
270.3175 + v = new Vector(1);
270.3176 + h.put(s, v);
270.3177 + }
270.3178 + v.add(td);
270.3179 + }
270.3180 +
270.3181 + private boolean processAll(Hashtable h, Short key, boolean add) {
270.3182 + boolean change = false;
270.3183 + Vector v = (Vector) h.get(key);
270.3184 + if (v != null) {
270.3185 + int s = v.size();
270.3186 + for (int i = 0; i < s; i++) {
270.3187 + TrapData td = (TrapData) v.elementAt(i);
270.3188 + if (add) {
270.3189 + add(td);
270.3190 + change = true;
270.3191 + } else {
270.3192 + remove(td);
270.3193 + change = true;
270.3194 + }
270.3195 + }
270.3196 + }
270.3197 + return change;
270.3198 + }
270.3199 +
270.3200 + public boolean advanceTo(int i) {
270.3201 + Short s = Short.valueOf((short) i);
270.3202 + boolean ch1 = processAll(exStart, s, true);
270.3203 + boolean ch2 = processAll(exStop, s, false);
270.3204 + return ch1 || ch2;
270.3205 + }
270.3206 +
270.3207 + public boolean useTry() {
270.3208 + return currentCount > 0;
270.3209 + }
270.3210 +
270.3211 + public TrapData[] current() {
270.3212 + TrapData[] copy = new TrapData[currentCount];
270.3213 + for (int i = 0; i < currentCount; i++) {
270.3214 + copy[i] = current[i];
270.3215 + }
270.3216 + return copy;
270.3217 + }
270.3218 +
270.3219 + private void add(TrapData e) {
270.3220 + if (currentCount == current.length) {
270.3221 + TrapData[] data = new TrapData[currentCount * 2];
270.3222 + for (int i = 0; i < currentCount; i++) {
270.3223 + data[i] = current[i];
270.3224 + }
270.3225 + current = data;
270.3226 + }
270.3227 + current[currentCount++] = e;
270.3228 + }
270.3229 +
270.3230 + private void remove(TrapData e) {
270.3231 + if (currentCount == 0) {
270.3232 + return;
270.3233 + }
270.3234 + int from = 0;
270.3235 + while (from < currentCount) {
270.3236 + if (e == current[from++]) {
270.3237 + break;
270.3238 + }
270.3239 + }
270.3240 + while (from < currentCount) {
270.3241 + current[from - 1] = current[from];
270.3242 + current[from] = null;
270.3243 + from++;
270.3244 + }
270.3245 + currentCount--;
270.3246 + }
270.3247 + }
270.3248 + static final class TypeArray {
270.3249 +
270.3250 + private static final int CAPACITY_INCREMENT = 16;
270.3251 + private int[] types;
270.3252 + private int size;
270.3253 +
270.3254 + public TypeArray() {
270.3255 + }
270.3256 +
270.3257 + public TypeArray(final TypeArray initialTypes) {
270.3258 + setAll(initialTypes);
270.3259 + }
270.3260 +
270.3261 + public void add(final int newType) {
270.3262 + ensureCapacity(size + 1);
270.3263 + types[size++] = newType;
270.3264 + }
270.3265 +
270.3266 + public void addAll(final TypeArray newTypes) {
270.3267 + addAll(newTypes.types, 0, newTypes.size);
270.3268 + }
270.3269 +
270.3270 + public void addAll(final int[] newTypes) {
270.3271 + addAll(newTypes, 0, newTypes.length);
270.3272 + }
270.3273 +
270.3274 + public void addAll(final int[] newTypes,
270.3275 + final int offset,
270.3276 + final int count) {
270.3277 + if (count > 0) {
270.3278 + ensureCapacity(size + count);
270.3279 + arraycopy(newTypes, offset, types, size, count);
270.3280 + size += count;
270.3281 + }
270.3282 + }
270.3283 +
270.3284 + public void set(final int index, final int newType) {
270.3285 + types[index] = newType;
270.3286 + }
270.3287 +
270.3288 + public void setAll(final TypeArray newTypes) {
270.3289 + setAll(newTypes.types, 0, newTypes.size);
270.3290 + }
270.3291 +
270.3292 + public void setAll(final int[] newTypes) {
270.3293 + setAll(newTypes, 0, newTypes.length);
270.3294 + }
270.3295 +
270.3296 + public void setAll(final int[] newTypes,
270.3297 + final int offset,
270.3298 + final int count) {
270.3299 + if (count > 0) {
270.3300 + ensureCapacity(count);
270.3301 + arraycopy(newTypes, offset, types, 0, count);
270.3302 + size = count;
270.3303 + } else {
270.3304 + clear();
270.3305 + }
270.3306 + }
270.3307 +
270.3308 + public void setSize(final int newSize) {
270.3309 + if (size != newSize) {
270.3310 + ensureCapacity(newSize);
270.3311 +
270.3312 + for (int i = size; i < newSize; ++i) {
270.3313 + types[i] = 0;
270.3314 + }
270.3315 + size = newSize;
270.3316 + }
270.3317 + }
270.3318 +
270.3319 + public void clear() {
270.3320 + size = 0;
270.3321 + }
270.3322 +
270.3323 + public int getSize() {
270.3324 + return size;
270.3325 + }
270.3326 +
270.3327 + public int get(final int index) {
270.3328 + return types[index];
270.3329 + }
270.3330 +
270.3331 + public static String typeString(final int type) {
270.3332 + switch (type & 0xff) {
270.3333 + case ITEM_Bogus:
270.3334 + return "_top_";
270.3335 + case ITEM_Integer:
270.3336 + return "_int_";
270.3337 + case ITEM_Float:
270.3338 + return "_float_";
270.3339 + case ITEM_Double:
270.3340 + return "_double_";
270.3341 + case ITEM_Long:
270.3342 + return "_long_";
270.3343 + case ITEM_Null:
270.3344 + return "_null_";
270.3345 + case ITEM_InitObject: // UninitializedThis
270.3346 + return "_init_";
270.3347 + case ITEM_Object:
270.3348 + return "_object_";
270.3349 + case ITEM_NewObject: // Uninitialized
270.3350 + return "_new_";
270.3351 + default:
270.3352 + throw new IllegalArgumentException("Unknown type");
270.3353 + }
270.3354 + }
270.3355 +
270.3356 + @Override
270.3357 + public String toString() {
270.3358 + final StringBuilder sb = new StringBuilder("[");
270.3359 + if (size > 0) {
270.3360 + sb.append(typeString(types[0]));
270.3361 + for (int i = 1; i < size; ++i) {
270.3362 + sb.append(", ");
270.3363 + sb.append(typeString(types[i]));
270.3364 + }
270.3365 + }
270.3366 +
270.3367 + return sb.append(']').toString();
270.3368 + }
270.3369 +
270.3370 + private void ensureCapacity(final int minCapacity) {
270.3371 + if ((minCapacity == 0)
270.3372 + || (types != null) && (minCapacity <= types.length)) {
270.3373 + return;
270.3374 + }
270.3375 +
270.3376 + final int newCapacity =
270.3377 + ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
270.3378 + * CAPACITY_INCREMENT;
270.3379 + final int[] newTypes = new int[newCapacity];
270.3380 +
270.3381 + if (size > 0) {
270.3382 + arraycopy(types, 0, newTypes, 0, size);
270.3383 + }
270.3384 +
270.3385 + types = newTypes;
270.3386 + }
270.3387 +
270.3388 + // no System.arraycopy
270.3389 + private void arraycopy(final int[] src, final int srcPos,
270.3390 + final int[] dest, final int destPos,
270.3391 + final int length) {
270.3392 + for (int i = 0; i < length; ++i) {
270.3393 + dest[destPos + i] = src[srcPos + i];
270.3394 + }
270.3395 + }
270.3396 + }
270.3397 + /**
270.3398 + * A JavaScript ready replacement for java.util.Vector
270.3399 + *
270.3400 + * @author Jaroslav Tulach <jtulach@netbeans.org>
270.3401 + */
270.3402 + @JavaScriptPrototype(prototype = "new Array")
270.3403 + private static final class Vector {
270.3404 +
270.3405 + private Object[] arr;
270.3406 +
270.3407 + Vector() {
270.3408 + }
270.3409 +
270.3410 + Vector(int i) {
270.3411 + }
270.3412 +
270.3413 + void add(Object objectType) {
270.3414 + addElement(objectType);
270.3415 + }
270.3416 +
270.3417 + @JavaScriptBody(args = {"obj"}, body =
270.3418 + "this.push(obj);")
270.3419 + void addElement(Object obj) {
270.3420 + final int s = size();
270.3421 + setSize(s + 1);
270.3422 + setElementAt(obj, s);
270.3423 + }
270.3424 +
270.3425 + @JavaScriptBody(args = {}, body =
270.3426 + "return this.length;")
270.3427 + int size() {
270.3428 + return arr == null ? 0 : arr.length;
270.3429 + }
270.3430 +
270.3431 + @JavaScriptBody(args = {"newArr"}, body =
270.3432 + "for (var i = 0; i < this.length; i++) {\n"
270.3433 + + " newArr[i] = this[i];\n"
270.3434 + + "}\n")
270.3435 + void copyInto(Object[] newArr) {
270.3436 + if (arr == null) {
270.3437 + return;
270.3438 + }
270.3439 + int min = Math.min(newArr.length, arr.length);
270.3440 + for (int i = 0; i < min; i++) {
270.3441 + newArr[i] = arr[i];
270.3442 + }
270.3443 + }
270.3444 +
270.3445 + @JavaScriptBody(args = {"index"}, body =
270.3446 + "return this[index];")
270.3447 + Object elementAt(int index) {
270.3448 + return arr[index];
270.3449 + }
270.3450 +
270.3451 + private void setSize(int len) {
270.3452 + Object[] newArr = new Object[len];
270.3453 + copyInto(newArr);
270.3454 + arr = newArr;
270.3455 + }
270.3456 +
270.3457 + @JavaScriptBody(args = {"val", "index"}, body =
270.3458 + "this[index] = val;")
270.3459 + void setElementAt(Object val, int index) {
270.3460 + arr[index] = val;
270.3461 + }
270.3462 + }
270.3463 +
270.3464 +}
271.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Feb 27 17:50:47 2013 +0100
271.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Oct 07 14:20:58 2013 +0200
271.3 @@ -19,15 +19,7 @@
271.4
271.5 import java.io.IOException;
271.6 import java.io.InputStream;
271.7 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
271.8 -import org.apidesign.javap.AnnotationParser;
271.9 -import org.apidesign.javap.ClassData;
271.10 -import org.apidesign.javap.FieldData;
271.11 -import org.apidesign.javap.MethodData;
271.12 -import org.apidesign.javap.StackMapIterator;
271.13 -import static org.apidesign.javap.RuntimeConstants.*;
271.14 -import org.apidesign.javap.TrapData;
271.15 -import org.apidesign.javap.TrapDataIterator;
271.16 +import static org.apidesign.vm4brwsr.ByteCodeParser.*;
271.17
271.18 /** Translator of the code inside class files to JavaScript.
271.19 *
271.20 @@ -36,9 +28,16 @@
271.21 abstract class ByteCodeToJavaScript {
271.22 private ClassData jc;
271.23 final Appendable out;
271.24 + final ObfuscationDelegate obfuscationDelegate;
271.25
271.26 protected ByteCodeToJavaScript(Appendable out) {
271.27 + this(out, ObfuscationDelegate.NULL);
271.28 + }
271.29 +
271.30 + protected ByteCodeToJavaScript(
271.31 + Appendable out, ObfuscationDelegate obfuscationDelegate) {
271.32 this.out = out;
271.33 + this.obfuscationDelegate = obfuscationDelegate;
271.34 }
271.35
271.36 /* Collects additional required resources.
271.37 @@ -66,7 +65,9 @@
271.38 /* protected */ String accessClass(String classOperation) {
271.39 return classOperation;
271.40 }
271.41 -
271.42 +
271.43 + abstract String getVMObject();
271.44 +
271.45 /** Prints out a debug message.
271.46 *
271.47 * @param msg the message
271.48 @@ -95,14 +96,34 @@
271.49 );
271.50 }
271.51 byte[] arrData = jc.findAnnotationData(true);
271.52 - String[] arr = findAnnotation(arrData, jc,
271.53 - "org.apidesign.bck2brwsr.core.ExtraJavaScript",
271.54 - "resource", "processByteCode"
271.55 - );
271.56 - if (arr != null) {
271.57 - requireScript(arr[0]);
271.58 - if ("0".equals(arr[1])) {
271.59 - return null;
271.60 + {
271.61 + String[] arr = findAnnotation(arrData, jc,
271.62 + "org.apidesign.bck2brwsr.core.ExtraJavaScript",
271.63 + "resource", "processByteCode"
271.64 + );
271.65 + if (arr != null) {
271.66 + if (!arr[0].isEmpty()) {
271.67 + requireScript(arr[0]);
271.68 + }
271.69 + if ("0".equals(arr[1])) {
271.70 + return null;
271.71 + }
271.72 + }
271.73 + }
271.74 + {
271.75 + String[] arr = findAnnotation(arrData, jc,
271.76 + "net.java.html.js.JavaScriptResource",
271.77 + "value"
271.78 + );
271.79 + if (arr != null) {
271.80 + if (arr[0].startsWith("/")) {
271.81 + requireScript(arr[0]);
271.82 + } else {
271.83 + int last = jc.getClassName().lastIndexOf('/');
271.84 + requireScript(
271.85 + jc.getClassName().substring(0, last + 1).replace('.', '/') + arr[0]
271.86 + );
271.87 + }
271.88 }
271.89 }
271.90 String[] proto = findAnnotation(arrData, jc,
271.91 @@ -112,7 +133,8 @@
271.92 StringArray toInitilize = new StringArray();
271.93 final String className = className(jc);
271.94 out.append("\n\n").append(assignClass(className));
271.95 - out.append("function CLS() {");
271.96 + out.append("function ").append(className).append("() {");
271.97 + out.append("\n var CLS = ").append(className).append(';');
271.98 out.append("\n if (!CLS.$class) {");
271.99 if (proto == null) {
271.100 String sc = jc.getSuperClassName(); // with _
271.101 @@ -132,6 +154,10 @@
271.102 for (FieldData v : jc.getFields()) {
271.103 if (v.isStatic()) {
271.104 out.append("\n CLS.").append(v.getName()).append(initField(v));
271.105 + out.append("\n c._").append(v.getName()).append(" = function (v) {")
271.106 + .append(" if (arguments.length == 1) CLS.").append(v.getName())
271.107 + .append(" = v; return CLS.").
271.108 + append(v.getName()).append("; };");
271.109 } else {
271.110 out.append("\n c._").append(v.getName()).append(" = function (v) {")
271.111 .append(" if (arguments.length == 1) this.fld_").
271.112 @@ -140,6 +166,8 @@
271.113 append(className).append('_').append(v.getName())
271.114 .append("; };");
271.115 }
271.116 +
271.117 + obfuscationDelegate.exportField(out, "c", "_" + v.getName(), v);
271.118 }
271.119 for (MethodData m : jc.getMethods()) {
271.120 byte[] onlyArr = m.findAnnotationData(true);
271.121 @@ -154,34 +182,44 @@
271.122 }
271.123 continue;
271.124 }
271.125 - String prefix;
271.126 + String destObject;
271.127 String mn;
271.128 + out.append("\n ");
271.129 if (m.isStatic()) {
271.130 - prefix = "\n c.";
271.131 - mn = generateStaticMethod(prefix, m, toInitilize);
271.132 + destObject = "c";
271.133 + mn = generateStaticMethod(destObject, m, toInitilize);
271.134 } else {
271.135 if (m.isConstructor()) {
271.136 - prefix = "\n CLS.";
271.137 - mn = generateInstanceMethod(prefix, m);
271.138 + destObject = "CLS";
271.139 + mn = generateInstanceMethod(destObject, m);
271.140 } else {
271.141 - prefix = "\n c.";
271.142 - mn = generateInstanceMethod(prefix, m);
271.143 + destObject = "c";
271.144 + mn = generateInstanceMethod(destObject, m);
271.145 }
271.146 }
271.147 + obfuscationDelegate.exportMethod(out, destObject, mn, m);
271.148 byte[] runAnno = m.findAnnotationData(false);
271.149 if (runAnno != null) {
271.150 - out.append(prefix).append(mn).append(".anno = {");
271.151 + out.append("\n ").append(destObject).append(".").append(mn).append(".anno = {");
271.152 generateAnno(jc, out, runAnno);
271.153 out.append("\n };");
271.154 }
271.155 - out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";");
271.156 - out.append(prefix).append(mn).append(".cls = CLS;");
271.157 + out.append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";");
271.158 + out.append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;");
271.159 }
271.160 out.append("\n c.constructor = CLS;");
271.161 - out.append("\n c.$instOf_").append(className).append(" = true;");
271.162 + out.append("\n function fillInstOf(x) {");
271.163 + String instOfName = "$instOf_" + className;
271.164 + out.append("\n x.").append(instOfName).append(" = true;");
271.165 for (String superInterface : jc.getSuperInterfaces()) {
271.166 - out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
271.167 + String intrfc = superInterface.replace('/', '_');
271.168 + out.append("\n vm.").append(intrfc).append("(false).fillInstOf(x);");
271.169 + requireReference(superInterface);
271.170 }
271.171 + out.append("\n }");
271.172 + out.append("\n c.fillInstOf = fillInstOf;");
271.173 + out.append("\n fillInstOf(c);");
271.174 + obfuscationDelegate.exportJSProperty(out, "c", instOfName);
271.175 out.append("\n CLS.$class = 'temp';");
271.176 out.append("\n CLS.$class = ");
271.177 out.append(accessClass("java_lang_Class(true);"));
271.178 @@ -195,6 +233,9 @@
271.179 generateAnno(jc, out, classAnno);
271.180 out.append("\n };");
271.181 }
271.182 + for (String init : toInitilize.toArray()) {
271.183 + out.append("\n ").append(init).append("();");
271.184 + }
271.185 out.append("\n }");
271.186 out.append("\n if (arguments.length === 0) {");
271.187 out.append("\n if (!(this instanceof CLS)) {");
271.188 @@ -223,14 +264,17 @@
271.189 out.append("\n }");
271.190 out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
271.191 out.append("\n};");
271.192 - StringBuilder sb = new StringBuilder();
271.193 - for (String init : toInitilize.toArray()) {
271.194 - sb.append("\n").append(init).append("();");
271.195 - }
271.196 - return sb.toString();
271.197 +
271.198 + obfuscationDelegate.exportClass(out, getVMObject(), className, jc);
271.199 +
271.200 +// StringBuilder sb = new StringBuilder();
271.201 +// for (String init : toInitilize.toArray()) {
271.202 +// sb.append("\n").append(init).append("();");
271.203 +// }
271.204 + return "";
271.205 }
271.206 - private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
271.207 - String jsb = javaScriptBody(prefix, m, true);
271.208 + private String generateStaticMethod(String destObject, MethodData m, StringArray toInitilize) throws IOException {
271.209 + String jsb = javaScriptBody(destObject, m, true);
271.210 if (jsb != null) {
271.211 return jsb;
271.212 }
271.213 @@ -238,28 +282,28 @@
271.214 if (mn.equals("class__V")) {
271.215 toInitilize.add(accessClass(className(jc)) + "(false)." + mn);
271.216 }
271.217 - generateMethod(prefix, mn, m);
271.218 + generateMethod(destObject, mn, m);
271.219 return mn;
271.220 }
271.221
271.222 - private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
271.223 - String jsb = javaScriptBody(prefix, m, false);
271.224 + private String generateInstanceMethod(String destObject, MethodData m) throws IOException {
271.225 + String jsb = javaScriptBody(destObject, m, false);
271.226 if (jsb != null) {
271.227 return jsb;
271.228 }
271.229 final String mn = findMethodName(m, new StringBuilder());
271.230 - generateMethod(prefix, mn, m);
271.231 + generateMethod(destObject, mn, m);
271.232 return mn;
271.233 }
271.234
271.235 - private void generateMethod(String prefix, String name, MethodData m)
271.236 + private void generateMethod(String destObject, String name, MethodData m)
271.237 throws IOException {
271.238 final StackMapIterator stackMapIterator = m.createStackMapIterator();
271.239 TrapDataIterator trap = m.getTrapDataIterator();
271.240 final LocalsMapper lmapper =
271.241 new LocalsMapper(stackMapIterator.getArguments());
271.242
271.243 - out.append(prefix).append(name).append(" = function(");
271.244 + out.append(destObject).append(".").append(name).append(" = function(");
271.245 lmapper.outputArguments(out, m.isStatic());
271.246 out.append(") {").append("\n");
271.247
271.248 @@ -282,22 +326,36 @@
271.249 TrapData[] previousTrap = null;
271.250 boolean wide = false;
271.251
271.252 - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
271.253 + out.append("\n var gt = 0;\n");
271.254 + int openBraces = 0;
271.255 + int topMostLabel = 0;
271.256 for (int i = 0; i < byteCodes.length; i++) {
271.257 int prev = i;
271.258 stackMapIterator.advanceTo(i);
271.259 boolean changeInCatch = trap.advanceTo(i);
271.260 if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
271.261 if (previousTrap != null) {
271.262 - generateCatch(previousTrap);
271.263 + generateCatch(previousTrap, i, topMostLabel);
271.264 previousTrap = null;
271.265 }
271.266 }
271.267 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
271.268 + if (i != 0) {
271.269 + out.append(" }\n");
271.270 + }
271.271 + if (openBraces > 64) {
271.272 + for (int c = 0; c < 64; c++) {
271.273 + out.append("break;}\n");
271.274 + }
271.275 + openBraces = 1;
271.276 + topMostLabel = i;
271.277 + }
271.278 +
271.279 lastStackFrame = stackMapIterator.getFrameIndex();
271.280 lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
271.281 smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
271.282 - out.append(" case " + i).append(": ");
271.283 + out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
271.284 + openBraces++;
271.285 changeInCatch = true;
271.286 } else {
271.287 debug(" /* " + i + " */ ");
271.288 @@ -769,7 +827,7 @@
271.289 }
271.290 case opc_ldc_w:
271.291 case opc_ldc2_w: {
271.292 - int indx = readIntArg(byteCodes, i);
271.293 + int indx = readUShortArg(byteCodes, i);
271.294 i += 2;
271.295 String v = encodeConstant(indx);
271.296 int type = VarType.fromConstantType(jc.getTag(indx));
271.297 @@ -800,133 +858,104 @@
271.298 break;
271.299 case opc_if_acmpeq:
271.300 i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
271.301 - "===");
271.302 + "===", topMostLabel);
271.303 break;
271.304 case opc_if_acmpne:
271.305 i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
271.306 - "!=");
271.307 + "!==", topMostLabel);
271.308 break;
271.309 case opc_if_icmpeq:
271.310 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.311 - "==");
271.312 + "==", topMostLabel);
271.313 break;
271.314 case opc_ifeq: {
271.315 - int indx = i + readIntArg(byteCodes, i);
271.316 - emit(out, "if (@1 == 0) { gt = @2; continue; }",
271.317 - smapper.popI(), Integer.toString(indx));
271.318 + int indx = i + readShortArg(byteCodes, i);
271.319 + emitIf(out, "if (@1 == 0) ",
271.320 + smapper.popI(), i, indx, topMostLabel);
271.321 i += 2;
271.322 break;
271.323 }
271.324 case opc_ifne: {
271.325 - int indx = i + readIntArg(byteCodes, i);
271.326 - emit(out, "if (@1 != 0) { gt = @2; continue; }",
271.327 - smapper.popI(), Integer.toString(indx));
271.328 + int indx = i + readShortArg(byteCodes, i);
271.329 + emitIf(out, "if (@1 != 0) ",
271.330 + smapper.popI(), i, indx, topMostLabel);
271.331 i += 2;
271.332 break;
271.333 }
271.334 case opc_iflt: {
271.335 - int indx = i + readIntArg(byteCodes, i);
271.336 - emit(out, "if (@1 < 0) { gt = @2; continue; }",
271.337 - smapper.popI(), Integer.toString(indx));
271.338 + int indx = i + readShortArg(byteCodes, i);
271.339 + emitIf(out, "if (@1 < 0) ",
271.340 + smapper.popI(), i, indx, topMostLabel);
271.341 i += 2;
271.342 break;
271.343 }
271.344 case opc_ifle: {
271.345 - int indx = i + readIntArg(byteCodes, i);
271.346 - emit(out, "if (@1 <= 0) { gt = @2; continue; }",
271.347 - smapper.popI(), Integer.toString(indx));
271.348 + int indx = i + readShortArg(byteCodes, i);
271.349 + emitIf(out, "if (@1 <= 0) ",
271.350 + smapper.popI(), i, indx, topMostLabel);
271.351 i += 2;
271.352 break;
271.353 }
271.354 case opc_ifgt: {
271.355 - int indx = i + readIntArg(byteCodes, i);
271.356 - emit(out, "if (@1 > 0) { gt = @2; continue; }",
271.357 - smapper.popI(), Integer.toString(indx));
271.358 + int indx = i + readShortArg(byteCodes, i);
271.359 + emitIf(out, "if (@1 > 0) ",
271.360 + smapper.popI(), i, indx, topMostLabel);
271.361 i += 2;
271.362 break;
271.363 }
271.364 case opc_ifge: {
271.365 - int indx = i + readIntArg(byteCodes, i);
271.366 - emit(out, "if (@1 >= 0) { gt = @2; continue; }",
271.367 - smapper.popI(), Integer.toString(indx));
271.368 + int indx = i + readShortArg(byteCodes, i);
271.369 + emitIf(out, "if (@1 >= 0) ",
271.370 + smapper.popI(), i, indx, topMostLabel);
271.371 i += 2;
271.372 break;
271.373 }
271.374 case opc_ifnonnull: {
271.375 - int indx = i + readIntArg(byteCodes, i);
271.376 - emit(out, "if (@1 !== null) { gt = @2; continue; }",
271.377 - smapper.popA(), Integer.toString(indx));
271.378 + int indx = i + readShortArg(byteCodes, i);
271.379 + emitIf(out, "if (@1 !== null) ",
271.380 + smapper.popA(), i, indx, topMostLabel);
271.381 i += 2;
271.382 break;
271.383 }
271.384 case opc_ifnull: {
271.385 - int indx = i + readIntArg(byteCodes, i);
271.386 - emit(out, "if (@1 === null) { gt = @2; continue; }",
271.387 - smapper.popA(), Integer.toString(indx));
271.388 + int indx = i + readShortArg(byteCodes, i);
271.389 + emitIf(out, "if (@1 === null) ",
271.390 + smapper.popA(), i, indx, topMostLabel);
271.391 i += 2;
271.392 break;
271.393 }
271.394 case opc_if_icmpne:
271.395 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.396 - "!=");
271.397 + "!=", topMostLabel);
271.398 break;
271.399 case opc_if_icmplt:
271.400 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.401 - "<");
271.402 + "<", topMostLabel);
271.403 break;
271.404 case opc_if_icmple:
271.405 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.406 - "<=");
271.407 + "<=", topMostLabel);
271.408 break;
271.409 case opc_if_icmpgt:
271.410 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.411 - ">");
271.412 + ">", topMostLabel);
271.413 break;
271.414 case opc_if_icmpge:
271.415 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
271.416 - ">=");
271.417 + ">=", topMostLabel);
271.418 break;
271.419 case opc_goto: {
271.420 - int indx = i + readIntArg(byteCodes, i);
271.421 - emit(out, "gt = @1; continue;", Integer.toString(indx));
271.422 + int indx = i + readShortArg(byteCodes, i);
271.423 + goTo(out, i, indx, topMostLabel);
271.424 i += 2;
271.425 break;
271.426 }
271.427 case opc_lookupswitch: {
271.428 - int table = i / 4 * 4 + 4;
271.429 - int dflt = i + readInt4(byteCodes, table);
271.430 - table += 4;
271.431 - int n = readInt4(byteCodes, table);
271.432 - table += 4;
271.433 - out.append("switch (").append(smapper.popI()).append(") {\n");
271.434 - while (n-- > 0) {
271.435 - int cnstnt = readInt4(byteCodes, table);
271.436 - table += 4;
271.437 - int offset = i + readInt4(byteCodes, table);
271.438 - table += 4;
271.439 - out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
271.440 - }
271.441 - out.append(" default: gt = " + dflt).append("; continue;\n}");
271.442 - i = table - 1;
271.443 + i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel);
271.444 break;
271.445 }
271.446 case opc_tableswitch: {
271.447 - int table = i / 4 * 4 + 4;
271.448 - int dflt = i + readInt4(byteCodes, table);
271.449 - table += 4;
271.450 - int low = readInt4(byteCodes, table);
271.451 - table += 4;
271.452 - int high = readInt4(byteCodes, table);
271.453 - table += 4;
271.454 - out.append("switch (").append(smapper.popI()).append(") {\n");
271.455 - while (low <= high) {
271.456 - int offset = i + readInt4(byteCodes, table);
271.457 - table += 4;
271.458 - out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
271.459 - low++;
271.460 - }
271.461 - out.append(" default: gt = " + dflt).append("; continue;\n}");
271.462 - i = table - 1;
271.463 + i = generateTableSwitch(i, byteCodes, smapper, topMostLabel);
271.464 break;
271.465 }
271.466 case opc_invokeinterface: {
271.467 @@ -943,7 +972,7 @@
271.468 i = invokeStaticMethod(byteCodes, i, smapper, true);
271.469 break;
271.470 case opc_new: {
271.471 - int indx = readIntArg(byteCodes, i);
271.472 + int indx = readUShortArg(byteCodes, i);
271.473 String ci = jc.getClassName(indx);
271.474 emit(out, "var @1 = new @2;",
271.475 smapper.pushA(), accessClass(ci.replace('/', '_')));
271.476 @@ -953,50 +982,18 @@
271.477 }
271.478 case opc_newarray:
271.479 int atype = readUByte(byteCodes, ++i);
271.480 - String jvmType;
271.481 - switch (atype) {
271.482 - case 4: jvmType = "[Z"; break;
271.483 - case 5: jvmType = "[C"; break;
271.484 - case 6: jvmType = "[F"; break;
271.485 - case 7: jvmType = "[D"; break;
271.486 - case 8: jvmType = "[B"; break;
271.487 - case 9: jvmType = "[S"; break;
271.488 - case 10: jvmType = "[I"; break;
271.489 - case 11: jvmType = "[J"; break;
271.490 - default: throw new IllegalStateException("Array type: " + atype);
271.491 - }
271.492 - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
271.493 - smapper.popI(), smapper.pushA(), jvmType);
271.494 + generateNewArray(atype, smapper);
271.495 break;
271.496 case opc_anewarray: {
271.497 - int type = readIntArg(byteCodes, i);
271.498 + int type = readUShortArg(byteCodes, i);
271.499 i += 2;
271.500 - String typeName = jc.getClassName(type);
271.501 - if (typeName.startsWith("[")) {
271.502 - typeName = "[" + typeName;
271.503 - } else {
271.504 - typeName = "[L" + typeName + ";";
271.505 - }
271.506 - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
271.507 - smapper.popI(), smapper.pushA(), typeName);
271.508 + generateANewArray(type, smapper);
271.509 break;
271.510 }
271.511 case opc_multianewarray: {
271.512 - int type = readIntArg(byteCodes, i);
271.513 + int type = readUShortArg(byteCodes, i);
271.514 i += 2;
271.515 - String typeName = jc.getClassName(type);
271.516 - int dim = readUByte(byteCodes, ++i);
271.517 - StringBuilder dims = new StringBuilder();
271.518 - dims.append('[');
271.519 - for (int d = 0; d < dim; d++) {
271.520 - if (d != 0) {
271.521 - dims.append(",");
271.522 - }
271.523 - dims.append(smapper.popI());
271.524 - }
271.525 - dims.append(']');
271.526 - emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
271.527 - dims.toString(), smapper.pushA(), typeName);
271.528 + i = generateMultiANewArray(type, byteCodes, i, smapper);
271.529 break;
271.530 }
271.531 case opc_arraylength:
271.532 @@ -1210,11 +1207,11 @@
271.533 case opc_sipush:
271.534 emit(out, "var @1 = @2;",
271.535 smapper.pushI(),
271.536 - Integer.toString(readIntArg(byteCodes, i)));
271.537 + Integer.toString(readShortArg(byteCodes, i)));
271.538 i += 2;
271.539 break;
271.540 case opc_getfield: {
271.541 - int indx = readIntArg(byteCodes, i);
271.542 + int indx = readUShortArg(byteCodes, i);
271.543 String[] fi = jc.getFieldInfoName(indx);
271.544 final int type = VarType.fromFieldType(fi[2].charAt(0));
271.545 final String mangleClass = mangleSig(fi[0]);
271.546 @@ -1227,7 +1224,7 @@
271.547 break;
271.548 }
271.549 case opc_putfield: {
271.550 - int indx = readIntArg(byteCodes, i);
271.551 + int indx = readUShortArg(byteCodes, i);
271.552 String[] fi = jc.getFieldInfoName(indx);
271.553 final int type = VarType.fromFieldType(fi[2].charAt(0));
271.554 final String mangleClass = mangleSig(fi[0]);
271.555 @@ -1241,10 +1238,10 @@
271.556 break;
271.557 }
271.558 case opc_getstatic: {
271.559 - int indx = readIntArg(byteCodes, i);
271.560 + int indx = readUShortArg(byteCodes, i);
271.561 String[] fi = jc.getFieldInfoName(indx);
271.562 final int type = VarType.fromFieldType(fi[2].charAt(0));
271.563 - emit(out, "var @1 = @2(false).constructor.@3;",
271.564 + emit(out, "var @1 = @2(false)._@3();",
271.565 smapper.pushT(type),
271.566 accessClass(fi[0].replace('/', '_')), fi[1]);
271.567 i += 2;
271.568 @@ -1252,10 +1249,10 @@
271.569 break;
271.570 }
271.571 case opc_putstatic: {
271.572 - int indx = readIntArg(byteCodes, i);
271.573 + int indx = readUShortArg(byteCodes, i);
271.574 String[] fi = jc.getFieldInfoName(indx);
271.575 final int type = VarType.fromFieldType(fi[2].charAt(0));
271.576 - emit(out, "@1(false).constructor.@2 = @3;",
271.577 + emit(out, "@1(false)._@2(@3);",
271.578 accessClass(fi[0].replace('/', '_')), fi[1],
271.579 smapper.popT(type));
271.580 i += 2;
271.581 @@ -1263,33 +1260,14 @@
271.582 break;
271.583 }
271.584 case opc_checkcast: {
271.585 - int indx = readIntArg(byteCodes, i);
271.586 - final String type = jc.getClassName(indx);
271.587 - if (!type.startsWith("[")) {
271.588 - emit(out,
271.589 - "if (@1 !== null && !@1.$instOf_@2) throw {};",
271.590 - smapper.getA(0), type.replace('/', '_'));
271.591 - } else {
271.592 - emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
271.593 - smapper.getA(0), type
271.594 - );
271.595 - }
271.596 + int indx = readUShortArg(byteCodes, i);
271.597 + generateCheckcast(indx, smapper);
271.598 i += 2;
271.599 break;
271.600 }
271.601 case opc_instanceof: {
271.602 - int indx = readIntArg(byteCodes, i);
271.603 - final String type = jc.getClassName(indx);
271.604 - if (!type.startsWith("[")) {
271.605 - emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
271.606 - smapper.popA(), smapper.pushI(),
271.607 - type.replace('/', '_'));
271.608 - } else {
271.609 - emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
271.610 - smapper.popA(), smapper.pushI(),
271.611 - type
271.612 - );
271.613 - }
271.614 + int indx = readUShortArg(byteCodes, i);
271.615 + generateInstanceOf(indx, smapper);
271.616 i += 2;
271.617 break;
271.618 }
271.619 @@ -1325,37 +1303,29 @@
271.620 }
271.621 }
271.622 if (debug(" //")) {
271.623 - for (int j = prev; j <= i; j++) {
271.624 - out.append(" ");
271.625 - final int cc = readUByte(byteCodes, j);
271.626 - out.append(Integer.toString(cc));
271.627 - }
271.628 + generateByteCodeComment(prev, i, byteCodes);
271.629 }
271.630 out.append("\n");
271.631 }
271.632 if (previousTrap != null) {
271.633 - generateCatch(previousTrap);
271.634 + generateCatch(previousTrap, byteCodes.length, topMostLabel);
271.635 }
271.636 - out.append(" }\n");
271.637 - out.append("};");
271.638 + out.append("\n }\n");
271.639 + while (openBraces-- > 0) {
271.640 + out.append('}');
271.641 + }
271.642 + out.append("\n};");
271.643 }
271.644
271.645 - private int generateIf(byte[] byteCodes, int i,
271.646 - final Variable v2, final Variable v1,
271.647 - final String test) throws IOException {
271.648 - int indx = i + readIntArg(byteCodes, i);
271.649 + private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
271.650 + int indx = i + readShortArg(byteCodes, i);
271.651 out.append("if (").append(v1)
271.652 .append(' ').append(test).append(' ')
271.653 - .append(v2).append(") { gt = " + indx)
271.654 - .append("; continue; }");
271.655 + .append(v2).append(") ");
271.656 + goTo(out, i, indx, topMostLabel);
271.657 return i + 2;
271.658 }
271.659 -
271.660 - private int readIntArg(byte[] byteCodes, int offsetInstruction) {
271.661 - final int indxHi = byteCodes[offsetInstruction + 1] << 8;
271.662 - final int indxLo = byteCodes[offsetInstruction + 2];
271.663 - return (indxHi & 0xffffff00) | (indxLo & 0xff);
271.664 - }
271.665 +
271.666 private int readInt4(byte[] byteCodes, int offset) {
271.667 final int d = byteCodes[offset + 0] << 24;
271.668 final int c = byteCodes[offset + 1] << 16;
271.669 @@ -1363,18 +1333,25 @@
271.670 final int a = byteCodes[offset + 3];
271.671 return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
271.672 }
271.673 - private int readUByte(byte[] byteCodes, int offset) {
271.674 + private static int readUByte(byte[] byteCodes, int offset) {
271.675 return byteCodes[offset] & 0xff;
271.676 }
271.677
271.678 - private int readUShort(byte[] byteCodes, int offset) {
271.679 + private static int readUShort(byte[] byteCodes, int offset) {
271.680 return ((byteCodes[offset] & 0xff) << 8)
271.681 | (byteCodes[offset + 1] & 0xff);
271.682 }
271.683 + private static int readUShortArg(byte[] byteCodes, int offsetInstruction) {
271.684 + return readUShort(byteCodes, offsetInstruction + 1);
271.685 + }
271.686
271.687 - private int readShort(byte[] byteCodes, int offset) {
271.688 - return (byteCodes[offset] << 8)
271.689 - | (byteCodes[offset + 1] & 0xff);
271.690 + private static int readShort(byte[] byteCodes, int offset) {
271.691 + int signed = byteCodes[offset];
271.692 + byte b0 = (byte)signed;
271.693 + return (b0 << 8) | (byteCodes[offset + 1] & 0xff);
271.694 + }
271.695 + private static int readShortArg(byte[] byteCodes, int offsetInstruction) {
271.696 + return readShort(byteCodes, offsetInstruction + 1);
271.697 }
271.698
271.699 private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) {
271.700 @@ -1502,7 +1479,7 @@
271.701
271.702 private int invokeStaticMethod(byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic)
271.703 throws IOException {
271.704 - int methodIndex = readIntArg(byteCodes, i);
271.705 + int methodIndex = readUShortArg(byteCodes, i);
271.706 String[] mi = jc.getFieldInfoName(methodIndex);
271.707 char[] returnType = { 'V' };
271.708 StringBuilder cnt = new StringBuilder();
271.709 @@ -1547,7 +1524,7 @@
271.710 }
271.711 private int invokeVirtualMethod(byte[] byteCodes, int i, final StackMapper mapper)
271.712 throws IOException {
271.713 - int methodIndex = readIntArg(byteCodes, i);
271.714 + int methodIndex = readUShortArg(byteCodes, i);
271.715 String[] mi = jc.getFieldInfoName(methodIndex);
271.716 char[] returnType = { 'V' };
271.717 StringBuilder cnt = new StringBuilder();
271.718 @@ -1614,12 +1591,13 @@
271.719 return s;
271.720 }
271.721
271.722 - private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
271.723 + private String javaScriptBody(String destObject, MethodData m, boolean isStatic) throws IOException {
271.724 byte[] arr = m.findAnnotationData(true);
271.725 if (arr == null) {
271.726 return null;
271.727 }
271.728 final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
271.729 + final String htmlType = "Lnet/java/html/js/JavaScriptBody;";
271.730 class P extends AnnotationParser {
271.731 public P() {
271.732 super(false, true);
271.733 @@ -1628,6 +1606,7 @@
271.734 int cnt;
271.735 String[] args = new String[30];
271.736 String body;
271.737 + boolean javacall;
271.738
271.739 @Override
271.740 protected void visitAttr(String type, String attr, String at, String value) {
271.741 @@ -1640,6 +1619,17 @@
271.742 throw new IllegalArgumentException(attr);
271.743 }
271.744 }
271.745 + if (type.equals(htmlType)) {
271.746 + if ("body".equals(attr)) {
271.747 + body = value;
271.748 + } else if ("args".equals(attr)) {
271.749 + args[cnt++] = value;
271.750 + } else if ("javacall".equals(attr)) {
271.751 + javacall = "1".equals(value);
271.752 + } else {
271.753 + throw new IllegalArgumentException(attr);
271.754 + }
271.755 + }
271.756 }
271.757 }
271.758 P p = new P();
271.759 @@ -1649,7 +1639,7 @@
271.760 }
271.761 StringBuilder cnt = new StringBuilder();
271.762 final String mn = findMethodName(m, cnt);
271.763 - out.append(prefix).append(mn);
271.764 + out.append(destObject).append(".").append(mn);
271.765 out.append(" = function(");
271.766 String space = "";
271.767 int index = 0;
271.768 @@ -1659,10 +1649,121 @@
271.769 index++;
271.770 }
271.771 out.append(") {").append("\n");
271.772 - out.append(p.body);
271.773 + if (p.javacall) {
271.774 + int lastSlash = jc.getClassName().lastIndexOf('/');
271.775 + final String pkg = jc.getClassName().substring(0, lastSlash);
271.776 + out.append(mangleCallbacks(pkg, p.body));
271.777 + requireReference(pkg + "/$JsCallbacks$");
271.778 + } else {
271.779 + out.append(p.body);
271.780 + }
271.781 out.append("\n}\n");
271.782 return mn;
271.783 }
271.784 +
271.785 + private static CharSequence mangleCallbacks(String pkgName, String body) {
271.786 + StringBuilder sb = new StringBuilder();
271.787 + int pos = 0;
271.788 + for (;;) {
271.789 + int next = body.indexOf(".@", pos);
271.790 + if (next == -1) {
271.791 + sb.append(body.substring(pos));
271.792 + body = sb.toString();
271.793 + break;
271.794 + }
271.795 + int ident = next;
271.796 + while (ident > 0) {
271.797 + if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
271.798 + ident++;
271.799 + break;
271.800 + }
271.801 + }
271.802 + String refId = body.substring(ident, next);
271.803 +
271.804 + sb.append(body.substring(pos, ident));
271.805 +
271.806 + int sigBeg = body.indexOf('(', next);
271.807 + int sigEnd = body.indexOf(')', sigBeg);
271.808 + int colon4 = body.indexOf("::", next);
271.809 + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
271.810 + throw new IllegalStateException("Malformed body " + body);
271.811 + }
271.812 + String fqn = body.substring(next + 2, colon4);
271.813 + String method = body.substring(colon4 + 2, sigBeg);
271.814 + String params = body.substring(sigBeg, sigEnd + 1);
271.815 +
271.816 + int paramBeg = body.indexOf('(', sigEnd + 1);
271.817 +
271.818 + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
271.819 + sb.append(mangle(fqn, method, params, false));
271.820 + sb.append("(").append(refId);
271.821 + if (body.charAt(paramBeg + 1) != ')') {
271.822 + sb.append(",");
271.823 + }
271.824 + pos = paramBeg + 1;
271.825 + }
271.826 + sb = null;
271.827 + pos = 0;
271.828 + for (;;) {
271.829 + int next = body.indexOf("@", pos);
271.830 + if (next == -1) {
271.831 + if (sb == null) {
271.832 + return body;
271.833 + }
271.834 + sb.append(body.substring(pos));
271.835 + return sb;
271.836 + }
271.837 + if (sb == null) {
271.838 + sb = new StringBuilder();
271.839 + }
271.840 +
271.841 + sb.append(body.substring(pos, next));
271.842 +
271.843 + int sigBeg = body.indexOf('(', next);
271.844 + int sigEnd = body.indexOf(')', sigBeg);
271.845 + int colon4 = body.indexOf("::", next);
271.846 + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
271.847 + throw new IllegalStateException("Malformed body " + body);
271.848 + }
271.849 + String fqn = body.substring(next + 1, colon4);
271.850 + String method = body.substring(colon4 + 2, sigBeg);
271.851 + String params = body.substring(sigBeg, sigEnd + 1);
271.852 +
271.853 + int paramBeg = body.indexOf('(', sigEnd + 1);
271.854 +
271.855 + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
271.856 + sb.append(mangle(fqn, method, params, true));
271.857 + sb.append("(");
271.858 + pos = paramBeg + 1;
271.859 + }
271.860 + }
271.861 + private static String mangle(String fqn, String method, String params, boolean isStatic) {
271.862 + if (params.startsWith("(")) {
271.863 + params = params.substring(1);
271.864 + }
271.865 + if (params.endsWith(")")) {
271.866 + params = params.substring(0, params.length() - 1);
271.867 + }
271.868 + StringBuilder sb = new StringBuilder();
271.869 + final String rfqn = replace(fqn);
271.870 + final String rm = replace(method);
271.871 + final String rp = replace(params);
271.872 + sb.append(rfqn).append("$").append(rm).
271.873 + append('$').append(rp).append("__Ljava_lang_Object_2");
271.874 + if (!isStatic) {
271.875 + sb.append('L').append(rfqn).append("_2");
271.876 + }
271.877 + sb.append(rp);
271.878 + return sb.toString();
271.879 + }
271.880 +
271.881 + private static String replace(String orig) {
271.882 + return orig.replace("_", "_1").
271.883 + replace(";", "_2").
271.884 + replace("[", "_3").
271.885 + replace('.', '_').replace('/', '_');
271.886 + }
271.887 +
271.888 private static String className(ClassData jc) {
271.889 //return jc.getName().getInternalName().replace('/', '_');
271.890 return jc.getClassName().replace('/', '_');
271.891 @@ -1822,7 +1923,7 @@
271.892 out.append(format, processed, length);
271.893 }
271.894
271.895 - private void generateCatch(TrapData[] traps) throws IOException {
271.896 + private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException {
271.897 out.append("} catch (e) {\n");
271.898 int finallyPC = -1;
271.899 for (TrapData e : traps) {
271.900 @@ -1832,19 +1933,11 @@
271.901 if (e.catch_cpx != 0) { //not finally
271.902 final String classInternalName = jc.getClassName(e.catch_cpx);
271.903 addReference(classInternalName);
271.904 - if ("java/lang/Throwable".equals(classInternalName)) {
271.905 - out.append("if (e.$instOf_java_lang_Throwable) {");
271.906 - out.append(" var stA0 = e;");
271.907 - out.append("} else {");
271.908 - out.append(" var stA0 = vm.java_lang_Throwable(true);");
271.909 - out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
271.910 - out.append("}");
271.911 - out.append("gt=" + e.handler_pc + "; continue;");
271.912 - } else {
271.913 - out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
271.914 - out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
271.915 - out.append("}\n");
271.916 - }
271.917 + out.append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
271.918 + out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
271.919 + out.append("var stA0 = e;");
271.920 + goTo(out, current, e.handler_pc, topMostLabel);
271.921 + out.append("}\n");
271.922 } else {
271.923 finallyPC = e.handler_pc;
271.924 }
271.925 @@ -1852,8 +1945,152 @@
271.926 if (finallyPC == -1) {
271.927 out.append("throw e;");
271.928 } else {
271.929 - out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
271.930 + out.append("var stA0 = e;");
271.931 + goTo(out, current, finallyPC, topMostLabel);
271.932 }
271.933 out.append("\n}");
271.934 }
271.935 +
271.936 + private static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
271.937 + if (to < current) {
271.938 + if (canBack < to) {
271.939 + out.append("{ gt = 0; continue X_" + to + "; }");
271.940 + } else {
271.941 + out.append("{ gt = " + to + "; continue X_0; }");
271.942 + }
271.943 + } else {
271.944 + out.append("{ gt = " + to + "; break IF; }");
271.945 + }
271.946 + }
271.947 +
271.948 + private static void emitIf(
271.949 + Appendable out, String pattern, Variable param,
271.950 + int current, int to, int canBack
271.951 + ) throws IOException {
271.952 + emit(out, pattern, param);
271.953 + goTo(out, current, to, canBack);
271.954 + }
271.955 +
271.956 + private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException {
271.957 + String jvmType;
271.958 + switch (atype) {
271.959 + case 4: jvmType = "[Z"; break;
271.960 + case 5: jvmType = "[C"; break;
271.961 + case 6: jvmType = "[F"; break;
271.962 + case 7: jvmType = "[D"; break;
271.963 + case 8: jvmType = "[B"; break;
271.964 + case 9: jvmType = "[S"; break;
271.965 + case 10: jvmType = "[I"; break;
271.966 + case 11: jvmType = "[J"; break;
271.967 + default: throw new IllegalStateException("Array type: " + atype);
271.968 + }
271.969 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
271.970 + smapper.popI(), smapper.pushA(), jvmType);
271.971 + }
271.972 +
271.973 + private void generateANewArray(int type, final StackMapper smapper) throws IOException {
271.974 + String typeName = jc.getClassName(type);
271.975 + if (typeName.startsWith("[")) {
271.976 + typeName = "[" + typeName;
271.977 + } else {
271.978 + typeName = "[L" + typeName + ";";
271.979 + }
271.980 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
271.981 + smapper.popI(), smapper.pushA(), typeName);
271.982 + }
271.983 +
271.984 + private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
271.985 + String typeName = jc.getClassName(type);
271.986 + int dim = readUByte(byteCodes, ++i);
271.987 + StringBuilder dims = new StringBuilder();
271.988 + dims.append('[');
271.989 + for (int d = 0; d < dim; d++) {
271.990 + if (d != 0) {
271.991 + dims.insert(1, ",");
271.992 + }
271.993 + dims.insert(1, smapper.popI());
271.994 + }
271.995 + dims.append(']');
271.996 + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
271.997 + dims.toString(), smapper.pushA(), typeName);
271.998 + return i;
271.999 + }
271.1000 +
271.1001 + private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
271.1002 + int table = i / 4 * 4 + 4;
271.1003 + int dflt = i + readInt4(byteCodes, table);
271.1004 + table += 4;
271.1005 + int low = readInt4(byteCodes, table);
271.1006 + table += 4;
271.1007 + int high = readInt4(byteCodes, table);
271.1008 + table += 4;
271.1009 + out.append("switch (").append(smapper.popI()).append(") {\n");
271.1010 + while (low <= high) {
271.1011 + int offset = i + readInt4(byteCodes, table);
271.1012 + table += 4;
271.1013 + out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
271.1014 + low++;
271.1015 + }
271.1016 + out.append(" default: ");
271.1017 + goTo(out, i, dflt, topMostLabel);
271.1018 + out.append("\n}");
271.1019 + i = table - 1;
271.1020 + return i;
271.1021 + }
271.1022 +
271.1023 + private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
271.1024 + int table = i / 4 * 4 + 4;
271.1025 + int dflt = i + readInt4(byteCodes, table);
271.1026 + table += 4;
271.1027 + int n = readInt4(byteCodes, table);
271.1028 + table += 4;
271.1029 + out.append("switch (").append(smapper.popI()).append(") {\n");
271.1030 + while (n-- > 0) {
271.1031 + int cnstnt = readInt4(byteCodes, table);
271.1032 + table += 4;
271.1033 + int offset = i + readInt4(byteCodes, table);
271.1034 + table += 4;
271.1035 + out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
271.1036 + }
271.1037 + out.append(" default: ");
271.1038 + goTo(out, i, dflt, topMostLabel);
271.1039 + out.append("\n}");
271.1040 + i = table - 1;
271.1041 + return i;
271.1042 + }
271.1043 +
271.1044 + private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
271.1045 + final String type = jc.getClassName(indx);
271.1046 + if (!type.startsWith("[")) {
271.1047 + emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
271.1048 + smapper.popA(), smapper.pushI(),
271.1049 + type.replace('/', '_'));
271.1050 + } else {
271.1051 + emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
271.1052 + smapper.popA(), smapper.pushI(),
271.1053 + type
271.1054 + );
271.1055 + }
271.1056 + }
271.1057 +
271.1058 + private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
271.1059 + final String type = jc.getClassName(indx);
271.1060 + if (!type.startsWith("[")) {
271.1061 + emit(out,
271.1062 + "if (@1 !== null && !@1.$instOf_@2) throw vm.java_lang_ClassCastException(true);",
271.1063 + smapper.getA(0), type.replace('/', '_'));
271.1064 + } else {
271.1065 + emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
271.1066 + smapper.getA(0), type
271.1067 + );
271.1068 + }
271.1069 + }
271.1070 +
271.1071 + private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException {
271.1072 + for (int j = prev; j <= i; j++) {
271.1073 + out.append(" ");
271.1074 + final int cc = readUByte(byteCodes, j);
271.1075 + out.append(Integer.toString(cc));
271.1076 + }
271.1077 + }
271.1078 }
272.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
272.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Mon Oct 07 14:20:58 2013 +0200
272.3 @@ -0,0 +1,334 @@
272.4 +/**
272.5 + * Back 2 Browser Bytecode Translator
272.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
272.7 + *
272.8 + * This program is free software: you can redistribute it and/or modify
272.9 + * it under the terms of the GNU General Public License as published by
272.10 + * the Free Software Foundation, version 2 of the License.
272.11 + *
272.12 + * This program is distributed in the hope that it will be useful,
272.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
272.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
272.15 + * GNU General Public License for more details.
272.16 + *
272.17 + * You should have received a copy of the GNU General Public License
272.18 + * along with this program. Look for COPYING file in the top folder.
272.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
272.20 + */
272.21 +package org.apidesign.vm4brwsr;
272.22 +
272.23 +import com.google.javascript.jscomp.CommandLineRunner;
272.24 +import com.google.javascript.jscomp.SourceFile;
272.25 +import java.io.IOException;
272.26 +import java.io.OutputStream;
272.27 +import java.io.PrintStream;
272.28 +import java.util.ArrayList;
272.29 +import java.util.Arrays;
272.30 +import java.util.Collection;
272.31 +import java.util.Collections;
272.32 +import java.util.List;
272.33 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
272.34 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
272.35 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
272.36 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
272.37 +
272.38 +/**
272.39 + *
272.40 + * @author Jaroslav Tulach <jtulach@netbeans.org>
272.41 + */
272.42 +@ExtraJavaScript(processByteCode = false, resource="")
272.43 +final class ClosureWrapper extends CommandLineRunner {
272.44 + private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" /*, "--debug", "--formatting", "PRETTY_PRINT" */ };
272.45 +
272.46 + private final ClosuresObfuscationDelegate obfuscationDelegate;
272.47 + private final Bck2Brwsr.Resources res;
272.48 + private final StringArray classes;
272.49 +
272.50 + private String compiledCode;
272.51 + private String externsCode;
272.52 +
272.53 + private ClosureWrapper(Appendable out,
272.54 + String compilationLevel,
272.55 + ClosuresObfuscationDelegate obfuscationDelegate,
272.56 + Bck2Brwsr.Resources res, StringArray classes) {
272.57 + super(
272.58 + generateArguments(compilationLevel),
272.59 + new PrintStream(new APS(out)), System.err
272.60 + );
272.61 + this.obfuscationDelegate = obfuscationDelegate;
272.62 + this.res = res;
272.63 + this.classes = classes;
272.64 + }
272.65 +
272.66 + @Override
272.67 + protected List<SourceFile> createInputs(List<String> files, boolean allowStdIn) throws FlagUsageException, IOException {
272.68 + if (files.size() != 1 || !"bck2brwsr-raw.js".equals(files.get(0))) {
272.69 + throw new IOException("Unexpected files: " + files);
272.70 + }
272.71 + return Collections.nCopies(
272.72 + 1,
272.73 + SourceFile.fromGenerator(
272.74 + "bck2brwsr-raw.js",
272.75 + new SourceFile.Generator() {
272.76 + @Override
272.77 + public String getCode() {
272.78 + return getCompiledCode();
272.79 + }
272.80 + }));
272.81 + }
272.82 +
272.83 +
272.84 + @Override
272.85 + protected List<SourceFile> createExterns()
272.86 + throws FlagUsageException, IOException {
272.87 + final List<SourceFile> externsFiles =
272.88 + new ArrayList<SourceFile>(super.createExterns());
272.89 +
272.90 + externsFiles.add(
272.91 + SourceFile.fromGenerator(
272.92 + "bck2brwsr_externs.js",
272.93 + new SourceFile.Generator() {
272.94 + @Override
272.95 + public String getCode() {
272.96 + return getExternsCode();
272.97 + }
272.98 + }));
272.99 + return externsFiles;
272.100 + }
272.101 +
272.102 + private String getCompiledCode() {
272.103 + if (compiledCode == null) {
272.104 + StringBuilder sb = new StringBuilder();
272.105 + try {
272.106 + VM.compile(res, sb, classes, obfuscationDelegate);
272.107 + compiledCode = sb.toString();
272.108 + } catch (IOException ex) {
272.109 + compiledCode = ex.getMessage();
272.110 + }
272.111 + }
272.112 + return compiledCode;
272.113 + }
272.114 +
272.115 + private String getExternsCode() {
272.116 + if (externsCode == null) {
272.117 + // need compiled code at this point
272.118 + getCompiledCode();
272.119 +
272.120 + final StringBuilder sb = new StringBuilder("function RAW() {};\n");
272.121 + for (final String extern: obfuscationDelegate.getExterns()) {
272.122 + sb.append("RAW.prototype.").append(extern).append(";\n");
272.123 + }
272.124 + externsCode = sb.toString();
272.125 + }
272.126 + return externsCode;
272.127 + }
272.128 +
272.129 + private static final class APS extends OutputStream {
272.130 + private final Appendable out;
272.131 +
272.132 + public APS(Appendable out) {
272.133 + this.out = out;
272.134 + }
272.135 + @Override
272.136 + public void write(int b) throws IOException {
272.137 + out.append((char)b);
272.138 + }
272.139 + }
272.140 +
272.141 + private static String[] generateArguments(String compilationLevel) {
272.142 + String[] finalArgs = ARGS.clone();
272.143 + finalArgs[1] = compilationLevel;
272.144 +
272.145 + return finalArgs;
272.146 + }
272.147 +
272.148 + static int produceTo(Appendable w, ObfuscationLevel obfuscationLevel, Bck2Brwsr.Resources resources, StringArray arr) throws IOException {
272.149 + ClosureWrapper cw = create(w, obfuscationLevel, resources, arr);
272.150 + try {
272.151 + return cw.doRun();
272.152 + } catch (FlagUsageException ex) {
272.153 + throw new IOException(ex);
272.154 + }
272.155 + }
272.156 +
272.157 + private static ClosureWrapper create(Appendable w,
272.158 + ObfuscationLevel obfuscationLevel,
272.159 + Bck2Brwsr.Resources resources,
272.160 + StringArray arr) {
272.161 + switch (obfuscationLevel) {
272.162 + case MINIMAL:
272.163 + return new ClosureWrapper(w, "SIMPLE_OPTIMIZATIONS",
272.164 + new SimpleObfuscationDelegate(),
272.165 + resources, arr);
272.166 +/*
272.167 + case MEDIUM:
272.168 + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
272.169 + new MediumObfuscationDelegate(),
272.170 + resources, arr);
272.171 +*/
272.172 + case FULL:
272.173 + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
272.174 + new FullObfuscationDelegate(),
272.175 + resources, arr);
272.176 + default:
272.177 + throw new IllegalArgumentException(
272.178 + "Unsupported level: " + obfuscationLevel);
272.179 + }
272.180 + }
272.181 +
272.182 + private static abstract class ClosuresObfuscationDelegate
272.183 + extends ObfuscationDelegate {
272.184 + public abstract Collection<String> getExterns();
272.185 + }
272.186 +
272.187 + private static final class SimpleObfuscationDelegate
272.188 + extends ClosuresObfuscationDelegate {
272.189 + @Override
272.190 + public void exportJSProperty(Appendable out,
272.191 + String destObject,
272.192 + String propertyName) throws IOException {
272.193 + }
272.194 +
272.195 + @Override
272.196 + public void exportClass(Appendable out,
272.197 + String destObject,
272.198 + String mangledName,
272.199 + ClassData classData) throws IOException {
272.200 + }
272.201 +
272.202 + @Override
272.203 + public void exportMethod(Appendable out,
272.204 + String destObject,
272.205 + String mangledName,
272.206 + MethodData methodData) throws IOException {
272.207 + }
272.208 +
272.209 + @Override
272.210 + public void exportField(Appendable out,
272.211 + String destObject,
272.212 + String mangledName,
272.213 + FieldData fieldData) throws IOException {
272.214 + }
272.215 +
272.216 + @Override
272.217 + public Collection<String> getExterns() {
272.218 + return Collections.EMPTY_LIST;
272.219 + }
272.220 + }
272.221 +
272.222 + private static abstract class AdvancedObfuscationDelegate
272.223 + extends ClosuresObfuscationDelegate {
272.224 + private static final String[] INITIAL_EXTERNS = {
272.225 + "bck2brwsr",
272.226 + "$class",
272.227 + "anno",
272.228 + "array",
272.229 + "access",
272.230 + "cls",
272.231 + "vm",
272.232 + "loadClass",
272.233 + "loadBytes",
272.234 + "jvmName",
272.235 + "primitive",
272.236 + "superclass",
272.237 + "cnstr",
272.238 + "add32",
272.239 + "sub32",
272.240 + "mul32",
272.241 + "neg32",
272.242 + "toInt8",
272.243 + "toInt16",
272.244 + "next32",
272.245 + "high32",
272.246 + "toInt32",
272.247 + "toFP",
272.248 + "toLong",
272.249 + "toExactString",
272.250 + "add64",
272.251 + "sub64",
272.252 + "mul64",
272.253 + "and64",
272.254 + "or64",
272.255 + "xor64",
272.256 + "shl64",
272.257 + "shr64",
272.258 + "ushr64",
272.259 + "compare64",
272.260 + "neg64",
272.261 + "div32",
272.262 + "mod32",
272.263 + "div64",
272.264 + "mod64",
272.265 + "at",
272.266 + "getClass__Ljava_lang_Class_2",
272.267 + "clone__Ljava_lang_Object_2"
272.268 + };
272.269 +
272.270 + private final Collection<String> externs;
272.271 +
272.272 + protected AdvancedObfuscationDelegate() {
272.273 + externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
272.274 + }
272.275 +
272.276 + @Override
272.277 + public void exportClass(Appendable out,
272.278 + String destObject,
272.279 + String mangledName,
272.280 + ClassData classData) throws IOException {
272.281 + exportJSProperty(out, destObject, mangledName);
272.282 + }
272.283 +
272.284 + @Override
272.285 + public void exportMethod(Appendable out,
272.286 + String destObject,
272.287 + String mangledName,
272.288 + MethodData methodData) throws IOException {
272.289 + if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
272.290 + exportJSProperty(out, destObject, mangledName);
272.291 + }
272.292 + }
272.293 +
272.294 + @Override
272.295 + public void exportField(Appendable out,
272.296 + String destObject,
272.297 + String mangledName,
272.298 + FieldData fieldData) throws IOException {
272.299 + if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
272.300 + exportJSProperty(out, destObject, mangledName);
272.301 + }
272.302 + }
272.303 +
272.304 + @Override
272.305 + public Collection<String> getExterns() {
272.306 + return externs;
272.307 + }
272.308 +
272.309 + protected void addExtern(String extern) {
272.310 + externs.add(extern);
272.311 + }
272.312 + }
272.313 +
272.314 + private static final class MediumObfuscationDelegate
272.315 + extends AdvancedObfuscationDelegate {
272.316 + @Override
272.317 + public void exportJSProperty(Appendable out,
272.318 + String destObject,
272.319 + String propertyName) {
272.320 + addExtern(propertyName);
272.321 + }
272.322 + }
272.323 +
272.324 + private static final class FullObfuscationDelegate
272.325 + extends AdvancedObfuscationDelegate {
272.326 + @Override
272.327 + public void exportJSProperty(Appendable out,
272.328 + String destObject,
272.329 + String propertyName) throws IOException {
272.330 + out.append("\n").append(destObject).append("['")
272.331 + .append(propertyName)
272.332 + .append("'] = ")
272.333 + .append(destObject).append(".").append(propertyName)
272.334 + .append(";\n");
272.335 + }
272.336 + }
272.337 +}
273.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
273.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java Mon Oct 07 14:20:58 2013 +0200
273.3 @@ -0,0 +1,48 @@
273.4 +/**
273.5 + * Back 2 Browser Bytecode Translator
273.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
273.7 + *
273.8 + * This program is free software: you can redistribute it and/or modify
273.9 + * it under the terms of the GNU General Public License as published by
273.10 + * the Free Software Foundation, version 2 of the License.
273.11 + *
273.12 + * This program is distributed in the hope that it will be useful,
273.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
273.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
273.15 + * GNU General Public License for more details.
273.16 + *
273.17 + * You should have received a copy of the GNU General Public License
273.18 + * along with this program. Look for COPYING file in the top folder.
273.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
273.20 + */
273.21 +package org.apidesign.vm4brwsr;
273.22 +
273.23 +import java.io.IOException;
273.24 +import java.io.InputStream;
273.25 +import java.net.URL;
273.26 +import java.util.Enumeration;
273.27 +
273.28 +/** Implementation of Resources that delegates to some class loader.
273.29 + *
273.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
273.31 + */
273.32 +final class LdrRsrcs implements Bck2Brwsr.Resources {
273.33 + private final ClassLoader loader;
273.34 +
273.35 + LdrRsrcs(ClassLoader loader) {
273.36 + this.loader = loader;
273.37 + }
273.38 +
273.39 + @Override
273.40 + public InputStream get(String name) throws IOException {
273.41 + Enumeration<URL> en = loader.getResources(name);
273.42 + URL u = null;
273.43 + while (en.hasMoreElements()) {
273.44 + u = en.nextElement();
273.45 + }
273.46 + if (u == null) {
273.47 + throw new IOException("Can't find " + name);
273.48 + }
273.49 + return u.openStream();
273.50 + }
273.51 +}
274.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Wed Feb 27 17:50:47 2013 +0100
274.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Mon Oct 07 14:20:58 2013 +0200
274.3 @@ -18,8 +18,7 @@
274.4 package org.apidesign.vm4brwsr;
274.5
274.6 import java.io.IOException;
274.7 -import org.apidesign.javap.RuntimeConstants;
274.8 -import org.apidesign.javap.TypeArray;
274.9 +import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
274.10
274.11 final class LocalsMapper {
274.12 private final TypeArray argTypeRecords;
274.13 @@ -113,7 +112,7 @@
274.14 final int srcSize = stackMapTypes.getSize();
274.15 for (int i = 0, dstIndex = 0; i < srcSize; ++i) {
274.16 final int smType = stackMapTypes.get(i);
274.17 - if (smType == RuntimeConstants.ITEM_Bogus) {
274.18 + if (smType == ByteCodeParser.ITEM_Bogus) {
274.19 ++dstIndex;
274.20 continue;
274.21 }
275.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Wed Feb 27 17:50:47 2013 +0100
275.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Mon Oct 07 14:20:58 2013 +0200
275.3 @@ -18,6 +18,7 @@
275.4 package org.apidesign.vm4brwsr;
275.5
275.6 import java.io.BufferedWriter;
275.7 +import java.io.File;
275.8 import java.io.FileWriter;
275.9 import java.io.IOException;
275.10 import java.io.Writer;
275.11 @@ -31,20 +32,69 @@
275.12 private Main() {}
275.13
275.14 public static void main(String... args) throws IOException {
275.15 + final String obfuscate = "--obfuscatelevel";
275.16 +
275.17 if (args.length < 2) {
275.18 System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
275.19 - System.err.println("Usage: java -cp ... -jar ... <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
275.20 - return;
275.21 + System.err.println("Usage: java -cp ... -jar ... [");
275.22 + System.err.print(obfuscate);
275.23 + System.err.print(" [");
275.24 + boolean first = true;
275.25 + for (ObfuscationLevel l : ObfuscationLevel.values()) {
275.26 + if (!first) {
275.27 + System.err.print('|');
275.28 + }
275.29 + System.err.print(l.name());
275.30 + first = false;
275.31 + }
275.32 +
275.33 + System.err.println("] <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
275.34 + System.exit(9);
275.35 }
275.36
275.37 - Writer w = new BufferedWriter(new FileWriter(args[0]));
275.38 - StringArray classes = StringArray.asList(args);
275.39 - classes.delete(0);
275.40 - try {
275.41 - Bck2Brwsr.generate(w, Main.class.getClassLoader(),
275.42 - classes.toArray());
275.43 - } finally {
275.44 - w.close();
275.45 + ObfuscationLevel obfLevel = ObfuscationLevel.NONE;
275.46 + StringArray classes = new StringArray();
275.47 + String generateTo = null;
275.48 + for (int i = 0; i < args.length; i++) {
275.49 + if (obfuscate.equals(args[i])) { // NOI18N
275.50 + i++;
275.51 + try {
275.52 + obfLevel = ObfuscationLevel.valueOf(args[i]);
275.53 + } catch (Exception e) {
275.54 + System.err.print(obfuscate);
275.55 + System.err.print(" parameter needs to be followed by one of ");
275.56 + boolean first = true;
275.57 + for (ObfuscationLevel l : ObfuscationLevel.values()) {
275.58 + if (!first) {
275.59 + System.err.print(", ");
275.60 + }
275.61 + System.err.print(l.name());
275.62 + first = false;
275.63 + }
275.64 + System.err.println();
275.65 + System.exit(1);
275.66 + }
275.67 + continue;
275.68 + }
275.69 + if (generateTo == null) {
275.70 + generateTo = args[i];
275.71 + } else {
275.72 + classes = classes.addAndNew(args[i]);
275.73 + }
275.74 + }
275.75 +
275.76 + File gt = new File(generateTo);
275.77 + if (Boolean.getBoolean("skip.if.exists") && gt.isFile()) {
275.78 + System.err.println("Skipping as " + gt + " exists.");
275.79 + System.exit(0);
275.80 + }
275.81 +
275.82 + try (Writer w = new BufferedWriter(new FileWriter(gt))) {
275.83 + Bck2Brwsr.newCompiler().
275.84 + obfuscation(obfLevel).
275.85 + addRootClasses(classes.toArray()).
275.86 + resources(Main.class.getClassLoader()).
275.87 + generate(w);
275.88 }
275.89 }
275.90 }
276.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationDelegate.java Mon Oct 07 14:20:58 2013 +0200
276.3 @@ -0,0 +1,75 @@
276.4 +/**
276.5 + * Back 2 Browser Bytecode Translator
276.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
276.7 + *
276.8 + * This program is free software: you can redistribute it and/or modify
276.9 + * it under the terms of the GNU General Public License as published by
276.10 + * the Free Software Foundation, version 2 of the License.
276.11 + *
276.12 + * This program is distributed in the hope that it will be useful,
276.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
276.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
276.15 + * GNU General Public License for more details.
276.16 + *
276.17 + * You should have received a copy of the GNU General Public License
276.18 + * along with this program. Look for COPYING file in the top folder.
276.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
276.20 + */
276.21 +package org.apidesign.vm4brwsr;
276.22 +
276.23 +import java.io.IOException;
276.24 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
276.25 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
276.26 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
276.27 +
276.28 +abstract class ObfuscationDelegate {
276.29 + static ObfuscationDelegate NULL =
276.30 + new ObfuscationDelegate() {
276.31 + @Override
276.32 + public void exportJSProperty(Appendable out,
276.33 + String destObject,
276.34 + String propertyName)
276.35 + throws IOException {
276.36 + }
276.37 +
276.38 + @Override
276.39 + public void exportClass(Appendable out,
276.40 + String destObject,
276.41 + String mangledName,
276.42 + ClassData classData)
276.43 + throws IOException {
276.44 + }
276.45 +
276.46 + @Override
276.47 + public void exportMethod(Appendable out,
276.48 + String destObject,
276.49 + String mangledName,
276.50 + MethodData methodData)
276.51 + throws IOException {
276.52 + }
276.53 +
276.54 + @Override
276.55 + public void exportField(Appendable out,
276.56 + String destObject,
276.57 + String mangledName,
276.58 + FieldData fieldData)
276.59 + throws IOException {
276.60 + }
276.61 + };
276.62 +
276.63 + public abstract void exportJSProperty(
276.64 + Appendable out, String destObject, String propertyName)
276.65 + throws IOException;
276.66 +
276.67 + public abstract void exportClass(
276.68 + Appendable out, String destObject, String mangledName,
276.69 + ClassData classData) throws IOException;
276.70 +
276.71 + public abstract void exportMethod(
276.72 + Appendable out, String destObject, String mangledName,
276.73 + MethodData methodData) throws IOException;
276.74 +
276.75 + public abstract void exportField(
276.76 + Appendable out, String destObject, String mangledName,
276.77 + FieldData fieldData) throws IOException;
276.78 +}
277.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
277.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationLevel.java Mon Oct 07 14:20:58 2013 +0200
277.3 @@ -0,0 +1,41 @@
277.4 +/**
277.5 + * Back 2 Browser Bytecode Translator
277.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
277.7 + *
277.8 + * This program is free software: you can redistribute it and/or modify
277.9 + * it under the terms of the GNU General Public License as published by
277.10 + * the Free Software Foundation, version 2 of the License.
277.11 + *
277.12 + * This program is distributed in the hope that it will be useful,
277.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
277.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
277.15 + * GNU General Public License for more details.
277.16 + *
277.17 + * You should have received a copy of the GNU General Public License
277.18 + * along with this program. Look for COPYING file in the top folder.
277.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
277.20 + */
277.21 +package org.apidesign.vm4brwsr;
277.22 +
277.23 +/**
277.24 + * Defines obfuscation level of produced JavaScript files.
277.25 + *
277.26 + * @since 0.5
277.27 + */
277.28 +public enum ObfuscationLevel {
277.29 + /** Generated JavaScript is (sort of) human readable. Useful for debugging.
277.30 + * Dynamic capabilities of the virtual machine work on all classes.
277.31 + */
277.32 + NONE,
277.33 + /** White spaces are removed. Names of external symbols remain unchanged.
277.34 + * Dynamic capabilities of the virtual machine work on all classes.
277.35 + */
277.36 + MINIMAL,
277.37 +// temporarily commented out before merge. not well defined yet:
277.38 +// MEDIUM,
277.39 + /** Aggressive obfuscation of everything. Compact, unreadable "one-liner".
277.40 + * One cannot load classes dynamically. Useful mostly for static compilation
277.41 + * of self contained application.
277.42 + */
277.43 + FULL
277.44 +}
278.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Wed Feb 27 17:50:47 2013 +0100
278.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Mon Oct 07 14:20:58 2013 +0200
278.3 @@ -17,7 +17,7 @@
278.4 */
278.5 package org.apidesign.vm4brwsr;
278.6
278.7 -import org.apidesign.javap.TypeArray;
278.8 +import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
278.9
278.10 final class StackMapper {
278.11 private final TypeArray stackTypeIndexPairs;
279.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Wed Feb 27 17:50:47 2013 +0100
279.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Mon Oct 07 14:20:58 2013 +0200
279.3 @@ -43,6 +43,25 @@
279.4 }
279.5 arr[arr.length - 1] = s;
279.6 }
279.7 +
279.8 + StringArray addAndNew(String... values) {
279.9 + int j;
279.10 + String[] tmp;
279.11 + if (arr == null) {
279.12 + tmp = new String[values.length];
279.13 + j = 0;
279.14 + } else {
279.15 + tmp = new String[arr.length + values.length];
279.16 + for (int i = 0; i < arr.length; i++) {
279.17 + tmp[i] = arr[i];
279.18 + }
279.19 + j = arr.length;
279.20 + }
279.21 + for (int i = 0; i < values.length;) {
279.22 + tmp[j++] = values[i++];
279.23 + }
279.24 + return new StringArray(tmp);
279.25 + }
279.26
279.27 public String[] toArray() {
279.28 return arr == null ? new String[0] : arr;
279.29 @@ -93,5 +112,4 @@
279.30 }
279.31 return -1;
279.32 }
279.33 -
279.34 }
280.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed Feb 27 17:50:47 2013 +0100
280.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Mon Oct 07 14:20:58 2013 +0200
280.3 @@ -28,7 +28,11 @@
280.4 public VM(Appendable out) {
280.5 super(out);
280.6 }
280.7 -
280.8 +
280.9 + private VM(Appendable out, ObfuscationDelegate obfuscationDelegate) {
280.10 + super(out, obfuscationDelegate);
280.11 + }
280.12 +
280.13 static {
280.14 // uses VMLazy to load dynamic classes
280.15 boolean assertsOn = false;
280.16 @@ -47,6 +51,12 @@
280.17 static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
280.18 new VM(out).doCompile(l, names);
280.19 }
280.20 +
280.21 + static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names,
280.22 + ObfuscationDelegate obfuscationDelegate) throws IOException {
280.23 + new VM(out, obfuscationDelegate).doCompile(l, names);
280.24 + }
280.25 +
280.26 protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
280.27 out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
280.28 StringArray processed = new StringArray();
280.29 @@ -110,7 +120,10 @@
280.30 for (String ic : toInit.toArray()) {
280.31 int indx = processed.indexOf(ic);
280.32 if (indx >= 0) {
280.33 - out.append(initCode.toArray()[indx]).append("\n");
280.34 + final String theCode = initCode.toArray()[indx];
280.35 + if (!theCode.isEmpty()) {
280.36 + out.append(theCode).append("\n");
280.37 + }
280.38 initCode.toArray()[indx] = "";
280.39 }
280.40 }
280.41 @@ -227,4 +240,9 @@
280.42 String accessClass(String className) {
280.43 return "vm." + className;
280.44 }
280.45 +
280.46 + @Override
280.47 + String getVMObject() {
280.48 + return "vm";
280.49 + }
280.50 }
281.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Wed Feb 27 17:50:47 2013 +0100
281.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Mon Oct 07 14:20:58 2013 +0200
281.3 @@ -56,7 +56,7 @@
281.4 throw new ClassNotFoundException(name);
281.5 }
281.6 // beingDefined(loader, name);
281.7 - StringBuilder out = new StringBuilder();
281.8 + StringBuilder out = new StringBuilder(65535);
281.9 out.append("var loader = arguments[0];\n");
281.10 out.append("var vm = loader.vm;\n");
281.11 int prelude = out.length();
281.12 @@ -130,6 +130,14 @@
281.13
281.14 @Override
281.15 protected void requireScript(String resourcePath) throws IOException {
281.16 + if (!resourcePath.startsWith("/")) {
281.17 + resourcePath = "/" + resourcePath;
281.18 + }
281.19 + String code = readCode(resourcePath);
281.20 + applyCode(lazy.loader, null, code, false);
281.21 + }
281.22 +
281.23 + private String readCode(String resourcePath) throws IOException {
281.24 InputStream is = getClass().getResourceAsStream(resourcePath);
281.25 StringBuilder sb = new StringBuilder();
281.26 for (;;) {
281.27 @@ -139,7 +147,7 @@
281.28 }
281.29 sb.append((char)ch);
281.30 }
281.31 - applyCode(lazy.loader, null, sb.toString(), false);
281.32 + return sb.toString();
281.33 }
281.34
281.35 @Override
281.36 @@ -151,5 +159,10 @@
281.37 String accessClass(String classOperation) {
281.38 return "vm." + classOperation;
281.39 }
281.40 +
281.41 + @Override
281.42 + String getVMObject() {
281.43 + return "vm";
281.44 + }
281.45 }
281.46 }
282.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VarType.java Wed Feb 27 17:50:47 2013 +0100
282.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VarType.java Mon Oct 07 14:20:58 2013 +0200
282.3 @@ -17,8 +17,6 @@
282.4 */
282.5 package org.apidesign.vm4brwsr;
282.6
282.7 -import org.apidesign.javap.RuntimeConstants;
282.8 -
282.9 final class VarType {
282.10 public static final int INTEGER = 0;
282.11 public static final int LONG = 1;
282.12 @@ -37,21 +35,21 @@
282.13
282.14 public static int fromStackMapType(final int smType) {
282.15 switch (smType & 0xff) {
282.16 - case RuntimeConstants.ITEM_Integer:
282.17 + case ByteCodeParser.ITEM_Integer:
282.18 return VarType.INTEGER;
282.19 - case RuntimeConstants.ITEM_Float:
282.20 + case ByteCodeParser.ITEM_Float:
282.21 return VarType.FLOAT;
282.22 - case RuntimeConstants.ITEM_Double:
282.23 + case ByteCodeParser.ITEM_Double:
282.24 return VarType.DOUBLE;
282.25 - case RuntimeConstants.ITEM_Long:
282.26 + case ByteCodeParser.ITEM_Long:
282.27 return VarType.LONG;
282.28 - case RuntimeConstants.ITEM_Null:
282.29 - case RuntimeConstants.ITEM_InitObject:
282.30 - case RuntimeConstants.ITEM_Object:
282.31 - case RuntimeConstants.ITEM_NewObject:
282.32 + case ByteCodeParser.ITEM_Null:
282.33 + case ByteCodeParser.ITEM_InitObject:
282.34 + case ByteCodeParser.ITEM_Object:
282.35 + case ByteCodeParser.ITEM_NewObject:
282.36 return VarType.REFERENCE;
282.37
282.38 - case RuntimeConstants.ITEM_Bogus:
282.39 + case ByteCodeParser.ITEM_Bogus:
282.40 /* unclear how to handle for now */
282.41 default:
282.42 throw new IllegalStateException("Unhandled stack map type");
282.43 @@ -60,25 +58,25 @@
282.44
282.45 public static int fromConstantType(final byte constantTag) {
282.46 switch (constantTag) {
282.47 - case RuntimeConstants.CONSTANT_INTEGER:
282.48 + case ByteCodeParser.CONSTANT_INTEGER:
282.49 return VarType.INTEGER;
282.50 - case RuntimeConstants.CONSTANT_FLOAT:
282.51 + case ByteCodeParser.CONSTANT_FLOAT:
282.52 return VarType.FLOAT;
282.53 - case RuntimeConstants.CONSTANT_LONG:
282.54 + case ByteCodeParser.CONSTANT_LONG:
282.55 return VarType.LONG;
282.56 - case RuntimeConstants.CONSTANT_DOUBLE:
282.57 + case ByteCodeParser.CONSTANT_DOUBLE:
282.58 return VarType.DOUBLE;
282.59
282.60 - case RuntimeConstants.CONSTANT_CLASS:
282.61 - case RuntimeConstants.CONSTANT_UTF8:
282.62 - case RuntimeConstants.CONSTANT_UNICODE:
282.63 - case RuntimeConstants.CONSTANT_STRING:
282.64 + case ByteCodeParser.CONSTANT_CLASS:
282.65 + case ByteCodeParser.CONSTANT_UTF8:
282.66 + case ByteCodeParser.CONSTANT_UNICODE:
282.67 + case ByteCodeParser.CONSTANT_STRING:
282.68 return VarType.REFERENCE;
282.69
282.70 - case RuntimeConstants.CONSTANT_FIELD:
282.71 - case RuntimeConstants.CONSTANT_METHOD:
282.72 - case RuntimeConstants.CONSTANT_INTERFACEMETHOD:
282.73 - case RuntimeConstants.CONSTANT_NAMEANDTYPE:
282.74 + case ByteCodeParser.CONSTANT_FIELD:
282.75 + case ByteCodeParser.CONSTANT_METHOD:
282.76 + case ByteCodeParser.CONSTANT_INTERFACEMETHOD:
282.77 + case ByteCodeParser.CONSTANT_NAMEANDTYPE:
282.78 /* unclear how to handle for now */
282.79 default:
282.80 throw new IllegalStateException("Unhandled constant tag");
283.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Wed Feb 27 17:50:47 2013 +0100
283.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Mon Oct 07 14:20:58 2013 +0200
283.3 @@ -132,4 +132,8 @@
283.4 arraycopy(arr()[0][0].chars, 0, arr, 0, 1);
283.5 return arr[0];
283.6 }
283.7 +
283.8 + public static int multiLen() {
283.9 + return new int[1][0].length;
283.10 + }
283.11 }
284.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Wed Feb 27 17:50:47 2013 +0100
284.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Mon Oct 07 14:20:58 2013 +0200
284.3 @@ -18,6 +18,7 @@
284.4 package org.apidesign.vm4brwsr;
284.5
284.6 import static org.testng.Assert.*;
284.7 +import org.testng.annotations.AfterClass;
284.8 import org.testng.annotations.BeforeClass;
284.9 import org.testng.annotations.Test;
284.10
284.11 @@ -74,6 +75,9 @@
284.12 @Test public void verifyInstanceOfArray() throws Exception {
284.13 assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(0), "non-array");
284.14 }
284.15 + @Test public void verifyMultiLen() throws Exception {
284.16 + assertExec("Multi len is one", Array.class, "multiLen__I", Double.valueOf(1));
284.17 + }
284.18
284.19 private static TestVM code;
284.20
284.21 @@ -81,6 +85,10 @@
284.22 public void compileTheCode() throws Exception {
284.23 code = TestVM.compileClass("org/apidesign/vm4brwsr/Array");
284.24 }
284.25 + @AfterClass
284.26 + public static void releaseTheCode() {
284.27 + code = null;
284.28 + }
284.29 private static void assertExec(String msg, Class clazz, String method, Object expRes, Object... args) throws Exception {
284.30 code.assertExec(msg, clazz, method, expRes, args);
284.31 }
285.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Wed Feb 27 17:50:47 2013 +0100
285.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Mon Oct 07 14:20:58 2013 +0200
285.3 @@ -19,6 +19,7 @@
285.4
285.5 import org.testng.annotations.Test;
285.6 import static org.testng.Assert.*;
285.7 +import org.testng.annotations.AfterClass;
285.8 import org.testng.annotations.BeforeClass;
285.9
285.10 /**
285.11 @@ -190,6 +191,10 @@
285.12 public void compileTheCode() throws Exception {
285.13 code = TestVM.compileClass("org/apidesign/vm4brwsr/Classes");
285.14 }
285.15 + @AfterClass
285.16 + public static void releaseTheCode() {
285.17 + code = null;
285.18 + }
285.19
285.20 private void assertExec(
285.21 String msg, Class clazz, String method, Object expRes, Object... args
285.22 @@ -203,4 +208,24 @@
285.23 );
285.24 }
285.25
285.26 + @Test public void valueOfEnum() throws Exception {
285.27 + assertExec("can get value of enum", Classes.class,
285.28 + "valueEnum__Ljava_lang_String_2Ljava_lang_String_2",
285.29 + "TWO", "TWO"
285.30 + );
285.31 + }
285.32 +
285.33 + @Test public void typeOfFn() throws Exception {
285.34 + assertExec("Type of function is Object", Classes.class,
285.35 + "typeOfFn__Ljava_lang_String_2",
285.36 + "java.lang.Object"
285.37 + );
285.38 + }
285.39 +
285.40 + @Test public void instanceOfSuperInterface() throws Exception {
285.41 + assertExec("Is iof super interface", Classes.class,
285.42 + "instanceOfSuperInterface__Z",
285.43 + 1.0
285.44 + );
285.45 + }
285.46 }
286.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Wed Feb 27 17:50:47 2013 +0100
286.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Mon Oct 07 14:20:58 2013 +0200
286.3 @@ -18,6 +18,7 @@
286.4 package org.apidesign.vm4brwsr;
286.5
286.6 import java.io.IOException;
286.7 +import java.io.Serializable;
286.8 import java.lang.annotation.Annotation;
286.9 import java.lang.annotation.Retention;
286.10 import java.lang.annotation.RetentionPolicy;
286.11 @@ -230,4 +231,23 @@
286.12 return Application.class.isAssignableFrom(MyApplication.class);
286.13 }
286.14
286.15 + public static String valueEnum(String v) {
286.16 + return ClassesMarker.E.valueOf(v).toString();
286.17 + }
286.18 +
286.19 + public static String typeOfFn() {
286.20 + return fn().getClass().getName();
286.21 + }
286.22 +
286.23 + @JavaScriptBody(args = { }, body = "return function() { alert('x'); };")
286.24 + private native static Object fn();
286.25 +
286.26 + public static boolean instanceOfSuperInterface() {
286.27 + Object obj = new SuperSerial() {
286.28 + };
286.29 + return obj instanceof Serializable;
286.30 + }
286.31 +
286.32 + private static interface SuperSerial extends Serializable {
286.33 + }
286.34 }
287.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ExceptionsTest.java Wed Feb 27 17:50:47 2013 +0100
287.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ExceptionsTest.java Mon Oct 07 14:20:58 2013 +0200
287.3 @@ -19,6 +19,7 @@
287.4
287.5 import javax.script.ScriptException;
287.6 import static org.testng.Assert.*;
287.7 +import org.testng.annotations.AfterClass;
287.8 import org.testng.annotations.BeforeClass;
287.9 import org.testng.annotations.Test;
287.10
287.11 @@ -108,6 +109,10 @@
287.12 public void compileTheCode() throws Exception {
287.13 code = TestVM.compileClass("org/apidesign/vm4brwsr/Exceptions");
287.14 }
287.15 + @AfterClass
287.16 + public static void releaseTheCode() {
287.17 + code = null;
287.18 + }
287.19 private static void assertExec(String msg, Class clazz, String method, Object expRes, Object... args) throws Exception {
287.20 code.assertExec(msg, clazz, method, expRes, args);
287.21 }
288.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java Wed Feb 27 17:50:47 2013 +0100
288.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java Mon Oct 07 14:20:58 2013 +0200
288.3 @@ -17,6 +17,7 @@
288.4 */
288.5 package org.apidesign.vm4brwsr;
288.6
288.7 +import org.testng.annotations.AfterClass;
288.8 import org.testng.annotations.Test;
288.9 import org.testng.annotations.BeforeClass;
288.10
288.11 @@ -156,6 +157,10 @@
288.12 public void compileTheCode() throws Exception {
288.13 code = TestVM.compileClass(startCompilationWith());
288.14 }
288.15 + @AfterClass
288.16 + public static void releaseTheCode() {
288.17 + code = null;
288.18 + }
288.19
288.20 private void assertExec(
288.21 String msg, Class clazz, String method, Object expRes, Object... args
289.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Wed Feb 27 17:50:47 2013 +0100
289.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Mon Oct 07 14:20:58 2013 +0200
289.3 @@ -18,6 +18,7 @@
289.4 package org.apidesign.vm4brwsr;
289.5
289.6 import static org.testng.Assert.*;
289.7 +import org.testng.annotations.AfterClass;
289.8 import org.testng.annotations.BeforeClass;
289.9 import org.testng.annotations.Test;
289.10
289.11 @@ -184,13 +185,36 @@
289.12 Double.valueOf(Long.MAX_VALUE / 5), 9
289.13 );
289.14 }
289.15 + @Test public void valueOfLongCharA() throws Exception {
289.16 + assertExec("Can we call JavaScripts valueOf on Character?",
289.17 + Numbers.class, "seven__DI",
289.18 + Double.valueOf('A'), 65
289.19 + );
289.20 + }
289.21 +
289.22 + @Test public void valueOfLongBooleanTrue() throws Exception {
289.23 + assertExec("Can we call JavaScripts valueOf on Boolean?",
289.24 + Numbers.class, "bseven__ZI",
289.25 + true, 31
289.26 + );
289.27 + }
289.28 + @Test public void valueOfLongBooleanFalse() throws Exception {
289.29 + assertExec("Can we call JavaScripts valueOf on Boolean?",
289.30 + Numbers.class, "bseven__ZI",
289.31 + false, 30
289.32 + );
289.33 + }
289.34
289.35 private static TestVM code;
289.36
289.37 @BeforeClass
289.38 - public void compileTheCode() throws Exception {
289.39 + public static void compileTheCode() throws Exception {
289.40 code = TestVM.compileClass("org/apidesign/vm4brwsr/Numbers");
289.41 }
289.42 + @AfterClass
289.43 + public static void releaseTheCode() {
289.44 + code = null;
289.45 + }
289.46
289.47 private static void assertExec(
289.48 String msg, Class<?> clazz, String method, Object expRes, Object... args) throws Exception
290.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Wed Feb 27 17:50:47 2013 +0100
290.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Mon Oct 07 14:20:58 2013 +0200
290.3 @@ -78,13 +78,26 @@
290.4 case 4: return sevenNew().byteValue();
290.5 case 8: return valueOf(Double.valueOf(7.0));
290.6 case 9: return valueOf(Long.valueOf(Long.MAX_VALUE / 5));
290.7 + case 30: return valueOf(Boolean.FALSE);
290.8 + case 31: return valueOf(Boolean.TRUE);
290.9 + case 65: return valueOf(Character.valueOf('A'));
290.10 + default: throw new IllegalStateException();
290.11 + }
290.12 + }
290.13 + static boolean bseven(int todo) {
290.14 + switch (todo) {
290.15 + case 30: return bvalueOf(Boolean.FALSE);
290.16 + case 31: return bvalueOf(Boolean.TRUE);
290.17 default: throw new IllegalStateException();
290.18 }
290.19 }
290.20
290.21 @JavaScriptBody(args = {}, body = "return 7;")
290.22 private static native Number sevenNew();
290.23 +
290.24 + @JavaScriptBody(args = { "o" }, body = "return o.valueOf();")
290.25 + private static native double valueOf(Object o);
290.26
290.27 @JavaScriptBody(args = { "o" }, body = "return o.valueOf();")
290.28 - private static native double valueOf(Object o);
290.29 + private static native boolean bvalueOf(Object o);
290.30 }
291.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Wed Feb 27 17:50:47 2013 +0100
291.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Mon Oct 07 14:20:58 2013 +0200
291.3 @@ -18,6 +18,7 @@
291.4 package org.apidesign.vm4brwsr;
291.5
291.6 import static org.testng.Assert.*;
291.7 +import org.testng.annotations.AfterClass;
291.8 import org.testng.annotations.BeforeClass;
291.9 import org.testng.annotations.Test;
291.10
291.11 @@ -324,10 +325,14 @@
291.12 private static TestVM code;
291.13
291.14 @BeforeClass
291.15 - public void compileTheCode() throws Exception {
291.16 + public static void compileTheCode() throws Exception {
291.17 StringBuilder sb = new StringBuilder();
291.18 code = TestVM.compileClass(sb, "org/apidesign/vm4brwsr/StaticMethod");
291.19 }
291.20 + @AfterClass
291.21 + public static void releaseTheCode() {
291.22 + code = null;
291.23 + }
291.24
291.25 private void assertExec(
291.26 String msg, Class<?> clazz, String method,
292.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
292.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticUseSub.java Mon Oct 07 14:20:58 2013 +0200
292.3 @@ -0,0 +1,24 @@
292.4 +/**
292.5 + * Back 2 Browser Bytecode Translator
292.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
292.7 + *
292.8 + * This program is free software: you can redistribute it and/or modify
292.9 + * it under the terms of the GNU General Public License as published by
292.10 + * the Free Software Foundation, version 2 of the License.
292.11 + *
292.12 + * This program is distributed in the hope that it will be useful,
292.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
292.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
292.15 + * GNU General Public License for more details.
292.16 + *
292.17 + * You should have received a copy of the GNU General Public License
292.18 + * along with this program. Look for COPYING file in the top folder.
292.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
292.20 + */
292.21 +package org.apidesign.vm4brwsr;
292.22 +
292.23 +public class StaticUseSub extends StaticUse {
292.24 + public static String getNonNull() {
292.25 + return NON_NULL.getClass().getName();
292.26 + }
292.27 +}
293.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
293.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticUseSubTest.java Mon Oct 07 14:20:58 2013 +0200
293.3 @@ -0,0 +1,48 @@
293.4 +/**
293.5 + * Back 2 Browser Bytecode Translator
293.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
293.7 + *
293.8 + * This program is free software: you can redistribute it and/or modify
293.9 + * it under the terms of the GNU General Public License as published by
293.10 + * the Free Software Foundation, version 2 of the License.
293.11 + *
293.12 + * This program is distributed in the hope that it will be useful,
293.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
293.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
293.15 + * GNU General Public License for more details.
293.16 + *
293.17 + * You should have received a copy of the GNU General Public License
293.18 + * along with this program. Look for COPYING file in the top folder.
293.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
293.20 + */
293.21 +package org.apidesign.vm4brwsr;
293.22 +
293.23 +import org.testng.annotations.AfterClass;
293.24 +import org.testng.annotations.BeforeClass;
293.25 +import org.testng.annotations.Test;
293.26 +
293.27 +/**
293.28 + *
293.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
293.30 + */
293.31 +public class StaticUseSubTest {
293.32 + private static TestVM code;
293.33 +
293.34 + @BeforeClass
293.35 + public static void compileTheCode() throws Exception {
293.36 + StringBuilder sb = new StringBuilder();
293.37 + code = TestVM.compileClass(sb, "org/apidesign/vm4brwsr/StaticUseSub");
293.38 + }
293.39 + @AfterClass
293.40 + public static void releaseTheCode() {
293.41 + code = null;
293.42 + }
293.43 +
293.44 + @Test public void getInheritedStaticField() throws Exception {
293.45 + code.assertExec(
293.46 + "Obtains non-null", StaticUseSub.class,
293.47 + "getNonNull__Ljava_lang_String_2",
293.48 + "java.lang.Object"
293.49 + );
293.50 + }
293.51 +}
294.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Wed Feb 27 17:50:47 2013 +0100
294.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Mon Oct 07 14:20:58 2013 +0200
294.3 @@ -18,6 +18,7 @@
294.4 package org.apidesign.vm4brwsr;
294.5
294.6 import java.io.UnsupportedEncodingException;
294.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
294.8
294.9 /**
294.10 *
294.11 @@ -129,4 +130,20 @@
294.12 public String toString() {
294.13 return HELLO + cnt;
294.14 }
294.15 +
294.16 + @JavaScriptBody(args = {}, body = "return [1, 2];")
294.17 + private static native Object crtarr();
294.18 + @JavaScriptBody(args = { "o" }, body = "return o.toString();")
294.19 + private static native String toStrng(Object o);
294.20 +
294.21 + public static String toStringArray(boolean fakeArr, boolean toString) {
294.22 + final Object arr = fakeArr ? crtarr() : new Object[2];
294.23 + final String whole = toString ? arr.toString() : toStrng(arr);
294.24 + int zav = whole.indexOf('@');
294.25 + if (zav <= 0) {
294.26 + zav = whole.length();
294.27 + }
294.28 + return whole.substring(0, zav).toString().toString();
294.29 + }
294.30 +
294.31 }
295.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Wed Feb 27 17:50:47 2013 +0100
295.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Mon Oct 07 14:20:58 2013 +0200
295.3 @@ -19,6 +19,7 @@
295.4
295.5 import org.testng.annotations.Test;
295.6 import static org.testng.Assert.*;
295.7 +import org.testng.annotations.AfterClass;
295.8 import org.testng.annotations.BeforeClass;
295.9
295.10 /**
295.11 @@ -193,15 +194,47 @@
295.12
295.13 }
295.14
295.15 + @Test public void toStringOnJSArray() throws Exception {
295.16 + String exp = StringSample.toStringArray(false, true);
295.17 +
295.18 + assertExec(
295.19 + "Treated as Java Object array",
295.20 + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ",
295.21 + exp, true, true
295.22 + );
295.23 + }
295.24 +
295.25 + @Test public void toStringOnRealArray() throws Exception {
295.26 + String exp = StringSample.toStringArray(false, true);
295.27 +
295.28 + assertExec(
295.29 + "Is Java Object array",
295.30 + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ",
295.31 + exp, false, true
295.32 + );
295.33 + }
295.34 +
295.35 + @Test public void valueOfOnJSArray() throws Exception {
295.36 + assertExec(
295.37 + "Treated as classical JavaScript array",
295.38 + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ",
295.39 + "1,2", true, false
295.40 + );
295.41 + }
295.42 +
295.43 private static TestVM code;
295.44
295.45 @BeforeClass
295.46 - public void compileTheCode() throws Exception {
295.47 + public static void compileTheCode() throws Exception {
295.48 code = TestVM.compileClass(
295.49 "org/apidesign/vm4brwsr/StringSample",
295.50 "java/lang/String"
295.51 );
295.52 }
295.53 + @AfterClass
295.54 + public static void releaseTheCode() {
295.55 + code = null;
295.56 + }
295.57
295.58 private static void assertExec(String msg,
295.59 Class<?> clazz, String method, Object expRes, Object... args
296.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/SystemTest.java Wed Feb 27 17:50:47 2013 +0100
296.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SystemTest.java Mon Oct 07 14:20:58 2013 +0200
296.3 @@ -19,6 +19,7 @@
296.4
296.5 import org.testng.annotations.BeforeClass;
296.6 import static org.testng.Assert.*;
296.7 +import org.testng.annotations.AfterClass;
296.8 import org.testng.annotations.Test;
296.9
296.10 /**
296.11 @@ -51,6 +52,10 @@
296.12 code = TestVM.compileClass(
296.13 "org/apidesign/bck2brwsr/emul/lang/System");
296.14 }
296.15 + @AfterClass
296.16 + public static void releaseTheCode() {
296.17 + code = null;
296.18 + }
296.19
296.20 }
296.21
297.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Wed Feb 27 17:50:47 2013 +0100
297.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Mon Oct 07 14:20:58 2013 +0200
297.3 @@ -51,7 +51,7 @@
297.4 ret = code.invokeMethod(bck2brwsr, "loadClass", clazz.getName());
297.5 ret = code.invokeMethod(ret, method, args);
297.6 } catch (ScriptException ex) {
297.7 - fail("Execution failed in " + dumpJS(codeSeq), ex);
297.8 + fail("Execution failed in " + dumpJS(codeSeq) + ": " + ex.getMessage(), ex);
297.9 } catch (NoSuchMethodException ex) {
297.10 fail("Cannot find method in " + dumpJS(codeSeq), ex);
297.11 }
297.12 @@ -68,9 +68,9 @@
297.13 ret = code.invokeMethod(ret, "toFP");
297.14 ret = code.invokeFunction("Number", ret);
297.15 } catch (ScriptException ex) {
297.16 - fail("Conversion to number failed in " + dumpJS(codeSeq), ex);
297.17 + fail("Conversion to number failed in " + dumpJS(codeSeq) + ": " + ex.getMessage(), ex);
297.18 } catch (NoSuchMethodException ex) {
297.19 - fail("Cannot find global Number(x) function in " + dumpJS(codeSeq), ex);
297.20 + fail("Cannot find global Number(x) function in " + dumpJS(codeSeq) + ": " + ex.getMessage(), ex);
297.21 }
297.22 }
297.23 return ret;
297.24 @@ -115,7 +115,7 @@
297.25 if (sb.length() > 2000) {
297.26 sb = dumpJS(sb);
297.27 }
297.28 - fail("Could not evaluate:\n" + sb, ex);
297.29 + fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex);
297.30 return null;
297.31 }
297.32 }
298.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Wed Feb 27 17:50:47 2013 +0100
298.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Mon Oct 07 14:20:58 2013 +0200
298.3 @@ -22,6 +22,7 @@
298.4 import javax.script.ScriptException;
298.5 import org.testng.annotations.BeforeClass;
298.6 import static org.testng.Assert.*;
298.7 +import org.testng.annotations.AfterClass;
298.8 import org.testng.annotations.Test;
298.9
298.10 /** Implements loading class by class.
298.11 @@ -32,7 +33,7 @@
298.12 private static TestVM code;
298.13
298.14 @BeforeClass
298.15 - public void compileTheCode() throws Exception {
298.16 + public static void compileTheCode() throws Exception {
298.17 StringBuilder sb = new StringBuilder();
298.18 sb.append("\nvar data = {};");
298.19 sb.append("\nfunction test(clazz, method) {");
298.20 @@ -51,6 +52,10 @@
298.21 );
298.22 arr[0].getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
298.23 }
298.24 + @AfterClass
298.25 + public static void releaseTheCode() {
298.26 + code = null;
298.27 + }
298.28
298.29 @Test public void invokeStaticMethod() throws Exception {
298.30 assertExec("Trying to get -1", "test", Double.valueOf(-1),
299.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java Wed Feb 27 17:50:47 2013 +0100
299.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java Mon Oct 07 14:20:58 2013 +0200
299.3 @@ -43,4 +43,9 @@
299.4 @Override
299.5 protected void requireScript(String resourcePath) {
299.6 }
299.7 +
299.8 + @Override
299.9 + String getVMObject() {
299.10 + return "global";
299.11 + }
299.12 }
300.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Wed Feb 27 17:50:47 2013 +0100
300.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Mon Oct 07 14:20:58 2013 +0200
300.3 @@ -21,6 +21,7 @@
300.4 import java.io.FileWriter;
300.5 import java.io.IOException;
300.6 import static org.testng.Assert.*;
300.7 +import org.testng.annotations.AfterClass;
300.8 import org.testng.annotations.BeforeClass;
300.9 import org.testng.annotations.Test;
300.10
300.11 @@ -39,12 +40,24 @@
300.12 compareCode("org/apidesign/vm4brwsr/Classes.class");
300.13 }
300.14
300.15 + @Test public void compareGeneratedCodeForToolkitClass() throws Exception {
300.16 + String genCode = compareCode("org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class");
300.17 + int indx = genCode.indexOf("gt = 65604");
300.18 + if (indx >= 0) {
300.19 + fail("Goto to an invalid label:\n...." + genCode.substring(indx - 30, indx + 30) + "....");
300.20 + }
300.21 + }
300.22 +
300.23 @BeforeClass
300.24 - public void compileTheCode() throws Exception {
300.25 + public static void compileTheCode() throws Exception {
300.26 code = TestVM.compileClass("org/apidesign/vm4brwsr/VMinVM");
300.27 }
300.28 + @AfterClass
300.29 + public static void releaseTheCode() {
300.30 + code = null;
300.31 + }
300.32
300.33 - private void compareCode(final String nm) throws Exception, IOException {
300.34 + private String compareCode(final String nm) throws Exception, IOException {
300.35 byte[] arr = BytesLoader.readClass(nm);
300.36 String ret1 = VMinVM.toJavaScript(arr);
300.37
300.38 @@ -83,5 +96,7 @@
300.39 msg.append(code.toString());
300.40 fail(msg.toString());
300.41 }
300.42 +
300.43 + return ret1;
300.44 }
300.45 }
301.1 Binary file rt/vm/src/test/resources/org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class has changed
302.1 --- a/rt/vmtest/pom.xml Wed Feb 27 17:50:47 2013 +0100
302.2 +++ b/rt/vmtest/pom.xml Mon Oct 07 14:20:58 2013 +0200
302.3 @@ -1,15 +1,14 @@
302.4 <?xml version="1.0"?>
302.5 -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
302.6 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
302.7 +<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/xsd/maven-4.0.0.xsd">
302.8 <modelVersion>4.0.0</modelVersion>
302.9 <parent>
302.10 <groupId>org.apidesign.bck2brwsr</groupId>
302.11 <artifactId>rt</artifactId>
302.12 - <version>0.3-SNAPSHOT</version>
302.13 + <version>0.9-SNAPSHOT</version>
302.14 </parent>
302.15 <groupId>org.apidesign.bck2brwsr</groupId>
302.16 <artifactId>vmtest</artifactId>
302.17 - <version>0.3-SNAPSHOT</version>
302.18 + <version>0.9-SNAPSHOT</version>
302.19
302.20 <name>VM Testing APIs</name>
302.21 <url>http://bck2brwsr.apidesign.org</url>
302.22 @@ -24,6 +23,14 @@
302.23 <target>1.7</target>
302.24 </configuration>
302.25 </plugin>
302.26 + <plugin>
302.27 + <groupId>org.apache.maven.plugins</groupId>
302.28 + <artifactId>maven-javadoc-plugin</artifactId>
302.29 + <configuration>
302.30 + <excludePackageNames>org.apidesign.bck2brwsr.vmtest.impl</excludePackageNames>
302.31 + <skip>false</skip>
302.32 + </configuration>
302.33 + </plugin>
302.34 </plugins>
302.35 </build>
302.36 <properties>
302.37 @@ -43,18 +50,6 @@
302.38 </dependency>
302.39 <dependency>
302.40 <groupId>${project.groupId}</groupId>
302.41 - <artifactId>vm4brwsr</artifactId>
302.42 - <version>${project.version}</version>
302.43 - <type>jar</type>
302.44 - </dependency>
302.45 - <dependency>
302.46 - <groupId>${project.groupId}</groupId>
302.47 - <artifactId>emul.mini</artifactId>
302.48 - <version>${project.version}</version>
302.49 - <scope>test</scope>
302.50 - </dependency>
302.51 - <dependency>
302.52 - <groupId>${project.groupId}</groupId>
302.53 <artifactId>launcher</artifactId>
302.54 <version>${project.version}</version>
302.55 </dependency>
303.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Wed Feb 27 17:50:47 2013 +0100
303.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Mon Oct 07 14:20:58 2013 +0200
303.3 @@ -29,6 +29,10 @@
303.4 * The browser to is by default executed via {@link java.awt.Desktop#browse(java.net.URI)},
303.5 * but one can change that by specifying <code>-Dvmtest.brwsrs=firefox,google-chrome</code>
303.6 * property.
303.7 + * <p>
303.8 + * If the annotated method throws {@link InterruptedException}, it will return
303.9 + * the processing to the browser and after 100ms, called again. This is useful
303.10 + * for testing asynchronous communication, etc.
303.11 *
303.12 * @author Jaroslav Tulach <jtulach@netbeans.org>
303.13 */
304.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Http.java Wed Feb 27 17:50:47 2013 +0100
304.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Http.java Mon Oct 07 14:20:58 2013 +0200
304.3 @@ -23,8 +23,7 @@
304.4 import java.lang.annotation.Target;
304.5
304.6 /**
304.7 - * Exposes HTTP page or pages to the running {@link BrwsrTest}, so it can access under
304.8 - * the relative path.
304.9 + * Exposes an {@link Resource HTTP page} or a set of {@link #value() pages} to the running {@link BrwsrTest}.
304.10 *
304.11 * @author Jaroslav Tulach <jtulach@netbeans.org>
304.12 */
304.13 @@ -34,8 +33,10 @@
304.14 /** Set of pages to make available */
304.15 public Resource[] value();
304.16
304.17 - /** Exposes an HTTP page to the running {@link BrwsrTest}, so it can access
304.18 - * under the relative path.
304.19 + /** Describes single HTTP page to the running {@link BrwsrTest}, so it can be
304.20 + * accessed under the specified {@link #path() relative path}. The page
304.21 + * content can either be specified inline via {@link #content()} or as
304.22 + * an external {@link #resource() resource}.
304.23 *
304.24 * @author Jaroslav Tulach <jtulach@netbeans.org>
304.25 */
304.26 @@ -44,7 +45,7 @@
304.27 public @interface Resource {
304.28 /** path on the server that the test can use to access the exposed resource */
304.29 String path();
304.30 - /** the content of the HttpResource */
304.31 + /** the content of the <code>Http.Resource</code> */
304.32 String content();
304.33 /** resource relative to the class that should be used instead of <code>content</code>.
304.34 * Leave content equal to empty string.
304.35 @@ -52,5 +53,10 @@
304.36 String resource() default "";
304.37 /** mime type of the resource */
304.38 String mimeType();
304.39 + /** query parameters. Can be referenced from the {@link #content} as
304.40 + * <code>$0</code>, <code>$1</code>, etc. The values will be extracted
304.41 + * from URL parameters of the request.
304.42 + */
304.43 + String[] parameters() default {};
304.44 }
304.45 }
305.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Wed Feb 27 17:50:47 2013 +0100
305.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Mon Oct 07 14:20:58 2013 +0200
305.3 @@ -17,27 +17,123 @@
305.4 */
305.5 package org.apidesign.bck2brwsr.vmtest;
305.6
305.7 +import java.lang.annotation.Annotation;
305.8 +import java.util.ArrayList;
305.9 +import java.util.Arrays;
305.10 +import java.util.List;
305.11 +import org.apidesign.bck2brwsr.launcher.Launcher;
305.12 import org.apidesign.bck2brwsr.vmtest.impl.CompareCase;
305.13 import org.testng.annotations.Factory;
305.14
305.15 -/** A TestNG {@link Factory} that seeks for {@link Compare} annotations
305.16 - * in provided class and builds set of tests that compare the computations
305.17 - * in real as well as JavaScript virtual machines. Use as:<pre>
305.18 +/** A TestNG {@link Factory} that seeks for {@link Compare} and {@link BrwsrTest} annotations
305.19 + * in provided class and builds set of tests that verify the functionality of <b>Bck2Brwsr</b>
305.20 + * based system. Use as:
305.21 + * <pre>
305.22 * {@code @}{@link Factory} public static create() {
305.23 - * return @{link VMTest}.{@link #create(YourClass.class);
305.24 + * return @{link VMTest}.{@link #create(java.lang.Class) create}(YourClass.class);
305.25 * }</pre>
305.26 - *
305.27 + * where <code>YourClass</code> contains methods annotated with
305.28 + * {@link Compare} and {@link BrwsrTest} annotations.
305.29 + *
305.30 * @author Jaroslav Tulach <jtulach@netbeans.org>
305.31 */
305.32 public final class VMTest {
305.33 - /** Inspects <code>clazz</code> and for each {@lik Compare} method creates
305.34 - * instances of tests. Each instance runs the test in different virtual
305.35 + private final List<Class> classes = new ArrayList<>();
305.36 + private final List<String> launcher = new ArrayList<>();
305.37 + private Class<? extends Annotation> annotation = BrwsrTest.class;
305.38 +
305.39 + private VMTest() {
305.40 + }
305.41 +
305.42 + /** Inspects <code>clazz</code> and for each method annotated by
305.43 + * {@link Compare} or {@link BrwsrTest} creates
305.44 + * instances of tests.
305.45 + * <p>
305.46 + * Each {@link Compare} instance runs the test in different virtual
305.47 * machine and at the end they compare the results.
305.48 + * <p>
305.49 + * Each {@link BrwsrTest} annotated method is executed once in {@link Launcher started
305.50 + * browser}.
305.51 *
305.52 - * @param clazz the class to inspect
305.53 + * @param clazz the class (or classes) to inspect
305.54 * @return the set of created tests
305.55 */
305.56 - public static Object[] create(Class<?> clazz) {
305.57 - return CompareCase.create(clazz);
305.58 + public static Object[] create(Class clazz) {
305.59 + return newTests().withClasses(clazz).build();
305.60 + }
305.61 +
305.62 + /** Creates new builder for test execution. Continue with methods
305.63 + * like {@link #withClasses(java.lang.Class[])} or {@link #withLaunchers(java.lang.String[])}.
305.64 + * Finish the process by calling {@link #build()}.
305.65 + *
305.66 + * @return new instance of a builder
305.67 + * @since 0.7
305.68 + */
305.69 + public static VMTest newTests() {
305.70 + return new VMTest();
305.71 + }
305.72 +
305.73 + /** Adds class (or classes) to the test execution. The classes are inspected
305.74 + * to contain methods annotated by
305.75 + * {@link Compare} or {@link BrwsrTest}. Appropriate set of TestNG test
305.76 + * cases is then created.
305.77 + * <p>
305.78 + * Each {@link Compare} instance runs the test in different virtual
305.79 + * machine and at the end they compare the results.
305.80 + * <p>
305.81 + * Each {@link BrwsrTest} annotated method is executed once in {@link Launcher started
305.82 + * browser}.
305.83 + *
305.84 + * @param classes one or more classes to inspect
305.85 + * @since 0.7
305.86 + */
305.87 + public final VMTest withClasses(Class... classes) {
305.88 + this.classes.addAll(Arrays.asList(classes));
305.89 + return this;
305.90 + }
305.91 +
305.92 + /** Adds list of launchers that should be used to execute tests defined
305.93 + * by {@link Compare} and {@link BrwsrTest} annotations. This value
305.94 + * can be overrided by using <code>vmtest.brwsrs</code> property.
305.95 + * List of supported launchers is available in the documentation of
305.96 + * {@link Launcher}.
305.97 + *
305.98 + * @param launcher names of one or more launchers to use for the execution
305.99 + * of tests
305.100 + * @since 0.7
305.101 + */
305.102 + public final VMTest withLaunchers(String... launcher) {
305.103 + this.launcher.addAll(Arrays.asList(launcher));
305.104 + return this;
305.105 + }
305.106 +
305.107 + /** Specifies which annotation annotates the test methods
305.108 + * to be executed. By
305.109 + * default it is the {@link BrwsrTest} annotation. Methods in
305.110 + * {@link #withClasses(java.lang.Class[]) test classes} annotated by
305.111 + * this annotation will be executed.
305.112 + *
305.113 + * @param aClass an annotation class
305.114 + * @return this
305.115 + * @since 0.8
305.116 + */
305.117 + public final VMTest withTestAnnotation(Class<? extends Annotation> aClass) {
305.118 + if (!aClass.isAnnotation()) {
305.119 + throw new IllegalStateException();
305.120 + }
305.121 + this.annotation = aClass;
305.122 + return this;
305.123 + }
305.124 +
305.125 + /** Assembles the provided information into the final array of tests.
305.126 + * @return array of TestNG tests
305.127 + * @since 0.7
305.128 + */
305.129 + public final Object[] build() {
305.130 + return CompareCase.create(
305.131 + launcher.toArray(new String[0]),
305.132 + classes.toArray(new Class[0]),
305.133 + annotation
305.134 + );
305.135 }
305.136 }
306.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Wed Feb 27 17:50:47 2013 +0100
306.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Mon Oct 07 14:20:58 2013 +0200
306.3 @@ -65,17 +65,17 @@
306.4 for (Http.Resource r : http) {
306.5 if (!r.content().isEmpty()) {
306.6 InputStream is = new ByteArrayInputStream(r.content().getBytes("UTF-8"));
306.7 - c.addHttpResource(r.path(), r.mimeType(), is);
306.8 + c.addHttpResource(r.path(), r.mimeType(), r.parameters(), is);
306.9 } else {
306.10 InputStream is = m.getDeclaringClass().getResourceAsStream(r.resource());
306.11 - c.addHttpResource(r.path(), r.mimeType(), is);
306.12 + c.addHttpResource(r.path(), r.mimeType(), r.parameters(), is);
306.13 }
306.14 }
306.15 }
306.16 String res = c.invoke();
306.17 value = res;
306.18 if (fail) {
306.19 - int idx = res.indexOf(':');
306.20 + int idx = res == null ? -1 : res.indexOf(':');
306.21 if (idx >= 0) {
306.22 Class<? extends Throwable> thrwbl = null;
306.23 try {
307.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Wed Feb 27 17:50:47 2013 +0100
307.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Mon Oct 07 14:20:58 2013 +0200
307.3 @@ -17,6 +17,7 @@
307.4 */
307.5 package org.apidesign.bck2brwsr.vmtest.impl;
307.6
307.7 +import java.lang.annotation.Annotation;
307.8 import org.apidesign.bck2brwsr.vmtest.*;
307.9 import java.lang.reflect.Method;
307.10 import java.util.ArrayList;
307.11 @@ -53,26 +54,25 @@
307.12 * @param clazz the class to inspect
307.13 * @return the set of created tests
307.14 */
307.15 - public static Object[] create(Class<?> clazz) {
307.16 - Method[] arr = clazz.getMethods();
307.17 + public static Object[] create(String[] brwsr, Class[] classes, Class<? extends Annotation> brwsrTest) {
307.18 List<Object> ret = new ArrayList<>();
307.19
307.20 final LaunchSetup l = LaunchSetup.INSTANCE;
307.21 ret.add(l);
307.22
307.23 - String[] brwsr;
307.24 {
307.25 String p = System.getProperty("vmtest.brwsrs");
307.26 if (p != null) {
307.27 brwsr = p.split(",");
307.28 - } else {
307.29 - brwsr = new String[0];
307.30 }
307.31 }
307.32
307.33 - for (Method m : arr) {
307.34 - registerCompareCases(m, l, ret, brwsr);
307.35 - registerBrwsrCases(m, l, ret, brwsr);
307.36 + for (Class clazz : classes) {
307.37 + Method[] arr = clazz.getMethods();
307.38 + for (Method m : arr) {
307.39 + registerCompareCases(m, l, ret, brwsr);
307.40 + registerBrwsrCases(brwsrTest, m, l, ret, brwsr);
307.41 + }
307.42 }
307.43 return ret.toArray();
307.44 }
307.45 @@ -83,10 +83,34 @@
307.46 @Test(dependsOnGroups = "run") public void compareResults() throws Throwable {
307.47 Object v1 = first.value;
307.48 Object v2 = second.value;
307.49 - if (v1 != null) {
307.50 - v1 = v1.toString();
307.51 + if (v1 instanceof Integer || v1 instanceof Long || v1 instanceof Byte || v1 instanceof Short) {
307.52 + try {
307.53 + v1 = Long.parseLong(v1.toString());
307.54 + } catch (NumberFormatException nfe) {
307.55 + v1 = "Can't parse " + v1.toString();
307.56 + }
307.57 + try {
307.58 + v2 = Long.parseLong(v2.toString());
307.59 + } catch (NumberFormatException nfe) {
307.60 + v2 = "Can't parse " + v2.toString();
307.61 + }
307.62 + } else if (v1 instanceof Number) {
307.63 + try {
307.64 + v1 = Double.parseDouble(v1.toString());
307.65 + } catch (NumberFormatException nfe) {
307.66 + v1 = "Can't parse " + v1.toString();
307.67 + }
307.68 + try {
307.69 + v2 = Double.parseDouble(v2.toString());
307.70 + } catch (NumberFormatException nfe) {
307.71 + v2 = "Can't parse " + v2.toString();
307.72 + }
307.73 } else {
307.74 - v1 = "null";
307.75 + if (v1 != null) {
307.76 + v1 = v1.toString();
307.77 + } else {
307.78 + v1 = "null";
307.79 + }
307.80 }
307.81 try {
307.82 Assert.assertEquals(v2, v1, "Comparing results");
307.83 @@ -126,8 +150,8 @@
307.84 ret.add(new CompareCase(m, real, cse));
307.85 }
307.86 }
307.87 - private static void registerBrwsrCases(Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
307.88 - BrwsrTest c = m.getAnnotation(BrwsrTest.class);
307.89 + private static void registerBrwsrCases(Class<? extends Annotation> brwsrTest, Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
307.90 + Object c = m.getAnnotation(brwsrTest);
307.91 if (c == null) {
307.92 return;
307.93 }
308.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/LaunchSetup.java Wed Feb 27 17:50:47 2013 +0100
308.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/LaunchSetup.java Mon Oct 07 14:20:58 2013 +0200
308.3 @@ -42,7 +42,14 @@
308.4 }
308.5 private synchronized Launcher js(boolean create) {
308.6 if (js == null && create) {
308.7 - js = Launcher.createJavaScript();
308.8 + final String p = System.getProperty("vmtest.js", "script"); // NOI18N
308.9 + switch (p) {
308.10 + case "brwsr": js = Launcher.createBrowser(null); break; // NOI18N
308.11 + case "script": js = Launcher.createJavaScript(); break; // NOI18N
308.12 + default: throw new IllegalArgumentException(
308.13 + "Unknown value of vmtest.js property: " + p
308.14 + );
308.15 + }
308.16 }
308.17 return js;
308.18 }
309.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Wed Feb 27 17:50:47 2013 +0100
309.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
309.3 @@ -1,43 +0,0 @@
309.4 -/**
309.5 - * Back 2 Browser Bytecode Translator
309.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
309.7 - *
309.8 - * This program is free software: you can redistribute it and/or modify
309.9 - * it under the terms of the GNU General Public License as published by
309.10 - * the Free Software Foundation, version 2 of the License.
309.11 - *
309.12 - * This program is distributed in the hope that it will be useful,
309.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
309.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
309.15 - * GNU General Public License for more details.
309.16 - *
309.17 - * You should have received a copy of the GNU General Public License
309.18 - * along with this program. Look for COPYING file in the top folder.
309.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
309.20 - */
309.21 -package org.apidesign.bck2brwsr.tck;
309.22 -
309.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
309.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
309.25 -import org.testng.annotations.Factory;
309.26 -
309.27 -/**
309.28 - *
309.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
309.30 - */
309.31 -public class AssertionTest {
309.32 -
309.33 - @Compare public Object checkAssert() throws ClassNotFoundException {
309.34 - try {
309.35 - assert false : "Is assertion status on?";
309.36 - return null;
309.37 - } catch (AssertionError ex) {
309.38 - return ex.getClass().getName();
309.39 - }
309.40 - }
309.41 -
309.42 - @Factory
309.43 - public static Object[] create() {
309.44 - return VMTest.create(AssertionTest.class);
309.45 - }
309.46 -}
310.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Wed Feb 27 17:50:47 2013 +0100
310.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
310.3 @@ -1,57 +0,0 @@
310.4 -/**
310.5 - * Back 2 Browser Bytecode Translator
310.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
310.7 - *
310.8 - * This program is free software: you can redistribute it and/or modify
310.9 - * it under the terms of the GNU General Public License as published by
310.10 - * the Free Software Foundation, version 2 of the License.
310.11 - *
310.12 - * This program is distributed in the hope that it will be useful,
310.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
310.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
310.15 - * GNU General Public License for more details.
310.16 - *
310.17 - * You should have received a copy of the GNU General Public License
310.18 - * along with this program. Look for COPYING file in the top folder.
310.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
310.20 - */
310.21 -package org.apidesign.bck2brwsr.tck;
310.22 -
310.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
310.24 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
310.25 -import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
310.26 -import org.apidesign.bck2brwsr.vmtest.VMTest;
310.27 -import org.testng.annotations.Factory;
310.28 -
310.29 -/**
310.30 - *
310.31 - * @author Jaroslav Tulach <jtulach@netbeans.org>
310.32 - */
310.33 -public class BrwsrCheckTest {
310.34 -
310.35 - @BrwsrTest public void assertWindowObjectIsDefined() {
310.36 - assert window() != null : "No window object found!";
310.37 - }
310.38 -
310.39 -
310.40 -
310.41 -
310.42 - @HtmlFragment("<h1 id='hello'>\n"
310.43 - + "Hello!\n"
310.44 - + "</h1>\n")
310.45 - @BrwsrTest public void accessProvidedFragment() {
310.46 - assert getElementById("hello") != null : "Element with 'hello' ID found";
310.47 - }
310.48 -
310.49 - @Factory
310.50 - public static Object[] create() {
310.51 - return VMTest.create(BrwsrCheckTest.class);
310.52 - }
310.53 -
310.54 -
310.55 - @JavaScriptBody(args = {}, body = "return window;")
310.56 - private static native Object window();
310.57 -
310.58 - @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);")
310.59 - private static native Object getElementById(String id);
310.60 -}
311.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Wed Feb 27 17:50:47 2013 +0100
311.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
311.3 @@ -1,102 +0,0 @@
311.4 -/**
311.5 - * Back 2 Browser Bytecode Translator
311.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
311.7 - *
311.8 - * This program is free software: you can redistribute it and/or modify
311.9 - * it under the terms of the GNU General Public License as published by
311.10 - * the Free Software Foundation, version 2 of the License.
311.11 - *
311.12 - * This program is distributed in the hope that it will be useful,
311.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
311.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
311.15 - * GNU General Public License for more details.
311.16 - *
311.17 - * You should have received a copy of the GNU General Public License
311.18 - * along with this program. Look for COPYING file in the top folder.
311.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
311.20 - */
311.21 -package org.apidesign.bck2brwsr.tck;
311.22 -
311.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
311.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
311.25 -import org.testng.annotations.Factory;
311.26 -
311.27 -/**
311.28 - *
311.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
311.30 - */
311.31 -public class ByteArithmeticTest {
311.32 -
311.33 - private static byte add(byte x, byte y) {
311.34 - return (byte)(x + y);
311.35 - }
311.36 -
311.37 - private static byte sub(byte x, byte y) {
311.38 - return (byte)(x - y);
311.39 - }
311.40 -
311.41 - private static byte mul(byte x, byte y) {
311.42 - return (byte)(x * y);
311.43 - }
311.44 -
311.45 - private static byte div(byte x, byte y) {
311.46 - return (byte)(x / y);
311.47 - }
311.48 -
311.49 - private static byte mod(byte x, byte y) {
311.50 - return (byte)(x % y);
311.51 - }
311.52 -
311.53 - @Compare public byte conversion() {
311.54 - return (byte)123456;
311.55 - }
311.56 -
311.57 - @Compare public byte addOverflow() {
311.58 - return add(Byte.MAX_VALUE, (byte)1);
311.59 - }
311.60 -
311.61 - @Compare public byte subUnderflow() {
311.62 - return sub(Byte.MIN_VALUE, (byte)1);
311.63 - }
311.64 -
311.65 - @Compare public byte addMaxByteAndMaxByte() {
311.66 - return add(Byte.MAX_VALUE, Byte.MAX_VALUE);
311.67 - }
311.68 -
311.69 - @Compare public byte subMinByteAndMinByte() {
311.70 - return sub(Byte.MIN_VALUE, Byte.MIN_VALUE);
311.71 - }
311.72 -
311.73 - @Compare public byte multiplyMaxByte() {
311.74 - return mul(Byte.MAX_VALUE, (byte)2);
311.75 - }
311.76 -
311.77 - @Compare public byte multiplyMaxByteAndMaxByte() {
311.78 - return mul(Byte.MAX_VALUE, Byte.MAX_VALUE);
311.79 - }
311.80 -
311.81 - @Compare public byte multiplyMinByte() {
311.82 - return mul(Byte.MIN_VALUE, (byte)2);
311.83 - }
311.84 -
311.85 - @Compare public byte multiplyMinByteAndMinByte() {
311.86 - return mul(Byte.MIN_VALUE, Byte.MIN_VALUE);
311.87 - }
311.88 -
311.89 - @Compare public byte multiplyPrecision() {
311.90 - return mul((byte)17638, (byte)1103);
311.91 - }
311.92 -
311.93 - @Compare public byte division() {
311.94 - return div((byte)1, (byte)2);
311.95 - }
311.96 -
311.97 - @Compare public byte divisionReminder() {
311.98 - return mod((byte)1, (byte)2);
311.99 - }
311.100 -
311.101 - @Factory
311.102 - public static Object[] create() {
311.103 - return VMTest.create(ByteArithmeticTest.class);
311.104 - }
311.105 -}
312.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java Wed Feb 27 17:50:47 2013 +0100
312.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
312.3 @@ -1,73 +0,0 @@
312.4 -/**
312.5 - * Back 2 Browser Bytecode Translator
312.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
312.7 - *
312.8 - * This program is free software: you can redistribute it and/or modify
312.9 - * it under the terms of the GNU General Public License as published by
312.10 - * the Free Software Foundation, version 2 of the License.
312.11 - *
312.12 - * This program is distributed in the hope that it will be useful,
312.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
312.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
312.15 - * GNU General Public License for more details.
312.16 - *
312.17 - * You should have received a copy of the GNU General Public License
312.18 - * along with this program. Look for COPYING file in the top folder.
312.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
312.20 - */
312.21 -package org.apidesign.bck2brwsr.tck;
312.22 -
312.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
312.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
312.25 -import org.testng.annotations.Factory;
312.26 -
312.27 -/**
312.28 - *
312.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
312.30 - */
312.31 -public class CloneTest {
312.32 - private int value;
312.33 -
312.34 - @Compare
312.35 - public Object notSupported() throws CloneNotSupportedException {
312.36 - return this.clone();
312.37 - }
312.38 -
312.39 - @Compare public String sameClass() throws CloneNotSupportedException {
312.40 - return new Clnbl().clone().getClass().getName();
312.41 - }
312.42 -
312.43 - @Compare public boolean differentInstance() throws CloneNotSupportedException {
312.44 - Clnbl orig = new Clnbl();
312.45 - return orig == orig.clone();
312.46 - }
312.47 -
312.48 - @Compare public int sameReference() throws CloneNotSupportedException {
312.49 - CloneTest self = this;
312.50 - Clnbl orig = new Clnbl();
312.51 - self.value = 33;
312.52 - orig.ref = self;
312.53 - return ((Clnbl)orig.clone()).ref.value;
312.54 - }
312.55 -
312.56 - @Compare public int sameValue() throws CloneNotSupportedException {
312.57 - Clnbl orig = new Clnbl();
312.58 - orig.value = 10;
312.59 - return ((Clnbl)orig.clone()).value;
312.60 - }
312.61 -
312.62 - @Factory
312.63 - public static Object[] create() {
312.64 - return VMTest.create(CloneTest.class);
312.65 - }
312.66 -
312.67 - public static final class Clnbl implements Cloneable {
312.68 - public CloneTest ref;
312.69 - private int value;
312.70 -
312.71 - @Override
312.72 - public Object clone() throws CloneNotSupportedException {
312.73 - return super.clone();
312.74 - }
312.75 - }
312.76 -}
313.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Wed Feb 27 17:50:47 2013 +0100
313.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
313.3 @@ -1,93 +0,0 @@
313.4 -/**
313.5 - * Back 2 Browser Bytecode Translator
313.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
313.7 - *
313.8 - * This program is free software: you can redistribute it and/or modify
313.9 - * it under the terms of the GNU General Public License as published by
313.10 - * the Free Software Foundation, version 2 of the License.
313.11 - *
313.12 - * This program is distributed in the hope that it will be useful,
313.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
313.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
313.15 - * GNU General Public License for more details.
313.16 - *
313.17 - * You should have received a copy of the GNU General Public License
313.18 - * along with this program. Look for COPYING file in the top folder.
313.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
313.20 - */
313.21 -package org.apidesign.bck2brwsr.tck;
313.22 -
313.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
313.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
313.25 -import org.testng.annotations.Factory;
313.26 -
313.27 -/**
313.28 - *
313.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
313.30 - */
313.31 -public class CompareByteArrayTest {
313.32 - @Compare public int byteArraySum() {
313.33 - byte[] arr = createArray();
313.34 - return sumByteArr(arr);
313.35 - }
313.36 -
313.37 - @Compare public int countZeros() {
313.38 - int zeros = 0;
313.39 - for (Byte b : createArray()) {
313.40 - if (b == 0) {
313.41 - zeros++;
313.42 - }
313.43 - }
313.44 - return zeros;
313.45 - }
313.46 -
313.47 - private static int sumByteArr(byte[] arr) {
313.48 - int sum = 0;
313.49 - for (int i = 0; i < arr.length; i++) {
313.50 - sum += arr[i];
313.51 - }
313.52 - return sum;
313.53 - }
313.54 -
313.55 - @Compare public String noOutOfBounds() {
313.56 - return atIndex(1);
313.57 - }
313.58 -
313.59 - @Compare public String outOfBounds() {
313.60 - return atIndex(5);
313.61 - }
313.62 -
313.63 - @Compare public String outOfBoundsMinus() {
313.64 - return atIndex(-1);
313.65 - }
313.66 -
313.67 - @Compare public String toOfBounds() {
313.68 - return toIndex(5);
313.69 - }
313.70 -
313.71 - @Compare public String toOfBoundsMinus() {
313.72 - return toIndex(-1);
313.73 - }
313.74 -
313.75 - private static final int[] arr = { 0, 1, 2 };
313.76 - public static String atIndex(int at) {
313.77 - return "at@" + arr[at];
313.78 - }
313.79 - public static String toIndex(int at) {
313.80 - arr[at] = 10;
313.81 - return "ok";
313.82 - }
313.83 -
313.84 -
313.85 - @Factory
313.86 - public static Object[] create() {
313.87 - return VMTest.create(CompareByteArrayTest.class);
313.88 - }
313.89 -
313.90 - private byte[] createArray() {
313.91 - byte[] arr = new byte[10];
313.92 - arr[5] = 3;
313.93 - arr[7] = 8;
313.94 - return arr;
313.95 - }
313.96 -}
314.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Wed Feb 27 17:50:47 2013 +0100
314.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
314.3 @@ -1,50 +0,0 @@
314.4 -/**
314.5 - * Back 2 Browser Bytecode Translator
314.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
314.7 - *
314.8 - * This program is free software: you can redistribute it and/or modify
314.9 - * it under the terms of the GNU General Public License as published by
314.10 - * the Free Software Foundation, version 2 of the License.
314.11 - *
314.12 - * This program is distributed in the hope that it will be useful,
314.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
314.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314.15 - * GNU General Public License for more details.
314.16 - *
314.17 - * You should have received a copy of the GNU General Public License
314.18 - * along with this program. Look for COPYING file in the top folder.
314.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
314.20 - */
314.21 -package org.apidesign.bck2brwsr.tck;
314.22 -
314.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
314.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
314.25 -import org.testng.annotations.Factory;
314.26 -
314.27 -/**
314.28 - *
314.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
314.30 - */
314.31 -public class CompareHashTest {
314.32 - @Compare public int hashOfString() {
314.33 - return "Ahoj".hashCode();
314.34 - }
314.35 -
314.36 - @Compare public int hashRemainsYieldsZero() {
314.37 - Object o = new Object();
314.38 - return o.hashCode() - o.hashCode();
314.39 - }
314.40 -
314.41 - @Compare public int initializeInStatic() {
314.42 - return StaticUse.NON_NULL.hashCode() - StaticUse.NON_NULL.hashCode();
314.43 - }
314.44 -
314.45 - @Compare public int hashOfInt() {
314.46 - return Integer.valueOf(Integer.MAX_VALUE).hashCode();
314.47 - }
314.48 -
314.49 - @Factory
314.50 - public static Object[] create() {
314.51 - return VMTest.create(CompareHashTest.class);
314.52 - }
314.53 -}
315.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java Wed Feb 27 17:50:47 2013 +0100
315.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
315.3 @@ -1,63 +0,0 @@
315.4 -/**
315.5 - * Back 2 Browser Bytecode Translator
315.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
315.7 - *
315.8 - * This program is free software: you can redistribute it and/or modify
315.9 - * it under the terms of the GNU General Public License as published by
315.10 - * the Free Software Foundation, version 2 of the License.
315.11 - *
315.12 - * This program is distributed in the hope that it will be useful,
315.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
315.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
315.15 - * GNU General Public License for more details.
315.16 - *
315.17 - * You should have received a copy of the GNU General Public License
315.18 - * along with this program. Look for COPYING file in the top folder.
315.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
315.20 - */
315.21 -package org.apidesign.bck2brwsr.tck;
315.22 -
315.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
315.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
315.25 -import org.testng.annotations.Factory;
315.26 -
315.27 -/**
315.28 - *
315.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
315.30 - */
315.31 -public class CompareIntArrayTest {
315.32 - @Compare public int integerArraySum() {
315.33 - int[] arr = createArray();
315.34 - return sumIntArr(arr);
315.35 - }
315.36 -
315.37 - @Compare public int countZeros() {
315.38 - int zeros = 0;
315.39 - for (Integer i : createArray()) {
315.40 - if (i == 0) {
315.41 - zeros++;
315.42 - }
315.43 - }
315.44 - return zeros;
315.45 - }
315.46 -
315.47 - private static int sumIntArr(int[] arr) {
315.48 - int sum = 0;
315.49 - for (int i = 0; i < arr.length; i++) {
315.50 - sum += arr[i];
315.51 - }
315.52 - return sum;
315.53 - }
315.54 -
315.55 - @Factory
315.56 - public static Object[] create() {
315.57 - return VMTest.create(CompareIntArrayTest.class);
315.58 - }
315.59 -
315.60 - private int[] createArray() {
315.61 - int[] arr = new int[10];
315.62 - arr[5] = 3;
315.63 - arr[7] = 8;
315.64 - return arr;
315.65 - }
315.66 -}
316.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Wed Feb 27 17:50:47 2013 +0100
316.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
316.3 @@ -1,162 +0,0 @@
316.4 -/**
316.5 - * Back 2 Browser Bytecode Translator
316.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
316.7 - *
316.8 - * This program is free software: you can redistribute it and/or modify
316.9 - * it under the terms of the GNU General Public License as published by
316.10 - * the Free Software Foundation, version 2 of the License.
316.11 - *
316.12 - * This program is distributed in the hope that it will be useful,
316.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
316.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
316.15 - * GNU General Public License for more details.
316.16 - *
316.17 - * You should have received a copy of the GNU General Public License
316.18 - * along with this program. Look for COPYING file in the top folder.
316.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
316.20 - */
316.21 -package org.apidesign.bck2brwsr.tck;
316.22 -
316.23 -import java.io.UnsupportedEncodingException;
316.24 -import java.net.MalformedURLException;
316.25 -import java.net.URL;
316.26 -import org.apidesign.bck2brwsr.vmtest.Compare;
316.27 -import org.apidesign.bck2brwsr.vmtest.VMTest;
316.28 -import org.testng.annotations.Factory;
316.29 -
316.30 -/**
316.31 - *
316.32 - * @author Jaroslav Tulach <jtulach@netbeans.org>
316.33 - */
316.34 -public class CompareStringsTest {
316.35 - @Compare public String firstChar() {
316.36 - return "" + ("Hello".toCharArray()[0]);
316.37 - }
316.38 -
316.39 - @Compare public String classCast() {
316.40 - Object o = firstChar();
316.41 - return String.class.cast(o);
316.42 - }
316.43 -
316.44 - @Compare public String classCastThrown() {
316.45 - Object o = null;
316.46 - return String.class.cast(o);
316.47 - }
316.48 -
316.49 - @Compare public boolean equalToNull() {
316.50 - return "Ahoj".equals(null);
316.51 - }
316.52 -
316.53 - @Compare public int highByteLenght() {
316.54 - byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
316.55 - return new String(arr, 0).length();
316.56 - }
316.57 -
316.58 - @Compare public String highByte() {
316.59 - byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
316.60 - StringBuilder sb = new StringBuilder();
316.61 - sb.append("pref:");
316.62 - sb.append(new String(arr, 0));
316.63 - return sb.toString();
316.64 - }
316.65 -
316.66 - @Compare public static Object compareURLs() throws MalformedURLException {
316.67 - return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
316.68 - }
316.69 -
316.70 - @Compare public String deleteLastTwoCharacters() {
316.71 - StringBuilder sb = new StringBuilder();
316.72 - sb.append("453.0");
316.73 - if (sb.toString().endsWith(".0")) {
316.74 - final int l = sb.length();
316.75 - sb.delete(l - 2, l);
316.76 - }
316.77 - return sb.toString().toString();
316.78 - }
316.79 -
316.80 - @Compare public String nameOfStringClass() throws Exception {
316.81 - return Class.forName("java.lang.String").getName();
316.82 - }
316.83 - @Compare public String nameOfArrayClass() throws Exception {
316.84 - return Class.forName("org.apidesign.bck2brwsr.tck.CompareHashTest").getName();
316.85 - }
316.86 -
316.87 - @Compare public String lowerHello() {
316.88 - return "HeLlO".toLowerCase();
316.89 - }
316.90 -
316.91 - @Compare public String lowerA() {
316.92 - return String.valueOf(Character.toLowerCase('A')).toString();
316.93 - }
316.94 - @Compare public String upperHello() {
316.95 - return "hello".toUpperCase();
316.96 - }
316.97 -
316.98 - @Compare public String upperA() {
316.99 - return String.valueOf(Character.toUpperCase('a')).toString();
316.100 - }
316.101 -
316.102 - @Compare public boolean matchRegExp() throws Exception {
316.103 - return "58038503".matches("\\d*");
316.104 - }
316.105 -
316.106 - @Compare public boolean doesNotMatchRegExp() throws Exception {
316.107 - return "58038503GH".matches("\\d*");
316.108 - }
316.109 -
316.110 - @Compare public boolean doesNotMatchRegExpFully() throws Exception {
316.111 - return "Hello".matches("Hell");
316.112 - }
316.113 -
316.114 - @Compare public String emptyCharArray() {
316.115 - char[] arr = new char[10];
316.116 - return new String(arr);
316.117 - }
316.118 -
316.119 - @Compare public String variousCharacterTests() throws Exception {
316.120 - StringBuilder sb = new StringBuilder();
316.121 -
316.122 - sb.append(Character.isUpperCase('a'));
316.123 - sb.append(Character.isUpperCase('A'));
316.124 - sb.append(Character.isLowerCase('a'));
316.125 - sb.append(Character.isLowerCase('A'));
316.126 -
316.127 - sb.append(Character.isLetter('A'));
316.128 - sb.append(Character.isLetterOrDigit('9'));
316.129 - sb.append(Character.isLetterOrDigit('A'));
316.130 - sb.append(Character.isLetter('0'));
316.131 -
316.132 - return sb.toString().toString();
316.133 - }
316.134 -
316.135 - @Compare
316.136 - public String nullFieldInitialized() {
316.137 - NullField nf = new NullField();
316.138 - return ("" + nf.name).toString();
316.139 - }
316.140 - @Compare
316.141 - public String toUTFString() throws UnsupportedEncodingException {
316.142 - byte[] arr = {
316.143 - (byte) -59, (byte) -67, (byte) 108, (byte) 117, (byte) -59, (byte) -91,
316.144 - (byte) 111, (byte) 117, (byte) -60, (byte) -115, (byte) 107, (byte) -61,
316.145 - (byte) -67, (byte) 32, (byte) 107, (byte) -59, (byte) -81, (byte) -59,
316.146 - (byte) -120
316.147 - };
316.148 - return new String(arr, "utf-8");
316.149 - }
316.150 -
316.151 - @Compare
316.152 - public int stringToBytesLenght() throws UnsupportedEncodingException {
316.153 - return "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("utf8").length;
316.154 - }
316.155 -
316.156 - @Factory
316.157 - public static Object[] create() {
316.158 - return VMTest.create(CompareStringsTest.class);
316.159 - }
316.160 -
316.161 - private static final class NullField {
316.162 -
316.163 - String name;
316.164 - }
316.165 -}
317.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java Wed Feb 27 17:50:47 2013 +0100
317.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
317.3 @@ -1,106 +0,0 @@
317.4 -/**
317.5 - * Back 2 Browser Bytecode Translator
317.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
317.7 - *
317.8 - * This program is free software: you can redistribute it and/or modify
317.9 - * it under the terms of the GNU General Public License as published by
317.10 - * the Free Software Foundation, version 2 of the License.
317.11 - *
317.12 - * This program is distributed in the hope that it will be useful,
317.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
317.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
317.15 - * GNU General Public License for more details.
317.16 - *
317.17 - * You should have received a copy of the GNU General Public License
317.18 - * along with this program. Look for COPYING file in the top folder.
317.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
317.20 - */
317.21 -package org.apidesign.bck2brwsr.tck;
317.22 -
317.23 -import java.io.InputStream;
317.24 -import java.net.URL;
317.25 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
317.26 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
317.27 -import org.apidesign.bck2brwsr.vmtest.Http;
317.28 -import org.apidesign.bck2brwsr.vmtest.VMTest;
317.29 -import org.testng.annotations.Factory;
317.30 -
317.31 -/**
317.32 - *
317.33 - * @author Jaroslav Tulach <jtulach@netbeans.org>
317.34 - */
317.35 -public class HttpResourceTest {
317.36 -
317.37 - @Http({
317.38 - @Http.Resource(path = "/xhr", content = "Hello Brwsr!", mimeType = "text/plain")
317.39 - })
317.40 - @BrwsrTest
317.41 -
317.42 -
317.43 - public String testReadContentViaXHR() throws Exception {
317.44 - String msg = read("/xhr");
317.45 - assert "Hello Brwsr!".equals(msg) : "The message was " + msg;
317.46 - return msg;
317.47 - }
317.48 -
317.49 - @Http({
317.50 - @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain")
317.51 - })
317.52 - @BrwsrTest
317.53 - public String testReadContentViaURL() throws Exception {
317.54 - URL url = new URL("http:/url");
317.55 - String msg = (String) url.getContent();
317.56 - assert "Hello via URL!".equals(msg) : "The message was " + msg;
317.57 - return msg;
317.58 - }
317.59 - @Http({
317.60 - @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain")
317.61 - })
317.62 - @BrwsrTest
317.63 - public String testReadContentViaURLWithStringParam() throws Exception {
317.64 - URL url = new URL("http:/url");
317.65 - String msg = (String) url.getContent(new Class[] { String.class });
317.66 - assert "Hello via URL!".equals(msg) : "The message was " + msg;
317.67 - return msg;
317.68 - }
317.69 -
317.70 - @Http({
317.71 - @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary")
317.72 - })
317.73 - @BrwsrTest
317.74 - public void testReadByte() throws Exception {
317.75 - URL url = new URL("http:/bytes");
317.76 - final Object res = url.getContent(new Class[] { byte[].class });
317.77 - assert res instanceof byte[] : "Expecting byte[]: " + res;
317.78 - byte[] arr = (byte[]) res;
317.79 - assert arr.length == 1 : "One byte " + arr.length;
317.80 - assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]);
317.81 - }
317.82 -
317.83 - @Http({
317.84 - @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary")
317.85 - })
317.86 - @BrwsrTest
317.87 - public void testReadByteViaInputStream() throws Exception {
317.88 - URL url = new URL("http:/bytes");
317.89 - InputStream is = url.openStream();
317.90 - byte[] arr = new byte[10];
317.91 - int len = is.read(arr);
317.92 - assert len == 1 : "One byte " + len;
317.93 - assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]);
317.94 - }
317.95 -
317.96 - @JavaScriptBody(args = { "url" }, body =
317.97 - "var req = new XMLHttpRequest();\n"
317.98 - + "req.open('GET', url, false);\n"
317.99 - + "req.send();\n"
317.100 - + "return req.responseText;"
317.101 - )
317.102 - private static native String read(String url);
317.103 -
317.104 -
317.105 - @Factory
317.106 - public static Object[] create() {
317.107 - return VMTest.create(HttpResourceTest.class);
317.108 - }
317.109 -}
318.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java Wed Feb 27 17:50:47 2013 +0100
318.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
318.3 @@ -1,34 +0,0 @@
318.4 -/**
318.5 - * Back 2 Browser Bytecode Translator
318.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
318.7 - *
318.8 - * This program is free software: you can redistribute it and/or modify
318.9 - * it under the terms of the GNU General Public License as published by
318.10 - * the Free Software Foundation, version 2 of the License.
318.11 - *
318.12 - * This program is distributed in the hope that it will be useful,
318.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
318.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
318.15 - * GNU General Public License for more details.
318.16 - *
318.17 - * You should have received a copy of the GNU General Public License
318.18 - * along with this program. Look for COPYING file in the top folder.
318.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
318.20 - */
318.21 -package org.apidesign.bck2brwsr.tck;
318.22 -
318.23 -/**
318.24 - *
318.25 - * @author Jaroslav Tulach <jtulach@netbeans.org>
318.26 - */
318.27 -public class InheritanceA {
318.28 - private String name;
318.29 -
318.30 - public void setA(String n) {
318.31 - this.name = n;
318.32 - }
318.33 -
318.34 - public String getA() {
318.35 - return name;
318.36 - }
318.37 -}
319.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java Wed Feb 27 17:50:47 2013 +0100
319.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
319.3 @@ -1,34 +0,0 @@
319.4 -/**
319.5 - * Back 2 Browser Bytecode Translator
319.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
319.7 - *
319.8 - * This program is free software: you can redistribute it and/or modify
319.9 - * it under the terms of the GNU General Public License as published by
319.10 - * the Free Software Foundation, version 2 of the License.
319.11 - *
319.12 - * This program is distributed in the hope that it will be useful,
319.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
319.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
319.15 - * GNU General Public License for more details.
319.16 - *
319.17 - * You should have received a copy of the GNU General Public License
319.18 - * along with this program. Look for COPYING file in the top folder.
319.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
319.20 - */
319.21 -package org.apidesign.bck2brwsr.tck;
319.22 -
319.23 -/**
319.24 - *
319.25 - * @author Jaroslav Tulach <jtulach@netbeans.org>
319.26 - */
319.27 -public class InheritanceB extends InheritanceA {
319.28 - private String name;
319.29 -
319.30 - public void setB(String n) {
319.31 - this.name = n;
319.32 - }
319.33 -
319.34 - public String getB() {
319.35 - return name;
319.36 - }
319.37 -}
320.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java Wed Feb 27 17:50:47 2013 +0100
320.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
320.3 @@ -1,41 +0,0 @@
320.4 -/**
320.5 - * Back 2 Browser Bytecode Translator
320.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
320.7 - *
320.8 - * This program is free software: you can redistribute it and/or modify
320.9 - * it under the terms of the GNU General Public License as published by
320.10 - * the Free Software Foundation, version 2 of the License.
320.11 - *
320.12 - * This program is distributed in the hope that it will be useful,
320.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
320.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
320.15 - * GNU General Public License for more details.
320.16 - *
320.17 - * You should have received a copy of the GNU General Public License
320.18 - * along with this program. Look for COPYING file in the top folder.
320.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
320.20 - */
320.21 -package org.apidesign.bck2brwsr.tck;
320.22 -
320.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
320.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
320.25 -import org.testng.annotations.Factory;
320.26 -
320.27 -/**
320.28 - *
320.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
320.30 - */
320.31 -public class InheritanceTest {
320.32 -
320.33 - @Compare public String checkFieldsIndependent() throws ClassNotFoundException {
320.34 - InheritanceB ib = new InheritanceB();
320.35 - ib.setA("A");
320.36 - ib.setB("B");
320.37 - return "A: " + ib.getA() + " B: " + ib.getB();
320.38 - }
320.39 -
320.40 - @Factory
320.41 - public static Object[] create() {
320.42 - return VMTest.create(InheritanceTest.class);
320.43 - }
320.44 -}
321.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Wed Feb 27 17:50:47 2013 +0100
321.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
321.3 @@ -1,166 +0,0 @@
321.4 -/**
321.5 - * Back 2 Browser Bytecode Translator
321.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
321.7 - *
321.8 - * This program is free software: you can redistribute it and/or modify
321.9 - * it under the terms of the GNU General Public License as published by
321.10 - * the Free Software Foundation, version 2 of the License.
321.11 - *
321.12 - * This program is distributed in the hope that it will be useful,
321.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
321.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
321.15 - * GNU General Public License for more details.
321.16 - *
321.17 - * You should have received a copy of the GNU General Public License
321.18 - * along with this program. Look for COPYING file in the top folder.
321.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
321.20 - */
321.21 -package org.apidesign.bck2brwsr.tck;
321.22 -
321.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
321.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
321.25 -import org.testng.annotations.Factory;
321.26 -
321.27 -/**
321.28 - *
321.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
321.30 - */
321.31 -public class IntegerArithmeticTest {
321.32 -
321.33 - private static int add(int x, int y) {
321.34 - return x + y;
321.35 - }
321.36 -
321.37 - private static int sub(int x, int y) {
321.38 - return x - y;
321.39 - }
321.40 -
321.41 - private static int mul(int x, int y) {
321.42 - return x * y;
321.43 - }
321.44 -
321.45 - private static int div(int x, int y) {
321.46 - return x / y;
321.47 - }
321.48 -
321.49 - private static int mod(int x, int y) {
321.50 - return x % y;
321.51 - }
321.52 -
321.53 - private static int neg(int x) {
321.54 - return (-x);
321.55 - }
321.56 -
321.57 - private static float fadd(float x, float y) {
321.58 - return x + y;
321.59 - }
321.60 -
321.61 - private static double dadd(double x, double y) {
321.62 - return x + y;
321.63 - }
321.64 -
321.65 - @Compare public int addOverflow() {
321.66 - return add(Integer.MAX_VALUE, 1);
321.67 - }
321.68 -
321.69 - @Compare public int subUnderflow() {
321.70 - return sub(Integer.MIN_VALUE, 1);
321.71 - }
321.72 -
321.73 - @Compare public int addMaxIntAndMaxInt() {
321.74 - return add(Integer.MAX_VALUE, Integer.MAX_VALUE);
321.75 - }
321.76 -
321.77 - @Compare public int subMinIntAndMinInt() {
321.78 - return sub(Integer.MIN_VALUE, Integer.MIN_VALUE);
321.79 - }
321.80 -
321.81 - @Compare public int multiplyMaxInt() {
321.82 - return mul(Integer.MAX_VALUE, 2);
321.83 - }
321.84 -
321.85 - @Compare public int multiplyMaxIntAndMaxInt() {
321.86 - return mul(Integer.MAX_VALUE, Integer.MAX_VALUE);
321.87 - }
321.88 -
321.89 - @Compare public int multiplyMinInt() {
321.90 - return mul(Integer.MIN_VALUE, 2);
321.91 - }
321.92 -
321.93 - @Compare public int multiplyMinIntAndMinInt() {
321.94 - return mul(Integer.MIN_VALUE, Integer.MIN_VALUE);
321.95 - }
321.96 -
321.97 - @Compare public int multiplyPrecision() {
321.98 - return mul(119106029, 1103515245);
321.99 - }
321.100 -
321.101 - @Compare public int division() {
321.102 - return div(1, 2);
321.103 - }
321.104 -
321.105 - @Compare public int divisionReminder() {
321.106 - return mod(1, 2);
321.107 - }
321.108 -
321.109 - @Compare public int negativeDivision() {
321.110 - return div(-7, 3);
321.111 - }
321.112 -
321.113 - @Compare public int negativeDivisionReminder() {
321.114 - return mod(-7, 3);
321.115 - }
321.116 -
321.117 - @Compare public int conversionFromFloat() {
321.118 - return (int) fadd(-2, -0.6f);
321.119 - }
321.120 -
321.121 - @Compare public int conversionFromDouble() {
321.122 - return (int) dadd(-2, -0.6);
321.123 - }
321.124 -
321.125 - @Compare public boolean divByZeroThrowsArithmeticException() {
321.126 - try {
321.127 - div(1, 0);
321.128 - return false;
321.129 - } catch (final ArithmeticException e) {
321.130 - return true;
321.131 - }
321.132 - }
321.133 -
321.134 - @Compare public boolean modByZeroThrowsArithmeticException() {
321.135 - try {
321.136 - mod(1, 0);
321.137 - return false;
321.138 - } catch (final ArithmeticException e) {
321.139 - return true;
321.140 - }
321.141 - }
321.142 -
321.143 - @Compare public int negate() {
321.144 - return neg(123456);
321.145 - }
321.146 -
321.147 - @Compare public int negateMaxInt() {
321.148 - return neg(Integer.MAX_VALUE);
321.149 - }
321.150 -
321.151 - @Compare public int negateMinInt() {
321.152 - return neg(Integer.MIN_VALUE);
321.153 - }
321.154 -
321.155 - @Compare public int sumTwoDimensions() {
321.156 - int[][] matrix = createMatrix(4, 3);
321.157 - matrix[0][0] += 10;
321.158 - return matrix[0][0];
321.159 - }
321.160 -
321.161 - static int[][] createMatrix(int x, int y) {
321.162 - return new int[x][y];
321.163 - }
321.164 -
321.165 - @Factory
321.166 - public static Object[] create() {
321.167 - return VMTest.create(IntegerArithmeticTest.class);
321.168 - }
321.169 -}
322.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Wed Feb 27 17:50:47 2013 +0100
322.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
322.3 @@ -1,376 +0,0 @@
322.4 -/**
322.5 - * Back 2 Browser Bytecode Translator
322.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
322.7 - *
322.8 - * This program is free software: you can redistribute it and/or modify
322.9 - * it under the terms of the GNU General Public License as published by
322.10 - * the Free Software Foundation, version 2 of the License.
322.11 - *
322.12 - * This program is distributed in the hope that it will be useful,
322.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
322.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
322.15 - * GNU General Public License for more details.
322.16 - *
322.17 - * You should have received a copy of the GNU General Public License
322.18 - * along with this program. Look for COPYING file in the top folder.
322.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
322.20 - */
322.21 -package org.apidesign.bck2brwsr.tck;
322.22 -
322.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
322.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
322.25 -import org.testng.annotations.Factory;
322.26 -
322.27 -/**
322.28 - *
322.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
322.30 - */
322.31 -public class LongArithmeticTest {
322.32 -
322.33 - private static long add(long x, long y) {
322.34 - return (x + y);
322.35 - }
322.36 -
322.37 - private static long sub(long x, long y) {
322.38 - return (x - y);
322.39 - }
322.40 -
322.41 - private static long mul(long x, long y) {
322.42 - return (x * y);
322.43 - }
322.44 -
322.45 - private static long div(long x, long y) {
322.46 - return (x / y);
322.47 - }
322.48 -
322.49 - private static long mod(long x, long y) {
322.50 - return (x % y);
322.51 - }
322.52 -
322.53 - private static long neg(long x) {
322.54 - return (-x);
322.55 - }
322.56 -
322.57 - private static long shl(long x, int b) {
322.58 - return (x << b);
322.59 - }
322.60 -
322.61 - private static long shr(long x, int b) {
322.62 - return (x >> b);
322.63 - }
322.64 -
322.65 - private static long ushr(long x, int b) {
322.66 - return (x >>> b);
322.67 - }
322.68 -
322.69 - private static long and(long x, long y) {
322.70 - return (x & y);
322.71 - }
322.72 -
322.73 - private static long or(long x, long y) {
322.74 - return (x | y);
322.75 - }
322.76 -
322.77 - private static long xor(long x, long y) {
322.78 - return (x ^ y);
322.79 - }
322.80 -
322.81 - private static float fadd(float x, float y) {
322.82 - return x + y;
322.83 - }
322.84 -
322.85 - private static double dadd(double x, double y) {
322.86 - return x + y;
322.87 - }
322.88 -
322.89 - public static int compare(long x, long y, int zero) {
322.90 - final int xyResult = compareL(x, y, zero);
322.91 - final int yxResult = compareL(y, x, zero);
322.92 -
322.93 - return ((xyResult + yxResult) == 0) ? xyResult : -2;
322.94 - }
322.95 -
322.96 - private static int compareL(long x, long y, int zero) {
322.97 - int result = -2;
322.98 - int trueCount = 0;
322.99 -
322.100 - x += zero;
322.101 - if (x == y) {
322.102 - result = 0;
322.103 - ++trueCount;
322.104 - }
322.105 -
322.106 - x += zero;
322.107 - if (x < y) {
322.108 - result = -1;
322.109 - ++trueCount;
322.110 - }
322.111 -
322.112 - x += zero;
322.113 - if (x > y) {
322.114 - result = 1;
322.115 - ++trueCount;
322.116 - }
322.117 -
322.118 - return (trueCount == 1) ? result : -2;
322.119 - }
322.120 -
322.121 - @Compare public long conversion() {
322.122 - return Long.MAX_VALUE;
322.123 - }
322.124 -
322.125 - @Compare public long negate1() {
322.126 - return neg(0x00fa37d7763e0ca1l);
322.127 - }
322.128 -
322.129 - @Compare public long negate2() {
322.130 - return neg(0x80fa37d7763e0ca1l);
322.131 - }
322.132 -
322.133 - @Compare public long negate3() {
322.134 - return neg(0xfffffffffffffeddl);
322.135 - }
322.136 -
322.137 - @Compare public long addOverflow() {
322.138 - return add(Long.MAX_VALUE, 1l);
322.139 - }
322.140 -
322.141 - @Compare public long subUnderflow() {
322.142 - return sub(Long.MIN_VALUE, 1l);
322.143 - }
322.144 -
322.145 - @Compare public long addMaxLongAndMaxLong() {
322.146 - return add(Long.MAX_VALUE, Long.MAX_VALUE);
322.147 - }
322.148 -
322.149 - @Compare public long subMinLongAndMinLong() {
322.150 - return sub(Long.MIN_VALUE, Long.MIN_VALUE);
322.151 - }
322.152 -
322.153 - @Compare public long subMinLongAndMaxLong() {
322.154 - return sub(Long.MIN_VALUE, Long.MAX_VALUE);
322.155 - }
322.156 -
322.157 - @Compare public long multiplyMaxLong() {
322.158 - return mul(Long.MAX_VALUE, 2l);
322.159 - }
322.160 -
322.161 - @Compare public long multiplyMaxLongAndMaxLong() {
322.162 - return mul(Long.MAX_VALUE, Long.MAX_VALUE);
322.163 - }
322.164 -
322.165 - @Compare public long multiplyMinLong() {
322.166 - return mul(Long.MIN_VALUE, 2l);
322.167 - }
322.168 -
322.169 - @Compare public long multiplyMinLongAndMinLong() {
322.170 - return mul(Long.MIN_VALUE, Long.MIN_VALUE);
322.171 - }
322.172 -
322.173 - @Compare public long multiplyPrecision() {
322.174 - return mul(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
322.175 - }
322.176 -
322.177 - @Compare public long divideSmallPositiveNumbers() {
322.178 - return div(0xabcdef, 0x123);
322.179 - }
322.180 -
322.181 - @Compare public long divideSmallNegativeNumbers() {
322.182 - return div(-0xabcdef, -0x123);
322.183 - }
322.184 -
322.185 - @Compare public long divideSmallMixedNumbers() {
322.186 - return div(0xabcdef, -0x123);
322.187 - }
322.188 -
322.189 - @Compare public long dividePositiveNumbersOneDigitDenom() {
322.190 - return div(0xabcdef0102ffffl, 0x654);
322.191 - }
322.192 -
322.193 - @Compare public long divideNegativeNumbersOneDigitDenom() {
322.194 - return div(-0xabcdef0102ffffl, -0x654);
322.195 - }
322.196 -
322.197 - @Compare public long divideMixedNumbersOneDigitDenom() {
322.198 - return div(-0xabcdef0102ffffl, 0x654);
322.199 - }
322.200 -
322.201 - @Compare public long dividePositiveNumbersMultiDigitDenom() {
322.202 - return div(0x7ffefc003322aabbl, 0x89ab1000l);
322.203 - }
322.204 -
322.205 - @Compare public long divideNegativeNumbersMultiDigitDenom() {
322.206 - return div(-0x7ffefc003322aabbl, -0x123489ab1001l);
322.207 - }
322.208 -
322.209 - @Compare public long divideMixedNumbersMultiDigitDenom() {
322.210 - return div(0x7ffefc003322aabbl, -0x38f49b0b7574e36l);
322.211 - }
322.212 -
322.213 - @Compare public long divideWithOverflow() {
322.214 - return div(0x8000fffe0000l, 0x8000ffffl);
322.215 - }
322.216 -
322.217 - @Compare public long divideWithCorrection() {
322.218 - return div(0x7fff800000000000l, 0x800000000001l);
322.219 - }
322.220 -
322.221 - @Compare public long moduloSmallPositiveNumbers() {
322.222 - return mod(0xabcdef, 0x123);
322.223 - }
322.224 -
322.225 - @Compare public long moduloSmallNegativeNumbers() {
322.226 - return mod(-0xabcdef, -0x123);
322.227 - }
322.228 -
322.229 - @Compare public long moduloSmallMixedNumbers() {
322.230 - return mod(0xabcdef, -0x123);
322.231 - }
322.232 -
322.233 - @Compare public long moduloPositiveNumbersOneDigitDenom() {
322.234 - return mod(0xabcdef0102ffffl, 0x654);
322.235 - }
322.236 -
322.237 - @Compare public long moduloNegativeNumbersOneDigitDenom() {
322.238 - return mod(-0xabcdef0102ffffl, -0x654);
322.239 - }
322.240 -
322.241 - @Compare public long moduloMixedNumbersOneDigitDenom() {
322.242 - return mod(-0xabcdef0102ffffl, 0x654);
322.243 - }
322.244 -
322.245 - @Compare public long moduloPositiveNumbersMultiDigitDenom() {
322.246 - return mod(0x7ffefc003322aabbl, 0x89ab1000l);
322.247 - }
322.248 -
322.249 - @Compare public long moduloNegativeNumbersMultiDigitDenom() {
322.250 - return mod(-0x7ffefc003322aabbl, -0x123489ab1001l);
322.251 - }
322.252 -
322.253 - @Compare public long moduloMixedNumbersMultiDigitDenom() {
322.254 - return mod(0x7ffefc003322aabbl, -0x38f49b0b7574e36l);
322.255 - }
322.256 -
322.257 - @Compare public long moduloWithOverflow() {
322.258 - return mod(0x8000fffe0000l, 0x8000ffffl);
322.259 - }
322.260 -
322.261 - @Compare public long moduloWithCorrection() {
322.262 - return mod(0x7fff800000000000l, 0x800000000001l);
322.263 - }
322.264 -
322.265 - @Compare public long conversionFromFloatPositive() {
322.266 - return (long) fadd(2, 0.6f);
322.267 - }
322.268 -
322.269 - @Compare public long conversionFromFloatNegative() {
322.270 - return (long) fadd(-2, -0.6f);
322.271 - }
322.272 -
322.273 - @Compare public long conversionFromDoublePositive() {
322.274 - return (long) dadd(0x20ffff0000L, 0.6);
322.275 - }
322.276 -
322.277 - @Compare public long conversionFromDoubleNegative() {
322.278 - return (long) dadd(-0x20ffff0000L, -0.6);
322.279 - }
322.280 -
322.281 - @Compare public boolean divByZeroThrowsArithmeticException() {
322.282 - try {
322.283 - div(1, 0);
322.284 - return false;
322.285 - } catch (final ArithmeticException e) {
322.286 - return true;
322.287 - }
322.288 - }
322.289 -
322.290 - @Compare public boolean modByZeroThrowsArithmeticException() {
322.291 - try {
322.292 - mod(1, 0);
322.293 - return false;
322.294 - } catch (final ArithmeticException e) {
322.295 - return true;
322.296 - }
322.297 - }
322.298 -
322.299 - @Compare public long shiftL1() {
322.300 - return shl(0x00fa37d7763e0ca1l, 5);
322.301 - }
322.302 -
322.303 - @Compare public long shiftL2() {
322.304 - return shl(0x00fa37d7763e0ca1l, 32);
322.305 - }
322.306 -
322.307 - @Compare public long shiftL3() {
322.308 - return shl(0x00fa37d7763e0ca1l, 45);
322.309 - }
322.310 -
322.311 - @Compare public long shiftR1() {
322.312 - return shr(0x00fa37d7763e0ca1l, 5);
322.313 - }
322.314 -
322.315 - @Compare public long shiftR2() {
322.316 - return shr(0x00fa37d7763e0ca1l, 32);
322.317 - }
322.318 -
322.319 - @Compare public long shiftR3() {
322.320 - return shr(0x00fa37d7763e0ca1l, 45);
322.321 - }
322.322 -
322.323 - @Compare public long uShiftR1() {
322.324 - return ushr(0x00fa37d7763e0ca1l, 5);
322.325 - }
322.326 -
322.327 - @Compare public long uShiftR2() {
322.328 - return ushr(0x00fa37d7763e0ca1l, 45);
322.329 - }
322.330 -
322.331 - @Compare public long uShiftR3() {
322.332 - return ushr(0xf0fa37d7763e0ca1l, 5);
322.333 - }
322.334 -
322.335 - @Compare public long uShiftR4() {
322.336 - return ushr(0xf0fa37d7763e0ca1l, 45);
322.337 - }
322.338 -
322.339 - @Compare public long and1() {
322.340 - return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
322.341 - }
322.342 -
322.343 - @Compare public long or1() {
322.344 - return or(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
322.345 - }
322.346 -
322.347 - @Compare public long xor1() {
322.348 - return xor(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
322.349 - }
322.350 -
322.351 - @Compare public long xor2() {
322.352 - return xor(0x00fa37d7763e0ca1l, 0x00000000ff00123el);
322.353 - }
322.354 -
322.355 - @Compare public long xor3() {
322.356 - return xor(0x00000000763e0ca1l, 0x00000000ff00123el);
322.357 - }
322.358 -
322.359 - @Compare public int compareSameNumbers() {
322.360 - return compare(0x0000000000000000l, 0x0000000000000000l, 0);
322.361 - }
322.362 -
322.363 - @Compare public int comparePositiveNumbers() {
322.364 - return compare(0x0000000000200000l, 0x0000000010000000l, 0);
322.365 - }
322.366 -
322.367 - @Compare public int compareNegativeNumbers() {
322.368 - return compare(0xffffffffffffffffl, 0xffffffff00000000l, 0);
322.369 - }
322.370 -
322.371 - @Compare public int compareMixedNumbers() {
322.372 - return compare(0x8000000000000000l, 0x7fffffffffffffffl, 0);
322.373 - }
322.374 -
322.375 - @Factory
322.376 - public static Object[] create() {
322.377 - return VMTest.create(LongArithmeticTest.class);
322.378 - }
322.379 -}
323.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Wed Feb 27 17:50:47 2013 +0100
323.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
323.3 @@ -1,135 +0,0 @@
323.4 -/**
323.5 - * Back 2 Browser Bytecode Translator
323.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
323.7 - *
323.8 - * This program is free software: you can redistribute it and/or modify
323.9 - * it under the terms of the GNU General Public License as published by
323.10 - * the Free Software Foundation, version 2 of the License.
323.11 - *
323.12 - * This program is distributed in the hope that it will be useful,
323.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
323.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
323.15 - * GNU General Public License for more details.
323.16 - *
323.17 - * You should have received a copy of the GNU General Public License
323.18 - * along with this program. Look for COPYING file in the top folder.
323.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
323.20 - */
323.21 -package org.apidesign.bck2brwsr.tck;
323.22 -
323.23 -import java.lang.reflect.Array;
323.24 -import org.apidesign.bck2brwsr.vmtest.Compare;
323.25 -import org.apidesign.bck2brwsr.vmtest.VMTest;
323.26 -import org.testng.annotations.Factory;
323.27 -
323.28 -/**
323.29 - *
323.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
323.31 - */
323.32 -public class ReflectionArrayTest {
323.33 - @Compare public int lengthOfStringArray() {
323.34 - String[] arr = (String[]) Array.newInstance(String.class, 10);
323.35 - return arr.length;
323.36 - }
323.37 -
323.38 - @Compare public int reflectiveLengthOfStringArray() {
323.39 - Object arr = Array.newInstance(String.class, 10);
323.40 - return Array.getLength(arr);
323.41 - }
323.42 -
323.43 - @Compare public int reflectiveLengthOneNonArray() {
323.44 - Object arr = "non-array";
323.45 - return Array.getLength(arr);
323.46 - }
323.47 -
323.48 - @Compare public String compTypeOfStringArray() {
323.49 - String[] arr = (String[]) Array.newInstance(String.class, 10);
323.50 - return arr.getClass().getComponentType().getName();
323.51 - }
323.52 -
323.53 - @Compare public Object negativeArrayExcp() {
323.54 - return Array.newInstance(String.class, -5);
323.55 - }
323.56 -
323.57 - @Compare public int lengthOfIntArray() {
323.58 - int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10);
323.59 - return arr.length;
323.60 - }
323.61 -
323.62 - @Compare public int reflectiveLengthOfIntArray() {
323.63 - Object arr = Array.newInstance(Integer.TYPE, 10);
323.64 - return Array.getLength(arr);
323.65 - }
323.66 -
323.67 - @Compare public String compTypeOfIntArray() {
323.68 - int[] arr = (int[]) Array.newInstance(int.class, 10);
323.69 - return arr.getClass().getComponentType().getName();
323.70 - }
323.71 -
323.72 - @Compare public Object intNegativeArrayExcp() {
323.73 - return Array.newInstance(int.class, -5);
323.74 - }
323.75 -
323.76 - @Compare public Integer verifyAutobox() {
323.77 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.78 - return (Integer) Array.get(arr, 0);
323.79 - }
323.80 - @Compare public String verifyObjectArray() {
323.81 - String[] arr = (String[]) Array.newInstance(String.class, 5);
323.82 - Array.set(arr, 0, "Hello");
323.83 - return (String) Array.get(arr, 0);
323.84 - }
323.85 - @Compare public int verifyInt() {
323.86 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.87 - return Array.getInt(arr, 0);
323.88 - }
323.89 - @Compare public long verifyConvertToLong() {
323.90 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.91 - return Array.getLong(arr, 0);
323.92 - }
323.93 -
323.94 - @Compare public Object verifySetIntToObject() {
323.95 - try {
323.96 - Object[] arr = (Object[]) Array.newInstance(Object.class, 5);
323.97 - Array.setInt(arr, 0, 10);
323.98 - return Array.get(arr, 0);
323.99 - } catch (Exception exception) {
323.100 - return exception.getClass().getName();
323.101 - }
323.102 - }
323.103 - @Compare public long verifySetShort() {
323.104 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.105 - Array.setShort(arr, 0, (short)10);
323.106 - return Array.getLong(arr, 0);
323.107 - }
323.108 - @Compare public long verifyCantSetLong() {
323.109 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.110 - Array.setLong(arr, 0, 10);
323.111 - return Array.getLong(arr, 0);
323.112 - }
323.113 - @Compare public float verifyLongToFloat() {
323.114 - Object arr = Array.newInstance(float.class, 5);
323.115 - Array.setLong(arr, 0, 10);
323.116 - return Array.getFloat(arr, 0);
323.117 - }
323.118 -
323.119 - @Compare public double verifyConvertToDouble() {
323.120 - int[] arr = (int[]) Array.newInstance(int.class, 5);
323.121 - return Array.getDouble(arr, 0);
323.122 - }
323.123 -
323.124 - @Compare public int multiIntArray() {
323.125 - int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
323.126 - return arr[0][1][2] + 5 + arr[2][2][0];
323.127 - }
323.128 -
323.129 - @Compare public String multiIntArrayCompType() {
323.130 - return Array.newInstance(int.class, 3, 3, 3).getClass().getName();
323.131 - }
323.132 -
323.133 -
323.134 - @Factory
323.135 - public static Object[] create() {
323.136 - return VMTest.create(ReflectionArrayTest.class);
323.137 - }
323.138 -}
324.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Wed Feb 27 17:50:47 2013 +0100
324.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
324.3 @@ -1,242 +0,0 @@
324.4 -/**
324.5 - * Back 2 Browser Bytecode Translator
324.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
324.7 - *
324.8 - * This program is free software: you can redistribute it and/or modify
324.9 - * it under the terms of the GNU General Public License as published by
324.10 - * the Free Software Foundation, version 2 of the License.
324.11 - *
324.12 - * This program is distributed in the hope that it will be useful,
324.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
324.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
324.15 - * GNU General Public License for more details.
324.16 - *
324.17 - * You should have received a copy of the GNU General Public License
324.18 - * along with this program. Look for COPYING file in the top folder.
324.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
324.20 - */
324.21 -package org.apidesign.bck2brwsr.tck;
324.22 -
324.23 -import java.lang.annotation.Retention;
324.24 -import java.lang.annotation.RetentionPolicy;
324.25 -import java.lang.reflect.Method;
324.26 -import java.util.Arrays;
324.27 -import java.util.Collections;
324.28 -import java.util.List;
324.29 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
324.30 -import org.apidesign.bck2brwsr.vmtest.Compare;
324.31 -import org.apidesign.bck2brwsr.vmtest.VMTest;
324.32 -import org.testng.annotations.Factory;
324.33 -
324.34 -/**
324.35 - *
324.36 - * @author Jaroslav Tulach <jtulach@netbeans.org>
324.37 - */
324.38 -public class ReflectionTest {
324.39 - @Compare public boolean nonNullThis() {
324.40 - return this == null;
324.41 - }
324.42 -
324.43 - @Compare public String intType() {
324.44 - return Integer.TYPE.toString();
324.45 - }
324.46 -
324.47 - @Compare public String voidType() throws Exception {
324.48 - return void.class.toString();
324.49 - }
324.50 -
324.51 - @Compare public String longClass() {
324.52 - return long.class.toString();
324.53 - }
324.54 -
324.55 - @Compare public boolean isRunnableInterface() {
324.56 - return Runnable.class.isInterface();
324.57 - }
324.58 -
324.59 - @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException {
324.60 - return Runnable.class.getMethod("run").getName();
324.61 - }
324.62 -
324.63 - @Compare public String namesOfMethods() {
324.64 - StringBuilder sb = new StringBuilder();
324.65 - String[] arr = new String[20];
324.66 - int i = 0;
324.67 - for (Method m : StaticUse.class.getMethods()) {
324.68 - arr[i++] = m.getName();
324.69 - }
324.70 - for (String s : sort(arr, i)) {
324.71 - sb.append(s).append("\n");
324.72 - }
324.73 - return sb.toString();
324.74 - }
324.75 -
324.76 - @Compare public String namesOfDeclaringClassesOfMethods() {
324.77 - StringBuilder sb = new StringBuilder();
324.78 - String[] arr = new String[20];
324.79 - int i = 0;
324.80 - for (Method m : StaticUse.class.getMethods()) {
324.81 - arr[i++] = m.getName() + "@" + m.getDeclaringClass().getName();
324.82 - }
324.83 - for (String s : sort(arr, i)) {
324.84 - sb.append(s).append("\n");
324.85 - }
324.86 - return sb.toString();
324.87 - }
324.88 -
324.89 - @Compare public String cannotCallNonStaticMethodWithNull() throws Exception {
324.90 - StaticUse.class.getMethod("instanceMethod").invoke(null);
324.91 - return "should not happen";
324.92 - }
324.93 -
324.94 - @Compare public Object voidReturnType() throws Exception {
324.95 - return StaticUse.class.getMethod("instanceMethod").getReturnType();
324.96 - }
324.97 -
324.98 - @Retention(RetentionPolicy.RUNTIME)
324.99 - @interface Ann {
324.100 - }
324.101 -
324.102 - @Compare public String annoClass() throws Exception {
324.103 - Retention r = Ann.class.getAnnotation(Retention.class);
324.104 - assert r != null : "Annotation is present";
324.105 - assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value();
324.106 - return r.annotationType().getName();
324.107 - }
324.108 -
324.109 - @Compare public boolean isAnnotation() {
324.110 - return Ann.class.isAnnotation();
324.111 - }
324.112 - @Compare public boolean isNotAnnotation() {
324.113 - return String.class.isAnnotation();
324.114 - }
324.115 - @Compare public boolean isNotAnnotationEnum() {
324.116 - return E.class.isAnnotation();
324.117 - }
324.118 - enum E { A, B };
324.119 - @Compare public boolean isEnum() {
324.120 - return E.A.getClass().isEnum();
324.121 - }
324.122 -
324.123 - @Compare public boolean isNotEnum() {
324.124 - return "".getClass().isEnum();
324.125 - }
324.126 -
324.127 - @Compare public String newInstanceFails() throws InstantiationException {
324.128 - try {
324.129 - return "success: " + StaticUse.class.newInstance();
324.130 - } catch (IllegalAccessException ex) {
324.131 - return ex.getClass().getName();
324.132 - }
324.133 - }
324.134 -
324.135 - @Compare public String paramTypes() throws Exception {
324.136 - Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE);
324.137 - final Class[] pt = plus.getParameterTypes();
324.138 - return pt[0].getName();
324.139 - }
324.140 - @Compare public String paramTypesNotFound() throws Exception {
324.141 - return StaticUse.class.getMethod("plus", int.class, double.class).toString();
324.142 - }
324.143 - @Compare public int methodWithArgs() throws Exception {
324.144 - Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE);
324.145 - return (Integer)plus.invoke(null, 2, 3);
324.146 - }
324.147 -
324.148 - @Compare public String classGetNameForByte() {
324.149 - return byte.class.getName();
324.150 - }
324.151 - @Compare public String classGetNameForBaseObject() {
324.152 - return newObject().getClass().getName();
324.153 - }
324.154 - @Compare public String classGetNameForJavaObject() {
324.155 - return new Object().getClass().getName();
324.156 - }
324.157 - @Compare public String classGetNameForObjectArray() {
324.158 - return (new Object[3]).getClass().getName();
324.159 - }
324.160 - @Compare public String classGetNameForSimpleIntArray() {
324.161 - return (new int[3]).getClass().getName();
324.162 - }
324.163 - @Compare public boolean sameClassGetNameForSimpleCharArray() {
324.164 - return (new char[3]).getClass() == (new char[34]).getClass();
324.165 - }
324.166 - @Compare public String classGetNameForMultiIntArray() {
324.167 - return (new int[3][4][5][6][7][8][9]).getClass().getName();
324.168 - }
324.169 - @Compare public String classGetNameForMultiIntArrayInner() {
324.170 - final int[][][][][][][] arr = new int[3][4][5][6][7][8][9];
324.171 - int[][][][][][] subarr = arr[0];
324.172 - int[][][][][] subsubarr = subarr[0];
324.173 - return subsubarr.getClass().getName();
324.174 - }
324.175 - @Compare public String classGetNameForMultiStringArray() {
324.176 - return (new String[3][4][5][6][7][8][9]).getClass().getName();
324.177 - }
324.178 -
324.179 - @Compare public String classForByte() throws Exception {
324.180 - return Class.forName("[Z").getName();
324.181 - }
324.182 -
324.183 - @Compare public String classForUnknownArray() {
324.184 - try {
324.185 - return Class.forName("[W").getName();
324.186 - } catch (Exception ex) {
324.187 - return ex.getClass().getName();
324.188 - }
324.189 - }
324.190 -
324.191 - @Compare public String classForUnknownDeepArray() {
324.192 - try {
324.193 - return Class.forName("[[[[[W").getName();
324.194 - } catch (Exception ex) {
324.195 - return ex.getClass().getName();
324.196 - }
324.197 - }
324.198 -
324.199 - @Compare public String componentGetNameForObjectArray() {
324.200 - return (new Object[3]).getClass().getComponentType().getName();
324.201 - }
324.202 - @Compare public boolean sameComponentGetNameForObjectArray() {
324.203 - return (new Object[3]).getClass().getComponentType() == Object.class;
324.204 - }
324.205 - @Compare public String componentGetNameForSimpleIntArray() {
324.206 - return (new int[3]).getClass().getComponentType().getName();
324.207 - }
324.208 - @Compare public String componentGetNameForMultiIntArray() {
324.209 - return (new int[3][4][5][6][7][8][9]).getClass().getComponentType().getName();
324.210 - }
324.211 - @Compare public String componentGetNameForMultiStringArray() {
324.212 - Class<?> c = (new String[3][4][5][6][7][8][9]).getClass();
324.213 - StringBuilder sb = new StringBuilder();
324.214 - for (;;) {
324.215 - sb.append(c.getName()).append("\n");
324.216 - c = c.getComponentType();
324.217 - if (c == null) {
324.218 - break;
324.219 - }
324.220 - }
324.221 - return sb.toString();
324.222 - }
324.223 -
324.224 - @Compare public boolean isArray() {
324.225 - return new Object[0].getClass().isArray();
324.226 - }
324.227 -
324.228 - @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;")
324.229 - private static String[] sort(String[] arr, int len) {
324.230 - List<String> list = Arrays.asList(arr).subList(0, len);
324.231 - Collections.sort(list);
324.232 - return list.toArray(new String[0]);
324.233 - }
324.234 -
324.235 - @JavaScriptBody(args = {}, body = "return new Object();")
324.236 - private static Object newObject() {
324.237 - return new Object();
324.238 - }
324.239 -
324.240 - @Factory
324.241 - public static Object[] create() {
324.242 - return VMTest.create(ReflectionTest.class);
324.243 - }
324.244 -
324.245 -}
325.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Wed Feb 27 17:50:47 2013 +0100
325.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
325.3 @@ -1,45 +0,0 @@
325.4 -/**
325.5 - * Back 2 Browser Bytecode Translator
325.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
325.7 - *
325.8 - * This program is free software: you can redistribute it and/or modify
325.9 - * it under the terms of the GNU General Public License as published by
325.10 - * the Free Software Foundation, version 2 of the License.
325.11 - *
325.12 - * This program is distributed in the hope that it will be useful,
325.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
325.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
325.15 - * GNU General Public License for more details.
325.16 - *
325.17 - * You should have received a copy of the GNU General Public License
325.18 - * along with this program. Look for COPYING file in the top folder.
325.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
325.20 - */
325.21 -package org.apidesign.bck2brwsr.tck;
325.22 -
325.23 -import java.io.InputStream;
325.24 -import org.apidesign.bck2brwsr.vmtest.Compare;
325.25 -import org.apidesign.bck2brwsr.vmtest.VMTest;
325.26 -import org.testng.annotations.Factory;
325.27 -
325.28 -/**
325.29 - *
325.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
325.31 - */
325.32 -public class ResourcesTest {
325.33 -
325.34 - @Compare public String readResourceAsStream() throws Exception {
325.35 - InputStream is = getClass().getResourceAsStream("Resources.txt");
325.36 - byte[] b = new byte[30];
325.37 - int len = is.read(b);
325.38 - StringBuilder sb = new StringBuilder();
325.39 - for (int i = 0; i < len; i++) {
325.40 - sb.append((char)b[i]);
325.41 - }
325.42 - return sb.toString();
325.43 - }
325.44 -
325.45 - @Factory public static Object[] create() {
325.46 - return VMTest.create(ResourcesTest.class);
325.47 - }
325.48 -}
326.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java Wed Feb 27 17:50:47 2013 +0100
326.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
326.3 @@ -1,102 +0,0 @@
326.4 -/**
326.5 - * Back 2 Browser Bytecode Translator
326.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
326.7 - *
326.8 - * This program is free software: you can redistribute it and/or modify
326.9 - * it under the terms of the GNU General Public License as published by
326.10 - * the Free Software Foundation, version 2 of the License.
326.11 - *
326.12 - * This program is distributed in the hope that it will be useful,
326.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
326.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
326.15 - * GNU General Public License for more details.
326.16 - *
326.17 - * You should have received a copy of the GNU General Public License
326.18 - * along with this program. Look for COPYING file in the top folder.
326.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
326.20 - */
326.21 -package org.apidesign.bck2brwsr.tck;
326.22 -
326.23 -import org.apidesign.bck2brwsr.vmtest.Compare;
326.24 -import org.apidesign.bck2brwsr.vmtest.VMTest;
326.25 -import org.testng.annotations.Factory;
326.26 -
326.27 -/**
326.28 - *
326.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
326.30 - */
326.31 -public class ShortArithmeticTest {
326.32 -
326.33 - private static short add(short x, short y) {
326.34 - return (short)(x + y);
326.35 - }
326.36 -
326.37 - private static short sub(short x, short y) {
326.38 - return (short)(x - y);
326.39 - }
326.40 -
326.41 - private static short mul(short x, short y) {
326.42 - return (short)(x * y);
326.43 - }
326.44 -
326.45 - private static short div(short x, short y) {
326.46 - return (short)(x / y);
326.47 - }
326.48 -
326.49 - private static short mod(short x, short y) {
326.50 - return (short)(x % y);
326.51 - }
326.52 -
326.53 - @Compare public short conversion() {
326.54 - return (short)123456;
326.55 - }
326.56 -
326.57 - @Compare public short addOverflow() {
326.58 - return add(Short.MAX_VALUE, (short)1);
326.59 - }
326.60 -
326.61 - @Compare public short subUnderflow() {
326.62 - return sub(Short.MIN_VALUE, (short)1);
326.63 - }
326.64 -
326.65 - @Compare public short addMaxShortAndMaxShort() {
326.66 - return add(Short.MAX_VALUE, Short.MAX_VALUE);
326.67 - }
326.68 -
326.69 - @Compare public short subMinShortAndMinShort() {
326.70 - return sub(Short.MIN_VALUE, Short.MIN_VALUE);
326.71 - }
326.72 -
326.73 - @Compare public short multiplyMaxShort() {
326.74 - return mul(Short.MAX_VALUE, (short)2);
326.75 - }
326.76 -
326.77 - @Compare public short multiplyMaxShortAndMaxShort() {
326.78 - return mul(Short.MAX_VALUE, Short.MAX_VALUE);
326.79 - }
326.80 -
326.81 - @Compare public short multiplyMinShort() {
326.82 - return mul(Short.MIN_VALUE, (short)2);
326.83 - }
326.84 -
326.85 - @Compare public short multiplyMinShortAndMinShort() {
326.86 - return mul(Short.MIN_VALUE, Short.MIN_VALUE);
326.87 - }
326.88 -
326.89 - @Compare public short multiplyPrecision() {
326.90 - return mul((short)17638, (short)1103);
326.91 - }
326.92 -
326.93 - @Compare public short division() {
326.94 - return div((short)1, (short)2);
326.95 - }
326.96 -
326.97 - @Compare public short divisionReminder() {
326.98 - return mod((short)1, (short)2);
326.99 - }
326.100 -
326.101 - @Factory
326.102 - public static Object[] create() {
326.103 - return VMTest.create(ShortArithmeticTest.class);
326.104 - }
326.105 -}
327.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Wed Feb 27 17:50:47 2013 +0100
327.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
327.3 @@ -1,31 +0,0 @@
327.4 -/**
327.5 - * Back 2 Browser Bytecode Translator
327.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
327.7 - *
327.8 - * This program is free software: you can redistribute it and/or modify
327.9 - * it under the terms of the GNU General Public License as published by
327.10 - * the Free Software Foundation, version 2 of the License.
327.11 - *
327.12 - * This program is distributed in the hope that it will be useful,
327.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
327.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
327.15 - * GNU General Public License for more details.
327.16 - *
327.17 - * You should have received a copy of the GNU General Public License
327.18 - * along with this program. Look for COPYING file in the top folder.
327.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
327.20 - */
327.21 -package org.apidesign.bck2brwsr.tck;
327.22 -
327.23 -class StaticUse {
327.24 - public static final Object NON_NULL = new Object();
327.25 - private StaticUse() {
327.26 - }
327.27 -
327.28 - public void instanceMethod() {
327.29 - }
327.30 -
327.31 - public static int plus(int a, int b) {
327.32 - return a + b;
327.33 - }
327.34 -}
328.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java Wed Feb 27 17:50:47 2013 +0100
328.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
328.3 @@ -1,41 +0,0 @@
328.4 -/**
328.5 - * Back 2 Browser Bytecode Translator
328.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
328.7 - *
328.8 - * This program is free software: you can redistribute it and/or modify
328.9 - * it under the terms of the GNU General Public License as published by
328.10 - * the Free Software Foundation, version 2 of the License.
328.11 - *
328.12 - * This program is distributed in the hope that it will be useful,
328.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
328.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
328.15 - * GNU General Public License for more details.
328.16 - *
328.17 - * You should have received a copy of the GNU General Public License
328.18 - * along with this program. Look for COPYING file in the top folder.
328.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
328.20 - */
328.21 -package org.apidesign.bck2brwsr.vmtest.impl;
328.22 -
328.23 -import java.io.UnsupportedEncodingException;
328.24 -import java.util.zip.CRC32;
328.25 -import org.apidesign.bck2brwsr.vmtest.Compare;
328.26 -import org.apidesign.bck2brwsr.vmtest.VMTest;
328.27 -import org.testng.annotations.Factory;
328.28 -
328.29 -/**
328.30 - *
328.31 - * @author Jaroslav Tulach <jtulach@netbeans.org>
328.32 - */
328.33 -public class CRC32Test {
328.34 -
328.35 - @Compare public long crc1() throws UnsupportedEncodingException {
328.36 - CRC32 crc = new CRC32();
328.37 - crc.update("Hello World!".getBytes("UTF-8"));
328.38 - return crc.getValue();
328.39 - }
328.40 -
328.41 - @Factory public static Object[] create() {
328.42 - return VMTest.create(CRC32Test.class);
328.43 - }
328.44 -}
329.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java Wed Feb 27 17:50:47 2013 +0100
329.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
329.3 @@ -1,67 +0,0 @@
329.4 -/**
329.5 - * Back 2 Browser Bytecode Translator
329.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
329.7 - *
329.8 - * This program is free software: you can redistribute it and/or modify
329.9 - * it under the terms of the GNU General Public License as published by
329.10 - * the Free Software Foundation, version 2 of the License.
329.11 - *
329.12 - * This program is distributed in the hope that it will be useful,
329.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
329.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
329.15 - * GNU General Public License for more details.
329.16 - *
329.17 - * You should have received a copy of the GNU General Public License
329.18 - * along with this program. Look for COPYING file in the top folder.
329.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
329.20 - */
329.21 -package org.apidesign.bck2brwsr.vmtest.impl;
329.22 -
329.23 -import java.io.ByteArrayInputStream;
329.24 -import java.io.IOException;
329.25 -import java.io.InputStream;
329.26 -import org.apidesign.bck2brwsr.emul.zip.FastJar;
329.27 -import org.testng.annotations.Test;
329.28 -import static org.testng.Assert.*;
329.29 -
329.30 -/**
329.31 - *
329.32 - * @author Jaroslav Tulach <jtulach@netbeans.org>
329.33 - */
329.34 -@GenerateZip(name = "five.zip", contents = {
329.35 - "1.txt", "one",
329.36 - "2.txt", "duo",
329.37 - "3.txt", "three",
329.38 - "4.txt", "four",
329.39 - "5.txt", "five"
329.40 -})
329.41 -public class ZipEntryTest {
329.42 - @Test
329.43 - public void readEntriesEffectively() throws IOException {
329.44 - InputStream is = ZipEntryTest.class.getResourceAsStream("five.zip");
329.45 - byte[] arr = new byte[is.available()];
329.46 - int len = is.read(arr);
329.47 - assertEquals(len, arr.length, "Read fully");
329.48 -
329.49 - FastJar fj = new FastJar(arr);
329.50 - FastJar.Entry[] entrs = fj.list();
329.51 -
329.52 - assertEquals(5, entrs.length, "Five entries");
329.53 -
329.54 - for (int i = 1; i <= 5; i++) {
329.55 - FastJar.Entry en = entrs[i - 1];
329.56 - assertEquals(en.name, i + ".txt");
329.57 -// assertEquals(cis.cnt, 0, "Content of the file should be skipped, not read");
329.58 - }
329.59 -
329.60 - assertContent("three", fj.getInputStream(entrs[3 - 1]), "read OK");
329.61 - assertContent("five", fj.getInputStream(entrs[5 - 1]), "read OK");
329.62 - }
329.63 -
329.64 - private static void assertContent(String exp, InputStream is, String msg) throws IOException {
329.65 - byte[] arr = new byte[512];
329.66 - int len = is.read(arr);
329.67 - String s = new String(arr, 0, len);
329.68 - assertEquals(exp, s, msg);
329.69 - }
329.70 -}
330.1 --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Wed Feb 27 17:50:47 2013 +0100
330.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
330.3 @@ -1,108 +0,0 @@
330.4 -/**
330.5 - * Back 2 Browser Bytecode Translator
330.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
330.7 - *
330.8 - * This program is free software: you can redistribute it and/or modify
330.9 - * it under the terms of the GNU General Public License as published by
330.10 - * the Free Software Foundation, version 2 of the License.
330.11 - *
330.12 - * This program is distributed in the hope that it will be useful,
330.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
330.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
330.15 - * GNU General Public License for more details.
330.16 - *
330.17 - * You should have received a copy of the GNU General Public License
330.18 - * along with this program. Look for COPYING file in the top folder.
330.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
330.20 - */
330.21 -package org.apidesign.bck2brwsr.vmtest.impl;
330.22 -
330.23 -import java.io.IOException;
330.24 -import java.io.InputStream;
330.25 -import java.util.Objects;
330.26 -import java.util.zip.ZipEntry;
330.27 -import java.util.zip.ZipInputStream;
330.28 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
330.29 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
330.30 -import org.apidesign.bck2brwsr.vmtest.Compare;
330.31 -import org.apidesign.bck2brwsr.vmtest.Http;
330.32 -import org.apidesign.bck2brwsr.vmtest.VMTest;
330.33 -import org.testng.annotations.Factory;
330.34 -
330.35 -/**
330.36 - *
330.37 - * @author Jaroslav Tulach <jtulach@netbeans.org>
330.38 - */
330.39 -@GenerateZip(name = "readAnEntry.zip", contents = {
330.40 - "my/main/file.txt", "Hello World!"
330.41 -})
330.42 -public class ZipFileTest {
330.43 -
330.44 - @Compare public String readAnEntry() throws IOException {
330.45 - InputStream is = ZipFileTest.class.getResourceAsStream("readAnEntry.zip");
330.46 - ZipInputStream zip = new ZipInputStream(is);
330.47 - ZipEntry entry = zip.getNextEntry();
330.48 - assertEquals(entry.getName(), "my/main/file.txt", "Correct entry");
330.49 -
330.50 - byte[] arr = new byte[4096];
330.51 - int len = zip.read(arr);
330.52 -
330.53 - assertEquals(zip.getNextEntry(), null, "No next entry");
330.54 -
330.55 - final String ret = new String(arr, 0, len, "UTF-8");
330.56 - return ret;
330.57 - }
330.58 -
330.59 - @JavaScriptBody(args = { "res", "path" }, body =
330.60 - "var myvm = bck2brwsr.apply(null, path);\n"
330.61 - + "var cls = myvm.loadClass('java.lang.String');\n"
330.62 - + "return cls.getClass__Ljava_lang_Class_2().getResourceAsStream__Ljava_io_InputStream_2Ljava_lang_String_2(res);\n"
330.63 - )
330.64 - private static native Object loadVMResource(String res, String...path);
330.65 -
330.66 - @Http({
330.67 - @Http.Resource(path = "/readAnEntry.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip")
330.68 - })
330.69 - @BrwsrTest public void canVmLoadResourceFromZip() throws IOException {
330.70 - Object res = loadVMResource("/my/main/file.txt", "/readAnEntry.jar");
330.71 - assert res instanceof InputStream : "Got array of bytes: " + res;
330.72 - InputStream is = (InputStream)res;
330.73 -
330.74 - byte[] arr = new byte[4096];
330.75 - int len = is.read(arr);
330.76 -
330.77 - final String ret = new String(arr, 0, len, "UTF-8");
330.78 -
330.79 - assertEquals(ret, "Hello World!", "Can read the bytes");
330.80 - }
330.81 -
330.82 - @GenerateZip(name = "cpattr.zip", contents = {
330.83 - "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n"
330.84 - + "Created-By: hand\n"
330.85 - + "Class-Path: realJar.jar\n\n\n"
330.86 - })
330.87 - @Http({
330.88 - @Http.Resource(path = "/readComplexEntry.jar", mimeType = "x-application/zip", content = "", resource="cpattr.zip"),
330.89 - @Http.Resource(path = "/realJar.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip"),
330.90 - })
330.91 - @BrwsrTest public void understandsClassPathAttr() throws IOException {
330.92 - Object res = loadVMResource("/my/main/file.txt", "/readComplexEntry.jar");
330.93 - assert res instanceof InputStream : "Got array of bytes: " + res;
330.94 - InputStream is = (InputStream)res;
330.95 -
330.96 - byte[] arr = new byte[4096];
330.97 - int len = is.read(arr);
330.98 -
330.99 - final String ret = new String(arr, 0, len, "UTF-8");
330.100 -
330.101 - assertEquals(ret, "Hello World!", "Can read the bytes from secondary JAR");
330.102 - }
330.103 -
330.104 - private static void assertEquals(Object real, Object exp, String msg) {
330.105 - assert Objects.equals(exp, real) : msg + " exp: " + exp + " real: " + real;
330.106 - }
330.107 -
330.108 - @Factory public static Object[] create() {
330.109 - return VMTest.create(ZipFileTest.class);
330.110 - }
330.111 -}
331.1 --- a/rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe Wed Feb 27 17:50:47 2013 +0100
331.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
331.3 @@ -1,1 +0,0 @@
331.4 -þ
331.5 \ No newline at end of file
332.1 --- a/rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt Wed Feb 27 17:50:47 2013 +0100
332.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
332.3 @@ -1,1 +0,0 @@
332.4 -Ahoj