티스토리 툴바


Eclipse + GAE class hot deploy

2011/05/20 17:23 | Posted by 포데브(엄지사랑) 엄지사랑
개발환경: JDK1.6.0_24 + Eclipse Helios SR2 + appengine-java-sdk-1.5.0 + Googel App Engine for Eclipe 

서블릿 클래스를 아무리 변경해도 반영이 안되고 서버를 재시작해야 반영이 되었다.
분명 클래스의 변경은 서버 재시작과 상관이 없다고 했거늘....

그런데 서버를 시작하는 방법이 이상했다. 많은 곳에서 서버를 시작할 때 [Debug As]로 실행하는 것이 아닌가? 나는 Debug는 안할 거니 [Run As]로 실행했다. 

이런! 바로 이 차이가 서블릿 클래스의 변화를 감지하지 못하는 원인이 었다.
즉, Debug As로 서버를 시작해야 서블릿 클래스 등 클래스의 변화를 감지하여 서버 재시작과 무관하게 되는 것이 었다. 

결론: GAE는 Debug As로 실행시켜라!

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

GAE/J(Google App Engine for Java)에서 JPA를 사용할 때 지원되지 않는 것들

2009/09/23 11:51 | Posted by 포데브(엄지사랑) 엄지사랑
GAE/J와 DataStore(DataNuclues)를 접한지 일주일이 되었다.
처음엔 Maven을 적용하나라 고생했고 다음엔 Spring + Struts2를 적용하느라 삽질하고
이제좀 적응되려나 싶었는데 JPA때문에 또 힘들어 졌다.

Unsupported Features of JPA

The following features of the JPA interface are not supported by the App Engine implementation:

  • Owned many-to-many relationships, andunowned relationships. You can implement unowned relationships usingexplicit Key values, though type checking is not enforced in the API.
  • "Join"queries. You cannot use a field of a child entity in a filter whenperforming a query on the parent kind. Note that you can test theparent's relationship field directly in query using a key.
  • Aggregation queries (group by, having, sum, avg, max, min)
  • Polymorphicqueries. You cannot perform a query of a class to get instances of asubclass. Each class is represented by a separate entity kind in thedatastore.

http://code.google.com/intl/ko-KR/appengine/docs/java/datastore/usingjpa.html#Unsupported_Features_of_JPA 참고

이런 문제가 있다고 하니 이정도는 감수하려고 했다. 그런데 진행도중 다름과 같은 예외가 발생한다는 것을 디버깅해서(예외를 던져주지 않아서...) 알게 되었다.

Problem with query <SELECT count(entity.name) cnt FROM NameCard entity WHERE entity.name LIKE :name>: Unsupported method <matches> while parsing expression: InvokeExpression{[PrimaryExpression{name}].matches(ParameterExpression{name})}

위의 JPQL은 그닥 어렵지 않은 쿼리이다. 그런데 왜 동작하지 않을까?...
열심히 구글링을 한 결과 DataStore 라는 BigTable은 LIKE를 지원하지 않는다고 한다.

http://blog.newsplore.com/2009/06/06/reviewing-google-appengine-for-java-part-2

를 참고하기 바란다.

위의 사이트 내용중 DataStore의 제한사항(limitation)을 보면 아래와 같다.

1. LIKE 지원 안함
org.datanucleus.store.appengine.query.DatastoreQuery$UnsupportedDatastoreFeatureException:Problem with query : Unsupported method <upper> while parsing expression: InvokeExpression {[null].upper(PrimaryExpression {station, usState})}

org.datanucleus.store.appengine.query.DatastoreQuery$UnsupportedDatastoreOperatorException:Problem with query <SELECT station FROM com.newsplore.weather.bo.Station station WHERE UPPER(station.name) LIKE :stationName ORDER BY station.name>: App Engine datastore does not support operator  LIKE

2. PK로 int 타입을 사용할 수 없다. (내가 해본결과 long 타입도 안된다.) Long 으로 대체해야만한다.
3. JPA 쿼리는 클래의 완전한 경로명을 필요로 한다. select의 from 절에 사용할 때(지금은 약식명(SimpleName)을 사용해도 된다.)
4. 처음으로 어떤 엔티티를 액세스할때 일치하지 않는 NullPointerException이 발생한다.
ERROR MainHandlerExceptionResolver:18  Exception processing page: Name is null
java.lang.NullPointerException: Name is null
    at java.lang.Enum.valueOf(Enum.java:195)
    at com.google.appengine.api.datastore.dev.
