Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 23276 invoked from network); 1 Sep 2005 14:46:15 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 1 Sep 2005 14:46:14 -0000 Received: (qmail 82361 invoked by uid 500); 1 Sep 2005 14:46:14 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 82314 invoked by uid 500); 1 Sep 2005 14:46:13 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 82301 invoked by uid 99); 1 Sep 2005 14:46:13 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Sep 2005 07:46:13 -0700 X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Thu, 01 Sep 2005 07:46:27 -0700 Received: (qmail 23239 invoked by uid 65534); 1 Sep 2005 14:46:11 -0000 Message-ID: <20050901144611.23238.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r265740 - in /directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain: ./ Chain.java Command.java Context.java Filter.java impl/ impl/ChainBase.java impl/CommandBase.java impl/ContextBase.java Date: Thu, 01 Sep 2005 14:46:09 -0000 To: commits@directory.apache.org From: erodriguez@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: erodriguez Date: Thu Sep 1 07:45:13 2005 New Revision: 265740 URL: http://svn.apache.org/viewcvs?rev=265740&view=rev Log: Chain infrastructure for the DNS protocol provider. Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java (with props) directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java (with props) Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,117 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain; + + +/** + *

A {@link Chain} represents a configured list of + * {@link Command}s that will be executed in order to perform processing + * on a specified {@link Context}. Each included {@link Command} will be + * executed in turn, until either one of them returns true, + * one of the executed {@link Command}s throws an exception, + * or the end of the chain has been reached. The {@link Chain} itself will + * return the return value of the last {@link Command} that was executed + * (if no exception was thrown), or rethrow the thrown exception.

+ * + *

Note that {@link Chain} extends {@link Command}, so that the two can + * be used interchangeably when a {@link Command} is expected. This makes it + * easy to assemble workflows in a hierarchical manner by combining subchains + * into an overall processing chain.

+ * + *

To protect applications from evolution of this interface, specialized + * implementations of {@link Chain} should generally be created by extending + * the provided base class {@link org.apache.dns.chain.impl.ChainBase}) + * rather than directly implementing this interface.

+ * + *

