Adds some JCL dependencies required by html4j

This commit is contained in:
konsoletyper 2014-02-28 13:40:55 +04:00
parent 9e37304fdf
commit ce4f6dc5d5
12 changed files with 2270 additions and 32 deletions

View File

@ -0,0 +1,85 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.io;
import org.teavm.classlib.java.lang.TMath;
import org.teavm.classlib.java.lang.TString;
import org.teavm.classlib.java.util.TArrays;
import org.teavm.javascript.ni.Rename;
/**
*
* @author Alexey Andreev
*/
public class TByteArrayOutputStream extends TOutputStream {
protected byte[] buf;
protected int count;
public TByteArrayOutputStream() {
this(32);
}
public TByteArrayOutputStream(int size) {
buf = new byte[size];
}
@Override
public void write(int b) {
ensureCapacity(count + 1);
buf[count++] = (byte)b;
}
@Override
public void write(byte[] b, int off, int len) {
ensureCapacity(count + len);
for (int i = 0; i < len; ++i) {
buf[count++] = b[off++];
}
}
private void ensureCapacity(int capacity) {
if (buf.length < capacity) {
capacity = TMath.min(capacity, buf.length * 3 / 2);
buf = TArrays.copyOf(buf, capacity);
}
}
public byte[] toByteArray() {
return TArrays.copyOf(buf, count);
}
@Override
@Rename("toString")
public TString toString0() {
return new TString(buf, 0, count);
}
public TString toString(TString charsetName) throws TUnsupportedEncodingException {
return new TString(buf, 0, count, charsetName);
}
public void writeTo(TOutputStream out) throws TIOException {
out.write(buf, 0, count);
}
public void reset() {
count = 0;
}
public int size() {
return count;
}
}

View File

@ -64,11 +64,26 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
}
protected TAbstractStringBuilder append(TString string) {
return insert(length, string);
}
protected TAbstractStringBuilder insert(int index, TString string) {
if (index < 0 || index > length) {
throw new TStringIndexOutOfBoundsException();
}
if (string == null) {
string = TString.wrap("null");
} else if (string.isEmpty()) {
return this;
}
ensureCapacity(length + string.length());
int j = length;
if (index < length) {
for (int i = length - 1; i >= index; --i) {
buffer[i + string.length()] = buffer[i];
}
length += string.length();
}
int j = index;
for (int i = 0; i < string.length(); ++i) {
buffer[j++] = string.charAt(i);
}
@ -588,4 +603,16 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
public void setLength(int newLength) {
length = newLength;
}
public TAbstractStringBuilder deleteCharAt(int index) {
if (index < 0 || index >= length) {
throw new TStringIndexOutOfBoundsException();
}
length--;
for (int i = index; i < length; ++i) {
buffer[i] = buffer[i + 1];
}
--length;
return this;
}
}

View File

@ -100,6 +100,14 @@ public class TCharacter extends TObject {
return digit < 10 ? (char)('0' + digit) : (char)('a' + digit - 10);
}
public static boolean isDigit(char ch) {
return isDigit((int)ch);
}
public static boolean isDigit(int codePoint) {
return digit(codePoint) >= 0;
}
private static int[] getDigitMapping() {
if (digitMapping == null) {
digitMapping = UnicodeHelper.decodeIntByte(obtainDigitMapping());
@ -129,4 +137,12 @@ public class TCharacter extends TObject {
return new char[] { (char)codePoint };
}
}
public static boolean isISOControl(char ch) {
return isISOControl((int)ch);
}
public static boolean isISOControl(int codePoint) {
return codePoint >= 0 && codePoint <= 0x1F || codePoint >= 0x7F && codePoint <= 0x9F;
}
}

View File

