Główna » Google App Engine, Java, Polecane

Google AppEngine – kolejne schody…

12 October 2009 Brak komentarzy

AppEngine logo

Ech. Nie jest łatwo zaprzyjaźnić się z GAE. Ciągle jakieś schody…

Przed momentem odkryłem problem z dostępem za pomocą refleksji do java.util.TimeZone, chcąc wyświetlić listę stref czasowych.

Wszystko zaczęło się niewinnie, od atrybutu modelu, zawierającego przefiltrowane listy:

@ModelAttribute("timeZones")
public List<TimeZone> getTimeZones() {
    return TimeTools.TIME_ZONES;
}

i kodu jsp:

<form:select path="timeZoneID">
    <form:options items="${timeZones}" itemValue="id" itemLabel="displayName"/>
</form:select>

Po otwarciu tego JSP AppEngine wyrzuca błąd:

HTTP ERROR: 500
access denied (java.lang.RuntimePermission accessClassInPackage.sun.util.calendar)
RequestURI=/product/add.htm
Caused by:
java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.util.calendar)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at com.google.appengine.tools.development.DevAppServerFactory
$CustomSecurityManager.checkPermission(DevAppServerFactory.java:139)

Problem tkwi w tym, że form:options używa refleksji do pobrania pól id dla itemValue oraz displayName dla itemLabel. Więc jak potwierdza niniejszy bug powstaje problem…

Rozwiązanie?
Użyć wrappera dla TimeZone:

public class MyTimeZone {
 
    private String id;
    private String displayName;
 
    public MyTimeZone(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }
 
    public MyTimeZone(TimeZone timeZone) {
        id = timeZone.getID();
        displayName = timeZone.getDisplayName();
    }
 
    public String getId() {
        return id;
    }
 
    public String getDisplayName() {
        return displayName;
    }
}

i zmienić atrybut modelu na:

@ModelAttribute("timeZones")
public List<MyTimeZone> getTimeZones() {
    return TimeTools.TIME_ZONES;
}

A funkcja tworząca listę stref czasowych będzie wyglądać następująco:

public class TimeTools {
 
    private static final String TIMEZONE_ID_PREFIXES = "^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*";
    public static final List TIME_ZONES = new ArrayList();
 
    static {
        String[] timeZoneIds = TimeZone.getAvailableIDs();
        for (final String id : timeZoneIds)
            if (id.matches(TIMEZONE_ID_PREFIXES)) {
                TimeZone timeZone = TimeZone.getTimeZone(id);
                TIME_ZONES.add(new MyTimeZone(timeZone));
            }
 
        Collections.sort(TIME_ZONES, new Comparator() {
            public int compare(final MyTimeZone a, final MyTimeZone b) {
                return a.getId().compareTo(b.getId());
            }
        });
    }
}

Co jeszcze czeka mnie w walce z GAE? Zobaczymy niebawem :)

Zostaw odpowiedź!

Musisz się zalogować aby móc komentować.