Thorsten Scherler wrote:
I do not like this expression 'programming in xml' it is more (like I
stated in other threads) 'configuring components with xml'.
the crucial question will be where to draw the boundaries.
This code should help *user* easily change the output of forrest. In the
end this code should be produced by tools.
...and btw I would like to see such clear intuitive configuration and
separation in lenya and not a parameter overkilled framework that allows
user to extend the framework if they *exactly* follow the *not easy* to
understand boundaries and rules of the framework where you can do
everything you want as long it is the lenya way.
what you are proposing as an alternative is a domain-specific language
(DSL). i don't think that is any easier than java, especially
considering that you lose all the nice autocomplete, javadocs,
refactoring, testing etc features that have sprung up around java. it's
not the fault of the language if you use vi to write java when there are
better alternatives available.
*User* want to have a configuration file (or better (in the future) a
tool where they can create such a file) to alter the behavior of their
application. They do not want to learn cocoon/java to alter the default
behavior. You have worked on PostNuke, you should know that for
yourself, as a user you do not want to learn php. ;-)
if you have a tool, you don't need a DSL :) the effort spent on coming
up with a DSL could alternatively be spent on creating wizards for
common functionality, like 'create new publication' in the lenya case.
speaking of postnuke, that was a total disaster, totally unmaintainable
code. take a look at xaraya (and it's history), it's a rewrite that
avoids the problems postnuke has.
The goal is that a normal user do not have to understand much of
programming (nor cocoon or java) but rather can configure forrest in an
easy intuitive way to customize it the way they want. The view e.g.
should be created by a webdesigner that have *no* knowledge of
programming at all.
why not use CSS?
Devs on the other hand want an easy to understand and clear defined
interface where they can plugin new components.
are you suggesting that it is easier to learn and use a DSL than to use
java? i don't buy that, sorry. the DSL is just a layer of indirection,
the real implementation (at least in lenya, dunno about forrest) will be
java classes anyway, so why not try to have a sensible API rather than
hide it behind a bunch of xml?
i like xml as much as anyone, but there are limits (see below for a case
where the limit has been violated in a drastic way)
Search the ml for view;view helper;leather;...
cool, will do.
...or do you *really* consider
<logic:filter value="dirCut" parameter="p">
<forrest:view format="inx" />
</logic:filter>
<logic:filter value="actorCut" parameter="p">
<forrest:view format="inx" />
</logic:filter>
as programming???
if the expressive power of that XML is not severely restricted, then yes.
see http://ant.apache.org/ant2/features.html, heading "Simple
Flow-Control" for a similar argument.
cocoon moved away from having logic in the sitemap, and lenya 1.4 has
removed all the logic in XSP and other XML places, because XSP turned
out to be brittle: you don't get compile errors if a XSP has calls to an
API that has been removed.
i just refactored a cocoon app that has a 4000 line sitemap. below is a
sample of how things looked before the refactoring. this experience is
the reason why i am asking these questions.
i will try to find your RT to better understand what you have in mind.
best,
-gregor
<map:resource name="submitApproved">
<map:select type="parameter">
<map:parameter name="parameter-selector-test"
value="{cct-package:/deliveryMethod}"/>
<map:when test="email">
<map:act type="resource-load"
src="cocoon:/letter.submission">
<map:parameter name="write-to"
value="session"/>
<map:parameter name="attribute-name"
value="packageQueue.package"/>
<map:select type="parameter">
<map:parameter name="parameter-selector-test"
value="{cct-package:/lsttestmode}"/>
<map:when test="">
<map:act
type="jmsSender">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.email"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act
type="sendmail">
<map:parameter
name="from" value="@EMAIL_REPLYTO@"/>
<map:parameter name="to"
value="{cct-package:/recipient/email}"/>
<map:parameter name="cc"
value="{cct-package-concat:/recipient/advisor/email |
/copies-to/copy-to/email}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:parameter
name="subject" value="@EMAIL_SUBJECT@"/>
<map:parameter name="src"
value="cocoon:/letter.*.*.email"/>
<map:parameter
name="srcMimeType" value="text/html"/>
<map:parameter name="inlineparts"
value="cocoon:/letter.*.*.email.txt cocoon:/letter.*.*.email"/>
<map:parameter name="inlinepartsMimeType"
value="text/plain text/html"/>
<map:parameter
name="subtype" value="alternative"/>
<map:act
type="dbms-emailPackage">
<map:parameter name="table-set"
value="EmailPackage{../../../../fromInstance}"/>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../../unlock}"/>
<map:parameter name="actionType"
value="{../../../../actionType}"/>
<map:parameter name="redirect" value="showConfPage"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/emailPackage.error"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../../unlock}"/>
<map:parameter
name="redirect" value="cocoon:/emailLetter.error"/>
</map:call>
</map:act>
</map:when>
<map:otherwise>
<map:act
type="jmsSenderTest">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.email"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act
type="sendmail">
<map:parameter
name="from" value="@EMAIL_REPLYTO@"/>
<map:parameter name="to"
value="{cct-package:/recipient/email}"/>
<map:parameter name="cc"
value="{cct-package-concat:/recipient/advisor/email |
/copies-to/copy-to/email}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:parameter
name="subject" value="@EMAIL_SUBJECT@"/>
<map:parameter name="src"
value="cocoon:/letter.*.*.email"/>
<map:parameter
name="srcMimeType" value="text/html"/>
<map:parameter name="inlineparts"
value="cocoon:/letter.*.*.email.txt cocoon:/letter.*.*.email"/>
<map:parameter name="inlinepartsMimeType"
value="text/plain text/html"/>
<map:parameter
name="subtype" value="alternative"/>
<map:act
type="dbms-emailPackage">
<map:parameter name="table-set"
value="EmailPackage{../../../../fromInstance}"/>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../../unlock}"/>
<map:parameter name="actionType"
value="{../../../../actionType}"/>
<map:parameter name="redirect" value="showConfPage"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/emailPackage.error"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../../unlock}"/>
<map:parameter
name="redirect" value="cocoon:/emailLetter.error"/>
</map:call>
</map:act>
</map:otherwise>
</map:select>
<map:call
resource="processUnlockPackage">
<map:parameter name="unlock"
value="{../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/onDemandArchive.error"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter name="unlock"
value="{../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/generateSubmission.error"/>
</map:call>
</map:when>
<map:when test="local">
<map:act type="resource-load"
src="cocoon:/letter.submission">
<map:parameter name="write-to"
value="session"/>
<map:parameter name="attribute-name"
value="packageQueue.package"/>
<map:select type="parameter">
<map:parameter name="parameter-selector-test"
value="{cct-package:/lsttestmode}"/>
<map:when test="">
<map:act
type="jmsSender">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.view.ondemand"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act
type="dbms-printLocalPackage">
<map:parameter name="table-set"
value="PrintLocalPackage{../../../fromInstance}"/>
<map:redirect-to uri="cctUserIndex.html"/>
</map:act>
<map:redirect-to
uri="cocoon:/printLocalPackage.error"/>
</map:act>
</map:when>
<map:otherwise>
<map:act
type="jmsSenderTest">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.view.ondemand"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act
type="dbms-printLocalPackage">
<map:parameter name="table-set"
value="PrintLocalPackage{../../../fromInstance}"/>
<map:redirect-to uri="cctUserIndex.html"/>
</map:act>
<map:redirect-to
uri="cocoon:/printLocalPackage.error"/>
</map:act>
</map:otherwise>
</map:select>
<map:redirect-to
uri="cocoon:/onDemandArchive.error"/>
</map:act>
<map:redirect-to
uri="cocoon:/generateSubmission.error"/>
</map:when>
<map:when test="central">
<map:act type="resource-load"
src="cocoon:/letter.submission">
<map:parameter name="write-to"
value="session"/>
<map:parameter name="attribute-name"
value="packageQueue.package"/>
<!-- Determine if we should queue this package or render/send it
immediately -->
<map:select type="parameter">
<map:parameter name="parameter-selector-test"
value="{cct-package:/sendAfter}{cct-package:/sendBefore}"/>
<map:when test="">
<map:act
type="set">
<map:parameter
name="write-to" value="request"/>
<map:parameter
name="attribute-name" value="QueuePackage"/>
<map:parameter
name="attribute-value" value="false"/>
</map:act>
</map:when>
<map:otherwise>
<map:select
type="parameter">
<map:parameter name="parameter-selector-test"
value="{request-param:/RenderImmediately}"/>
<map:when
test="true">
<map:act
type="set">
<map:parameter
name="write-to" value="request"/>
<map:parameter
name="attribute-name" value="QueuePackage"/>
<map:parameter
name="attribute-value" value="false"/>
</map:act>
</map:when>
<map:otherwise>
<map:act
type="set">
<map:parameter
name="write-to" value="request"/>
<map:parameter
name="attribute-name" value="QueuePackage"/>
<map:parameter
name="attribute-value" value="true"/>
</map:act>
</map:otherwise>
</map:select>
</map:otherwise>
</map:select>
<map:select type="parameter">
<map:parameter name="parameter-selector-test"
value="{request-attr:QueuePackage}"/> <!-- Should we queue instead of
render/send immediately? -->
<map:when test="false">
<!-- Render/Send
Immediately -->
<map:select
type="parameter">
<map:parameter name="parameter-selector-test"
value="{cct-package:/lsttestmode}"/>
<map:when
test="">
<map:act
type="jmsSender">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.view.ondemand"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act type="centralPrintCopy">
<map:parameter name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.print"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:parameter name="lst_test_mode"
value="{request-param:lst_test_mode}"/>
<map:act type="dbms-printCentralPackage">
<map:parameter name="table-set"
value="PrintCentralPackage{../../../../fromInstance}"/>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../../unlock}"/>
<map:parameter name="actionType"
value="{../../../../../actionType}"/>
<map:parameter name="redirect" value="showConfPage"/>
</map:call>
</map:act>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/printCentralPackage.error"/>
</map:call>
</map:act>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/printCentralLetter.error"/>
</map:call>
</map:act>
</map:when>
<map:otherwise>
<map:act
type="jmsSenderTest">
<map:parameter
name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.archive"/>
<map:parameter name="appendSrcPattern"
value="cocoon:/letter.*.*.view.ondemand"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:act type="centralPrintCopy">
<map:parameter name="packageID" value="{cct-package:/id}"/>
<map:parameter name="srcPattern"
value="cocoon:/letter.*.*.print"/>
<map:parameter name="ccRecipients"
value="{cct-package:count(/recipient/advisor)}"/>
<map:parameter name="requiredRecipients"
value="{cct-package:count(/requiredRecipients/requiredRecipient)}"/>
<map:parameter name="lst_test_mode"
value="{request-param:lst_test_mode}"/>
<map:act type="dbms-printCentralPackage">
<map:parameter name="table-set"
value="PrintCentralPackage{../../../../fromInstance}"/>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../../unlock}"/>
<map:parameter name="actionType"
value="{../../../../../actionType}"/>
<map:parameter name="redirect" value="showConfPage"/>
</map:call>
</map:act>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/printCentralPackage.error"/>
</map:call>
</map:act>
<map:call resource="processUnlockPackage">
<map:parameter name="unlock" value="{../../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/printCentralLetter.error"/>
</map:call>
</map:act>
</map:otherwise>
</map:select>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/onDemandArchive.error"/>
</map:call>
</map:when>
<map:otherwise>
<!-- Queue the
Central Print Package instead -->
<map:act
type="dbms-queueCentralPackage">
<map:parameter name="table-set"
value="QueueCentralPackage{../../fromInstance}"/>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../../unlock}"/>
<map:parameter name="actionType"
value="{../../../actionType}"/>
<map:parameter
name="redirect" value="showConfPage"/>
</map:call>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter
name="unlock" value="{../../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/queueCentralPackage.error"/>
</map:call>
</map:otherwise>
</map:select>
</map:act>
<map:call
resource="processUnlockPackage">
<map:parameter name="unlock"
value="{../unlock}"/>
<map:parameter name="redirect"
value="cocoon:/generateSubmission.error"/>
</map:call>
</map:when>
<map:otherwise>
<map:redirect-to
uri="cocoon:/invalidDeliveryMethodForSubmission.error"/>
</map:otherwise>
</map:select>
</map:resource>