블로그 이미지
올해목표 // 10월 어학연수 떠나자~ 자수씨

카테고리

전체글 (1457)
Brand New! (28)
주절주절 (213)
MOT (11)
해외쇼핑 (49)
쇼핑노트 (150)
취미생활 (94)
iPhone (4)
Eclipse (121)
Google (83)
Spring (31)
JAVA (176)
JavaScript (59)
WEB (49)
Database (20)
OS (26)
Tools (8)
Tips (26)
IT정보 (1)
Book (21)
Programming (37)
외부행사 (43)
주변인들 (17)
여행노트 (60)
학교생활 (30)
회사생활 (52)
사회생활 (5)
외국어공부 (12)
잡동사니 (30)
Total
Today
Yesterday
 
12-31 00:00
 

달력

« » 2024.12
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
 

최근에 올라온 글

최근에 달린 댓글

GWT로 엔터프라이즈 환경을 개발하려면 여러가지 문제점이 발생한다.

모 제약사 그룹웨어를 GWT로 개발하다보니 메인 모듈이 5~6개 정도로 구성이 되었는데

하나의 entry-point로 구성하기에는 소스크기가 너무 커지며 HTML로 컴파일하는데도

시간이 10여분이 걸리는 최악의 상황이 발생하기도 한다.

모듈별로 GWT 프로젝트 구성 (entry-point 분할하기)

Mail 모듈과 전자결재 모듈 간의 GWT를 통하여 작업을 처리할 일은 없을 것이다.

공통으로 사용하는 클래스들을 별도의 GWT 프로젝트로 구성하고 각각의 모듈에 대해서

GWT 프로젝트를 구성한 후 공통 프로젝트를 inherit 하는 형식으로 프로젝트를 구성한다.

이런식으로 나누어 컴파일 할 경우에는 결과물의 용량도 줄어들며 컴파일 시간도

많이 줄어들게 된다.

모듈별로 GWT 프로젝트를 분리할 경우 발생하는 문제는 엔터프라이즈 환경의 프로젝트는

혼자서 하는 것이 아니므로 CVS 나 SVN 과 같은 소스 서버를 사용할 경우 컴파일 결과가

동일한 이름으로 나오지 않기 때문에 관리에 어려움을 겪기도 한다.


컴파일 결과물 파일명 통일하기 (GWTCompiler 수정하기)

컴파일된 결과물 이름이 01C4D9CAEE45ACC08AEAA5EC3D15509D.cached.html 로 나오는데

버전관리가 안되는 것은 당연한 것이다. Mail 모듈은 MailModule.cached.html로 결과가 나오게 한다면

그 문제는 해결이 될 것이다.

GWTCompiler.java 파일을 다음과 같이 수정한다.

수정 전

	private String realizePermutation(TreeLogger logger,
			Property[] currentProps, String[] currentValues, int permNumber)
			throws UnableToCompleteException {
		String msg = "Analyzing permutation #" + permNumber;
		logger = logger.branch(TreeLogger.TRACE, msg, null);

		logProperties(logger, currentProps, currentValues);

		// Create a rebind oracle that will record decisions so that we can
		// cache
		// them and avoid future computations.
		//
		CompilationRebindOracle rebindOracle = new CompilationRebindOracle();

		// Tell the property provider above about the current property values.
		// Note that the rebindOracle is actually sensitive to these values
		// because
		// in its ctor is uses propOracle as its property oracle.
		//
		propOracle.setPropertyValues(currentProps, currentValues);

		// Check to see if we already have this compilation.
		// This will have the effect of filling the rebind oracle's cache.
		//
		String[] entryPts = module.getEntryPointTypeNames();
		Compilation cached = compilations.find(logger, rebindOracle, entryPts);
		if (cached != null) {
			msg = "Matches existing compilation " + cached.getStrongName();
			logger.log(TreeLogger.TRACE, msg, null);
			return cached.getStrongName();
		}

		// Now attach a compilation into which we can record the particular
		// inputs
		// and outputs used by this compile process.
		//
		Compilation compilation = new Compilation();
		rebindOracle.recordInto(compilation);

		// Create JavaScript.
		//
		String js = jjs.compile(logger, rebindOracle);

		// Create a wrapper and an unambiguous name for the file.
		//
		String strongName = writeHtmlAndJsWithStrongName(logger, js);

		// Write out a cache control file that correlates to this script.
		//
		compilation.setStrongName(strongName);
		writeCacheFile(logger, compilation);

		// Add this compilation to the list of known compilations.
		//
		compilations.add(compilation);
		return compilation.getStrongName();
	}

