Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for Android slim client #602

Merged
merged 9 commits into from
Jan 10, 2019
1 change: 1 addition & 0 deletions FitNesseRoot/FitNesse/ReleaseNotes/content.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
!2 ${FITNESSE_VERSION}
* Add support for Android Slim client ([[602][https://github.com/unclebob/fitnesse/pull/602]])
* Allow templates to access the current request ([[1174][https://github.com/unclebob/fitnesse/pull/1174]])

!2 20181224
Expand Down
18 changes: 18 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,23 @@ task standaloneJar(type: Jar) {
}
}

task slimJar(type: Jar) {
dependsOn jar
baseName = 'fitnesse'
classifier = 'slim'
from { jar.outputs.files.collect { zipTree(it) } }
{
include 'fitnesse/html/*.class'
include 'fitnesse/slim/**/*.class'
include 'fitnesse/socketservice/*.class'
include 'util/*.class'
include 'fitnesse/util/StringUtils.class'
}
manifest {
attributes("Implementation-Version": version)
}
}

task acceptanceTest(type: JavaExec) {
mustRunAfter test
onlyIf { test.didWork }
Expand Down Expand Up @@ -245,6 +262,7 @@ publishing {
artifact sourcesJar
artifact javadocJar
artifact standaloneJar
artifact slimJar
groupId 'org.fitnesse'
artifactId 'fitnesse'
pom.withXml {
Expand Down
19 changes: 10 additions & 9 deletions src/fitnesse/slim/converters/ConverterRegistry.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package fitnesse.slim.converters;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import fitnesse.slim.Converter;
import fitnesse.slim.converters.beans.JavaBeansConverterGateway;

import java.lang.reflect.ParameterizedType;
import java.util.*;

import fitnesse.slim.Converter;

public class ConverterRegistry {

private static final Map<Class<?>, Converter<?>> converters = new HashMap<>();
Expand All @@ -33,6 +32,9 @@ protected static void addStandardConverters() {
addConverter(Double.class, new DoubleConverter());
addConverter(double.class, new PrimitiveDoubleConverter());

addConverter(Long.class, new LongConverter());
addConverter(long.class, new PrimitiveLongConverter());

addConverter(Integer.class, new IntConverter());
addConverter(int.class, new PrimitiveIntConverter());

Expand Down Expand Up @@ -74,11 +76,10 @@ public static <T> Converter<T> getConverterForClass(Class<? extends T> clazz, Pa
return converterForInterface;
}

//use property editor
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
if (pe != null && !"EnumEditor".equals(pe.getClass().getSimpleName())) {
// com.sun.beans.EnumEditor and sun.beans.EnumEditor seem to be used in different usages.
return new PropertyEditorConverter<>(pe);
//use java beans property editor (does not work on Android)
Converter<T> javaBeansConverter = JavaBeansConverterGateway.getConverter(clazz);
if (javaBeansConverter != null) {
return javaBeansConverter;
}

//for enum, use generic enum converter
Expand Down
13 changes: 13 additions & 0 deletions src/fitnesse/slim/converters/LongConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fitnesse.slim.converters;

import fitnesse.slim.Converter;

public class LongConverter implements Converter<Long> {
public String toString(Long o) {
return o.toString();
}

public Long fromString(String arg) {
return Long.parseLong(arg);
}
}
11 changes: 11 additions & 0 deletions src/fitnesse/slim/converters/PrimitiveLongConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package fitnesse.slim.converters;

public class PrimitiveLongConverter extends LongConverter {
public static final Long DEFAULT_VALUE = Long.valueOf(0);

@Override
public Long fromString(String arg) {
Long i = super.fromString(arg);
return i != null ? i : DEFAULT_VALUE;
}
}
45 changes: 45 additions & 0 deletions src/fitnesse/slim/converters/beans/JavaBeansConverterGateway.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fitnesse.slim.converters.beans;

import fitnesse.slim.Converter;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Gateway providing converters based on Java Beans property editors.
* It uses reflection to call code which relies on the java.beans package,
* which is not available on Android.
* On Android these converters will not usable, i.e. #getConverter() will always return
* <code>null</code>.
*/
public class JavaBeansConverterGateway {
private static final Method javaBeansGetConverterMethod;

static {
Method getConverterMethod = null;
// java.beans is not available on Android, so we cannot use JavaBeansPropertyEditorConverterFactory
// directly but only via reflection
try {
Class<?> factory = Class.forName("fitnesse.slim.converters.beans.PropertyEditorConverterFactory");
getConverterMethod = factory.getMethod("getConverter", Class.class);
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
}
javaBeansGetConverterMethod = getConverterMethod;
}

private JavaBeansConverterGateway() {
}

@SuppressWarnings("unchecked")
public static <T> Converter<T> getConverter(Class<? extends T> clazz) {
if (javaBeansGetConverterMethod != null) {
try {
return (Converter<T>) javaBeansGetConverterMethod.invoke(null, clazz);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package fitnesse.slim.converters;

import java.beans.PropertyEditor;
package fitnesse.slim.converters.beans;

import fitnesse.slim.Converter;

import java.beans.PropertyEditor;

public class PropertyEditorConverter<T> implements Converter<T> {
private PropertyEditor editor;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package fitnesse.slim.converters.beans;

import fitnesse.slim.Converter;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;

/**
* Class to provide Converters based on JavaBeans PropertyEditors.
*
* (This class should not be referenced directly since java.beans package
* is not available on Android. It should only be called via reflection)
*/
public class PropertyEditorConverterFactory {

public static <T> Converter<T> getConverter(Class<?> clazz) {
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
if (pe != null && !"EnumEditor".equals(pe.getClass().getSimpleName())) {
// com.sun.beans.EnumEditor and sun.beans.EnumEditor seem to be used in different usages.
return new PropertyEditorConverter<>(pe);
}
return null;
}
}
25 changes: 17 additions & 8 deletions src/fitnesse/slim/instructions/SystemExitSecurityManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,24 @@ private SystemExitSecurityManager(SecurityManager delegate) {
* {@link SystemExitSecurityManager}.
*/
public static void activateIfWanted() {
if (isPreventSystemExit()) {
if (isPreventSystemExit() && !isAndroid()) {
SecurityManager currentSecMgr = System.getSecurityManager();
SystemExitSecurityManager systemExitSecurityManager = new SystemExitSecurityManager(
currentSecMgr);
System.setSecurityManager(systemExitSecurityManager);
tryUpdateSecurityManager(new SystemExitSecurityManager(currentSecMgr));
}
}

private static void tryUpdateSecurityManager(SecurityManager securityManager) {
try {
System.setSecurityManager(securityManager);
} catch (SecurityException e) {
System.err.println("Security manager could not be updated");
}
}

public static void restoreOriginalSecurityManager() {
SecurityManager currentSecMgr = System.getSecurityManager();
if (currentSecMgr != null
&& currentSecMgr instanceof SystemExitSecurityManager) {
SecurityManager originalSecurityManager = ((SystemExitSecurityManager) currentSecMgr).delegate;
System.setSecurityManager(originalSecurityManager);
if (currentSecMgr instanceof SystemExitSecurityManager) {
tryUpdateSecurityManager(((SystemExitSecurityManager) currentSecMgr).delegate);
}
}

Expand All @@ -50,6 +54,11 @@ private static boolean isPreventSystemExit() {
}
}

private static boolean isAndroid() {
String vendorUrl = System.getProperty("java.vendor.url", "");
return vendorUrl.toLowerCase().contains("android");
}

@Override
public void checkExit(int status) {
throw new SystemExitException("prevented system exit with exit code "
Expand Down
15 changes: 8 additions & 7 deletions test/fitnesse/slim/converters/ConverterRegistryTest.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package fitnesse.slim.converters;

import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.regex.Pattern;

import fitnesse.slim.Converter;
import fitnesse.slim.converters.beans.PropertyEditorConverter;
import fitnesse.slim.test.AnEnum;
import fitnesse.slim.test.AnotherEnum;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;

import fitnesse.slim.Converter;
import fitnesse.slim.test.AnEnum;
import fitnesse.slim.test.AnotherEnum;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.regex.Pattern;

import static org.junit.Assert.*;

public class ConverterRegistryTest {
Expand Down