{@link Chain} implementations should be designed in a thread-safe + * manner, suitable for execution on multiple threads simultaneously. In + * general, this implies that the state information identifying which + * {@link Command} is currently being executed should be maintained in a + * local variable inside the execute() method, rather than + * in an instance variable. The {@link Command}s in a {@link Chain} may be + * configured (via calls to addCommand()) at any time before + * the execute() method of the {@link Chain} is first called. + * After that, the configuration of the {@link Chain} is frozen.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.6 $ $Date: 2004/02/25 00:01:07 $ + */ + +public interface Chain extends Command { + + + /** + *

Add a {@link Command} to the list of {@link Command}s that will + * be called in turn when this {@link Chain}'s execute() + * method is called. Once execute() has been called + * at least once, it is no longer possible to add additional + * {@link Command}s; instead, an exception will be thrown.

+ * + * @param command The {@link Command} to be added + * + * @exception IllegalArgumentException if command + * is null + * @exception IllegalStateException if this {@link Chain} has already + * been executed at least once, so no further configuration is allowed + */ + void addCommand(Command command); + + + /** + *

Execute the processing represented by this {@link Chain} according + * to the following algorithm.

+ *
    + *
  • If there are no configured {@link Command}s in the {@link Chain}, + * return false.
  • + *
  • Call the execute() method of each {@link Command} + * configured on this chain, in the order they were added via calls + * to the addCommand() method, until the end of the + * configured {@link Command}s is encountered, or until one of + * the executed {@link Command}s returns true + * or throws an exception.
  • + *
  • Walk backwards through the {@link Command}s whose + * execute() methods, starting with the last one that + * was executed. If this {@link Command} instance is also a + * {@link Filter}, call its postprocess() method, + * discarding any exception that is thrown.
  • + *
  • If the last {@link Command} whose execute() method + * was called threw an exception, rethrow that exception.
  • + *
  • Otherwise, return the value returned by the execute() + * method of the last {@link Command} that was executed. This will be + * true if the last {@link Command} indicated that + * processing of this {@link Context} has been completed, or + * false if none of the called {@link Command}s + * returned true.
  • + *
+ * + * @param context The {@link Context} to be processed by this + * {@link Chain} + * + * @exception Exception if thrown by one of the {@link Command}s + * in this {@link Chain} but not handled by a postprocess() + * method of a {@link Filter} + * @exception IllegalArgumentException if context + * is null + * + * @return true if the processing of this {@link Context} + * has been completed, or false if the processing + * of this {@link Context} should be delegated to a subsequent + * {@link Command} in an enclosing {@link Chain} + */ + boolean execute(Context context) throws Exception; + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Chain.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,105 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain; + + +/** + *

A {@link Command} encapsulates a unit of processing work to be + * performed, whose purpose is to examine and/or modify the state of a + * transaction that is represented by a {@link Context}. Individual + * {@link Command}s can be assembled into a {@link Chain}, which allows + * them to either complete the required processing or delegate further + * processing to the next {@link Command} in the {@link Chain}.

+ * + *

{@link Command} implementations should be designed in a thread-safe + * manner, suitable for inclusion in multiple {@link Chain}s that might be + * processed by different threads simultaneously. In general, this implies + * that {@link Command} classes should not maintain state information in + * instance variables. Instead, state information should be maintained via + * suitable modifications to the attributes of the {@link Context} that is + * passed to the execute() command.

+ * + *

{@link Command} implementations typically retrieve and store state + * information in the {@link Context} instance that is passed as a parameter + * to the execute() method, using particular keys into the + * Map that can be acquired via + * Context.getAttributes(). To improve interoperability of + * {@link Command} implementations, a useful design pattern is to expose the + * key values used as JavaBeans properties of the {@link Command} + * implementation class itself. For example, a {@link Command} that requires + * an input and an output key might implement the following properties:

+ * + *
+ *   private String inputKey = "input";
+ *   public String getInputKey() {
+ *     return (this.inputKey);
+ *   }
+ *   public void setInputKey(String inputKey) {
+ *     this.inputKey = inputKey;
+ *   }
+ *
+ *   private String outputKey = "output";
+ *   public String getOutputKey() {
+ *     return (this.outputKey);
+ *   }
+ *   public void setOutputKey(String outputKey) {
+ *     this.outputKey = outputKey;
+ *   }
+ * 
+ * + *

And the operation of accessing the "input" information in the context + * would be executed by calling:

+ * + *
+ *   String input = (String) context.get(getInputKey());
+ * 
+ * + *

instead of hard coding the attribute name. The use of the "Key" + * suffix on such property names is a useful convention to identify properties + * being used in this fashion, as opposed to JavaBeans properties that simply + * configure the internal operation of this {@link Command}.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.5 $ $Date: 2004/02/25 00:01:07 $ + */ + +public interface Command { + + + /** + *

Execute a unit of processing work to be performed. This + * {@link Command} may either complete the required processing + * and return true, or delegate remaining processing + * to the next {@link Command} in a {@link Chain} containing this + * {@link Command} by returning false + * + * @param context The {@link Context} to be processed by this + * {@link Command} + * + * @exception Exception general purpose exception return + * to indicate abnormal termination + * @exception IllegalArgumentException if context + * is null + * + * @return true if the processing of this {@link Context} + * has been completed, or false if the processing + * of this {@link Context} should be delegated to a subsequent + * {@link Command} in an enclosing {@link Chain} + */ + boolean execute(Context context) throws Exception; + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Command.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,65 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain; + + +import java.util.Map; + + +/** + *

A {@link Context} represents the state information that is + * accessed and manipulated by the execution of a {@link Command} or a + * {@link Chain}. Specialized implementations of {@link Context} will + * typically add JavaBeans properties that contain typesafe accessors + * to information that is relevant to a particular use case for this + * context, and/or add operations that affect the state information + * that is saved in the context.

+ * + *

Implementations of {@link Context} must also implement all of the + * required and optional contracts of the java.util.Map + * interface.

+ * + *

It is strongly recommended, but not required, that JavaBeans + * properties added to a particular {@link Context} implementation exhibit + * Attribute-Property Transparency. In other words, + * a value stored via a call to setFoo(value) should be visible + * by calling get("foo"), and a value stored + * via a call to put("foo", value) should be + * visible by calling getFoo(). If your {@link Context} + * implementation class exhibits this featue, it becomes easier to reuse the + * implementation in multiple environments, without the need to cast to a + * particular implementation class in order to access the property getter + * and setter methods.

+ * + *

To protect applications from evolution of this interface, specialized + * implementations of {@link Context} should generally be created by extending + * the provided base class ({@link org.apache.dns.chain.impl.ContextBase}) + * rather than directly implementing this interface.

+ * + *

Applications should NOT assume that + * {@link Context} implementations, or the values stored in its + * attributes, may be accessed from multiple threads + * simultaneously unless this is explicitly documented for a particular + * implementation.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.6 $ $Date: 2004/02/25 00:01:07 $ + */ + +public interface Context extends Map { + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Context.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,67 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain; + + +/** + *

A {@link Filter} is a specialized {@link Command} that also expects + * the {@link Chain} that is executing it to call the + * postprocess() method if it called the execute() + * method. This promise must be fulfilled in spite of any possible + * exceptions thrown by the execute() method of this + * {@link Command}, or any subsequent {@link Command} whose + * execute() method was called. The owning {@link Chain} + * must call the postprocess() method of each {@link Filter} + * in a {@link Chain} in reverse order of the invocation of their + * execute() methods.

+ * + *

The most common use case for a {@link Filter}, as opposed to a + * {@link Command}, is where potentially expensive resources must be acquired + * and held until the processing of a particular request has been completed, + * even it execution is delegated to a subsequent {@link Command} via the + * execute() returning false. A {@link Filter} + * can reliably release such resources in the postprocess() + * method, which is guaranteed to be called by the owning {@link Chain}.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.6 $ $Date: 2004/11/30 05:52:23 $ + */ + +public interface Filter extends Command { + + + /** + *

Execute any cleanup activities, such as releasing resources that + * were acquired during the execute() method of this + * {@link Filter} instance.

+ * + * @param context The {@link Context} to be processed by this + * {@link Filter} + * @param exception The Exception (if any) that was thrown + * by the last {@link Command} that was executed; otherwise + * null + * + * @exception IllegalArgumentException if context + * is null + * + * @return If a non-null exception was "handled" by this + * method (and therefore need not be rethrown), return true; + * otherwise return false + */ + boolean postprocess(Context context, Exception exception); + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/Filter.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,223 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain.impl; + + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.dns.chain.Chain; +import org.apache.dns.chain.Command; +import org.apache.dns.chain.Context; +import org.apache.dns.chain.Filter; + + +/** + *

Convenience base class for {@link Chain} implementations.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.6 $ $Date: 2004/11/30 05:52:23 $ + */ + +public class ChainBase implements Chain { + + + // ----------------------------------------------------------- Constructors + + + /** + *

Construct a {@link Chain} with no configured {@link Command}s.

+ */ + public ChainBase() { + + } + + + /** + *

Construct a {@link Chain} configured with the specified + * {@link Command}.

+ * + * @param command The {@link Command} to be configured + * + * @exception IllegalArgumentException if command + * is null + */ + public ChainBase(Command command) { + + addCommand(command); + + } + + + /** + *

Construct a {@link Chain} configured with the specified + * {@link Command}s.

+ * + * @param commands The {@link Command}s to be configured + * + * @exception IllegalArgumentException if commands, + * or one of the individual {@link Command} elements, + * is null + */ + public ChainBase(Command[] commands) { + + if (commands == null) { + throw new IllegalArgumentException(); + } + for (int i = 0; i < commands.length; i++) { + addCommand(commands[i]); + } + + } + + + /** + *

Construct a {@link Chain} configured with the specified + * {@link Command}s.

+ * + * @param commands The {@link Command}s to be configured + * + * @exception IllegalArgumentException if commands, + * or one of the individual {@link Command} elements, + * is null + */ + public ChainBase(Collection commands) { + + if (commands == null) { + throw new IllegalArgumentException(); + } + Iterator elements = commands.iterator(); + while (elements.hasNext()) { + addCommand((Command) elements.next()); + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + *

The list of {@link Command}s configured for this {@link Chain}, in + * the order in which they may delegate processing to the remainder of + * the {@link Chain}.

+ */ + protected Command[] commands = new Command[0]; + + + /** + *

Flag indicating whether the configuration of our commands list + * has been frozen by a call to the execute() method.

+ */ + protected boolean frozen = false; + + + // ---------------------------------------------------------- Chain Methods + + + // Documented in Chain interface + public void addCommand(Command command) { + + if (command == null) { + throw new IllegalArgumentException(); + } + if (frozen) { + throw new IllegalStateException(); + } + Command[] results = new Command[commands.length + 1]; + System.arraycopy(commands, 0, results, 0, commands.length); + results[commands.length] = command; + commands = results; + + } + + + // Documented in Chain interface + public boolean execute(Context context) throws Exception { + + // Verify our parameters + if (context == null) { + throw new IllegalArgumentException(); + } + + // Freeze the configuration of the command list + frozen = true; + + // Execute the commands in this list until one returns true + // or throws an exception + boolean saveResult = false; + Exception saveException = null; + int i = 0; + int n = commands.length;; + for (i = 0; i < n; i++) { + try { + saveResult = commands[i].execute(context); + if (saveResult) { + break; + } + } catch (Exception e) { + saveException = e; + break; + } + } + + // Call postprocess methods on Filters in reverse order + if (i >= n) { // Fell off the end of the chain + i--; + } + boolean handled = false; + boolean result = false; + for (int j = i; j >= 0; j--) { + if (commands[j] instanceof Filter) { + try { + result = + ((Filter) commands[j]).postprocess(context, + saveException); + if (result) { + handled = true; + } + } catch (Exception e) { + ; // Silently ignore + } + } + } + + // Return the exception or result state from the last execute() + if ((saveException != null) && !handled) { + throw saveException; + } else { + return (saveResult); + } + + } + + + // -------------------------------------------------------- Package Methods + + + /** + *

Return an array of the configured {@link Command}s for this + * {@link Chain}. This method is package private, and is used only + * for the unit tests.

+ */ + Command[] getCommands() { + + return (commands); + + } + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ChainBase.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,31 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.dns.chain.impl; + +import org.apache.dns.chain.Command; + +/** + *

Convenience base class for {@link Command} implementations.

+ * + * @author Apache Directory Project + * @version $Rev$ + */ +public abstract class CommandBase implements Command +{ + public static final boolean STOP_CHAIN = true; + public static final boolean CONTINUE_CHAIN = false; +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/CommandBase.java ------------------------------------------------------------------------------ svn:eol-style = native Added: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java URL: http://svn.apache.org/viewcvs/directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java?rev=265740&view=auto ============================================================================== --- directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java (added) +++ directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java Thu Sep 1 07:45:13 2005 @@ -0,0 +1,790 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dns.chain.impl; + + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.dns.chain.Context; + + +/** + *

Convenience base class for {@link Context} implementations.

+ * + *

In addition to the minimal functionality required by the {@link Context} + * interface, this class implements the recommended support for + * Attribute-Property Transparency

. This is implemented by + * analyzing the available JavaBeans properties of this class (or its + * subclass), exposes them as key-value pairs in the Map, + * with the key being the name of the property itself.

+ * + *

IMPLEMENTATION NOTE - Because empty is a + * read-only property defined by the Map interface, it may not + * be utilized as an attribute key or property name.

+ * + * @author Craig R. McClanahan + * @version $Revision: 1.7 $ $Date: 2004/11/30 05:52:23 $ + */ + +public class ContextBase extends HashMap implements Context { + + + // ------------------------------------------------------------ Constructors + + + /** + * Default, no argument constructor. + */ + public ContextBase() { + + super(); + initialize(); + + } + + + /** + *

Initialize the contents of this {@link Context} by copying the + * values from the specified Map. Any keys in map + * that correspond to local properties will cause the setter method for + * that property to be called.

+ * + * @param map Map whose key-value pairs are added + * + * @exception IllegalArgumentException if an exception is thrown + * writing a local property value + * @exception UnsupportedOperationException if a local property does not + * have a write method. + */ + public ContextBase(Map map) { + + super(map); + initialize(); + putAll(map); + + } + + + // ------------------------------------------------------ Instance Variables + + + /** + *

The PropertyDescriptors for all JavaBeans properties + * of this {@link Context} implementation class, keyed by property name. + * This collection is allocated only if there are any JavaBeans + * properties.

+ */ + private Map descriptors = null; + + + /** + *

The same PropertyDescriptors as an array.

+ */ + private PropertyDescriptor[] pd = null; + + + /** + *

Distinguished singleton value that is stored in the map for each + * key that is actually a property. This value is used to ensure that + * equals() comparisons will always fail.

+ */ + private static Object singleton; + + static { + + singleton = new Object() { + public boolean equals(Object object) { + return (false); + } + }; + + } + + + /** + *

Zero-length array of parameter values for calling property getters. + *

+ */ + private static Object[] zeroParams = new Object[0]; + + + // ------------------------------------------------------------- Map Methods + + + /** + *

Override the default Map behavior to clear all keys and + * values except those corresponding to JavaBeans properties.

+ */ + public void clear() { + + if (descriptors == null) { + super.clear(); + } else { + Iterator keys = keySet().iterator(); + while (keys.hasNext()) { + Object key = keys.next(); + if (!descriptors.containsKey(key)) { + keys.remove(); + } + } + } + + } + + + /** + *

Override the default Map behavior to return + * true if the specified value is present in either the + * underlying Map or one of the local property values.

+ * + * @exception IllegalArgumentException if a property getter + * throws an exception + */ + public boolean containsValue(Object value) { + + // Case 1 -- no local properties + if (descriptors == null) { + return (super.containsValue(value)); + } + + // Case 2 -- value found in the underlying Map + else if (super.containsValue(value)) { + return (true); + } + + // Case 3 -- check the values of our readable properties + for (int i = 0; i < pd.length; i++) { + if (pd[i].getReadMethod() != null) { + Object prop = readProperty(pd[i]); + if (value == null) { + if (prop == null) { + return (true); + } + } else if (value.equals(prop)) { + return (true); + } + } + } + return (false); + + } + + + /** + *

Override the default Map behavior to return a + * Set that meets the specified default behavior except + * for attempts to remove the key for a property of the {@link Context} + * implementation class, which will throw + * UnsupportedOperationException.

+ */ + public Set entrySet() { + + return (new EntrySetImpl()); + + } + + + /** + *

Override the default Map behavior to return the value + * of a local property if the specified key matches a local property name. + *

+ * + *

IMPLEMENTATION NOTE - If the specified + * key identifies a write-only property, null + * will arbitrarily be returned, in order to avoid difficulties implementing + * the contracts of the Map interface.

+ * + * @param key Key of the value to be returned + * + * @exception IllegalArgumentException if an exception is thrown + * reading this local property value + * @exception UnsupportedOperationException if this local property does not + * have a read method. + */ + public Object get(Object key) { + + // Case 1 -- no local properties + if (descriptors == null) { + return (super.get(key)); + } + + // Case 2 -- this is a local property + if (key != null) { + PropertyDescriptor descriptor = + (PropertyDescriptor) descriptors.get(key); + if (descriptor != null) { + if (descriptor.getReadMethod() != null) { + return (readProperty(descriptor)); + } else { + return (null); + } + } + } + + // Case 3 -- retrieve value from our underlying Map + return (super.get(key)); + + } + + + /** + *

Override the default Map behavior to return + * true if the underlying Map only contains + * key-value pairs for local properties (if any).

+ */ + public boolean isEmpty() { + + // Case 1 -- no local properties + if (descriptors == null) { + return (super.isEmpty()); + } + + // Case 2 -- compare key count to property count + return (super.size() <= descriptors.size()); + + } + + + /** + *

Override the default Map behavior to return a + * Set that meets the specified default behavior except + * for attempts to remove the key for a property of the {@link Context} + * implementation class, which will throw + * UnsupportedOperationException.

+ */ + public Set keySet() { + + + return (super.keySet()); + + } + + + /** + *

Override the default Map behavior to set the value + * of a local property if the specified key matches a local property name. + *

+ * + * @param key Key of the value to be stored or replaced + * @param value New value to be stored + * + * @exception IllegalArgumentException if an exception is thrown + * reading or wrting this local property value + * @exception UnsupportedOperationException if this local property does not + * have both a read method and a write method + */ + public Object put(Object key, Object value) { + + // Case 1 -- no local properties + if (descriptors == null) { + return (super.put(key, value)); + } + + // Case 2 -- this is a local property + if (key != null) { + PropertyDescriptor descriptor = + (PropertyDescriptor) descriptors.get(key); + if (descriptor != null) { + Object previous = null; + if (descriptor.getReadMethod() != null) { + previous = readProperty(descriptor); + } + writeProperty(descriptor, value); + return (previous); + } + } + + // Case 3 -- store or replace value in our underlying map + return (super.put(key, value)); + + } + + + /** + *

Override the default Map behavior to call the + * put() method individually for each key-value pair + * in the specified Map.

+ * + * @param map Map containing key-value pairs to store + * (or replace) + * + * @exception IllegalArgumentException if an exception is thrown + * reading or wrting a local property value + * @exception UnsupportedOperationException if a local property does not + * have both a read method and a write method + */ + public void putAll(Map map) { + + Iterator pairs = map.entrySet().iterator(); + while (pairs.hasNext()) { + Map.Entry pair = (Map.Entry) pairs.next(); + put(pair.getKey(), pair.getValue()); + } + + } + + + /** + *

Override the default Map behavior to throw + * UnsupportedOperationException on any attempt to + * remove a key that is the name of a local property.

+ * + * @param key Key to be removed + * + * @exception UnsupportedOperationException if the specified + * key matches the name of a local property + */ + public Object remove(Object key) { + + // Case 1 -- no local properties + if (descriptors == null) { + return (super.remove(key)); + } + + // Case 2 -- this is a local property + if (key != null) { + PropertyDescriptor descriptor = + (PropertyDescriptor) descriptors.get(key); + if (descriptor != null) { + throw new UnsupportedOperationException + ("Local property '" + key + "' cannot be removed"); + } + } + + // Case 3 -- remove from underlying Map + return (super.remove(key)); + + } + + + /** + *

Override the default Map behavior to return a + * Collection that meets the specified default behavior except + * for attempts to remove the key for a property of the {@link Context} + * implementation class, which will throw + * UnsupportedOperationException.

+ */ + public Collection values() { + + return (new ValuesImpl()); + + } + + + // --------------------------------------------------------- Private Methods + + + /** + *

Eliminate the specified property descriptor from the list of + * property descriptors in pd.

+ * + * @param name Name of the property to eliminate + * + * @exception IllegalArgumentException if the specified property name + * is not present + */ + private void eliminate(String name) { + + int j = -1; + for (int i = 0; i < pd.length; i++) { + if (name.equals(pd[i].getName())) { + j = i; + break; + } + } + if (j < 0) { + throw new IllegalArgumentException("Property '" + name + + "' is not present"); + } + PropertyDescriptor[] results = new PropertyDescriptor[pd.length - 1]; + System.arraycopy(pd, 0, results, 0, j); + System.arraycopy(pd, j + 1, results, j, pd.length - (j + 1)); + pd = results; + + } + + + /** + *

Return an Iterator over the set of Map.Entry + * objects representing our key-value pairs.

+ */ + private Iterator entriesIterator() { + + return (new EntrySetIterator()); + + } + + + /** + *

Return a Map.Entry for the specified key value, if it + * is present; otherwise, return null.

+ * + * @param key Attribute key or property name + */ + private Map.Entry entry(Object key) { + + if (containsKey(key)) { + return (new MapEntryImpl(key, get(key))); + } else { + return (null); + } + + } + + + /** + *

Customize the contents of our underlying Map so that + * it contains keys corresponding to all of the JavaBeans properties of + * the {@link Context} implementation class.

+ * + * + * @exception IllegalArgumentException if an exception is thrown + * writing this local property value + * @exception UnsupportedOperationException if this local property does not + * have a write method. + */ + private void initialize() { + + // Retrieve the set of property descriptors for this Context class + try { + pd = Introspector.getBeanInfo + (getClass()).getPropertyDescriptors(); + } catch (IntrospectionException e) { + pd = new PropertyDescriptor[0]; // Should never happen + } + eliminate("class"); // Because of "getClass()" + eliminate("empty"); // Because of "isEmpty()" + + // Initialize the underlying Map contents + if (pd.length > 0) { + descriptors = new HashMap(); + for (int i = 0; i < pd.length; i++) { + descriptors.put(pd[i].getName(), pd[i]); + super.put(pd[i].getName(), singleton); + } + } + + } + + + /** + *

Get and return the value for the specified property.

+ * + * @param descriptor PropertyDescriptor for the + * specified property + * + * @exception IllegalArgumentException if an exception is thrown + * reading this local property value + * @exception UnsupportedOperationException if this local property does not + * have a read method. + */ + private Object readProperty(PropertyDescriptor descriptor) { + + try { + Method method = descriptor.getReadMethod(); + if (method == null) { + throw new UnsupportedOperationException + ("Property '" + descriptor.getName() + + "' is not readable"); + } + return (method.invoke(this, zeroParams)); + } catch (Exception e) { + throw new UnsupportedOperationException + ("Exception reading property '" + descriptor.getName() + + "': " + e.getMessage()); + } + + } + + + /** + *

Remove the specified key-value pair, if it exists, and return + * true. If this pair does not exist, return + * false.

+ * + * @param entry Key-value pair to be removed + * + * @exception UnsupportedOperationException if the specified key + * identifies a property instead of an attribute + */ + private boolean remove(Map.Entry entry) { + + Map.Entry actual = entry(entry.getKey()); + if (actual == null) { + return (false); + } else if (!entry.equals(actual)) { + return (false); + } else { + remove(entry.getKey()); + return (true); + } + + } + + + /** + *

Return an Iterator over the set of values in this + * Map.

+ */ + private Iterator valuesIterator() { + + return (new ValuesIterator()); + + } + + + /** + *

Set the value for the specified property.

+ * + * @param descriptor PropertyDescriptor for the + * specified property + * @param value The new value for this property (must be of the + * correct type) + * + * @exception IllegalArgumentException if an exception is thrown + * writing this local property value + * @exception UnsupportedOperationException if this local property does not + * have a write method. + */ + private void writeProperty(PropertyDescriptor descriptor, Object value) { + + try { + Method method = descriptor.getWriteMethod(); + if (method == null) { + throw new UnsupportedOperationException + ("Property '" + descriptor.getName() + + "' is not writeable"); + } + method.invoke(this, new Object[] { value }); + } catch (Exception e) { + throw new UnsupportedOperationException + ("Exception writing property '" + descriptor.getName() + + "': " + e.getMessage()); + } + + } + + + // --------------------------------------------------------- Private Classes + + + /** + *

Private implementation of Set that implements the + * semantics required for the value returned by entrySet().

+ */ + private class EntrySetImpl extends AbstractSet { + + public void clear() { + ContextBase.this.clear(); + } + + public boolean contains(Object obj) { + if (!(obj instanceof Map.Entry)) { + return (false); + } + Map.Entry entry = (Map.Entry) obj; + Entry actual = ContextBase.this.entry(entry.getKey()); + if (actual != null) { + return (actual.equals(entry)); + } else { + return (false); + } + } + + public boolean isEmpty() { + return (ContextBase.this.isEmpty()); + } + + public Iterator iterator() { + return (ContextBase.this.entriesIterator()); + } + + public boolean remove(Object obj) { + if (obj instanceof Map.Entry) { + return (ContextBase.this.remove((Map.Entry) obj)); + } else { + return (false); + } + } + + public int size() { + return (ContextBase.this.size()); + } + + } + + + /** + *

Private implementation of Iterator for the + * Set returned by entrySet().

+ */ + private class EntrySetIterator implements Iterator { + + Map.Entry entry = null; + private Iterator keys = ContextBase.this.keySet().iterator(); + + public boolean hasNext() { + return (keys.hasNext()); + } + + public Object next() { + entry = ContextBase.this.entry(keys.next()); + return (entry); + } + + public void remove() { + ContextBase.this.remove(entry); + } + + } + + + /** + *

Private implementation of Map.Entry for each item in + * EntrySetImpl.

+ */ + private class MapEntryImpl implements Map.Entry { + + MapEntryImpl(Object key, Object value) { + this.key = key; + this.value = value; + } + + private Object key; + private Object value; + + public boolean equals(Object obj) { + if (obj == null) { + return (false); + } else if (!(obj instanceof Map.Entry)) { + return (false); + } + Map.Entry entry = (Map.Entry) obj; + if (key == null) { + return (entry.getKey() == null); + } + if (key.equals(entry.getKey())) { + if (value == null) { + return (entry.getValue() == null); + } else { + return (value.equals(entry.getValue())); + } + } else { + return (false); + } + } + + public Object getKey() { + return (this.key); + } + + public Object getValue() { + return (this.value); + } + + public int hashCode() { + return (((key == null) ? 0 : key.hashCode()) + ^ ((value == null) ? 0 : value.hashCode())); + } + + public Object setValue(Object value) { + Object previous = this.value; + ContextBase.this.put(this.key, value); + this.value = value; + return (previous); + } + + + } + + + /** + *

Private implementation of Collection that implements the + * semantics required for the value returned by values().

+ */ + private class ValuesImpl extends AbstractCollection { + + public void clear() { + ContextBase.this.clear(); + } + + public boolean contains(Object obj) { + if (!(obj instanceof Map.Entry)) { + return (false); + } + Map.Entry entry = (Map.Entry) obj; + return (ContextBase.this.containsValue(entry.getValue())); + } + + public boolean isEmpty() { + return (ContextBase.this.isEmpty()); + } + + public Iterator iterator() { + return (ContextBase.this.valuesIterator()); + } + + public boolean remove(Object obj) { + if (obj instanceof Map.Entry) { + return (ContextBase.this.remove((Map.Entry) obj)); + } else { + return (false); + } + } + + public int size() { + return (ContextBase.this.size()); + } + + } + + + /** + *

Private implementation of Iterator for the + * Collection returned by values().

+ */ + private class ValuesIterator implements Iterator { + + Map.Entry entry = null; + private Iterator keys = ContextBase.this.keySet().iterator(); + + public boolean hasNext() { + return (keys.hasNext()); + } + + public Object next() { + entry = ContextBase.this.entry(keys.next()); + return (entry.getValue()); + } + + public void remove() { + ContextBase.this.remove(entry); + } + + } + + +} Propchange: directory/protocol-providers/dns/trunk/src/java/org/apache/dns/chain/impl/ContextBase.java ------------------------------------------------------------------------------ svn:eol-style = native