@ -103,4 +103,16 @@ public class TStringBuilder extends TAbstractStringBuilder implements TAppendabl
super.append(b);
return this;
}
@Override
public TStringBuilder deleteCharAt(int index) {
deleteCharAt(index);
return this;
}
@Override
public TStringBuilder insert(int index, TString string) {
super.insert(index, string);
return this;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.net;
import org.teavm.classlib.java.io.TByteArrayOutputStream;
import org.teavm.classlib.java.lang.TCharacter;
import org.teavm.classlib.java.lang.TIllegalArgumentException;
import org.teavm.classlib.java.lang.TString;
import org.teavm.classlib.java.lang.TStringBuilder;
/**
* This class is used to encode a string using the format required by {@code
* application/x-www-form-urlencoded} MIME content type. It contains helper
* methods used by the URI class, and performs encoding and decoding in a
* slightly different way than {@code URLEncoder} and {@code URLDecoder}.
*/
class TURIEncoderDecoder {
static final TString digits = TString.wrap("0123456789ABCDEF");
/**
* Validate a string by checking if it contains any characters other than:
* 1. letters ('a'..'z', 'A'..'Z') 2. numbers ('0'..'9') 3. characters in
* the legalset parameter 4. others (unicode characters that are not in
* US-ASCII set, and are not ISO Control or are not ISO Space characters)
* <p>
* called from {@code URI.Helper.parseURI()} to validate each component
*
* @param s
* {@code java.lang.String} the string to be validated
* @param legal
* {@code java.lang.String} the characters allowed in the String
* s
*/
static void validate(TString s, TString legal) throws TURISyntaxException {
for (int i = 0; i < s.length();) {
char ch = s.charAt(i);
if (ch == '%') {
do {
if (i + 2 >= s.length()) {
throw new TURISyntaxException(s, TString.wrap(""), i);
}
int d1 = TCharacter.digit(s.charAt(i + 1), 16);
int d2 = TCharacter.digit(s.charAt(i + 2), 16);
if (d1 == -1 || d2 == -1) {
throw new TURISyntaxException(s, TString.wrap(""), i);
}
i += 3;
} while (i < s.length() && s.charAt(i) == '%');
continue;
}
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1 || (ch > 127
&& !isSpaceChar(ch) && !TCharacter.isISOControl(ch)))) {
throw new TURISyntaxException(s, TString.wrap(""), i); //$NON-NLS-1$
}
i++;
}
}
private static boolean isSpaceChar(char c) {
switch (c) {
case ' ':
case '\t':
return true;
default:
return false;
}
}
static void validateSimple(TString s, TString legal)
throws TURISyntaxException {
for (int i = 0; i < s.length();) {
char ch = s.charAt(i);
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1)) {
throw new TURISyntaxException(s, TString.wrap(""), i); //$NON-NLS-1$
}
i++;
}
}
/**
* All characters except letters ('a'..'z', 'A'..'Z') and numbers ('0'..'9')
* and legal characters are converted into their hexidecimal value prepended
* by '%'.
* <p>
* For example: '#' -> %23
* Other characters, which are unicode chars that are not US-ASCII, and are
* not ISO Control or are not ISO Space chars, are preserved.
* <p>
* Called from {@code URI.quoteComponent()} (for multiple argument
* constructors)
*
* @param s
* java.lang.String the string to be converted
* @param legal
* java.lang.String the characters allowed to be preserved in the
* string s
* @return java.lang.String the converted string
*/
static TString quoteIllegal(TString s, TString legal) {
TStringBuilder buf = new TStringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if ((ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| legal.indexOf(ch) > -1
|| (ch > 127 && !isSpaceChar(ch) && !TCharacter.isISOControl(ch))) {
buf.append(ch);
} else {
byte[] bytes = new TString(new char[] { ch }).getBytes();
for (int j = 0; j < bytes.length; j++) {
buf.append('%');
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
buf.append(digits.charAt(bytes[j] & 0xf));
}
}
}
return TString.wrap(buf.toString());
}
/**
* Other characters, which are Unicode chars that are not US-ASCII, and are
* not ISO Control or are not ISO Space chars are not preserved. They are
* converted into their hexidecimal value prepended by '%'.
* <p>
* For example: Euro currency symbol -> "%E2%82%AC".
* <p>
* Called from URI.toASCIIString()
*
* @param s
* java.lang.String the string to be converted
* @return java.lang.String the converted string
*/
static TString encodeOthers(TString s) {
TStringBuilder buf = new TStringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch <= 127) {
buf.append(ch);
} else {
byte[] bytes = new TString(new char[] { ch }).getBytes();
for (int j = 0; j < bytes.length; j++) {
buf.append('%');
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
buf.append(digits.charAt(bytes[j] & 0xf));
}
}
}
return TString.wrap(buf.toString());
}
/**
* Decodes the string argument which is assumed to be encoded in the {@code
* x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
* <p>
*'%' and two following hex digit characters are converted to the
* equivalent byte value. All other characters are passed through
* unmodified.
* <p>
* e.g. "A%20B%20C %24%25" -> "A B C $%"
* <p>
* Called from URI.getXYZ() methods
*
* @param s
* java.lang.String The encoded string.
* @return java.lang.String The decoded version.
*/
static TString decode(TString s) {
TStringBuilder result = new TStringBuilder();
TByteArrayOutputStream out = new TByteArrayOutputStream();
for (int i = 0; i < s.length();) {
char c = s.charAt(i);
if (c == '%') {
out.reset();
do {
if (i + 2 >= s.length()) {
throw new TIllegalArgumentException();
}
int d1 = TCharacter.digit(s.charAt(i + 1), 16);
int d2 = TCharacter.digit(s.charAt(i + 2), 16);
if (d1 == -1 || d2 == -1) {
throw new TIllegalArgumentException();
}
out.write((byte) ((d1 << 4) + d2));
i += 3;
} while (i < s.length() && s.charAt(i) == '%');
result.append(TString.wrap(out.toString()));
continue;
}
result.append(c);
i++;
}
return TString.wrap(result.toString());
}
}

