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 파일을 다음과 같이 수정한다.
수정 전01 | private String realizePermutation(TreeLogger logger, |
02 | Property[] currentProps, String[] currentValues, int permNumber) |
03 | throws UnableToCompleteException { |
04 | String msg = "Analyzing permutation #" + permNumber; |
05 | logger = logger.branch(TreeLogger.TRACE, msg, null ); |
07 | logProperties(logger, currentProps, currentValues); |
13 | CompilationRebindOracle rebindOracle = new CompilationRebindOracle(); |
20 | propOracle.setPropertyValues(currentProps, currentValues); |
25 | String[] entryPts = module.getEntryPointTypeNames(); |
26 | Compilation cached = compilations.find(logger, rebindOracle, entryPts); |
28 | msg = "Matches existing compilation " + cached.getStrongName(); |
29 | logger.log(TreeLogger.TRACE, msg, null ); |
30 | return cached.getStrongName(); |
37 | Compilation compilation = new Compilation(); |
38 | rebindOracle.recordInto(compilation); |
42 | String js = jjs.compile(logger, rebindOracle); |
46 | String strongName = writeHtmlAndJsWithStrongName(logger, js); |
50 | compilation.setStrongName(strongName); |
51 | writeCacheFile(logger, compilation); |
55 | compilations.add(compilation); |
56 | 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개월 간의 노하우로 더 좋은 프로젝트를 해보고 싶다.