- 개요
- GAE 제약 사항
- GAE for Python 개발 환경
- GAE for Java 개발 환경
- GAE for Java의 주요 기능
- Google App Engine for Java 개요
- Memcache
- Blobstore
- Persistence
- Logging
- SSO with Google Apps
- GAE for Biz
- Google Web Toolkit
- 개발자 매뉴얼
- Query
- 참고 문헌
Google App Engine(GAE)을 정리 한다.
Java Doc
다운로드 :
라이선스 :
플랫폼 : Google App Engine, Java/Python
개요
LXC (LinuX Container)를 대체하는 Google의 Container에서 동작
2008년 4월 : GAE/P (Google App Engine for Python) 서비스 개시
2009년 4월 : GAE/J (Google App Engine for Java) 서비스 개시
가격 정책
500MB storage 무료
월 5백만 page view는 무료
계정당 10개의 애플리케이션 등록 가능
추가 용량에 따른 과금 정책
서비스 운영 유형
appspot.com 도메인을 사용하여 애플리케이션 서비스
Google Apps에서 애플리케이션 서비스
자신의 도메인으로 서비스가 가능함
GAE 제약 사항
Google App Engine Quotas : GAE의 Quotas가 모두 정리되어 있다.
Time-Out에 빠지지 않도록 GAE 내의 애플리케이션을 가볍게 작성 한다.
Blobstore는 GAE/J에 대해서 과금을 할 경우에만 사용할 수 있다.
com.google.apphosting.api.ApiProxy$FeatureNotEnabledException:
The Blobstore API will be enabled for this application once billing has been enabled in the admin console.
Socket을 사용할 수 없다.
GAE for Python 개발 환경
2008년 4월 GAE의 개발 환경을 Python 개발자에게도 공개, 현재 Python 2.5 지원
GAE for Java 개발 환경
GAE for Java의 주요 기능
appengine-api-1.0-sdk-1.3.6.jar 사용
Google App Engine for Java 개요
Java 개발 환경 (JavaScript, Ruby), Python 개발 환경
Google App Engine SDK 1.3.1 for Java
Google App Engine SDK 1.3.1 for Python
Google Plugin for Eclipse : Google App Engine, Google WebToolkit 1.7
Database : A set of properties (key-value)
JDO (Java Data Object), JPA (Java Persistence API)
App Engine Service : URL Fetch(java.net), Mail(JavaMail), Memcache, Image Manipulation
Scheduled Tasks and Task Queues
GAE 개발 환경
GAE (Google App Engine) 기반 개발
GAE 1.3.2
GAE에서 지원하는 Java Technologies
GWT (Google Web Toolkit) 기반 개발
GAE에 적용된 버전 : GWT 2.0.3, 2010.4
주의 : GWT를 사용하여 Eclipse에서 테스트하기 위해서는 브라우저에 GWT 개발 도구(plugin)이 설치되어야 한다.
표준 Java API
Java 6 VM
Servlet 2.5 Container
javax.net.URLConnection for URLFetch API
javax.mail for Mail API
JSR 107 for Memcache API : Key-value pair mapping
Application Service
사용자 인증 및 권한 부여 : ServletFilter, Spring Security에서 활용 가능
Cron
데이터 가져오기/내보내기 : Google Bigtable 기반 Database
방화벽 데이터에 대한 액세스
기타 환경
HTTP Session support
JDO/JPA for Database API : GQL (Google Query Language)
제약 사항
Only 1000 files per application
A web request must respond in 30 senconds otherwise GAE throw DeadlineExceededException
Memcache
package com.jopenbusiness.gae.sample;
import java.util.HashMap;
import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;
public class Memcache {
private static Cache cache = null;
@SuppressWarnings("unchecked")
public Memcache() {
CacheFactory factory = null;
try {
factory = CacheManager.getInstance().getCacheFactory();
cache = factory.createCache(new HashMap());
cache.put("name", "value");
cache.get("name");
} catch (CacheException e) {
e.printStackTrace();
}
}
}
Blobstore
Blobstore는 GAE/J에 대해서 과금을 할 경우에만 사용할 수 있다.
com.google.apphosting.api.ApiProxy$FeatureNotEnabledException:
The Blobstore API will be enabled for this application once billing has been enabled in the admin console.
Persistence
GAE for Java는 데이터 관리를 위해 JDO(Java Data Objects)와 JPA(Java Persistence API)를 지원한다. User 데이터 관리를 예제로 하여 이를 확인해 보자.
User.java
저장할 데이터를 어노테이션을 사용하여 식별한다.
package com.jopenbusiness.gae.client;
import java.io.Serializable;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
'''@PersistenceCapable(identityType = IdentityType.APPLICATION)'''
public class User implements Serializable {
private static final long serialVersionUID = 3438684493254005858L;
'''@PrimaryKey'''
'''@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)'''
private long id = 0l;
'''@Persistent'''
private String name = null;
'''@Persistent'''
private String username = null;
'''@Persistent'''
private String password = null;
'''@Persistent'''
private String email = null;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
UserDAO.java
package com.jopenbusiness.gae.server;
import java.util.ArrayList;
import com.jopenbusiness.gae.client.User;
public interface UserDAO {
void insertUser(User user);
void updateUser(User user);
void deleteUser(User user);
ArrayList selectUsers();
}
UserDAOJdo.java
PersistenceManager를 사용하여 데이터를 관리 한다.
package com.jopenbusiness.gae.server;
import java.util.ArrayList;
import javax.jdo.PersistenceManager;
import com.jopenbusiness.gae.client.User;
import com.jopenbusiness.gae.server.PMF;
public class UserDAOJdo implements UserDAO {
@Override
public void insertUser(User user) {
PersistenceManager pm = null;
try {
pm = PMF.getPersistenceManager();
pm.makePersistent(user);
} finally {
pm.close();
}
}
@Override
public void updateUser(User user) {
PersistenceManager pm = null;
User tmpUser = null;
try {
pm = PMF.getPersistenceManager();
pm.currentTransaction().begin();
tmpUser = pm.getObjectById(User.class, user.getId());
tmpUser.setName(user.getName());
tmpUser.setUsername(user.getUsername());
tmpUser.setPassword(user.getPassword());
tmpUser.setEmail(user.getEmail());
pm.makePersistent(tmpUser);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
@Override
public void deleteUser(User user) {
PersistenceManager pm = null;
try {
pm = PMF.getPersistenceManager();
pm.currentTransaction().begin();
user = pm.getObjectById(User.class, user.getId());
pm.deletePersistent(user);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
@Override
@SuppressWarnings("unchecked")
public ArrayList selectUsers() {
PersistenceManager pm = null;
String query = null;
pm = PMF.getPersistenceManager();
query = "select from " + User.class.getName();
return (ArrayList) pm.newQuery(query).execute();
}
}
PMF.java
PersistenceManagerFactory가 자원을 많이 차지하므로 유일하게 관리 한다.
package com.jopenbusiness.gae.server;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
public class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
private PMF() {
}
public static PersistenceManagerFactory get() {
return pmfInstance;
}
public static PersistenceManager getPersistenceManager() {
return pmfInstance.getPersistenceManager();
}
}
/src/META-INF/jdoconfig.xml
persistence-manager-factory를 정의 한다.
Logging
import java.util.logging.Level;
import java.util.logging.Logger;
private final static Logger log = Logger.getLogger(Memcache.class.getName());
log.log(Level.WARNING, "Start Memcache");
SSO with Google Apps
사용자가 접속할 때 보여줄 첫 화면
index.jsp
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" language="java"%>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
<%
UserService userService = null;
User user = null;
String domain = "jopenbusiness.co.kr";
String service = "http://www.jopenbusiness.co.kr/";
userService = UserServiceFactory.getUserService();
if (!userService.isUserLoggedIn()) {
out.print("");
return;
}
user = userService.getCurrentUser();
//user = (User) request.getAttribute("user");
if ((user == null) || (!user.getAuthDomain().equals(domain))) {
out.print("");
return;
}
out.print("");
%>
로그인된 사용자의 정보를 반환하는 화면
Google Apps의 각각의 서비스에서 로그아웃을 하면 Google Apps만 로그아웃됨
userService.createLogoutURL(loginURL)이 생성하는 URL로 로그아웃 요청을 하면 전체 서비스가 로그아웃됨
checkSSO.jsp
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" language="java"%>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
<%
UserService userService = null;
User user = null;
String domain = "jopenbusiness.co.kr";
String service = "http://www.jopenbusiness.co.kr/";
String loginURL = "http://www.jopenbusiness.co.kr/index.jsp";
userService = UserServiceFactory.getUserService();
if (!userService.isUserLoggedIn()) {
out.print("{");
out.print("errorCode:\"-1\",");
out.print("errorMessage:\"Error: not login.\"");
out.print("}");
return;
}
user = userService.getCurrentUser();
//user = (User) request.getAttribute("user");
if ((user == null) || (!user.getAuthDomain().equals(domain))) {
out.print("{");
out.print("errorCode:\"-2\",");
out.print("errorMessage:\"Error: authDomain not match.\"");
out.print("}");
return;
}
out.print("{");
out.print("errorCode:\"0\",");
out.print("errorMessage:\"OK\",");
out.print("authDomain:\"" + user.getAuthDomain() + "\",");
out.print("email:\"" + user.getEmail() + "\",");
out.print("userId:\"" + user.getUserId() + "\",");
out.print("nickname:\"" + user.getNickname() + "\",");
out.print("loginURL:\"" + userService.createLoginURL(loginURL) + "\",");
out.print("logoutURL:\"" + userService.createLogoutURL(loginURL) + "\"");
out.print("}");
%>
GAE for Biz
기업용 Google App Engine
SQL을 지원하는 Database 제공 예정
비용
1인당 월 $8, 최대 $1000
Google Web Toolkit
GWT는 Java를 JavaScript로 컴파일 하여 브라우저에서 실행(AJAX Application)할 수 있도록 하는 도구로 성능적인 부분에서 최적화되어 있다.
주의 : GWT를 사용하여 Eclipse에서 테스트하기 위해서는 브라우저에 GWT 개발 도구(plugin)이 설치되어야 한다.
참고 문헌
개발자 매뉴얼
Query
/war/WEB-INF/datastore-indexes.xml
참고 문헌
GAE - Google Groups : 오류 사항을 검색할 수 있음
Google App Engine Java Experiments : GAE/J 용 책을 편 사람의 블로그
Manual
[Design pattern](Design pattern.md)
http://www.slideshare.net/curioe_/lezhincomics-google-appengine-30453946
[[Category:Google|Category:Google]]
[[Category:Cloud|Category:Cloud]]
분류: Java