View File

@ -0,0 +1,134 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.net;
import org.teavm.classlib.java.lang.TException;
import org.teavm.classlib.java.lang.TIllegalArgumentException;
import org.teavm.classlib.java.lang.TNullPointerException;
import org.teavm.classlib.java.lang.TString;
import org.teavm.javascript.ni.Rename;
/**
* A {@code URISyntaxException} will be thrown if some information could not be parsed
* while creating a URI.
*/
public class TURISyntaxException extends TException {
private static final long serialVersionUID = 2137979680897488891L;
private TString input;
private int index;
/**
* Constructs a new {@code URISyntaxException} instance containing the
* string that caused the exception, a description of the problem and the
* index at which the error occurred.
*
* @param input
* the string that caused the exception.
* @param reason
* the reason why the exception occurred.
* @param index
* the position where the exception occurred.
* @throws NullPointerException
* if one of the arguments {@code input} or {@code reason} is
* {@code null}.
* @throws IllegalArgumentException
* if the value for {@code index} is lesser than {@code -1}.
*/
public TURISyntaxException(TString input, TString reason, int index) {
super(reason);
if (input == null || reason == null) {
throw new TNullPointerException();
}
if (index < -1) {
throw new TIllegalArgumentException();
}
this.input = input;
this.index = index;
}
/**
* Constructs a new {@code URISyntaxException} instance containing the
* string that caused the exception and a description of the problem.
*
*@param input
* the string that caused the exception.
* @param reason
* the reason why the exception occurred.
* @throws NullPointerException
* if one of the arguments {@code input} or {@code reason} is
* {@code null}.
*/
public TURISyntaxException(TString input, TString reason) {
super(reason);
if (input == null || reason == null) {
throw new TNullPointerException();
}
this.input = input;
index = -1;
}
/**
* Gets the index at which the syntax error was found or {@code -1} if the
* index is unknown/unavailable.
*
* @return the index of the syntax error.
*/
public int getIndex() {
return index;
}
/**
* Gets a description of the syntax error.
*
* @return the string describing the syntax error.
*/
public TString getReason() {
return TString.wrap(super.getMessage());
}
/**
* Gets the initial string that contains an invalid syntax.
*
* @return the string that caused the exception.
*/
public TString getInput() {
return input;
}
/**
* Gets a description of the exception, including the reason, the string
* that caused the syntax error and the position of the syntax error if
* available.
*
* @return a sting containing information about the exception.
* @see java.lang.Throwable#getMessage()
*/
@Override
@Rename("getMessage")
public TString getMessage0() {
return TString.wrap("");
}
}

View File

@ -164,6 +164,9 @@ public class DependencyChecker implements DependencyInfo {
}
public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) {
if (methodRef == null) {
throw new IllegalArgumentException();
}
stacks.putIfAbsent(methodRef, stack);
return methodCache.map(methodRef);
}

View File

