﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-hengheng123456789-随笔分类-JAVA-BI</title><link>http://www.blogjava.net/hengheng123456789/category/17304.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 04 Sep 2007 22:24:14 GMT</lastBuildDate><pubDate>Tue, 04 Sep 2007 22:24:14 GMT</pubDate><ttl>60</ttl><item><title>Give Your Business Logic a Framework with Drools</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142399.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 09:40:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142399.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142399.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142399.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142399.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142399.html</trackback:ping><description><![CDATA[<p>Most web and enterprise Java applications can be split into three parts: a front end to talk to the user, a service layer to talk to back-end systems such as databases, and business logic in between. While it is now common practice to use frameworks for both front- and back-end requirements (e.g., Struts, Cocoon, Spring, Hibernate, JDO, and Entity Beans), there is no standard way of structuring business logic. Frameworks like EJB and Spring do this at a high level, but don't help us in organizing our code. Wouldn't it would be great if we could replace messy, tangled <code>if</code>...<code>then</code> statements with a framework that gave us the same benefits of configurability, readability, and reuse that we already enjoy in other areas? This article suggests using the <a href="http://www.drools.org/">Drools rules engine</a> as a framework to solve the problem.</p>
<p>The sample code below gives a sample of the problem we're trying to avoid. It shows some business logic in a typical Java application.</p>
<br />
if ((user.isMemberOf(AdministratorGroup)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; user.isMemberOf(teleworkerGroup))<br />
&nbsp;&nbsp;&nbsp;&nbsp; || user.isSuperUser(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // more checks for specific cases<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((expenseRequest.code().equals("B203")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ||(expenseRequest.code().equals("A903")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp;(totalExpenses&lt;200)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp;(bossSignOff&gt; totalExpenses))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp;(deptBudget.notExceeded)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //issue payments<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //check lots of other conditions<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp; // even more business logic<br />
}<br />
<br />
<p>We've all come across similar (or even more complex) business logic. While this has been the standard way of implementing business logic in Java, there are many problems with it.</p>
<ul>
    <li>What if the business users come up with another form ("C987") that needs to be added to the already hard-to-understand code? Would you want to be the person to maintain it, once all of the original programmers had moved on?
    <li>How do we check that these rules are correct? It's hard enough for technical people--never mind commercial folks--to review. Do we have any methodical way of testing this business logic?
    <li>Many applications have similar business rules--if one of the rules change, can we be sure that it is changed consistently across all systems? If a new application uses some of these rules, but also adds some new ones, do we need to rewrite all of the logic from scratch?
    <li>Is the business logic easily configurable, not so firmly tied to Java code that we need to recompile/redeploy every time that a small change is made?
    <li>What if other (scripting) languages want to leverage the existing investment in business rule logic? </li>
</ul>
<br />
<p>J2EE/EJB and "inversion of control" frameworks (such as Spring, Pico, and Avalon) give us the ability to organize our code at a high level. While they are very good at providing reusability, configuration, and security, none of them would replace the "<a href="http://en.wikipedia.org/wiki/Spaghetti_code">spaghetti code</a>" in the above example. Ideally, whatever framework we choose will be compatible with not only J2EE applications, but also "normal" Java (J2SE--Standard Edition) programs, and most of the widely used presentation and persistence frameworks. Such a framework should allow us to do the following:</p>
<ul>
    <li>Business users should be able to easily read and verify the business logic.
    <li>Business rules should be reusable and configurable across applications.
    <li>The framework should be scalable and performant under heavy load.
    <li>It should be as easy to use for Java programmers as existing front-end (Struts, Spring) and back-end (object-relational mapping) frameworks. </li>
</ul>
<p>An additional problem is that while there are only so many ways to organize web pages and database access, business logic tends to differ widely between applications. Our framework should be able to cope with this and still promote code reuse. Ideally, our application would be "frameworks all the way down." By using frameworks in this way, we can a large amount of our application "out of the box," allowing us to write only the parts that add value for the customer.</p>
<h3>Rule Engines to the Rescue</h3>
<p>How are we going to solve this problem? One solution that is gaining traction is to use a <em>rule engine</em>. Rule engines are frameworks for organizing business logic that allow the developer to concentrate on things that are known to be true, rather than the low-level mechanics of making decisions.</p>
<p>Often, business users are more comfortable with expressing things that they know to be true, than to express things in an <code>if</code>...<code>then</code> format. Examples of things that you might hear from a business expert are:</p>
<ul>
    <li>"FORM 10A is used for expense claims over 200 Euro."
    <li>"We only trade shares in quantities of 10,000 or more."
    <li>"Purchases over €10m need the approval of a company director." </li>
</ul>
<p>By focusing on what we know to be true, rather than the mechanics of how to express it in Java code, the above statements are clearer than our previous code sample. Still, clear as they may be, we still need a mechanism to apply these rules to the facts that we know and get a decision. Such a mechanism is a rule engine.</p>
<br />
<h3>Rule Engines in Java</h3>
<p><a href="http://javaboutique.internet.com/tutorials/rules_engine/">JSR 94</a>, the <code>javax.rules</code> API, sets a common standard for interacting with rule engines, much as JDBC allows us to interact with varying databases. What JSR-94 does not specify is how the actual rules are written, leaving plenty of choice among the most widely used Java rule engines:</p>
<br />
<ul>
    <li><a href="http://herzberg.ca.sandia.gov/jess/index.shtml">Jess</a> is perhaps the most mature Java rule engine, with good tool support (including Eclipse plugins) and documentation. However it is a commercial product, and it writes its rules in a Prolog-style notation, which can be intimidating for many Java programmers.
    <li><a href="http://jena.sourceforge.net/">Jena</a> is an open source framework, originally from HP. While it has a rules engine, and is especially strong for those interested in the Semantic Web, it is not fully JSR-94-compliant.
    <li><a href="http://www.drools.org/">Drools</a> is a JSR-94-complaint rules engine, and is fully open source under an "Apache-style" license. Not only does it express rules in familiar Java and XML syntax, it has a strong user and developer community. For the examples in this article, we'll be using Drools, as it has the easiest to use Java-like syntax and it has the most open license. </li>
</ul>
<h3>Starting a Java Application using Drools</h3>
<p>Imagine this scenario: minutes after reading this article, your boss asks your to prototype a stock trading application. As the business users still haven't fully defined the business logic, you think it a good idea to implement it using a rules engine. The final system will be accessible over an intranet and will need to communicate with back-end database and messaging systems. To get started, download the Drools framework (with dependencies). Create a new project in your favorite IDE and make sure all of the .jars are referenced in it, as per Figure 1. This screenshot is Eclipse-based, but the setup will be similar for other IDEs.</p>
<p><img height="406" alt="Libraries needed to Run Drools" src="http://www.onjava.com/onjava/2005/08/03/graphics/diagramA1.gif" width="369" /><br />
<em>Figure 1. Libraries needed to run Drools</em></p>
<p>Due to the huge potential losses if our stock trading system went amok, it's vital that we have some sort of simulator to put our system through its paces. Such a simulator also gives you confidence that the decisions made by the system are those that are intended, even after rule changes are made. We'll borrow some tools from the Agile toolbox and use <a href="http://www.junit.org/">JUnit</a> as a framework for our simulations.</p>
<p>The first code we write is the JUnit Test/simulator, as per the following listing. Even if we can't test every combination of values likely to be input into our application, some tests are better than none at all. In this example, all of our files and classes (including unit tests) are in one folder/package, but in reality, you would implement a proper package and folder structure. We'd also use Log4j instead of the <code>System.out</code> calls in the sample code.</p>
<pre><code>
import junit.framework.TestCase;
/*
* JUnit test for the business rules in the
* application.
*
* This also acts a 'simulator' for the business
* rules - allowing us to specify the inputs,
* examine the outputs and see if they match our
* expectations before letting the code loose in
* the real world.
*/
public class BusinessRuleTest extends TestCase {
/**
* Tests the purchase of a stock
*/
public void testStockBuy() throws Exception{
//Create a Stock with simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue(
testOffer.getRecommendPurchase()!=null);
assertTrue("YES".equals(
testOffer.getRecommendPurchase()));
}
}
</code>
</pre>
<br />
<p>This is a basic JUnit test, as we know that our (very simple!) system should buy all stocks with a price of less than 100 Euro. Obviously, this won't compile without our data holding class (<em>StockOffer.java</em>) and our business layer class (<em>BusinessLayer.java</em>). These are provided in the following listings.</p>
<br />
<pre>/**
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
*/
public class BusinessLayer {
/**
* Evaluate whether or not it is a good idea
* to purchase this stock.
* @param stockToBuy
* @return true if the recommendation is to buy
*   the stock, false if otherwise
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy){
return false;
}
}
</pre>
<p>The <code>StockOffer</code> class looks like this:</p>
<pre>/**
* Simple JavaBean to hold StockOffer values.
* A 'Stock offer' is an offer (from somebody else)
* to sell us a Stock (or Company share).
*/
public class StockOffer {
//constants
public final static String YES="YES";
public final static String NO="NO";
//Internal Variables
private String stockName =null;
private int stockPrice=0;
private int stockQuantity=0;
private String recommendPurchase = null;
/**
* @return Returns the stockName.
*/
public String getStockName() {
return stockName;
}
/**
* @param stockName The stockName to set.
*/
public void setStockName(String stockName) {
this.stockName = stockName;
}
/**
* @return Returns the stockPrice.
*/
public int getStockPrice() {
return stockPrice;
}
/**
* @param stockPrice The stockPrice to set.
*/
public void setStockPrice(int stockPrice) {
this.stockPrice = stockPrice;
}
/**
* @return Returns the stockQuantity.
*/
public int getStockQuantity() {
return stockQuantity;
}
/**
* @param stockQuantity to set.
*/
public void setStockQuantity(int stockQuantity){
this.stockQuantity = stockQuantity;
}
/**
* @return Returns the recommendPurchase.
*/
public String getRecommendPurchase() {
return recommendPurchase;
}
}
</pre>
<br />
<p>We run <code>BusinessRuleTest</code> through the JUnit extension of our favorite IDE. If you're not familiar with JUnit, more information can be found at <a href="http://www.junit.org/">JUnit's website</a>. Not surprisingly, our test fails at the second assertion, shown in Figure 2, as we don't (yet) have the appropriate business logic in place. This is reassuring, as it shows that our simulator/unit tests are highlighting the problems that they should.</p>
<br />
<br clear="all" />
<!-- me -->
<p><img height="325" alt="JUnit Test Results" src="http://www.onjava.com/onjava/2005/08/03/graphics/diagramA2.gif" width="390" /><br />
<em>Figure 2. JUnit test results</em></p>
<h3>Writing the Business Logic using Rules</h3>
<p>At this point, we need to write some business logic that says, "If the stock price is less than 100 Euro, then we should buy it." To do this, we will modify <em>BusinessLayer.java</em> to read:</p>
<pre><code>
import java.io.IOException;
import org.drools.DroolsException;
import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.event.DebugWorkingMemoryEventListener;
import org.drools.io.RuleBaseLoader;
import org.xml.sax.SAXException;
/**
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
* @author default
*/
public class BusinessLayer {
//Name of the file containing the rules
private static final String BUSINESS_RULE_FILE=
"BusinessRules.drl";
//Internal handle to rule base
private static RuleBase businessRules = null;
/**
* Load the business rules if we have not
* already done so.
* @throws Exception - normally we try to
*          recover from these
*/
private static void loadRules()
throws Exception{
if (businessRules==null){
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE ) );
}
}
/**
* Evaluate whether or not to purchase stock.
* @param stockToBuy
* @return true if the recommendation is to buy
* @throws Exception
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy) throws Exception{
//Ensure that the business rules are loaded
loadRules();
//Some logging of what is going on
System.out.println( "FIRE RULES" );
System.out.println( "----------" );
//Clear any state from previous runs
WorkingMemory workingMemory
= businessRules.newWorkingMemory();
//Small ruleset, OK to add a debug listener
workingMemory.addEventListener(
new DebugWorkingMemoryEventListener());
//Let the rule engine know about the facts
workingMemory.assertObject(stockToBuy);
//Let the rule engine do its stuff!!
workingMemory.fireAllRules();
}
}</code>
</pre>
<br />
<p>This class now has some important methods:</p>
<!-- sidebar begins --><!-- don't move sidebars --><!-- sidebar ends -->
<ul>
    <li><code>loadRules()</code>, which loads the rules from the <em>BusinessRules.drl</em> file.
    <li>An updated <code>evaluateStockPurchase()</code>, which evaluates these business rules. Some points to note about this method are:
    <ul>
        <li>We can reuse the same <code>RuleSet</code> over and over (as business rules in memory are stateless).
        <li>We use a new <code>WorkingMemory</code> for every evaluation, as this is our knowledge of what we know to be true at this time. We use <code>assertObject()</code> to place known facts (as Java <code>Object</code>s) into this memory.
        <li>Drools has an event listener model, to allow us to "see" what is going on within the event model. Here we use it to print debug information. </li>
    </ul>
    <li>The <code>fireAllRules()</code> method on the working memory class causes the rules to be evaluated and updated (in this case, stock offer). </li>
</ul>
<p>Before we can run the example again, we need to create our <em>BusinessRules.drl</em> file, as follows:</p>
<pre><code>
&lt;?xml version="1.0"?&gt;
&lt;rule-set name="BusinessRulesSample"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs
="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation
="http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd"&gt;
&lt;!-- Import the Java Objects that we refer
to in our rules --&gt;
&lt;java:import&gt;
java.lang.Object
&lt;/java:import&gt;
&lt;java:import&gt;
java.lang.String
&lt;/java:import&gt;
&lt;java:import&gt;
net.firstpartners.rp.StockOffer
&lt;/java:import&gt;
&lt;!-- A Java (Utility) function we reference
in our rules--&gt;
&lt;java:functions&gt;
public void printStock(
net.firstpartners.rp.StockOffer stock)
{
System.out.println("Name:"
+stock.getStockName()
+" Price: "+stock.getStockPrice()
+" BUY:"
+stock.getRecommendPurchase());
}
&lt;/java:functions&gt;
&lt;rule-set&gt;
&lt;!-- Ensure stock price is not too high--&gt;
&lt;rule name="Stock Price Low Enough"&gt;
&lt;!-- Params to pass to business rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter&gt;
&lt;!-- Conditions or 'Left Hand Side'
(LHS) that must be met for
business rule to fire --&gt;
&lt;!-- note markup --&gt;
&lt;java:condition&gt;
stockOffer.getRecommendPurchase() == null
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &lt; 100
&lt;/java:condition&gt;
&lt;!-- What happens when the business
rule is activated --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase(
StockOffer.YES);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
&lt;/rule-set&gt;
</code>
</pre>
<p>This rules file has several interesting parts:</p>
<ul>
    <li>Just after the XML-Schema definitions come the Java objects we reference in our rules. These objects can come from any Java library as required.
    <li>Next comes our functions, which can incorporate standard Java code. In this case, we incorporate a logging function to help us see what is going on.
    <li>After that comes our rule set, consisting of one or more rules.
    <li>Each rule can take parameters (the <code>StockOffer</code> class), one or more conditions that need to be fulfilled, and a consequence that is carried out if and when the conditions are met. </li>
</ul>
<p>Having modified and compiled our code, we run the JUnit test simulations again. This time, the business rules are called, our logic evaluates correctly, and our tests pass, as seen in Figure 3. Congratulations--you've just built your first rule-based application!</p>
<p><img height="102" alt="Successful JUnit Test" src="http://www.onjava.com/onjava/2005/08/03/graphics/diagramA3.gif" width="393" /><br />
<em>Figure 3. Successful JUnit test</em></p>
<br />
<h3>Smarter Rules</h3>
<p>Fresh from building the application, you demonstrate the prototype above to the business users, and they remember a few more rules that they forgot to mention earlier. One of the new rules is that we shouldn't trade stocks where the quantity is a negative number (&lt;0). "No problem," you say, and return to your desk, secure in the knowledge that you can quickly evolve your system.</p>
<p>The first thing you do is to update your simulator, and add the following code to <em>BusinessRuleTest.java</em>:</p>
<pre><code>
/**
* Tests the purchase of a stock
* makes sure the system will not accept
* negative numbers.
*/
public void testNegativeStockBuy()
throws Exception{
//Create a Stock with our simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(-22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer
.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue("NO".equals(
testOffer.getRecommendPurchase()));
}</code>
</pre>
<p>This tests for the new rule described by the business users. If we run this JUnit test, our new test fails, as expected. We need to add a new rule to our .drl file, as follows.</p>
<pre><code>
&lt;!-- Ensure that negative prices
are not accepted--&gt;
&lt;rule name="Stock Price Not Negative"&gt;
&lt;!-- Parameters we can pass into
the business rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter&gt;
&lt;!-- Conditions or 'Left Hand Side' (LHS)
that must be met for rule to fire --&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &lt; 0
&lt;/java:condition&gt;
&lt;!-- What happens when the business rule
is activated --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
</code>
</pre>
<p>This rule is similar in format to the previous one, expect that our <code>&lt;java:condition&gt;</code> is different (testing for negative numbers) and the <code>&lt;java:consequence&gt;</code> sets the recommend purchase to <code>No</code>. We run our unit tests/simulator again, and this time the test passes.</p>
<p>At this point, if you're used to procedural programming (like most Java programmers), you may be scratching your head: here we have a file containing two separate business rules, yet we haven't told the rule engine which is more important. However, our stock price (of -22) satisfies both rules (i.e., it is less than 0 and it is less than 100). Despite this, we get the correct result, even if we swap the order of the rules around. How does this work?</p>
<p>The extract of the console output below helps us to see what is going on. We see that both rules are firing (the <code>[activationfired]</code> line), and that the <code>Recommend Buy</code> is first set to <code>Yes</code> and then to <code>No</code>. How does Drools know to fire these rules in the correct order? If you look at the <code>Stock Price Low Enough</code> rule, you will see that one of the conditions is that <code>recommendPurchase()</code> is null. This is enough for the Drools rule engine to decide that the <code>Stock Price Low Enough</code> rule should be fired before the <code>Stock Price Not Negative</code> rule. This process is called <em>conflict resolution</em>.</p>
<pre><code>
FIRE RULES
----------
[ConditionTested: rule=Stock Price Not Negative;
condition=[Condition: stockOffer.getStockPrice()
&lt; 0]; passed=true; tuple={[]}]
[ActivationCreated: rule=Stock Price Not Negative;
tuple={[]}]
[ObjectAsserted: handle=[fid:2];
object=net.firstpartners.rp.StockOffer@16546ef]
[ActivationFired: rule=Stock Price Low Enough;
tuple={[]}]
[ActivationFired: rule=Stock Price Not Negative;
tuple={[]}]
Name:MEGACORP Price: -22 BUY:YES
Name:MEGACORP Price: -22 BUY:NO
</code>
</pre>
<p>If you're a procedural programmer, no matter how clever you think this is, you still may not trust it completely. That is why we have our unit tests/simulator: "hard" JUnit tests (using normal Java code) ensure that the rule engine makes its decisions along the lines we want it to. (And doesn't spend billions on worthless stock!) At the same time, the power and the flexibility of our rule engine allows us to quickly develop the business logic.</p>
<p>Later on, we will see more sophisticated forms of conflict resolution.</p>
<br />
<h3>Conflict Resolution</h3>
<p>Now the folks on the business side are really impressed and are starting to think through the possible options. They've come across a problem with stocks of XYZ Corp and have decided to implement a new rule: Only buy stocks of XYZ Corp if they are less than 10 Euro.</p>
<p>As before, you add the test to our simulator and include the new business rule in our rules file, as per the following listings. First, we add a new method to <em>BusinessRuleTest.java</em>:</p>
<pre><code>
/**
* Makes sure the system will buy stocks
* of XYZ corp only if it really cheap
*/
public void testXYZStockBuy() throws Exception{
//Create a Stock with our simulated values
StockOffer testOfferLow = new StockOffer();
StockOffer testOfferHigh = new StockOffer();
testOfferLow.setStockName("XYZ");
testOfferLow.setStockPrice(9);
testOfferLow.setStockQuantity(1000);
testOfferHigh.setStockName("XYZ");
testOfferHigh.setStockPrice(11);
testOfferHigh.setStockQuantity(1000);
//Run the rules on it and test
BusinessLayer.evaluateStockPurchase(
testOfferLow);
assertTrue("YES".equals(
testOfferLow.getRecommendPurchase()));
BusinessLayer.evaluateStockPurchase(
testOfferHigh);
assertTrue("NO".equals(
testOfferHigh.getRecommendPurchase()));
}</code>
</pre>
<p>Next, we need a new <code>&lt;rule&gt;</code> in <em>BusinessRules.drl</em>:</p>
<pre><code>
&lt;rule name="XYZCorp" salience="-1"&gt;
&lt;!-- Parameters we pass to rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter&gt;
&lt;java:condition&gt;
stockOffer.getStockName().equals("XYZ")
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getRecommendPurchase() == null
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &gt; 10
&lt;/java:condition&gt;
&lt;!-- What happens when the business
rule is activated --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
</code>
</pre>
<p>Note that in the business rules file, after the rule name, we set our <code>salience</code> to <code>-1</code> (i.e., the lowest priority of all of the rules we have specified so far). Most of the rules in our system <em>conflict</em>, meaning Drools must make some decision on the order in which to fire rules, given that the conditions for all of the rules will be met. The default way of deciding is:</p>
<ul>
    <li><code>Salience</code>: A value we assign, as per the above listing.
    <li><code>Recency</code>: How many times we have used a rule.
    <li><code>Complexity</code>: Specific rules with more complicated values fire first.
    <li><code>LoadOrder</code>: The order in which rules are loaded. </li>
