001: package org.drools.brms.server.builder;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.IOException;
020: import java.io.StringReader;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.jar.JarInputStream;
025:
026: import org.drools.brms.client.common.AssetFormats;
027: import org.drools.brms.server.contenthandler.ContentHandler;
028: import org.drools.brms.server.contenthandler.IRuleAsset;
029: import org.drools.brms.server.selector.AssetSelector;
030: import org.drools.brms.server.selector.SelectorManager;
031: import org.drools.compiler.DroolsError;
032: import org.drools.compiler.DroolsParserException;
033: import org.drools.lang.descr.PackageDescr;
034: import org.drools.repository.AssetItem;
035: import org.drools.repository.AssetItemIterator;
036: import org.drools.repository.PackageItem;
037: import org.drools.repository.RulesRepositoryException;
038: import org.drools.repository.VersionableItem;
039: import org.drools.rule.Package;
040:
041: /**
042: * This assembles packages in the BRMS into binary package objects, and deals with errors etc.
043: * Each content type is responsible for contributing to the package.
044: *
045: * @author Michael Neale
046: */
047: public class ContentPackageAssembler {
048:
049: private PackageItem pkg;
050:
051: /**
052: * We accumulate errors here. If they come from the builder,
053: * then we reset the builders errors so as to not double report.
054: * It also means we can track errors to the exact asset that caused it.
055: */
056: private List<ContentAssemblyError> errors = new ArrayList<ContentAssemblyError>();
057:
058: BRMSPackageBuilder builder;
059:
060: private String selectorConfigName;
061:
062: /**
063: * Use this if you want to build the whole package.
064: */
065: public ContentPackageAssembler(PackageItem pkg) {
066: this (pkg, null);
067: }
068:
069: public ContentPackageAssembler(PackageItem pkg, boolean compile) {
070: this (pkg, compile, null);
071: }
072:
073: /**
074: * @param assetPackage The package.
075: * @param compile true if we want to build it. False and its just for looking at source.
076: */
077: public ContentPackageAssembler(PackageItem assetPackage,
078: boolean compile, String selectorConfigName) {
079: this .pkg = assetPackage;
080: this .selectorConfigName = selectorConfigName;
081: createBuilder();
082:
083: if (compile && preparePackage()) {
084: buildPackage();
085: }
086: }
087:
088: /**
089: * Use this if you want to build the whole package.
090: */
091: public ContentPackageAssembler(PackageItem assetPackage,
092: String selectorConfigName) {
093: this (assetPackage, true, selectorConfigName);
094: }
095:
096: /**
097: * Use this if you want to build and compile just the one asset.
098: */
099: public ContentPackageAssembler(AssetItem assetToBuild) {
100: this .pkg = assetToBuild.getPackage();
101: createBuilder();
102:
103: if (preparePackage()) {
104: buildAsset(assetToBuild);
105: }
106: }
107:
108: public void createBuilder() {
109: List<JarInputStream> jars = BRMSPackageBuilder.getJars(pkg);
110: builder = BRMSPackageBuilder.getInstance(jars);
111: }
112:
113: /**
114: * This will build the package.
115: */
116: private void buildPackage() {
117: AssetSelector selector = SelectorManager.getInstance()
118: .getSelector(selectorConfigName);
119: if (selector == null) {
120: this .errors.add(new ContentAssemblyError(this .pkg,
121: "The selector named " + selectorConfigName
122: + " is not available."));
123: return;
124: }
125: Iterator it = pkg.getAssets();
126: while (it.hasNext()) {
127:
128: AssetItem asset = (AssetItem) it.next();
129: if (!asset.isArchived() && (selector.isAssetAllowed(asset))) {
130: buildAsset(asset);
131: }
132: }
133: }
134:
135: /**
136: * Builds assets that are "rule" assets (ie things that are not functions etc).
137: */
138: private void buildAsset(AssetItem asset) {
139: ContentHandler h = ContentHandler.getHandler(asset.getFormat());
140: if (h instanceof IRuleAsset) {
141: try {
142: ((IRuleAsset) h).compile(builder, asset,
143: new ErrorLogger());
144: if (builder.hasErrors()) {
145: this .recordBuilderErrors(asset);
146: //clear the errors, so we don't double report.
147: builder.clearErrors();
148: }
149: } catch (DroolsParserException e) {
150: throw new RulesRepositoryException(e);
151: } catch (IOException e) {
152: throw new RulesRepositoryException(e);
153: }
154: }
155: }
156:
157: /**
158: * This prepares the package builder, loads the jars/classpath.
159: * @return true if everything is good to go, false if its all gone horribly wrong,
160: * and we can't even get the package header up.
161: */
162: private boolean preparePackage() {
163:
164: //firstly we loadup the classpath
165: builder.addPackage(new PackageDescr(pkg.getName()));
166:
167: //now we deal with the header (imports, templates, globals).
168: addDrl(pkg.getHeader());
169: if (builder.hasErrors()) {
170: recordBuilderErrors(pkg);
171: //if we have any failures, lets drop out now, no point in going
172: //any further
173: return false;
174: }
175:
176: loadDSLFiles();
177:
178: //finally, any functions we will load at this point.
179: AssetItemIterator it = this .pkg
180: .listAssetsByFormat(new String[] { AssetFormats.FUNCTION });
181: while (it.hasNext()) {
182: AssetItem func = (AssetItem) it.next();
183: addDrl(func.getContent());
184: if (builder.hasErrors()) {
185: recordBuilderErrors(func);
186: builder.clearErrors();
187: }
188: }
189:
190: return errors.size() == 0;
191: }
192:
193: private void loadDSLFiles() {
194: //now we load up the DSL files
195: builder.setDSLFiles(BRMSPackageBuilder.getDSLMappingFiles(pkg,
196: new BRMSPackageBuilder.DSLErrorEvent() {
197: public void recordError(AssetItem asset,
198: String message) {
199: errors.add(new ContentAssemblyError(asset,
200: message));
201: }
202: }));
203: }
204:
205: /**
206: * This will return true if there is an error in the package configuration or functions.
207: * @return
208: */
209: public boolean isPackageConfigurationInError() {
210: if (this .errors.size() > 0) {
211: return this .errors.get(0).itemInError instanceof PackageItem;
212: } else {
213: return false;
214: }
215: }
216:
217: private void addDrl(String drl) {
218: if ("".equals(drl)) {
219: return;
220: }
221: try {
222: builder.addPackageFromDrl(new StringReader(drl));
223: } catch (DroolsParserException e) {
224: throw new RulesRepositoryException(
225: "Unexpected error when parsing package.", e);
226: } catch (IOException e) {
227: throw new RulesRepositoryException(
228: "IO Exception occurred when parsing package.", e);
229: }
230: }
231:
232: /**
233: * This will accumulate the errors.
234: */
235: private void recordBuilderErrors(VersionableItem asset) {
236: DroolsError[] errs = builder.getErrors().getErrors();
237: for (int i = 0; i < errs.length; i++) {
238: this .errors.add(new ContentAssemblyError(asset, errs[i]
239: .getMessage()));
240: }
241:
242: }
243:
244: /**
245: * I've got a package people !
246: */
247: public Package getBinaryPackage() {
248: if (this .hasErrors()) {
249: throw new IllegalStateException(
250: "There is no package available, as there were errors.");
251: }
252: return builder.getPackage();
253: }
254:
255: public boolean hasErrors() {
256: return errors.size() > 0;
257: }
258:
259: public List<ContentAssemblyError> getErrors() {
260: return this .errors;
261: }
262:
263: /**
264: * This is passed in to the compilers so extra errors can be added.
265: *
266: * @author Michael Neale
267: */
268: public class ErrorLogger {
269: public void logError(ContentAssemblyError err) {
270: errors.add(err);
271: }
272: }
273:
274: public String getDRL() {
275: StringBuffer src = new StringBuffer();
276: src.append("package " + this .pkg.getName() + "\n");
277: src.append(this .pkg.getHeader() + "\n\n");
278:
279: //now we load up the DSL files
280: builder.setDSLFiles(BRMSPackageBuilder.getDSLMappingFiles(pkg,
281: new BRMSPackageBuilder.DSLErrorEvent() {
282: public void recordError(AssetItem asset,
283: String message) {
284: errors.add(new ContentAssemblyError(asset,
285: message));
286: }
287: }));
288:
289: //do the functions.
290: AssetItemIterator it = this .pkg
291: .listAssetsByFormat(new String[] { AssetFormats.FUNCTION });
292: while (it.hasNext()) {
293: AssetItem func = (AssetItem) it.next();
294: if (!func.isArchived()) {
295: src.append(func.getContent() + "\n\n");
296: }
297: }
298:
299: //now the rules
300: Iterator iter = pkg.getAssets();
301: while (iter.hasNext()) {
302: AssetItem asset = (AssetItem) iter.next();
303: if (!asset.isArchived()) {
304: ContentHandler h = ContentHandler.getHandler(asset
305: .getFormat());
306: if (h instanceof IRuleAsset) {
307: IRuleAsset ruleAsset = (IRuleAsset) h;
308: ruleAsset.assembleDRL(builder, asset, src);
309: }
310:
311: src.append("\n\n");
312: }
313: }
314:
315: return src.toString();
316: }
317:
318: }
|