CompositeIndexManager$IndexSource.valueOf(CompositeIndexManager.java:64)

이후 엔티티를 재요청하면 정상 페치된다.

5. 복합키를 수락하지 않는다. <== 요거는 확인해 봐야 겠다.  안되면 안되는데...
6. java.sql.TImestamp를 지원하지 않는다. 아래예외는 해당타입을 포함한 엔티티를 액세스할 때 발생한 것이다.
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: java.sql.Timestamp is not a supported property type.; nested exception is java.lang.IllegalArgumentException: java.sql.Timestamp is not a supported property type.]

7. 유니크 제약(uniqueness constraints)을 지원하지 않는다.
8. @ManyToOne 관계를 생성할 수 없다. <== 음 난 생성되었는데 좀더 해봐야 겠다.
9. Not equals(<>, !=)와 IN 연산자를 지원하지 않는다. <== 정말??.. IN은 그렇다쳐도

위의 내용을 내가 모두 테스트한 것은 아니므로 정말 모두 안되는지는 잘 모르겠다.
참고한 글이 쓰여진때가 2009.06.06 인걸로 보면 지금으로부터 3개월 전의 내용인데
제법 일치하지 않을까 조심스럽게 판단해본다.
위의 내용이 사실이 아니기를 아니면 언젠가 지원된다는 희망이라도 있었으면 하는 바램이다.
저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

Struts 2 ONGL issue on Google App Engine

2009/09/19 15:04 | Posted by 포데브(엄지사랑) 엄지사랑
GAE/J(Google App Engine for Java)는 매우 높은 보안 환경을 제공하고 있어서 struts2를 사용할 때 OgnlRuntime security manager를 변경해줘야 한다.

아래는 보안관리자때문에 속성을 설정하려고 할때 메소드에 접근할 수 없다는 예외가 발생한 결과를 보여주고 있다.

ognl.MethodFailedException: Method "setNameCardId" failed for object kr.nextree.ncbcrm.action.NameCardController@14e40da [java.lang.IllegalAccessException: Method [public void kr.nextree.ncbcrm.action.NameCardController.setNameCardId(long)]
cannot be accessed.]   
    at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:823)
    at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:823)
    at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)
    at ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:75)
    at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:131)
    at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:28)
    at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)
    at com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor.setProperty(CompoundRootAccessor.java:50)
    at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)
    at ognl.ASTProperty.setValueBody(ASTProperty.java:101)
    at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
    at ognl.SimpleNode.setValue(SimpleNode.java:246)
    at ognl.Ognl.setValue(Ognl.java:476)


이것을 해결하기 위해서는 security manager를 null로 설정한 listener를 추가해줘야한다.

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import ognl.OgnlRuntime;

/**
 * OgnlRuntime 보안관리자를 널로 설정하는 Servlet 리스너
 * @author <a href="mailto:byleem@nextree.co.kr">임병인</a>
 * @since 2009. 9. 17.
 */
public class ONGLFixListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {

    /** UID */
    private static final long serialVersionUID = 6090732506717974395L;

    /**
     * 기본생성자
     */
    public ONGLFixListener() {
        // nothing to do.
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce) {
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce) {
        OgnlRuntime.setSecurityManager(null);
    }
...


그런다음 web.xml에 아래와 같이 추가한다.

  <listener>
    <description>To change the OgnlRuntime security manager</description>
    <listener-class>kr.nextree.ncbcrm.util.ONGLFixListener</listener-class>
  </listener>


참고 :
http://programmingpanda.blogspot.com/2009/07/struts-2-ongl-issue-on-google-app.html
저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

GAE/J runserver : java.lang.NoClassDefFoundError: javax/jdo/metadata/TypeMetadata

2009/09/17 10:05 | Posted by 포데브(엄지사랑) 엄지사랑
GAE/J(Google App Engine for Java) + maven2 + spring + struts2 를 이용하여 프로젝트를 진행하는 도중에 제목과 같은 에러를 만나 더이상 진행하기 어려웠다.

의외로 해결방법은 간단했다.

http://www.jpox.org/servlet/forum/viewthread_thread,5723#30932

에서 그 해결방법을 찾을 수 있으며 그 내용은 아래와 같다.

use jdo2-api-2.3-eb

<dependency>
  <groupId>javax.jdo</groupId>
  <artifactId>jdo2-api</artifactId>
  <version>2.3-eb</version>
  <!-- architype으로 생성하면 2.3-ea 버전을 사용하고 있다  -->
</dependency>


from http://www.datanucleus.org/downloads/maven2/
저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License
이전 1 다음