</ul>
<p>If we did not specify the saliency of our rule in this example, what would happen is:</p>
<ul>
    <li>The XYZ Corp rule ("Don't buy XYZ if the price is more than 10 Euro") would fire first (the status of the <code>Recommend Buy</code> flag would be set to <code>No</code>).
    <li>Then the more general rule ("Buy all stock under 100") fires, setting the <code>Recommended Buy</code> flag to <code>yes</code>. </li>
</ul>
<p>This would give a result that we don't want. However, since our example <em>does</em> set the saliency factor, the test and our business rules work as expected.</p>
<p>While most of the time, writing clear rules and setting the saliency will give enough information to Drools for it to choose the proper order in which to fire rules, sometimes we want to change the entire manner in which rule conflicts are resolved. An example of how to change this is given below, where we tell the rule engine to fire the simplest rules first. A word of warning: be careful when changing conflict resolution, as it can fundamentally change the behavior of the rule engine--a lot of problems can be solved first with clear and well-written rules.</p>
<pre><code>
//Generate our list of conflict resolvers
ConflictResolver[] conflictResolvers =
new ConflictResolver[] {
SalienceConflictResolver.getInstance(),
RecencyConflictResolver.getInstance(),
SimplicityConflictResolver.getInstance(),
LoadOrderConflictResolver.getInstance()
};
//Wrap this up into one composite resolver
CompositeConflictResolver resolver =
new CompositeConflictResolver(
conflictResolvers);
//Specify this resolver when we load the rules
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE),resolver);
</code>
</pre>
<p>For our simple application, driven by JUnit tests, we don't need to alter the way the Drools resolves rule conflicts. It is useful to know how conflict resolution works, especially when your application grows to meet more complex and demanding requirements.</p>
<h3>Conclusion</h3>
<p>This article demonstrated a problem that most programmers have had to face: how to put some order on the complexity of business logic. We demonstrated a simple application using Drools as a solution and introduced the notion of rule-based programming, including how these rules are resolved at runtime. Later on, a follow-up article will take these foundations and show how to use them in an enterprise Java application.</p>
<h3>Resources</h3>
<ul>
    <li><a href="http://sourceforge.net/project/showfiles.php?group_id=99476&amp;package_id=158438">Sample code for this article</a>
    <li><a href="http://www.drools.org/">Drools Project home page</a>
    <li><a href="http://www.jroller.com/page/eu/20040810">Info on Drools rules</a>
    <li>"<a href="http://www.theserverside.com/articles/article.tss?l=Drools">Introduction to Drools and Rule Engines</a>," by the Drools project lead
    <li><a href="http://www.geocities.com/CapitolHill/5910/drltk/instructions.htm">Drools rules schema files</a>
    <li><a href="http://javaboutique.internet.com/tutorials/rules_engine/">JSR-94, Java Rule Engines, Overview</a>
    <li><a href="http://struts.apache.org/">Struts framework website</a>
    <li><a href="http://www.springframework.org/">Spring framework website</a>
    <li><a href="http://www.hibernate.org/">Hibernate website</a>
    <li><a href="http://www.junit.org/">JUnit test framework</a>
    <li><a href="http://herzberg.ca.sandia.gov/jess/index.shtml">Jess Java rule engine</a>
    <li><a href="http://jena.sourceforge.net/">Jena semantic and rule engine</a>
    <li><a href="http://jcp.org/aboutJava/communityprocess/review/jsr094/">JSR-94 home page</a>
    <li><a href="http://www.manning.com/friedman-hill">Jess in Action home page</a>
    <li>"<a href="http://herzberg.ca.sandia.gov/jess/zen.shtml">Business Rule Thinking</a>" (Jess-based)
    <li>"<a href="http://www.aaai.org/AITopics/html/expert.html">General Introduction to Rule Systems</a>"
    <li>"<a href="http://herzberg.ca.sandia.gov/jess/docs/61/rete.html">Jess Implementation of the Rete Algorithm</a>" </li>