수정 후
	private String realizePermutation(TreeLogger logger,
			Property[] currentProps, String[] currentValues, int permNumber)
			throws UnableToCompleteException {
		String msg = "Analyzing permutation #" + permNumber;
		logger = logger.branch(TreeLogger.TRACE, msg, null);

		logProperties(logger, currentProps, currentValues);

		// Create a rebind oracle that will record decisions so that we can
		// cache
		// them and avoid future computations.
		//
		CompilationRebindOracle rebindOracle = new CompilationRebindOracle();

		// Tell the property provider above about the current property values.
		// Note that the rebindOracle is actually sensitive to these values
		// because
		// in its ctor is uses propOracle as its property oracle.
		//
		propOracle.setPropertyValues(currentProps, currentValues);

		// Check to see if we already have this compilation.
		// This will have the effect of filling the rebind oracle's cache.
		//
		String[] entryPts = module.getEntryPointTypeNames();
		Compilation cached = compilations.find(logger, rebindOracle, entryPts);
		if (cached != null) {
			msg = "Matches existing compilation " + cached.getStrongName();
			logger.log(TreeLogger.TRACE, msg, null);
			return cached.getStrongName();
		}

		// Now attach a compilation into which we can record the particular
		// inputs
		// and outputs used by this compile process.
		//
		Compilation compilation = new Compilation();
		rebindOracle.recordInto(compilation);

		// Create JavaScript.
		//
		String js = jjs.compile(logger, rebindOracle);

		String entryPointName = entryPts[0].substring(entryPts[0]
				.lastIndexOf(".") + 1);
		String name = entryPointName + "_" + currentValues[2] + "_"
				+ currentValues[3];

		String strongName = writeHtmlAndJsWithStrongName(logger, js, name);

		compilation.setStrongName(strongName);
		writeCacheFile(logger, compilation);

		// Add this compilation to the list of known compilations.
		//
		compilations.add(compilation);
		return compilation.getStrongName();
	}

	private String writeHtmlAndJsWithStrongName(TreeLogger logger, String js,
			String strongName) throws UnableToCompleteException {
		try {

			byte[] scriptBytes = js.getBytes("UTF-8");
			{
				byte[] prefix = getHtmlPrefix().getBytes("UTF-8");
				byte[] suffix = getHtmlSuffix().getBytes("UTF-8");
				File outFile = new File(outDir, strongName + ".cache.html");
				Util.writeBytesToFile(logger, outFile, new byte[][] { prefix,
						scriptBytes, suffix });
				String msg = "Compilation written to "
						+ outFile.getAbsolutePath();
				logger.log(TreeLogger.TRACE, msg, null);
			}
			{
				byte[] prefix = getJsPrefix().getBytes("UTF-8");
				byte[] suffix = getJsSuffix().getBytes("UTF-8");
				File outFile = new File(outDir, strongName + ".cache.js");
				Util.writeBytesToFile(logger, outFile, new byte[][] { prefix,
						scriptBytes, suffix });
				String msg = "Compilation written to "
						+ outFile.getAbsolutePath();
				logger.log(TreeLogger.TRACE, msg, null);
			}
			return strongName;
		} catch (UnsupportedEncodingException e) {
			logger.log(TreeLogger.ERROR,
					"Unable to encode compiled script as UTF-8", e);
			throw new UnableToCompleteException();
		}
	}
 
 알 수 없던 바이트코드의 조합이었던 파일 명을 entry-point의 이름과 언어 코드, 브라우저 종류의 조합으로

항상 같은 형식으로 결과가 나오게 변경하였다. ex) MailModule_default_ie6.cache.html

realizePermutation 메소드의 44~49번째 라인이 수정되었으며, writeHtmlAndJsWithStrongName 메소드는

기존 메소드를 바탕으로 파일을 만드는 부분을 수정하였다.



지난 1년 6개월 동안 GWT를 통하여 그룹웨어를 만들면서 느낀점이 많다.

다음번 프로젝트 때는 1년 6개월 간의 노하우로 더 좋은 프로젝트를 해보고 싶다.

Posted by 자수씨
, |

LocalServer Module
출처: http://code.google.com/apis/gears/api_localserver.html

네트워크 연결이 끊긴 상태에서도 웹 어플리케이션의 HTTP 리소스들을 로컬에 저장하고 제공해주는 역할을 한다.

Resource Stores
 - ResourceStore : 자바스크립트를 이용하여 임시의 URL들을 캡쳐링
 - ManagedResourceStore : manifest 파일에 선언된 URL들을 캡쳐링

Updating of cached resources
 - ManagedResourceStore는 manifest 파일의 버전이 변경될 경우 자동적으로 업데이트를 한다.
   (checkForUpdate() 메소드를 이용)
 - ResourceStore는 웹 어플리케이션에 의해 변경된다. (자동 업데이트 X)

Local serving of cached resources
 - LocalServer는 HTTP/HTTPS 요청을 캐싱된 데이터를 이용하여 상황에 맞게 제공해준다.
 - 네트워크 상태와는 상관없이 요청된 URL이 캐싱된 경우에는 캐싱된 리소스들로 처리한다.

LocalServer Class
 로컬서버는 Gears Factory를 통하여 생성된다.



ManagedResourceStore Class

ResourceStore Class

FileSubmitter Class

Manifest File

{
	// version of the manifest file format
	"betaManifestVersion": 1,

	// version of the set of resources described in this manifest file
	"version": "my_version_string",

	// optional
	// If the store specifies a requiredCookie, when a request would hit
	// an entry contained in the manifest except the requiredCookie is
	// not present, the local server responds with a redirect to this URL.
	"redirectUrl": "login.html",
	// URLs to be cached (URLs are given relative to the manifest URL)
	"entries": [
		{ "url": "main.html", "src": "main_offline.html" },
		{ "url": ".", "redirect": "main.html" },
		{ "url": "main.js" }
		{ "url": "formHandler.html", "ignoreQuery": true },
	]
}


Posted by 자수씨
, |

글 보관함

최근에 받은 트랙백