@ -21,7 +21,7 @@ $rt_compare = function(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
}
$rt_isInstance = function(obj, cls) {
return $rt_isAssignable(obj.constructor, cls);
return obj != null && $rt_isAssignable(obj.constructor, cls);
}
$rt_isAssignable = function(from, to) {
if (from === to) {

View File

@ -27,5 +27,6 @@ public class HTML4JPlugin implements JavascriptBuilderPlugin {
public void install(JavascriptBuilderHost host) {
host.add(new JavaScriptBodyDependency());
host.add(new JavaScriptBodyTransformer());
host.add(new JCLHacks());
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.html4j;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class JCLHacks implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
if (cls.getName().equals("java.lang.Thread")) {
installThreadMethods(cls);
}
}
private void installThreadMethods(ClassHolder cls) {
cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setName",
ValueType.object("java.lang.String"), ValueType.VOID), false));
cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("start",
ValueType.VOID), false));
cls.addMethod(createMethodThrowingSecurityException(new MethodDescriptor("setDaemon",
ValueType.BOOLEAN, ValueType.VOID), false));
cls.addMethod(createThreadSleep());
}
private MethodHolder createMethodThrowingSecurityException(MethodDescriptor desc, boolean staticMethod) {
MethodHolder method = new MethodHolder(desc);
Program program = new Program();
for (int i = 0; i < desc.parameterCount(); ++i) {
program.createVariable();
}
if (!staticMethod) {
program.createVariable();
}
program.createVariable();
Variable var = program.createVariable();
BasicBlock block = program.createBasicBlock();
ConstructInstruction cons = new ConstructInstruction();
cons.setType("java.lang.SecurityException");
cons.setReceiver(var);
block.getInstructions().add(cons);
InvokeInstruction invoke = new InvokeInstruction();
invoke.setType(InvocationType.SPECIAL);
invoke.setInstance(var);
invoke.setMethod(new MethodReference("java.lang.SecurityException", "<init>", ValueType.VOID));
block.getInstructions().add(invoke);
RaiseInstruction raise = new RaiseInstruction();
raise.setException(var);
block.getInstructions().add(raise);
if (staticMethod) {
method.getModifiers().add(ElementModifier.STATIC);
}
method.setLevel(AccessLevel.PUBLIC);
method.setProgram(program);
return method;
}
private MethodHolder createThreadSleep() {
MethodHolder method = new MethodHolder("sleep", ValueType.LONG, ValueType.VOID);
Program program = new Program();
program.createVariable();
program.createVariable();
BasicBlock block = program.createBasicBlock();
ExitInstruction exit = new ExitInstruction();
block.getInstructions().add(exit);
method.setProgram(program);
method.setLevel(AccessLevel.PUBLIC);
method.getModifiers().add(ElementModifier.STATIC);
return method;
}
}

View File

@ -42,18 +42,17 @@
*/
package org.teavm.html4j.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import net.java.html.BrwsrCtx;
import net.java.html.js.JavaScriptBody;
import org.apidesign.html.boot.spi.Fn;
import org.apidesign.html.context.spi.Contexts;
import org.apidesign.html.json.spi.JSONCall;
import org.apidesign.html.json.spi.Technology;
import org.apidesign.html.json.spi.Transfer;
import org.apidesign.html.json.tck.KnockoutTCK;
@ -64,9 +63,11 @@ import org.testng.Assert;
*
* @author Jaroslav Tulach <jtulach@netbeans.org>
*/
public final class KnockoutFXTest extends KnockoutTCK {
public final class KnockoutFXTest extends KnockoutTCK implements Transfer {
private static Class<?> browserClass;
private static Fn.Presenter browserContext;
private KO4J ko4j = new KO4J();
private Map<String, String> urlMap = new HashMap<>();
public KnockoutFXTest() {
}
@ -98,8 +99,8 @@ public final class KnockoutFXTest extends KnockoutTCK {
public BrwsrCtx createContext() {
KO4J ko4j = new KO4J();
return Contexts.newBuilder()
.register(Transfer.class, ko4j.transfer(), 1)
.register(Technology.class, new KO4J().knockout(), 1)
.register(Transfer.class, this, 1)
.register(Technology.class, ko4j.knockout(), 1)
.build();
}
@ -137,23 +138,9 @@ public final class KnockoutFXTest extends KnockoutTCK {
@Override
public URI prepareURL(String content, String mimeType, String[] parameters) {
try {
final URL baseURL = new URL(findBaseURL());
StringBuilder sb = new StringBuilder();
sb.append("/dynamic?mimeType=").append(mimeType);
for (int i = 0; i < parameters.length; i++) {
sb.append("&param" + i).append("=").append(parameters[i]);
}
String mangle = content.replace("\n", "%0a")
.replace("\"", "\\\"").replace(" ", "%20");
sb.append("&content=").append(mangle);
URL query = new URL(baseURL, sb.toString());
URLConnection c = query.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
URI connectTo = new URI(br.readLine());
return connectTo;
} catch (IOException ex) {
throw new IllegalStateException(ex);
String url = "http://localhost/dynamic/" + urlMap.size();
urlMap.put(url, content);
return new URI(url);
} catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
@ -161,12 +148,27 @@ public final class KnockoutFXTest extends KnockoutTCK {
@Override
public boolean canFailWebSocketTest() {
try {
Class.forName("java.util.function.Function");
return false;
} catch (ClassNotFoundException ex) {
// running on JDK7, FX WebView WebSocket impl does not work
return true;
return true;
}
@Override
public void extract(Object obj, String[] props, Object[] values) {
ko4j.transfer().extract(obj, props, values);
}
@Override
public Object toJSON(InputStream is) throws IOException {
return ko4j.transfer().toJSON(is);
}
@Override
public void loadJSON(JSONCall call) {
String url = call.composeURL(null);
String data = urlMap.get(url);
if (data != null) {
call.notifySuccess(data);
} else {
call.notifyError(new IllegalStateException());
}
}
}