</ul>
<p><em><a href="http://www.onjava.com/pub/au/2366">Paul Browne</a> , based in Dublin, Ireland, has been consulting in enterprise Java with <a href="http://www.firstpartners.net/rp">FirstPartners.net</a> for almost seven years. </em></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142399.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 17:40 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142399.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Using Drools in Your Enterprise Java Application</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142394.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142394.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142394.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142394.html</trackback:ping><description><![CDATA[<h2>Using Drools in Your Enterprise Java Application</h2>
by <a href="http://www.onjava.com/pub/au/2366">Paul Browne</a><br />
08/24/2005
<p>These days enterprise Java could almost put you to sleep. How many hundreds of J2EE-EJB web applications have been written that capture information from a web page and store it in a database? What really keeps developers awake at night is trying to write and maintain the complex business logic in their applications. This is a problem not only for new applications, but increasingly, for long-lived, business-critical apps whose internal logic needs to change frequently, often at very short notice.</p>
<p>In an earlier article, "<a href="http://www.onjava.com/pub/a/onjava/2005/08/03/drools.html">Give Your Business Logic a Framework with Drools</a>," I introduced the Drools framework and showed how it could be used to organize complicated business logic. Drools replaced many tangled <code>if ... then</code> statements with a simple set of things known to be true. If you are ever in a meeting with business customers, and your head hurts with the complexity of what they want you to implement, then maybe you should consider a rule engine such as Drools. This article will show you how you can do this in an enterprise Java application.</p>
<h3>Frameworks All the Way Down</h3>
<p>Most enterprise Java developers already have their favorite frameworks. In no particular order, these include presentation frameworks (Struts, JSF, Cocoon, and Spring), persistence frameworks (JDO, Hibernate, Cayenne, and Entity Beans) and structural frameworks (EJB, Spring again, Pico, and Excalibur), as well as many others. Each framework does one very useful thing (or more), and gives developers a lot of instant "out of the box" functionality. Deploying an application using frameworks means you avoid a lot of the boring bits and concentrate on what is really needed.</p>
<p>Until now, there was a gap in what the frameworks were able to do, in that business logic had no framework. Tools like EJB and Spring are good, but have little to say about how to organize your <code>if ... then</code> statements! Adding Drools to your developer toolbox means that it is now possible to build an application with "frameworks all the way down." Figure 1 shows a diagram of such an application.</p>
<p><img height="386" alt="Figure 1" src="http://www.onjava.com/onjava/2005/08/24/graphics/diagramB1.gif" width="442" /><br />
<em>Figure 1. Frameworks for Java applications</em></p>
<p>This article will build on what we already know of the Drools framework and allow us to build such an application.</p>
<h3>When Should I Use a Rule Engine?</h3>
<!-- sidebar begins --><br />
<p>It's almost a cliche in software engineering to say that "if you have a hammer, everything looks like a nail." While rule engines can solve a lot of problems for us, it is worth considering whether a rule engine is really appropriate for our enterprise Java application. Some questions to ask are:</p>
<ul>
    <li><strong>How complex is my application?</strong> For applications that shuffle data to and from a database, but not much more, it is probably best not to use a rule engine. However, where there is even a moderate amount of processing implemented in Java, it is worthwhile to consider the use of Drools. This is because most applications develop complexity over time, and Drools will let you cope easily with this.
    <li><strong>What is the lifetime of my application?</strong> The answer to this is often "surprisingly long"--remember the mainframe programmers who thought their applications wouldn't be around for the year 2000? Using a rule engine pays off, especially in the medium to long term. As this article demonstrates, even prototypes can benefit from the combination of Drools and agile methods to take the "prototype" into production.
    <li><strong>Will my application need to change?</strong> The only sure thing about your requirements is that they will change, either during or just after development. Drools helps you cope with this by specifying the business rule in one or more easy-to-configure XML files. </li>
</ul>
<h3>What About Performance?</h3>
<p>If you're writing an enterprise application, chances are that it will need to scale to hundreds, if not thousands, of users. You know that existing Java and J2EE applications can do this, but how will a application using Drools cope with this pressure? The answer is "surprisingly well." While most developers hate to "lose control" and rely on other people's code (i.e., a framework), consider the points below--not only should your application be as fast as "traditional" coding methods, but Drools may even make your application run faster:</p>
<ul>
    <li><strong>Avoids badly written code:</strong>&nbsp;Drools guides developers to do "the right thing." You may be sure the code you are writing is good, but would you say the same for the code of your co-developers? Using a framework makes it easier to write good, fast code.
    <li><strong>Optimized framework:</strong>&nbsp;How often have you seen business logic that repeatedly accesses a database for the same information, slowing down the entire application? Used correctly, Drools can remember not only the information, but also the results of previous tests using this information, giving the entire application a speed boost.
    <li><strong>Rete algorithm:</strong>&nbsp;Many times we apply "if" conditions that we didn't really need. The Rete algorithm, as implemented by Drools, replaces all of the <code>if ... then</code> statements with an optimized network. It is important to note that the Rete algorithm involves a tradeoff between using more memory to reduce delays at run time. While this isn't a factor in most modern servers, we wouldn't yet recommend deploying Drools on your mobile phone! </li>
</ul>
<br />
<br />
<h3>Where Were We?</h3>
In our <a href="http://www.onjava.com/pub/a/onjava/2005/08/03/drools.html">previous article</a>, we wrote a simple stock trading application based around the Drools engine. We implemented various business rules, showed how we could rapidly change the rules to meet changing business requirements, and wrote JUnit tests to give us a high degree of confidence that the system would act as it was supposed to. However, the application as we left it had little or no user interface, and used hard-coded data instead of a database. To evolve our application into something that is more enterprise level, we need to add two main things:
<ul>
    <li>Some sort of user interface, ideally based one of the standard web-presentation frameworks.
    <li>A Data Access Object (DAO) to let Drools work with a database (or other back end system). </li>
</ul>
<h4>Calling the Rule Engine from a Presentation Framework</h4>
<p>Most enterprise Java applications are accessed using a web interface, and one of the most widely adopted web-presentation frameworks is <a href="http://struts.apache.org/">Struts</a>, from Apache. Ideally, we'll write our application so that the presentation layer knows about the business layer underneath, but not the other way around. This has the advantage not only of allowing us to change the presentation framework at a later date (e.g., to an Ajax or <a href="http://en.wikipedia.org/wiki/Web_service">web service</a> interface), but also means the code examples give should be readily applicable to other web frameworks like Spring.</p>
<br />
<p>The following code snippet demonstrates how to call the business logic tier (using the rule engine) from the web presentation layer. The code uses the results to decide which page to display. In this sample, we use a Struts action, but the code is similar for any other web framework or even a servlet or a JSP page. This snippet works with a supporting <em>struts-config.xml</em>, JSP pages to post/display data, and a way of generating the WAR file for deployment. The snippet shows how to integrate the rule engine with the web framework.</p>
<pre><code>
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import BusinessLayer;
/**
* Sample Struts action with Pseudocode
*/
public class SampleStrutsAction extends Action{
/**
* Standard Struts doPerfom method
*/
public ActionForward doPerform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws InvalidEntryPointException {
//Local Variables
StockOffer userOffer =null;
//Get any previous values from the session
userOffer=(StockOffer)request.getSession()
.getAttribute("PREVIOUS_STOCK_OFFER");
//create this object if it is null
if (null==userOffer){
userOffer = new StockOffer();
}
//Update with the incoming values
//These values match those on the form
userOffer.setStockName(request.
getParameterValue("STOCK_NAME"));
userOffer.setStockPrice(request
.getParameterValue("STOCK_PRICE"));
userOffer.setStockQuantity(request
.getParameterValue("STOCK_QTY"));
//Reset the output value
userOffer.setRecommendPurchase(null);
//Call the Business Layer
BusinessLayer
.evaluateStockPurchase(userOffer);
//Forward to the appropriate page
if ("YES".equals(
testOffer.getRecommendPurchase()){
return mapping.findForward("YES_WEB_PAGE");
}
//otherwise default to the no page
return mapping.findForward("NO_WEB_PAGE");
}
}</code>
</pre>
<p>There are a couple of things going on this sample. Often, we build up the data we need from the user over several web pages, so this sample shows how we can achieve this by retrieving the <code>StockOffer</code> object that we have previously stored in the web server session. Next, we update the <code>StockOffer</code> with any values that the user may have changed on the web page. We then reset the <code>recommendPurchase</code> flag to clear any previous results before we call the business logic layer. Finally, we take the response of the business logic and use it to decide which page to forward the user to.</p>
<p>In this example, note how we split the business logic (yes/no on whether or not to buy a stock) from the presentation logic (decide which page to go to). This allows us to reuse our business rules across several different applications In addition, take look at how the state information (i.e., things that the user has already told us) is stored in the <code>StockOffer</code> object/web server session, and not in the business layer. By keeping the business layer stateless in this way, we make the entire application much more scalable and performant.</p>
<br />
<h3>Integrating the Rule Engine with the Database Layer</h3>
<p>So far, our application has a web presentation layer and a rules engine for the business layer, but no means of getting data to and from a database. This section gives an example of how to do this. We base our example on the <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html">Data Access Object</a> (DAO) pattern, where we encapsulate all code that "talks" to the database (or back-end data source) in one pluggable, configurable class. As such, the example is applicable to other persistence frameworks, such as Hibernate and Cayenne.</p>
<br />
<p>Some important points about the way we want to organize the data layer are:</p>
<ul>
    <li>Only the business layer should talk to the data layer; if a class in the presentation layer (front end) wants some data, it should pass through the business layer first. This helps makes our code easier to organize and read.
    <li>As far as possible, we should keep our data layer stateless--we should hold client data elsewhere (e.g., in the server session at the web front end, as per the previous example). This is distinct from caching of data, which we can do at this level. The difference between the two is state information is often user-specific, while data we cache at the data access layer is mainly sharable across the application. Organizing our layer in this way increases performance.
    <li>We should allow the business logic to decide if data is needed or not--if not needed, the call to get the data should not be made. </li>
</ul>
<p>To implement our simple Data Access Object, we create three new objects: <code>StockNameDao</code>, <code>DaoImplementation</code>, and <code>DaoFactory</code>.</p>
<p><code>StockNameDao</code> is an interface that defines two methods: <code>getStockNames()</code> returns a list of the stock names that we deal with, and <code>isOnStockList()</code> checks that a given stock is on the list of stocks that we deal with. Our business layer will call these methods as and when it needs the information.</p>
<p><code>DaoImplementation</code> is an actual implementation of <code>StockNameDao</code>. In this case the values are hard-coded, but we could have queried a database or accessed an information system like Bloomberg via a web service.</p>
<p><code>DaoFactory</code> is what we use to create an appropriate instance of <code>StockNameDao</code>. The advantage this approach has over creating the class directly is that it allows us to configure what DAO implementation we use at runtime (frameworks like Spring are especially good at this). One factory can return many types of DAOs (e.g., <code>StockNameDao</code>, <code>StockPriceDao</code>, <code>StockHistoryDao</code>), which means we can pass in our <code>DaoFactory</code>, and let the individual rules decide on the data and DAOs that they require.</p>
<p>Here's what the <code>StockNameDao</code> interface looks like:</p>
<pre><code>
/**
* Defines a Data Access Object - a non data
* source specific way of obtaining data.
*/
public interface StockNameDao {
/**
* Get a list of stock names for the application
* @return String[] array of stock names
*/
public String [] getStockNames();
/**
* Check if our stock is on the list
* @param stockName
* @return
*/
public boolean isOnStockList(String stockName);
}</code>
</pre>
<p>And here's the <code>DaoImplementation</code>:</p>
<pre><code>
/**
* Concrete Definition of a Data Access Object
*/
public class DaoImplementation
implements StockNameDao {
/**
* Constructor with package level access only
* to encourage use of factory method
*
*/
DaoImplementation(){}
/**
* Get a list of stock names for the app.
* This is a hard coded sample
* normally we would get this from
* a database or other datasource.
* @return String[] array of stock names
*/
public String[] getStockNames() {
String[] stockNames=
{"XYZ","ABC","MEGACORP","SOMEOTHERCOMPANY"};
return stockNames;
}
/**
* Check if our stock is on the list
* @param stockName
* @return true / false as appropriate
*/
public boolean isOnStockList(String stockName){
//Get our list of stocks
String stockList[] = getStockNames();
//Loop and see if our stock is on it
// done this way for clarity . not speed!
for (int a=0; a&lt;stockList.length;a++){
if(stockList[a].equals(stockName)){
return true;
}
}
//Default return value
return false;
}
}</code>
</pre>
<p>The simple <code>DaoFactory</code> just returns a <code>DaoImplementation</code>:</p>
<pre><code>
package net.firstpartners.rp;
/**
* Factory Method to get the Data Access Object.
* Normally we could replace this with a
* framework like Spring or Hibernate
*/
public class DaoFactory {
/**
* Get the stock name Dao
* This sample is hardcoded - in reality
* we would make this configurable / cache
* instances of the Dao as appropriate
* @return an instance of StockNameDao
*/
public static StockNameDao getStockDao(){
return new DaoImplementation();
}
}
</code>
</pre>
<br />
<p>Now that we have our simple DAO implementation to serve as our database layer, how do we integrate it with the Drools business layer? The updated business rules file, <em>BusinessLayer.xml</em>, shows us how.</p>
<br />
<pre><code>
&lt;?xml version="1.0"?&gt;
&lt;rule-set name="BusinessRulesSample"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs="
http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="
http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd"&gt;
&lt;!-- Import the Java Objects that
we refer to in our rules --&gt;
&lt;java:import&gt;
java.lang.Object
&lt;/java:import&gt;
&lt;java:import&gt;
java.lang.String
&lt;/java:import&gt;
&lt;java:import&gt;
net.firstpartners.rp.StockOffer
&lt;/java:import&gt;
&lt;java:import&gt;
net.firstpartners.rp.DaoFactory
&lt;/java:import&gt;
&lt;java:import&gt;
net.firstpartners.rp.StockNameDao
&lt;/java:import&gt;
&lt;!-- Application Data not associated --&gt;
&lt;!-- with any particular rule --&gt;
&lt;!-- In this case it's our factory --&gt;
&lt;!-- object which gives us back --&gt;
&lt;!-- a handle to whatever Dao (Data --&gt;
&lt;!-- access object) that we need --&gt;
&lt;application-data
identifier="daoFactory"&gt;DaoFactory
&lt;/application-data&gt;
&lt;!-- A Java (Utility) function --&gt;
&lt;! we reference in our rules --&gt;
&lt;java:functions&gt;
public void printStock(
net.firstpartners.rp.StockOffer stock)
{
System.out.println(
"Name:"+stock.getStockName()
+" Price: "+stock.getStockPrice()
+" BUY:"+stock.getRecommendPurchase());
}
&lt;/java:functions&gt;
&lt;!-- Check for XYZ Corp--&gt;
&lt;rule name="XYZCorp" salience="-1"&gt;
&lt;!-- Parameters we can pass into--&gt;
&lt;!-- the business rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter"&gt;
&lt;!-- Conditions that must be met for --&gt;
&lt;!-- business rule to fire --&gt;
&lt;java:condition&gt;
stockOffer.getStockName().equals("XYZ")
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getRecommendPurchase() == null
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &gt; 10
&lt;/java:condition&gt;
&lt;!-- What happens when the business --&gt;
&lt;!-- rule is activated --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
&lt;!-- Ensure that negative prices --&gt;
&lt;!-- are not accepted --&gt;
&lt;rule name="Stock Price Not Negative"&gt;
&lt;!-- Parameters we can pass into the --&gt;
&lt;!-- business rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter&gt;
&lt;!-- Conditions for rule to fire --&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &lt; 0
&lt;/java:condition&gt;
&lt;!--When rule is activated then ... --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase
(StockOffer.NO);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
&lt;!-- Check for Negative Prices--&gt;
&lt;rule name="Stock Price Low Enough"&gt;
&lt;!-- Parameters for the rule --&gt;
&lt;parameter identifier="stockOffer"&gt;
&lt;class&gt;StockOffer&lt;/class&gt;
&lt;/parameter&gt;
&lt;!-- Now uses Dao to get stock list --&gt;
&lt;java:condition&gt;
daoFactory.getStockDao().isOnStockList(
stockOffer.getStockName())
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getRecommendPurchase() == null
&lt;/java:condition&gt;
&lt;java:condition&gt;
stockOffer.getStockPrice() &lt; 100
&lt;/java:condition&gt;
&lt;!-- When rule is activated do this --&gt;
&lt;java:consequence&gt;
stockOffer.setRecommendPurchase(
StockOffer.YES);
printStock(stockOffer);
&lt;/java:consequence&gt;
&lt;/rule&gt;
&lt;/rule-set&gt;
</code>
</pre>
<p>There are several changes to this file to integrate the data access layer with our business rules:</p>
<ul>
    <li>At the top of the file, we have several new <code>&lt;java:import&gt;</code> statements to reference the <code>StockNameDao</code>, <code>DaoImplementation</code>, and <code>DaoFactory</code> classes that we added to the system.
    <li>We have a new tag, <code>&lt;application-data&gt;</code>, which assigns an instance of the <code>DaoFactory</code> class to a variable. <code>&lt;application-data&gt;</code> tags are similar to parameters, except they apply to all business rules, and not just one.
    <li>The <code>Stock Price Low Enough</code> rule has a new condition, which uses the <code>DaoFactory</code> and <code>StockNameDao</code> to check if the stock is on the list of those that we deal with. </li>
</ul>
<p>We run our <code>BusinessRulesTest</code> (simulator) again. The simulator/unit tests run OK, since even though we have changed the structure of the program, we haven't (yet) changed what it does. From looking at the output logs, we can see that our business rules are using <code>StockNameDao</code> as part of their evaluations, and that <code>DaoImplementation.isOnStockList()</code> is being called.</p>
<p>While this example shows the reading of information from a data source, the principles are the same for writing information, if that is what a rule has decided should be done. The differences would be that our DAO would have a <code>setSomeInformation()</code> method, and that the method would be called in the <code>&lt;java:consequence&gt;</code> part of the business rule, once the specific conditions had been met.</p>
<!-- sidebar begins --><!-- don't move sidebars --><!-- sidebar ends -->
<h3>Summary</h3>
<p>In this article, we showed that most Java server applications have three tiers: presentation, business logic, and data persistence. While the use of frameworks is widely accepted in the presentation and persistence layers, until now no framework has been available to encapsulate low-level business logic. As we've seen in the examples, Drools and JSR-94 are ideal candidates for reducing the complexity and speeding the development of Java applications. I hope that these examples inspire you to take a closer look at rule engines, and that they save many hours of development and maintenance time in your applications.</p>
<h3>Resources</h3>
<ul>
    <li><a href="http://sourceforge.net/project/showfiles.php?group_id=99476&amp;package_id=158438">Sample code for this article</a>
    <li><a href="http://www.drools.org/">Drools Project home page</a>
    <li><a href="http://www.jroller.com/page/eu/20040810">Information on Drools rules</a>
    <li>"<a href="http://www.theserverside.com/articles/article.tss?l=Drools">Introduction to Drools and Rule Engines</a>," by the Drools project lead.
    <li><a href="http://www.geocities.com/CapitolHill/5910/drltk/instructions.htm">Drools rules schema files</a>
    <li><a href="http://javaboutique.internet.com/tutorials/rules_engine/">JSR-94: Java Rule Engines, Overview</a>
    <li><a href="http://struts.apache.org/">Struts framework website</a>
    <li><a href="http://www.springframework.org/">Spring framework website</a>
    <li><a href="http://www.hibernate.org/">Hibernate website</a>
    <li><a href="http://www.junit.org/">JUnit test framework</a>
    <li><a href="http://herzberg.ca.sandia.gov/jess/index.shtml">Jess Java rule engine</a>
    <li><a href="http://jena.sourceforge.net/">Jena semantic and rule engine</a>
    <li><a href="http://jcp.org/aboutJava/communityprocess/review/jsr094/">JSR-94 home page</a>
    <li><a href="http://www.manning.com/friedman-hill">Jess in Action home page</a>
    <li>"<a href="http://herzberg.ca.sandia.gov/jess/zen.shtml">Business Rule Thinking</a>" (Jess-based)
    <li><a href="http://www.aaai.org/AITopics/html/expert.html">General introduction to rule systems</a>
    <li>"<a href="http://herzberg.ca.sandia.gov/jess/docs/61/rete.html">Jess implementation of the Rete algorithm</a>" </li>
</ul>
<p><em><a href="http://www.onjava.com/pub/au/2366">Paul Browne</a> , based in Dublin, Ireland, has been consulting in enterprise Java with <a href="http://www.firstpartners.net/rp">FirstPartners.net</a> for almost seven years. </em></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 17:28 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Implement business logic with the Drools rules engine</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142392.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 09:24:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142392.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142392.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142392.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142392.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Implement business logic with the Drools rules engineUse a declarative programming approach to write your program's business logichttp://www-128.ibm.com/developerworks/java/library/j-drools/...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142392.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 17:24 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Drools Documentation</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142366.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142366.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142366.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142366.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142366.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: DroolsDrools Documentationhttp://anonsvn.labs.jboss.com/labs/jbossrulesMark ProctorMichael NealeMichael FrandsenSam Griffith Jr.Edson Tirelli...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142366.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 16:36 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BI相关的开源工具（转）</title><link>http://www.blogjava.net/hengheng123456789/archive/2006/12/30/90982.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Sat, 30 Dec 2006 04:26:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2006/12/30/90982.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/90982.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2006/12/30/90982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/90982.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/90982.html</trackback:ping><description><![CDATA[
		<p class="a14">
				<b>转自：<a href="http://challenger11.blogdriver.com/challenger11/1241587.html">http://challenger11.blogdriver.com/challenger11/1241587.html</a><br /><br />我们都知道“瞎子摸象”的故事。不同的瞎子对大象的认识不同，因为他们只认识了自己摸到的地方。而企业如果要避免重犯这样的错误，那就离不开商务智能（BI）。专家认为，BI对于企业的重要性就像聪明才智对于个人的重要性。欧美企业的经验也证明，企业避免无知和一知半解危险的有效手段就是商务智能。商务智能旨在充分利用企业在日常经营过程中收集的大量数据和资料，并将它们转化为信息和知识来免除各种无知状态和瞎猜行为。</b>  </p>
		<p class="a14">
				<font color="#b00e00">支持BI的开源工具数量众多，但是大多数的工具都是偏重某方面的。例如，CloverETL偏重ETL，JPivot偏重多维分析展现，Mondrian是OLAP服务器。而Bee、Pentaho和SpagoBI等项目则针对商务智能问题提供了完整的解决方案。</font>
		</p>
		<p class="a14">ETL 工具 </p>
		<p class="a14">ETL开源工具主要包括CloverETL和Octupus等。 </p>
		<p class="a14">（1）CloverETL是一个Java的ETL框架，用来转换结构化的数据，支持多种字符集之间的转换（如ASCII、UTF-8和ISO-8859-1等）；支持JDBC，同时支持dBase和FoxPro数据文件；支持基于XML的转换描述。 </p>
		<p class="a14">(2)Octupus是一个基于Java的ETL工具，它也支持JDBC数据源和基于XML的转换定义。Octupus提供通用的方法进行数据转换，用户可以通过实现转换接口或者使用Jscript代码来定义转换流程。 </p>
		<p class="a14">OLAP服务器 </p>
		<p class="a14">(1)Lemur主要面向HOLAP，虽然采用C++编写，但是可以被其他语言的程序所调用。Lemur支持基本的操作，如切片、切块和旋转等基本操作。 </p>
		<p class="a14">(2)Mondrian面向ROLAP包含4层：表示层、计算层、聚集层、存储层。 </p>
		<p class="a14">● 表示层：指最终呈现在用户显示器上的以及与用户之间的交互，有许多方法来展现多维数据，包括数据透视表、饼、柱、线状图。 </p>
		<p class="a14">● 计算层：分析、验证、执行MDX查询。 </p>
		<p class="a14">● 聚集层：一个聚集指内存中一组计算值(cell)，这些值通过维列来限制。计算层发送单元请求，如果请求不在缓存中，或者不能通过旋转聚集导出的话，那么聚集层向存储层发送请求。聚合层是一个数据缓冲层，从数据库来的单元数据，聚合后提供给计算层。聚合层的主要作用是提高系统的性能。 </p>
		<p class="a14">● 存储层：提供聚集单元数据和维表的成员。包括三种需要存储的数据，分别是事实数据、聚集和维。 </p>
		<p class="a14">OLAP客户端 </p>
		<p class="a14">JPivot是JSP风格的标签库，用来支持OLAP表，使用户可以执行典型的OLAP操作，如切片、切块、上钻、下钻等。JPivot使用Mondrian服务器，分析结果可以导出为Excel或PDF文件格式。 </p>
		<p class="a14">数据库管理系统 </p>
		<p class="a14">主要的开源工具包括MonetDB、MySQL、MaxDB和PostgreSQL等。这些数据库都被设计用来支持BI环境。MySQL、MaxDB和PostgreSQL均支持单向的数据复制。BizGres项目的目的在于使PostgreSQL成为数据仓库和 BI的开源标准。BizGres为BI环境构建专用的完整数据库平台。 </p>
		<p class="a14">完整的BI开源解决方案 </p>
		<p class="a14">1.Pentaho 公司的Pentaho BI 平台 </p>
		<p class="a14">它是一个以流程为中心的、面向解决方案的框架，具有商务智能组件。BI 平台是以流程为中心的，其中枢控制器是一个工作流引擎。工作流引擎使用流程定义来定义在 BI 平台上执行的商务智能流程。流程可以很容易被定制，也可以添加新的流程。BI 平台包含组件和报表，用以分析这些流程的性能。BI 平台是面向解决方案的，平台的操作是定义在流程定义和指定每个活动的 action 文档里。这些流程和操作共同定义了一个商务智能问题的解决方案。这个 BI 解决方案可以很容易地集成到平台外部的商业流程。一个解决方案的定义可以包含任意数量的流程和操作。 </p>
		<p class="a14">BI平台包括一个 BI 框架、BI 组件、一个 BI 工作台和桌面收件箱。BI 工作台是一套设计和管理工具，集成到Eclipse环境。这些工具允许商业分析人员或开发人员创建报表、仪表盘、分析模型、商业规则和 BI 流程。Pentaho BI 平台构建于服务器、引擎和组件的基础之上，包括J2EE 服务器、安全与权限控制、portal、工作流、规则引擎、图表、协作、内容管理、数据集成、多维分析和系统建模等功能。这些组件的大部分是基于标准的，可使用其他产品替换之。 </p>
		<p class="a14">2.ObjectWeb </p>
		<p class="a14">该项目近日发布了SpagoBi 1.8版本。SpagoBi 是一款基于Mondrain+JProvit的BI方案，能够通过OpenLaszlo产生实时报表，为商务智能项目提供了一个完整开源的解决方案，它涵盖了一个BI系统所有方面的功能，包括：数据挖掘、查询、分析、报告、Dashboard仪表板等等。SpagoBI使用核心系统与功能模块集成的架构，这样在确保平台稳定性与协调性的基础上又保证了系统具有很强的扩展能力。用户无需使用SpagoBI的所有模块，而是可以只利用其中的一些模块。 </p>
		<p class="a14">SpagoBI使用了许多已有的开源软件，如Spago和Spagosi等。因此，SpagoBI集成了 Spago的特征和技术特点，使用它们管理商务智能对象，如报表、OLAP分析、仪表盘、记分卡以及数据挖掘模型等。SpagoBI支持BI系统的监控管理，包括商务智能对象的控制、校验、认证和分配流程。SpagoBI采用Portalet技术将所有的BI对象发布到终端用户，因此BI对象就可以集成到为特定的企业需求而已经选择好的Portal系统中去。 </p>
		<p class="a14">3.Bee项目 </p>
		<p class="a14">该项目是一套支持商务智能项目实施的工具套件，包括ETL工具和OLAP 服务器。Bee的ETL工具使用基于Perl的BEI，通过界面描述流程，以XML形式进行存储。用户必须对转换过程进行编码。Bee的ROLAP 服务器保证多通SQL 生成和强有力的高速缓存管理(使用MySQL数据库管理系统)。ROLAP服务器通过SOAP应用接口提供丰富的客户应用。Web Portal作为主要的用户接口，通过Web浏览器进行报表设计、展示和管理控制，分析结果可以以Excel、PDF、PNG、PowerPoint、 text和XML等多种形式导出。 </p>
		<p class="a14">Bee项目的特点在于： </p>
		<p class="a14">● 简单快捷的数据访问； </p>
		<p class="a14">● 支持预先定义报表和实时查询； </p>
		<p class="a14">● 通过拖拽方式轻松实现报表定制； </p>
		<p class="a14">● 完整报表的轻松控制； </p>
		<p class="a14">● 以表和图进行高质量的数据展示。</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/90982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2006-12-30 12:26 <a href="http://www.blogjava.net/hengheng123456789/archive/2006/12/30/90982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>2006：中国BI市场的十大发展趋势</title><link>http://www.blogjava.net/hengheng123456789/archive/2006/09/08/68509.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 08 Sep 2006 06:18:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2006/09/08/68509.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/68509.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2006/09/08/68509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/68509.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/68509.html</trackback:ping><description><![CDATA[
		<p>
				<font class="font14">    2006年的BI产品将把数据仓库建模以及数据挖掘等技术实质性地应用进来。同时BI技术将与ERP、CRM、企业门户等技术相融合，形成集成化的产品。 </font>
		</p>
		<p>
				<font class="font14">    经过2005年的强劲发展，中国商业智能（BI）软件市场销售额达到10.15亿元人民币，年增长率达到54.96％。2006年，随着履行加入WTO全面开放市场承诺时间的临近和中国企业国际化的步伐加快以及政府职能的全面转变，中国金融、电信、政府、零售、制造等行业对商业智能技术应用的需求全面爆发。赛迪顾问预计2006年中国BI软件市场规模将超过16亿元人民币(见图1)。 <br />    <br />    国内商业智能软件市场将呈现十大发展趋势。 <br />    <br />    趋势一:融合多种技术的集成产品出现。 <br />    <br />    2006年BI产品技术的发展趋势是：由现有的初步应用如报表分析、数据集成，向深度和广度应用发展，数据仓库建模和数据挖掘等技术的应用将实质性推开。 <br />    <br />    2006年的BI产品将把数据仓库建模以及数据挖掘等技术实质性地应用进来。同时BI技术将与ERP、CRM、企业门户等技术相融合，形成集成化的产品。尤其在面向中小企业用户的企业管理软件方案中，ERP、CRM厂商会将BI方案嵌入到自己的ERP或CRM系统中。而整合了企业门户的BI产品，在人们缺少时间、必须将注意力放在真正重要的决策规则上的年代，可以减少作决策时必须分析的数据量。 <br />    <br />    趋势二:BI产品的整体价格在逐步下降。 <br />    <br />    在价格方面，BI软件一直处于高端价位，提供给信息化建设“贵族”使用。而以中小企业为代表的中、低端客户，也希望花上几十万就可以上一套BI软件。因此无论是国际BI厂商还是国内BI企业都针对高、中、低端用户呈现出不同的价格策略，总体价位呈现下降趋势。这为国内更广大的企业应用BI产品提供了可能。 <br />    <br />    趋势三:高端市场归属国际，中低端落户国内。 <br />    <br />    中国的BI市场从开始就经历了一个激烈竞争的时期，高端市场被国际大厂商所占据，低端市场是国内的BI厂商及行业的ISV及集成商在竞争。2006年中国的BI市场可能在低端市场初步出现像用友、金蝶在财务套装软件那样的格局，几个大的国内BI厂商凭借本地化和销售网络占据市场30％以上的市场份额。而在大的行业市场里，BI将会与解决方案融合在一起，市场被行业的ISV所把持。 <br />    <br />    趋势四:在营销策略上，整合营销趋势凸显。 <br />    <br />    2006年BI厂商将面临激烈而现实的市场竞争。营销手段、产品研发受到前所未有的重视。更多的软文宣传、研讨会（包括行业研讨会）、新品发布会、巡讲以及联合、并购等将会在2006年中国BI市场里上演。多种多样的营销方式将让人目不暇接。 <br />    <br />    趋势五:用户重视效益，关注BPM。 <br />    <br />    用户之所以投入巨额资金购买BI软件，目的都是希望对运营数据进行分析，以实现实时响应。对于企业来讲，还希望BI能够支持企业流程优化以及提高生产力。当然其最终目标都是向精益管理要效益。但是目前的很多组织并没有建立财务标准来衡量此项IT投入的效益。为此，将BI技术和绩效管理将结合而形成的BPM (企业绩效管理)成为BI领域用户的关注点。在应用领域方面，BPM可以深入特定的业务流程或功能；在功能划分方面，BPM可按企业业务功能划分，如财务绩效管理、客户关系绩效管理、生产运营绩效管理、交叉业务绩效管理；在系统构造方面，BPM能够协调业务活动以达到特定的结果，如编制预算、评估关键供应商等。因此，BI软件供应商在用BI技术提升企业绩效上面做文章，一定会达到一定的用户满意度。    </font>
		</p>
		<p>
				<font class="font14">                                                         <img src="http://www.226e.net/upload/2006-3-8/2006389252754100.jpg" border="1" /></font>
		</p>
		<p>
				<font class="font14">    趋势六:以产品为依托，增值服务成主角。 <br />    <br />    目前BI软件领域中的多数软件供应商，其软件授权收入和服务收入基本持平，但随着数据仓库和查询、报表工具软件的应用普及，下一步如何开展分析型应用将成为主导，从销售产品中可获得的收入将逐渐降低。此消彼长，帮助用户建立分析和挖掘模型等应用解决方案和咨询服务的收入将在明年上升，最终将超过软件产品授权收入。因此，如何在提供增值服务这新一轮的较量中胜出，是BI软件供应商现在需要未雨绸缪的。    <br />    <br />    趋势七:应用范围不断扩展，区域边界日趋模糊。 <br />    <br />    目前，华北、华东和华南地区BI软件占据了绝大部分的市场份额，而其它四地区的市场份额相对偏低。但华北、华东、华南地区由于电信、金融、政府等行业信息化水平较高，积累了大量数据，渴望从这些数据中获益，因此，2006年内将仍是BI软件的主要应用领域。但随着BI软件应用范围的不断扩大和用户认知度的提升，各BI软件供应商将致力于开拓其它区域的市场。另外2006年国家的“西部大开发”和“振兴东北老工业基地”两大战略的深入推进和实施，将促进西部和东北地区对于交通、能源、电信、电子政务的建设，这将在一定程度上带动西部和东北地区对于BI软件产品及应用的需求，从而为BI软件的推广和应用带来新的发展机遇。（见图2）</font>
		</p>
		<p>
				<font class="font14">                                                       <img src="http://www.226e.net/upload/2006-3-8/2006389252810298.jpg" border="1" /></font>
		</p>
		<p>
				<font class="font14">    趋势八:中小企业的BI应用市场份额将逐渐扩大。 <br />    <br />    虽然在垂直市场上，大型企业依然是BI的应用主体，但是中小企业的BI应用需求开始释放。 <br />    <br />    中小企业越来越注重自身建设，已经意识到信息化的重要性和迫切性。因此，国内广大的中小企业逐渐呈现对管理软件旺盛的需求态势，必将成为2006年国内 BI市场重要组成部分。国际一流的BI厂商BO公司和国内BI领域佼佼者菲奈特公司已经开发出适合中小企业应用的BI解决方案。 <br />    <br />    赛迪顾问预计2006年国内中小企业对BI的应用需求将快速增长，市场份额将由2005年的32.7%上升到42.5%，成为BI市场上新的增长亮点。（见图3） </font>
		</p>
		<p>
				<font class="font14">                                                        <img src="http://www.226e.net/upload/2006-3-8/2006389252972074.jpg" border="1" /></font>
		</p>
		<p>
				<font class="font14">    趋势九:优势行业地位不减，行业集成和解决方案成为主流。 <br />    <br />    从行业应用来看，中国的金融业、电信业在2006年仍将占据着BI应用的优势行业地位。另外政府和消费品制造业及零售业(如百货企业及连锁企业)对BI的需求也不容忽视。由于BI的分析型应用将在未来占主导地位，每个行业又都需要不同的行业知识，因此电信及金融的BI业务将会被行业的集成及ISV占据一定的市场份额。（见图4） </font>
		</p>
		<p>
				<font class="font14">                                                        <img src="http://www.226e.net/upload/2006-3-8/2006389253080974.jpg" border="1" /></font>
		</p>
		<font class="font14">    趋势十:主力厂商竞争从“群雄逐鹿”到“三足鼎立”。 <br />    <br />    2006年主力厂商的竞争将由“群雄逐鹿”态势转变到“三足鼎立”的格局。高端市场传统国际大厂商占有明显优势；中低端市场仍然是国内的BI厂家及行业的 ISV（独立软件开发商）及集成商的地盘；新兴的厂商后来居上，迅速抢占高、中、底端市场从而在BI市场里形成新的 “三足鼎立”态势竞争格局。 <br />    <br />    高端市场上BO、Hyperion、NCR、IBM 、甲骨文、微软、SAS等传统的国际专业BI厂商将继续占据高端市场相当份额。 <br />    <br />    国内的专业BI厂商及行业的ISV，专业BI厂商菲奈特，在2006年将继续作为国内BI厂商领先代表扛起国产化大旗，而用友、金蝶、博科等软件企业的市场潜力正逐步显现。2006年市场份额将快速上升。 <br />    <br />    2005年涌入国内BI市场的新兴力量，如三菱电机信息技术有限公司（MDIT）、上海润百等企业。将会成为2006年中国BI市场的黑马。传统国际厂商、国内BI企业和新进入企业将形成2006年中国BI市场“三足鼎立”之势。</font>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/68509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2006-09-08 14:18 <a href="http://www.blogjava.net/hengheng123456789/archive/2006/09/08/68509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>