Port extension activity and extension assign operation support from ODE 2.0 alpha branch
diff --git a/.gitignore b/.gitignore
index 27225ba..c7cf71d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@
 Gemfile.lock
 spoon
 *.log
+.m2/
+tmp/
diff --git a/axis2-war/src/main/webapp/WEB-INF/conf/ode-axis2.properties b/axis2-war/src/main/webapp/WEB-INF/conf/ode-axis2.properties
index 03ac79c..3c61926 100644
--- a/axis2-war/src/main/webapp/WEB-INF/conf/ode-axis2.properties
+++ b/axis2-war/src/main/webapp/WEB-INF/conf/ode-axis2.properties
@@ -101,3 +101,8 @@
 
 ## Clustering Implementation class.
 #ode-axis2.clustering.impl.class = org.apache.ode.clustering.hazelcast.HazelcastClusterImpl
+
+## Extension Bundles
+## FQCNs, comma separated.
+#ode-axis2.extension.bundles.runtime=[packageName].[bundleClassName]
+#ode-axis2.extension.bundles.validation=[packageName].[bundleClassName]
diff --git a/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java b/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java
index e002695..347f44c 100644
--- a/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java
+++ b/axis2/src/main/java/org/apache/ode/axis2/ODEServer.java
@@ -38,12 +38,16 @@
 import org.apache.ode.bpel.engine.BpelServerImpl;
 import org.apache.ode.bpel.engine.CountLRUDehydrationPolicy;
 import org.apache.ode.bpel.engine.cron.CronScheduler;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
+import org.apache.ode.bpel.extension.ExtensionBundleValidation;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.extvar.jdbc.JdbcExternalVariableModule;
 import org.apache.ode.bpel.iapi.*;
 import org.apache.ode.bpel.intercept.MessageExchangeInterceptor;
 import org.apache.ode.bpel.memdao.BpelDAOConnectionFactoryImpl;
 import org.apache.ode.bpel.pmapi.InstanceManagement;
 import org.apache.ode.bpel.pmapi.ProcessManagement;
+import org.apache.ode.bpel.runtime.common.extension.AbstractExtensionBundle;
 import org.apache.ode.il.config.OdeConfigProperties;
 import org.apache.ode.il.dbutil.Database;
 import org.apache.ode.scheduler.simple.JdbcDelegate;
@@ -58,6 +62,8 @@
 import javax.sql.DataSource;
 import javax.transaction.*;
 import javax.transaction.xa.XAResource;
+import javax.xml.namespace.QName;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -195,6 +201,7 @@
         registerEventListeners();
         registerMexInterceptors();
         registerExternalVariableModules();
+        registerExtensionActivityBundles();
 
         _store.loadAll();
         if (_clusterManager != null) {
@@ -691,6 +698,86 @@
 
     }
 
+    // Add support for extension bundles based on ODE 2.0 alpha branch
+    private void registerExtensionActivityBundles() {
+		String extensionsRTStr = _odeConfig.getExtensionActivityBundlesRT();
+		String extensionsValStr = _odeConfig
+				.getExtensionActivityBundlesValidation();
+		if (extensionsRTStr != null) {
+			// TODO replace StringTokenizer by regex
+			for (StringTokenizer tokenizer = new StringTokenizer(
+					extensionsRTStr, ",;"); tokenizer.hasMoreTokens();) {
+				String bundleCN = tokenizer.nextToken();
+				
+				//@hahnml: Remove any whitespaces
+				bundleCN = bundleCN.replaceAll(" ", "");
+				
+				try {
+					// instantiate bundle
+					ExtensionBundleRuntime bundleRT = (ExtensionBundleRuntime) Class
+							.forName(bundleCN).newInstance();
+					
+					// register extension bundle (BPEL server)
+					_bpelServer.registerExtensionBundle(bundleRT);
+					
+					if (bundleRT instanceof AbstractExtensionBundle) {
+						AbstractExtensionBundle bundle = (AbstractExtensionBundle) bundleRT;
+						
+						//@hahnml: Get the registered validators from the process store
+						Map<QName, ExtensionValidator> validators = _store.getExtensionValidators();
+						
+						//Add the validators of this bundle to the existing validators
+						validators.putAll(bundle.getExtensionValidators());
+						
+						// register extension bundle (BPEL store)
+						_store.setExtensionValidators(validators);
+					}
+				} catch (Exception e) {
+					__log.warn("Couldn't register the extension bundle runtime "
+							+ bundleCN
+							+ ", the class couldn't be "
+							+ "loaded properly.");
+				}
+			}
+		}
+		if (extensionsValStr != null) {
+			Map<QName, ExtensionValidator> validators = new HashMap<QName, ExtensionValidator>();
+			for (StringTokenizer tokenizer = new StringTokenizer(
+					extensionsValStr, ",;"); tokenizer.hasMoreTokens();) {
+				String bundleCN = tokenizer.nextToken();
+				
+				//@hahnml: Remove any whitespaces
+				bundleCN = bundleCN.replaceAll(" ", "");
+				
+				try {
+					// instantiate bundle
+					ExtensionBundleValidation bundleVal = (ExtensionBundleValidation) Class
+							.forName(bundleCN).newInstance();
+					// add validators
+					validators.putAll(bundleVal.getExtensionValidators());
+				} catch (Exception e) {
+					__log.warn("Couldn't register the extension bundle validator "
+							+ bundleCN
+							+ ", the class couldn't be "
+							+ "loaded properly.");
+				}
+			}
+			// register extension bundle (BPEL store)
+			//@hahnml: Check if validators are registered already
+			if (_store.getExtensionValidators().isEmpty()) {
+				_store.setExtensionValidators(validators);
+			} else {
+				//@hahnml: Get the registered validators from the process store
+				Map<QName, ExtensionValidator> allValidators = _store.getExtensionValidators();
+				
+				//Add the registered validators to the existing validators
+				allValidators.putAll(validators);
+				
+				// register extension bundle (BPEL store)
+				_store.setExtensionValidators(allValidators);
+			}
+		}
+	}
     private class ProcessStoreListenerImpl implements ProcessStoreListener {
 
         public void onProcessStoreEvent(ProcessStoreEvent event) {
diff --git a/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensibleElement.java b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensibleElement.java
new file mode 100644
index 0000000..f7922d4
--- /dev/null
+++ b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensibleElement.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.extension;
+
+import org.w3c.dom.Element;
+
+/**
+ * Common interface for ExtensionActivity and AssignExtensionOperation.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public interface ExtensibleElement {
+
+	Element getNestedElement();
+
+}
diff --git a/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleRuntime.java b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleRuntime.java
new file mode 100644
index 0000000..2ddf3ac
--- /dev/null
+++ b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleRuntime.java
@@ -0,0 +1,12 @@
+package org.apache.ode.bpel.extension;
+
+public interface ExtensionBundleRuntime {
+
+	String getNamespaceURI();
+
+	void registerExtensionActivities();
+
+	ExtensionOperation getExtensionOperationInstance(String localName)
+			throws InstantiationException, IllegalAccessException;
+
+}
diff --git a/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleValidation.java b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleValidation.java
new file mode 100644
index 0000000..f12cf14
--- /dev/null
+++ b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionBundleValidation.java
@@ -0,0 +1,13 @@
+package org.apache.ode.bpel.extension;
+
+import javax.xml.namespace.QName;
+import java.util.Map;
+
+/**
+ * Compile-time validation of extensions implemented by your bundle.
+ */
+public interface ExtensionBundleValidation {
+
+	Map<QName, ExtensionValidator> getExtensionValidators();
+
+}
diff --git a/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionOperation.java b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionOperation.java
new file mode 100644
index 0000000..da1c930
--- /dev/null
+++ b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionOperation.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.extension;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.w3c.dom.Element;
+
+/**
+ * This is the basis interface for implementations of
+ * <code>&lt;extensionAssignOperation&gt;</code> and
+ * <code>&lt;extensionActivity&gt;</code> nodes.
+ * 
+ * Implementations of this interface must provide a default constructor as they
+ * are created using reflection.
+ * 
+ * @see AbstractExtensionBundle
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public interface ExtensionOperation {
+
+	/**
+	 * Provides the runtime implementation.
+	 * 
+	 * <strong>Note:</strong> This method MAY run concurrently. Since Xerces'
+	 * DOM implementation is not thread-safe, please make sure to synchronize
+	 * the access to <code>element</code> if necessary.
+	 * 
+	 * @param context
+	 *            injected ExtensionContext
+	 * @param element
+	 *            the extension element (child of <code>extensionActivity</code>
+	 *            or <code>extensionAssignOperation</code>
+	 * @throws FaultException
+	 */
+	void run(Object context, Element element) throws FaultException;
+
+}
diff --git a/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionValidator.java b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionValidator.java
new file mode 100644
index 0000000..5159c1b
--- /dev/null
+++ b/bpel-api/src/main/java/org/apache/ode/bpel/extension/ExtensionValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.extension;
+
+import org.apache.ode.bpel.extension.ExtensibleElement;
+
+/**
+ * Interface that allows Ode extensions to validate an extension element's
+ * content during compilation.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public interface ExtensionValidator {
+
+	/**
+	 * 
+	 * @param compilerContext
+	 * @param element
+	 */
+	void validate(Object compilerContext, ExtensibleElement element);
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGenerator.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGenerator.java
index a2b5f25..91a6384 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGenerator.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGenerator.java
@@ -23,7 +23,9 @@
 import org.apache.ode.bpel.compiler.api.CompilationException;
 import org.apache.ode.bpel.compiler.bom.Activity;
 import org.apache.ode.bpel.compiler.bom.AssignActivity;
+import org.apache.ode.bpel.compiler.bom.AssignActivity.AssignOperation;
 import org.apache.ode.bpel.compiler.bom.Copy;
+import org.apache.ode.bpel.compiler.bom.ExtensionAssignOperation;
 import org.apache.ode.bpel.compiler.bom.ExtensionVal;
 import org.apache.ode.bpel.compiler.bom.From;
 import org.apache.ode.bpel.compiler.bom.LiteralVal;
@@ -31,6 +33,7 @@
 import org.apache.ode.bpel.compiler.bom.PropertyVal;
 import org.apache.ode.bpel.compiler.bom.To;
 import org.apache.ode.bpel.compiler.bom.VariableVal;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.DebugInfo;
 import org.apache.ode.bpel.obj.OActivity;
 import org.apache.ode.bpel.obj.OAssign;
@@ -62,7 +65,9 @@
     public void compile(OActivity dest, Activity source) {
         OAssign oassign = (OAssign) dest;
         AssignActivity ad = (AssignActivity) source;
-        for (Copy scopy : ad.getCopies()) {
+		for (AssignOperation operation : ad.getOperations()) {
+			if (operation instanceof Copy) {
+				Copy scopy = (Copy) operation;
             OAssign.Copy ocopy = new OAssign.Copy(_context.getOProcess());
             ocopy.setKeepSrcElementName(scopy.isKeepSrcElement());
             ocopy.setIgnoreMissingFromData(scopy.isIgnoreMissingFromData());
@@ -81,11 +86,45 @@
                 ocopy.setFrom(compileFrom(scopy.getFrom(), toResultType[0]));
 
                 verifyCopy(ocopy);
-                oassign.getCopy().add(ocopy);
+                oassign.getOperations().add(ocopy);
 
             } catch (CompilationException ce) {
                 _context.recoveredFromError(scopy, ce);
             }
+			} else if (operation instanceof ExtensionAssignOperation) {
+				ExtensionAssignOperation sop = (ExtensionAssignOperation) operation;
+				OAssign.ExtensionAssignOperation oext = new OAssign.ExtensionAssignOperation(
+						_context.getOProcess());
+				oext.setDebugInfo(new DebugInfo(_context.getSourceLocation(),
+						sop.getLineNo(), source.getExtensibilityElements()));
+				try {
+					if (source.is20Draft()) {
+						throw new CompilationException(
+								__cmsgs.errExtensibleAssignNotSupported());
+					}
+					Element el = sop.getNestedElement();
+					if (el == null) {
+						throw new CompilationException(__cmsgs
+								.errMissingExtensionAssignOperationElement()
+								.setSource(sop));
+					}
+					if (!_context.isExtensionDeclared(el.getNamespaceURI())) {
+						throw new CompilationException(__cmsgs
+								.errUndeclaredExtensionAssignOperation()
+								.setSource(sop));
+					}
+					ExtensionValidator validator = _context
+							.getExtensionValidator(DOMUtils.getElementQName(el));
+					if (validator != null) {
+						validator.validate(_context, sop);
+					}
+					oext.setExtensionName(DOMUtils.getElementQName(el));
+					oext.setNestedElement(DOMUtils.domToString(el));
+					oassign.getOperations().add(oext);
+				} catch (CompilationException ce) {
+					_context.recoveredFromError(sop, ce);
+				}
+			}
         }
     }
 
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGeneratorMessages.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGeneratorMessages.java
index 74252dc..abef091 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGeneratorMessages.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/AssignGeneratorMessages.java
@@ -86,4 +86,18 @@
         return this.formatCompilationMessage("To-spec format is unrecognized.");
     }
 
+    /**ExtensionAssignOperation's nested element missing*/
+    public CompilationMessage errMissingExtensionAssignOperationElement(){
+    	return this.formatCompilationMessage("Extensibility element in <extensionAssignOperation> is missing.");
+    }
+
+    /**ExtensionAssignOperation's nested element missing*/
+    public CompilationMessage errUndeclaredExtensionAssignOperation(){
+    	return this.formatCompilationMessage("Extension namespace of <extensionAssignOperation> has not been declared.");
+    }
+
+    /**Draft extensibleAssign is not supported.*/
+    public CompilationMessage errExtensibleAssignNotSupported(){
+    	return this.formatCompilationMessage("ExtensibleAssign is not supported, please upgrade to BPEL 2.0 final.");
+    }
 }
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelC.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelC.java
index ff1bd34..71cb107 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelC.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelC.java
@@ -38,6 +38,7 @@
 import org.apache.ode.bpel.compiler.api.SourceLocation;
 import org.apache.ode.bpel.compiler.bom.BpelObjectFactory;
 import org.apache.ode.bpel.compiler.bom.Process;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.OProcess;
 import org.apache.ode.bpel.obj.OProcessWrapper;
 import org.apache.ode.bpel.obj.serde.DeSerializer;
@@ -72,6 +73,8 @@
     private Map<String,Object> _compileProperties;
     private boolean _dryRun = false;
 
+    private Map<QName, ExtensionValidator> _extensionValidators;
+
     public static BpelC newBpelCompiler() {
         return new BpelC();
     }
@@ -252,6 +255,9 @@
                 if (_compileProperties.get(PROCESS_CUSTOM_PROPERTIES) != null)
                     compiler.setCustomProperties((Map<QName, Node>) _compileProperties.get(PROCESS_CUSTOM_PROPERTIES));
             }
+            if (_extensionValidators != null) {
+            	compiler.setExtensionValidators(_extensionValidators);
+            }
         } catch (CompilationException ce) {
             this.invalidate();
             throw ce;
@@ -523,4 +529,12 @@
         }
     }
 
+    /**
+     * Registers extension validators to eventually validate the content of extensibility
+     * elements. 
+     * @param extensionValidators
+     */
+    public void setExtensionValidators(Map<QName, ExtensionValidator> extensionValidators) {
+        _extensionValidators = extensionValidators;
+    }
 }
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler.java
index 00d8ccd..a1545ee 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler.java
@@ -63,6 +63,7 @@
 import org.apache.ode.bpel.compiler.bom.CorrelationSet;
 import org.apache.ode.bpel.compiler.bom.Expression;
 import org.apache.ode.bpel.compiler.bom.Expression11;
+import org.apache.ode.bpel.compiler.bom.Extension;
 import org.apache.ode.bpel.compiler.bom.FaultHandler;
 import org.apache.ode.bpel.compiler.bom.Import;
 import org.apache.ode.bpel.compiler.bom.LinkSource;
@@ -81,6 +82,7 @@
 import org.apache.ode.bpel.compiler.bom.Variable;
 import org.apache.ode.bpel.compiler.wsdl.Definition4BPEL;
 import org.apache.ode.bpel.compiler.wsdl.WSDLFactory4BPEL;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.DebugInfo;
 import org.apache.ode.bpel.obj.OActivity;
 import org.apache.ode.bpel.obj.OAssign;
@@ -138,7 +140,7 @@
 
     private Date _generatedDate;
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     private HashMap<Class, ActivityGenerator> _actGenerators = new HashMap<Class, ActivityGenerator>();
 
     private boolean _supressJoinFailure = false;
@@ -182,6 +184,9 @@
 
     private URI _processURI;
 
+    private final Set<String> _declaredExtensionNS = new HashSet<String>();
+	private Map<QName, ExtensionValidator> _extensionValidators = new HashMap<QName, ExtensionValidator>();
+
     BpelCompiler(WSDLFactory4BPEL wsdlFactory) {
         _wsdlFactory = wsdlFactory;
         _wsdlRegistry = new WSDLRegistry(this);
@@ -733,6 +738,11 @@
             }
         }
 
+        // compile extensions
+	for (Extension e : _processDef.getExtensions()) {
+		compileExtension(e);
+	}
+
         OScope procesScope = new OScope(_oprocess, null);
         procesScope.setName("__PROCESS_SCOPE:" + (process.getName()));
         procesScope.setDebugInfo(createDebugInfo(process, null));
@@ -1628,17 +1638,44 @@
         for (OActivity act : _compiledActivities) {
             if (act instanceof OAssign) {
                 OAssign assign = (OAssign) act;
-                for (OAssign.Copy copy : assign.getCopy()) {
-                    if (copy.getTo() instanceof OAssign.PartnerLinkRef) {
-                        if (((OAssign.PartnerLinkRef) copy.getTo()).getPartnerLink().getName().equals(plink))
-                            return true;
-                    }
-                }
+                for (OAssign.OAssignOperation operation : assign.getOperations()) {
+					if (operation instanceof OAssign.Copy) {
+						OAssign.Copy copy = (OAssign.Copy) operation;
+						if (copy.getTo() instanceof OAssign.PartnerLinkRef) {
+							if (((OAssign.PartnerLinkRef) copy.getTo()).getPartnerLink()
+									.getName().equals(plink))
+								return true;
+						}
+					}
+				}
             }
         }
         return false;
     }
 
+    /**
+	 * Registers a declared extension. Since compilation may take place
+	 * independently of the target engine configuration, the compiler will not
+	 * check whether a extension implementation is registered.
+	 */
+	private void compileExtension(Extension ext) {
+		OProcess.OExtension oextension = new OProcess.OExtension(_oprocess);
+		oextension.setNamespace(ext.getNamespaceURI());
+		oextension.setMustUnderstand(ext.isMustUnderstand());
+
+		oextension.setDebugInfo(createDebugInfo(_processDef,
+				"Extension " + ext.getNamespaceURI()));
+
+		_declaredExtensionNS.add(ext.getNamespaceURI());
+		_oprocess.getDeclaredExtensions().add(oextension);
+		if (ext.isMustUnderstand()) {
+			_oprocess.getMustUnderstandExtensions().add(oextension);
+		}
+
+		if (__log.isDebugEnabled())
+			__log.debug("Compiled extension " + oextension);
+	}
+
     public Definition[] getWsdlDefinitions() {
         Definition[] result = new Definition[_wsdlRegistry.getDefinitions().length];
         for (int m = 0; m < _wsdlRegistry.getDefinitions().length; m++) {
@@ -1657,7 +1694,7 @@
         return type;
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     private ActivityGenerator findActivityGen(Activity source) {
 
         Class actClass = source.getClass();
@@ -1674,7 +1711,7 @@
         throw new CompilationException(__cmsgs.errUnknownActivity(actClass.getName()).setSource(source));
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     protected void registerActivityCompiler(Class defClass, ActivityGenerator generator) {
         if (__log.isDebugEnabled()) {
             __log.debug("Adding compiler for nodes class \"" + defClass.getName() + " = " + generator);
@@ -1709,12 +1746,25 @@
         _expLanguageCompilers.put(expLangUri, expressionCompiler);
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     protected void registerExpressionLanguage(String expLangUri, String classname) throws Exception {
         Class cls = Class.forName(classname);
         registerExpressionLanguage(expLangUri, (ExpressionCompiler) cls.newInstance());
     }
 
+    public void setExtensionValidators(
+			Map<QName, ExtensionValidator> extensionValidators) {
+		_extensionValidators = extensionValidators;
+	}
+
+	public boolean isExtensionDeclared(String namespace) {
+		return _declaredExtensionNS.contains(namespace);
+	}
+
+	public ExtensionValidator getExtensionValidator(QName extensionElementName) {
+		return _extensionValidators.get(extensionElementName);
+	}
+
     public List<OActivity> getActivityStack() {
         ArrayList<OActivity> rval = new ArrayList<OActivity>(_structureStack._stack);
         Collections.reverse(rval);
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20.java
index 7bba612..e4b1f0d 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20.java
@@ -23,6 +23,7 @@
 import org.apache.ode.bpel.compiler.bom.CompensateActivity;
 import org.apache.ode.bpel.compiler.bom.CompensateScopeActivity;
 import org.apache.ode.bpel.compiler.bom.EmptyActivity;
+import org.apache.ode.bpel.compiler.bom.ExtensionActivity;
 import org.apache.ode.bpel.compiler.bom.FlowActivity;
 import org.apache.ode.bpel.compiler.bom.ForEachActivity;
 import org.apache.ode.bpel.compiler.bom.IfActivity;
@@ -71,6 +72,7 @@
         registerActivityCompiler(TerminateActivity.class, new TerminateGenerator());
         registerActivityCompiler(RethrowActivity.class, new RethrowGenerator());
         registerActivityCompiler(ForEachActivity.class, new ForEachGenerator());
+        registerActivityCompiler(ExtensionActivity.class, new ExtensionActivtityGenerator());
 
         registerExpressionLanguage(OASIS_EXPLANG_XPATH_1_0, new XPath10ExpressionCompilerBPEL20());
 
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20Draft.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20Draft.java
index 8faf69a..bb9f082 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20Draft.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/BpelCompiler20Draft.java
@@ -23,6 +23,7 @@
 import org.apache.ode.bpel.compiler.bom.Bpel20QNames;
 import org.apache.ode.bpel.compiler.bom.CompensateScopeActivity;
 import org.apache.ode.bpel.compiler.bom.EmptyActivity;
+import org.apache.ode.bpel.compiler.bom.ExtensionActivity;
 import org.apache.ode.bpel.compiler.bom.FlowActivity;
 import org.apache.ode.bpel.compiler.bom.ForEachActivity;
 import org.apache.ode.bpel.compiler.bom.IfActivity;
@@ -70,6 +71,7 @@
         registerActivityCompiler(TerminateActivity.class, new TerminateGenerator());
         registerActivityCompiler(RethrowActivity.class, new RethrowGenerator());
         registerActivityCompiler(ForEachActivity.class, new ForEachGenerator());
+        registerActivityCompiler(ExtensionActivity.class, new ExtensionActivtityGenerator());
 
         registerExpressionLanguage(OASIS_EXPLANG_XPATH_1_0, new XPath10ExpressionCompilerBPEL20Draft());
         try {
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivityGeneratorMessages.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivityGeneratorMessages.java
new file mode 100644
index 0000000..5971bc8
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivityGeneratorMessages.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler;
+
+import org.apache.ode.bpel.compiler.api.CompilationMessage;
+import org.apache.ode.bpel.compiler.api.CompilationMessageBundle;
+
+/**
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class ExtensionActivityGeneratorMessages extends
+		CompilationMessageBundle {
+
+	/** ExtensionActivity is empty. */
+	public CompilationMessage errMissingExtensionActivityElement() {
+		return this
+				.formatCompilationMessage("Extensibility element in <extensionActivity> is missing.");
+	}
+
+	/** Extension namespace is not yet declared. */
+	public CompilationMessage errUndeclaredExtensionActivity() {
+		return this
+				.formatCompilationMessage("Extension namespace of <extensionActivity> has not been declared.");
+	}
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivtityGenerator.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivtityGenerator.java
new file mode 100644
index 0000000..22d949b
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/ExtensionActivtityGenerator.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler;
+
+import org.apache.ode.bpel.compiler.api.CompilationException;
+import org.apache.ode.bpel.compiler.bom.Activity;
+import org.apache.ode.bpel.compiler.bom.CompositeActivity;
+import org.apache.ode.bpel.compiler.bom.ExtensionActivity;
+import org.apache.ode.bpel.extension.ExtensionValidator;
+import org.apache.ode.bpel.obj.OActivity;
+import org.apache.ode.bpel.obj.OExtensionActivity;
+import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.msg.MessageBundle;
+import org.w3c.dom.Element;
+
+/**
+ * Generates code for <code>&lt;empty&gt;</code> activities.
+ * 
+ * @author Tammo van Lessen
+ */
+public class ExtensionActivtityGenerator extends DefaultActivityGenerator {
+	private static final ExtensionActivityGeneratorMessages __cmsgs = MessageBundle
+			.getMessages(ExtensionActivityGeneratorMessages.class);
+
+	public void compile(OActivity output, Activity srcx) {
+		ExtensionActivity src = (ExtensionActivity) srcx;
+		OExtensionActivity oactivity = (OExtensionActivity) output;
+		Element child = src.getFirstExtensibilityElementElement();
+		try {
+			if (child == null) {
+				throw new CompilationException(
+						__cmsgs.errMissingExtensionActivityElement());
+			}
+			if (!_context.isExtensionDeclared(child.getNamespaceURI())) {
+				throw new CompilationException(__cmsgs
+						.errUndeclaredExtensionActivity().setSource(src));
+			}
+			ExtensionValidator validator = _context
+					.getExtensionValidator(DOMUtils.getElementQName(child));
+			if (validator != null) {
+				validator.validate(_context, src);
+			}
+			oactivity.setExtensionName(DOMUtils.getElementQName(child));
+			oactivity.setNestedElement(DOMUtils.domToString(child));
+
+			compileChildren(oactivity, (ExtensionActivity) src);
+
+		} catch (CompilationException e) {
+			_context.recoveredFromError(src, e);
+		}
+	}
+
+	public OActivity newInstance(Activity src) {
+		return new OExtensionActivity(_context.getOProcess(),
+				_context.getCurrent());
+	}
+
+	protected void compileChildren(OExtensionActivity dest,
+			CompositeActivity src) {
+		for (Activity child : src.getActivities()) {
+			try {
+				OActivity compiledChild = _context.compile(child);
+				dest.getChildren().add(compiledChild);
+			} catch (CompilationException ce) {
+				_context.recoveredFromError(child, ce);
+			}
+		}
+	}
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/api/CompilerContext.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/api/CompilerContext.java
index 5d9f634..83467df 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/api/CompilerContext.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/api/CompilerContext.java
@@ -29,6 +29,7 @@
 import org.apache.ode.bpel.compiler.bom.Activity;
 import org.apache.ode.bpel.compiler.bom.Expression;
 import org.apache.ode.bpel.compiler.bom.ScopeLikeActivity;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.OActivity;
 import org.apache.ode.bpel.obj.OExpression;
 import org.apache.ode.bpel.obj.OLValueExpression;
@@ -146,6 +147,10 @@
 
     Map<URI, Source> getSchemaSources();
 
+	boolean isExtensionDeclared(String namespace);
+
+	ExtensionValidator getExtensionValidator(QName extensionElementName);
+
     /**
      * Retrieves the base URI that the BPEL Process execution contextis running relative to.
      *
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/AssignActivity.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/AssignActivity.java
index f503a83..1c890aa 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/AssignActivity.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/AssignActivity.java
@@ -18,6 +18,7 @@
  */
 package org.apache.ode.bpel.compiler.bom;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.w3c.dom.Element;
@@ -41,4 +42,38 @@
     public List<Copy> getCopies() {
         return getChildren(Copy.class);
     }
+
+    /**
+     * Get the list of <code>&lt;extensionAssignOperation&gt;</code> entries for this activity.
+     * 
+     * @return extensionAssignOperation entries
+     */
+    public List<ExtensionAssignOperation> getExtensionAssignOperations() {
+        return getChildren(ExtensionAssignOperation.class);
+    }
+
+    /**
+     * Get the list of all assign operation entries (<code>copy</code> 
+     * and <code>extensionAssignOperation</code>) for this activity.
+     * 
+     * @return assign operation entries
+     */
+    public List<AssignOperation> getOperations() {
+    	//all children objects
+    	List<BpelObject> children = getChildren(BpelObject.class);
+    	
+    	//aggregate only copy and extensionAssignOperation entries
+    	List<AssignOperation> ops = new ArrayList<AssignOperation>();
+    	for (BpelObject bo: children) {
+    		if ((bo instanceof Copy)
+    				||(bo instanceof ExtensionAssignOperation)) {
+    			ops.add((AssignOperation)bo);				
+			}
+    	}    	
+
+    	return ops;
+    }
+
+    /** Marker interface for assign operations */
+    public static interface AssignOperation {}
 }
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Bpel20QNames.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Bpel20QNames.java
index 492514e..3e962a0 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Bpel20QNames.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Bpel20QNames.java
@@ -109,6 +109,10 @@
     public static final QName FINAL_PROPQUERY = new QName(NS_WSBPEL2_0_FINAL_VARPROP, "query");
     public static final QName FINAL_PLINKTYPE = new QName(NS_WSBPEL2_0_FINAL_PLINK, "partnerLinkType");
     public static final QName FINAL_PLINKROLE = new QName(NS_WSBPEL2_0_FINAL_PLINK, "role");
+    public static final QName FINAL_EXTENSIONS = newFinalQName("extensions");
+    public static final QName FINAL_EXTENSION = newFinalQName("extension");
+    public static final QName FINAL_EXTENSION_ASSIGN_OPERATION = newFinalQName("extensionAssignOperation");
+    public static final QName FINAL_EXTENSION_ACTIVITY = newFinalQName("extensionActivity");
 
     /** Some BPEL 2.0 Draft Elements **/
     public static final QName PROCESS = newQName("process");
@@ -183,6 +187,10 @@
     public static final QName PROPERTY = newQName("property");
     public static final QName PLINKTYPE = new QName(NS_WSBPEL_PARTNERLINK_2004_03, "partnerLinkType");
     public static final QName PLINKROLE = new QName(NS_WSBPEL_PARTNERLINK_2004_03, "role");
+    public static final QName EXTENSIONS = newQName("extensions");
+    public static final QName EXTENSION = newQName("extension");
+    public static final QName EXTENSIBLE_ASSIGN = newQName("extensibleAssign");
+    public static final QName EXTENSION_ACTIVITY = newQName("extensionActivity");
 
     /** Not part of BPEL, but handy to have. */
     public static final String NS_RDF = "http://www.w3.org/2000/01/rdf-schema#";
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/BpelObjectFactory.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/BpelObjectFactory.java
index 7ab2acb..f2b64aa 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/BpelObjectFactory.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/BpelObjectFactory.java
@@ -131,6 +131,10 @@
         _mappings.put(Bpel20QNames.FINAL_EVENTHANDLERS, BpelObject.class);
         _mappings.put(Bpel20QNames.FINAL_TARGETS,Targets.class);
         _mappings.put(Bpel20QNames.FINAL_SOURCES,Sources.class);
+        _mappings.put(Bpel20QNames.FINAL_EXTENSIONS,Extensions.class);
+        _mappings.put(Bpel20QNames.FINAL_EXTENSION,Extension.class);
+        _mappings.put(Bpel20QNames.FINAL_EXTENSION_ACTIVITY,ExtensionActivity.class);
+        _mappings.put(Bpel20QNames.FINAL_EXTENSION_ASSIGN_OPERATION,ExtensionAssignOperation.class);
 
         //
         // BPEL 2.0 draft Mappings
@@ -207,6 +211,10 @@
         _mappings.put(Bpel20QNames.TARGETS,Targets.class);
         _mappings.put(Bpel20QNames.SOURCES,Sources.class);
         _mappings.put(Bpel20QNames.RDF_LABEL,RdfLabel.class);
+        _mappings.put(Bpel20QNames.EXTENSIONS,Extensions.class);
+        _mappings.put(Bpel20QNames.EXTENSION,Extension.class);
+        _mappings.put(Bpel20QNames.EXTENSION_ACTIVITY,ExtensionActivity.class);
+        _mappings.put(Bpel20QNames.EXTENSIBLE_ASSIGN,ExtensionAssignOperation.class);
 
         //
         // BPEL 1.1 Mappings
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Copy.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Copy.java
index 1764828..22523e0 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Copy.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Copy.java
@@ -18,6 +18,7 @@
  */
 package org.apache.ode.bpel.compiler.bom;
 
+import org.apache.ode.bpel.compiler.bom.AssignActivity.AssignOperation;
 import org.w3c.dom.Element;
 
 /**
@@ -25,7 +26,7 @@
  * (L-value) and a "right hand side (R-value). The value on the right hand side
  * is copied to the location referenced in the left hand side.
  */
-public class Copy extends BpelObject {
+public class Copy extends BpelObject implements AssignOperation {
 
     public Copy(Element el) {
         super(el);
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extension.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extension.java
new file mode 100644
index 0000000..2a5a755
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extension.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler.bom;
+
+import org.w3c.dom.Element;
+
+/**
+ * BOM representation of the BPEL <code>&lt;extension&gt;</code> element.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class Extension extends BpelObject {
+
+	public Extension(Element el) {
+		super(el);
+	}
+
+	public boolean isMustUnderstand() {
+		return getAttribute("mustUnderstand", "no").equals("yes");
+	}
+
+	public String getNamespaceURI() {
+		return getAttribute("namespace", null);
+	}
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionActivity.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionActivity.java
new file mode 100644
index 0000000..78c5d87
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionActivity.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler.bom;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.w3c.dom.Element;
+import org.apache.ode.bpel.extension.ExtensibleElement;
+
+/**
+ * BOM representation of the BPEL <code>&lt;extensionActivity&gt;</code>
+ * activity. The <code>&lt;extensionActivity&gt;</code> activity contains a
+ * nested DOM element that represents the actual extension element. According to
+ * the BPEL 2.0 PR1 specification, the standards elements and standards
+ * attributes are not located in the extensionActivity element but in the nested
+ * element. Therefore the convenient access methods for standards
+ * attributes/elements are overridden to refer to the nested elements.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class ExtensionActivity extends CompositeActivity implements
+		ExtensibleElement {
+	private Activity _childActivity;
+
+	public ExtensionActivity(Element el) {
+		super(el);
+		_childActivity = null;
+		Element child = getFirstExtensibilityElementElement();
+		if (child != null) {
+			_childActivity = new Activity(getFirstExtensibilityElementElement());
+		}
+	}
+
+	@Override
+	public Expression getJoinCondition() {
+		if (_childActivity == null) {
+			return null;
+		}
+		return _childActivity.getJoinCondition();
+	}
+
+	@Override
+	public List<LinkSource> getLinkSources() {
+		if (_childActivity == null) {
+			return Collections.emptyList();
+		}
+		return _childActivity.getLinkSources();
+	}
+
+	@Override
+	public List<LinkTarget> getLinkTargets() {
+		if (_childActivity == null) {
+			return Collections.emptyList();
+		}
+		return _childActivity.getLinkTargets();
+	}
+
+	@Override
+	public String getName() {
+		if (_childActivity == null) {
+			return null;
+		}
+		return _childActivity.getName();
+	}
+
+	@Override
+	public SuppressJoinFailure getSuppressJoinFailure() {
+		if (_childActivity == null) {
+			return SuppressJoinFailure.NOTSET;
+		}
+		return _childActivity.getSuppressJoinFailure();
+	}
+
+	@Override
+	public List<Activity> getActivities() {
+		if (_childActivity == null) {
+			return Collections.emptyList();
+		}
+
+		return _childActivity.getChildren(Activity.class);
+	}
+
+	public Element getNestedElement() {
+		return getFirstExtensibilityElementElement();
+	}
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionAssignOperation.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionAssignOperation.java
new file mode 100644
index 0000000..6a18cdf
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/ExtensionAssignOperation.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler.bom;
+
+import org.apache.ode.bpel.compiler.bom.AssignActivity.AssignOperation;
+import org.apache.ode.bpel.extension.ExtensibleElement;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * BOM representation of the BPEL <code>&lt;extensionAssignOperation&gt;</code>.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class ExtensionAssignOperation extends BpelObject implements
+		AssignOperation, ExtensibleElement {
+	private Element _childElement;
+
+	public ExtensionAssignOperation(Element el) {
+		super(el);
+	}
+
+	public Element getNestedElement() {
+		// XXX
+		// return getFirstExtensibilityElement();
+		if (_childElement == null) {
+			NodeList nl = getElement().getChildNodes();
+			for (int i = 0; i < nl.getLength(); ++i) {
+				Node node = nl.item(i);
+				if (node.getNodeType() == Node.ELEMENT_NODE
+						&& !Bpel20QNames.NS_WSBPEL2_0.equals(node
+								.getNamespaceURI())) {
+					_childElement = (Element) node;
+					break;
+				}
+			}
+		}
+		return _childElement;
+	}
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extensions.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extensions.java
new file mode 100644
index 0000000..5f7365b
--- /dev/null
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Extensions.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.compiler.bom;
+
+import org.w3c.dom.Element;
+
+/**
+ * BOM representation of the BPEL <code>&lt;extension&gt;</code> element.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class Extensions extends BpelObject {
+
+	public Extensions(Element el) {
+		super(el);
+	}
+
+}
diff --git a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Process.java b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Process.java
index 694c10c..017c175 100644
--- a/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Process.java
+++ b/bpel-compiler/src/main/java/org/apache/ode/bpel/compiler/bom/Process.java
@@ -20,6 +20,7 @@
 
 import org.w3c.dom.Element;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -111,4 +112,16 @@
         return getChildren(Import.class);
     }
 
+    /**
+     * Get the <code>&lt;extensions&gt;</code>(s) of the process.
+     * 
+     * @return {@link Set} of {@link Extension}s
+     */
+    public List<Extension> getExtensions() {
+        Extensions extensions = getFirstChild(Extensions.class);
+        if (extensions == null)
+            return Collections.emptyList();
+        return extensions.getChildren(Extension.class);
+
+    }
 }
diff --git a/bpel-compiler/src/test/java/org/apache/ode/bpel/compiler/XPathTest.java b/bpel-compiler/src/test/java/org/apache/ode/bpel/compiler/XPathTest.java
index 57f6ea4..df00dac 100644
--- a/bpel-compiler/src/test/java/org/apache/ode/bpel/compiler/XPathTest.java
+++ b/bpel-compiler/src/test/java/org/apache/ode/bpel/compiler/XPathTest.java
@@ -44,6 +44,7 @@
 import org.apache.ode.bpel.elang.xpath10.compiler.XPath10ExpressionCompilerBPEL20Draft;
 import org.apache.ode.bpel.elang.xpath20.compiler.XPath20ExpressionCompilerBPEL20;
 import org.apache.ode.bpel.elang.xpath20.compiler.XPath20ExpressionCompilerBPEL20Draft;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.OActivity;
 import org.apache.ode.bpel.obj.OElementVarType;
 import org.apache.ode.bpel.obj.OExpression;
@@ -301,4 +302,12 @@
     public NSContext tryCacheNamespaceContext(NSContext nsContext) {
         return nsContext;
     }
+
+    public boolean isExtensionDeclared(String namespace) {
+		return false;
+	}
+
+	public ExtensionValidator getExtensionValidator(QName extensionElementName) {
+		return null;
+	}
 }
diff --git a/bpel-epr/src/main/java/org/apache/ode/il/config/OdeConfigProperties.java b/bpel-epr/src/main/java/org/apache/ode/il/config/OdeConfigProperties.java
index c03edf6..abfc50f 100644
--- a/bpel-epr/src/main/java/org/apache/ode/il/config/OdeConfigProperties.java
+++ b/bpel-epr/src/main/java/org/apache/ode/il/config/OdeConfigProperties.java
@@ -112,6 +112,10 @@
 
     public static final String DEFAULT_CLUSTERING_IMPL_CLASS_NAME = "org.apache.ode.clustering.hazelcast.HazelcastClusterImpl";
 
+    public static final String PROP_EXTENSION_BUNDLES_RT = "extension.bundles.runtime";
+    
+    public static final String PROP_EXTENSION_BUNDLES_VAL = "extension.bundles.validation";
+
     private File _cfgFile;
 
     private String _prefix;
@@ -384,4 +388,11 @@
         return Integer.valueOf(getProperty(PROP_MIGRATION_TRANSACTION_TIMEOUT, String.valueOf(0)));
     }
 
+    public String getExtensionActivityBundlesRT() {
+	return getProperty(PROP_EXTENSION_BUNDLES_RT);
+    }
+
+    public String getExtensionActivityBundlesValidation() {
+	return getProperty(PROP_EXTENSION_BUNDLES_VAL);
+    }
 }
diff --git a/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OAssign.java b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OAssign.java
index 8db6375..b0b5868 100644
--- a/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OAssign.java
+++ b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OAssign.java
@@ -32,36 +32,37 @@
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
-public class OAssign extends OActivity  implements Serializable{
+public class OAssign extends OActivity implements Serializable {
 	public static final long serialVersionUID = -1L;
-	private static final String COPY = "copy";
+	private static final String OPERATION = "operation";
 
 	@JsonCreator
 	public OAssign(){
 	}
+	
 	public OAssign(OProcess owner, OActivity parent) {
 		super(owner, parent);
-		setCopy(new ArrayList<Copy>());
+		setOperations(new ArrayList<OAssignOperation>());
 	}
 
 	@Override
 	public void dehydrate() {
 		super.dehydrate();
-		for (Copy copy : getCopy()) {
-			copy.dehydrate();
+		for (OAssignOperation operation : getOperations()) {
+			operation.dehydrate();
 		}
 	}
 
 	@SuppressWarnings("unchecked")
 	@JsonIgnore
-	public List<Copy> getCopy() {
-		Object o = fieldContainer.get(COPY);
-		return o == null ? null : (List<Copy>)o;
+	public List<OAssignOperation> getOperations() {
+		Object o = fieldContainer.get(OPERATION);
+		return o == null ? null : (List<OAssignOperation>)o;
 	}
 
-	public void setCopy(List<Copy> copy) {
-		if (getCopy() == null){
-			fieldContainer.put(COPY, copy);
+	public void setOperations(List<OAssignOperation> operation) {
+		if (getOperations() == null){
+			fieldContainer.put(OPERATION, operation);
 		}
 	}
 
@@ -69,12 +70,31 @@
 		return "{OAssign : " + getName() + ", joinCondition="
 				+ getJoinCondition() + "}";
 	}
+	
+	/** 
+     * Base class for assign operations.
+     */
+    public static abstract class OAssignOperation extends OBase implements Serializable {
+		private static final long serialVersionUID = -3042873658302758854L;
+
+		public enum Type { Copy, ExtensionOperation }
+
+		@JsonCreator
+		public OAssignOperation() {
+		}
+		
+    	public OAssignOperation(OProcess owner) {
+    		super(owner);
+    	}
+    	
+    	public abstract Type getType();
+    }
 
 	/**
-	 * Assignmenet copy entry, i.e. what the assignment consits of.
+	 * Assignment copy entry, i.e. what the assignment consists of.
 	 */
-	public static class Copy extends OBase  implements Serializable{
-	public static final long serialVersionUID = -1L;
+	public static class Copy extends OAssignOperation implements Serializable {
+	    public static final long serialVersionUID = -1L;
 		private static final String TO = "to";
 		private static final String FROM = "from";
 		private static final String KEEPSRCELEMENTNAME = "keepSrcElementName";
@@ -86,10 +106,12 @@
 		public Copy(){
 			initPrimitive();
 		}
+		
 		public Copy(OProcess owner) {
 			super(owner);
 			initPrimitive();
 		}
+		
 		private void initPrimitive(){
 			setIgnoreMissingFromData(false);
 			setIgnoreUninitializedFromVariable(false);
@@ -107,13 +129,13 @@
 		@JsonIgnore
 		public RValue getFrom() {
 			Object o = fieldContainer.get(FROM);
-		return o == null ? null : (RValue)o;
+			return o == null ? null : (RValue)o;
 		}
 
 		@JsonIgnore
 		public boolean isIgnoreMissingFromData() {
 			Object o = fieldContainer.get(IGNOREMISSINGFROMDATA);
-		return o == null ? false : (Boolean)o;
+			return o == null ? false : (Boolean)o;
 		}
 
 		@JsonIgnore
@@ -125,19 +147,19 @@
 		@JsonIgnore
 		public boolean isInsertMissingToData() {
 			Object o = fieldContainer.get(INSERTMISSINGTODATA);
-		return o == null ? false : (Boolean)o;
+			return o == null ? false : (Boolean)o;
 		}
 
 		@JsonIgnore
 		public boolean isKeepSrcElementName() {
 			Object o = fieldContainer.get(KEEPSRCELEMENTNAME);
-		return o == null ? false : (Boolean)o;
+			return o == null ? false : (Boolean)o;
 		}
 
 		@JsonIgnore
 		public LValue getTo() {
 			Object o = fieldContainer.get(TO);
-		return o == null ? null : (LValue)o;
+			return o == null ? null : (LValue)o;
 		}
 
 		public void setFrom(RValue from) {
@@ -169,7 +191,65 @@
 		public String toString() {
 			return "{OCopy " + getTo() + "=" + getFrom() + "}";
 		}
+		
+		@JsonIgnore
+		public Type getType() {
+        	return Type.Copy;
+        }
 	}
+	
+	/**
+     * Assignment extension operation entry, i.e. what the assignment consists of.
+     */
+    public static class ExtensionAssignOperation extends OAssignOperation {
+        private static final long serialVersionUID = 1L;
+        
+        private static final String EXTENSIONNAME = "extensionName";
+		private static final String NESTEDELEMENT = "nestedElement";
+		
+		@JsonCreator
+		public ExtensionAssignOperation(){
+		}
+
+        public ExtensionAssignOperation(OProcess owner) {
+            super(owner);
+        }
+
+        @JsonIgnore
+		public QName getExtensionName() {
+			Object o = fieldContainer.get(EXTENSIONNAME);
+			return o == null ? null : (QName) o;
+		}
+        
+        @JsonIgnore
+		public String getNestedElement() {
+			Object o = fieldContainer.get(NESTEDELEMENT);
+			return o == null ? null : (String)o;
+		}
+        
+        public void setExtensionName(QName extensionName) {
+			fieldContainer.put(EXTENSIONNAME, extensionName);
+		}
+        
+        public void setNestedElement(String nestedElement) {
+			fieldContainer.put(NESTEDELEMENT, nestedElement);
+		}
+
+        public String toString() {
+            return "{OExtensionAssignOperation; " + getExtensionName() + "}";
+        }
+        
+        @Override
+		public void dehydrate() {
+			super.dehydrate();
+			setExtensionName(null);
+			setNestedElement(null);
+		}
+
+        public Type getType() {
+			return Type.ExtensionOperation;
+		}
+    }
 
 	/**
 	 * Direct reference: selects named child of the message document element.
diff --git a/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OExtensionActivity.java b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OExtensionActivity.java
new file mode 100644
index 0000000..2c3632a
--- /dev/null
+++ b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OExtensionActivity.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.obj;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Compiled representation of the BPEL <code>&lt;extensionActivity&gt;</code>
+ * activity.
+ * <p>
+ * Adapted initial version for compatibility with new ODE object model (bpel-nobj).
+ * 
+ * @author Tammo van Lessen (University of Stuttgart), Michael Hahn (mhahn.dev@gmail.com)
+ */
+public class OExtensionActivity extends OActivity implements Serializable {
+
+	static final long serialVersionUID = -1L;
+
+	private static final String EXTENSIONNAME = "extensionName";
+	private static final String NESTEDELEMENT = "nestedElement";
+	private static final String CHILDREN = "children";
+	
+	@JsonCreator
+	public OExtensionActivity(){
+	}
+
+    public OExtensionActivity(OProcess owner, OActivity parent) {
+        super(owner, parent);
+        setChildren(new ArrayList<OActivity>());
+    }
+
+    @JsonIgnore
+	public QName getExtensionName() {
+		Object o = fieldContainer.get(EXTENSIONNAME);
+		return o == null ? null : (QName) o;
+	}
+    
+    @JsonIgnore
+	public String getNestedElement() {
+		Object o = fieldContainer.get(NESTEDELEMENT);
+		return o == null ? null : (String)o;
+	}
+    
+    @SuppressWarnings("unchecked")
+	@JsonIgnore
+	public List<OActivity> getChildren() {
+		Object o = fieldContainer.get(CHILDREN);
+		return o == null ? null : (List<OActivity>)o;
+	}
+    
+    public void setExtensionName(QName extensionName) {
+		fieldContainer.put(EXTENSIONNAME, extensionName);
+	}
+    
+    public void setNestedElement(String nestedElement) {
+		fieldContainer.put(NESTEDELEMENT, nestedElement);
+	}
+    
+    void setChildren(List<OActivity> children) {
+    	if (getChildren() == null) {
+		  fieldContainer.put(CHILDREN, children);
+    	}
+	}
+
+    public String toString() {
+        return "{OExtensionActivity; " + getExtensionName() + "}";
+    }
+    
+    @Override
+	public void dehydrate() {
+		super.dehydrate();
+		setExtensionName(null);
+		setNestedElement(null);
+		for (OBase obase : getChildren()) {
+			obase.dehydrate();
+		}
+		getChildren().clear();
+	}
+}
diff --git a/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OProcess.java b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OProcess.java
index 2296210..d8f0e67 100644
--- a/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OProcess.java
+++ b/bpel-nobj/src/main/java/org/apache/ode/bpel/obj/OProcess.java
@@ -20,7 +20,6 @@
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.net.URI;
 import java.util.ArrayList;
@@ -92,7 +91,12 @@
 	private static final String XSDTYPES = "xsdTypes";
 	private static final String XSLSHEETS = "xslSheets";
 	private static final String NAMESPACECONTEXT = "namespaceContext";
-
+	
+	/** All declared extensions in the process. **/
+	private static final String DECLAREDEXTENSIONS = "declaredExtensions";
+	/** All must-understand extensions in the process. **/
+	private static final String MUSTUNDERSTANDEXTENSIONS = "mustUnderstandExtensions";
+	
 	/**
 	 * This constructor should only be used by Jackson when deserialize.
 	 */
@@ -114,6 +118,9 @@
 		setXsdTypes(new HashMap<QName, OXsdTypeVarType>());
 		setXslSheets(new HashMap<URI, OXslSheet>());
 		
+		setDeclaredExtensions(new HashSet<OExtension>());
+		setMustUnderstandExtensions(new HashSet<OExtension>());
+		
 		setChildIdCounter(0);
 	}
 
@@ -130,6 +137,8 @@
 		getElementTypes().clear();
 		getXsdTypes().clear();
 		getXslSheets().clear();
+		getDeclaredExtensions().clear();
+		getMustUnderstandExtensions().clear();
 	}
 
 	@Override
@@ -164,6 +173,7 @@
 		return o == null ? 0 : (Integer)o;
 	}
 
+	@SuppressWarnings("unchecked")
 	@JsonIgnore
 	public List<OBase> getChildren() {
 		Object o = fieldContainer.get(CHILDREN);
@@ -182,9 +192,9 @@
 		return o == null ? null : (OConstants)o;
 	}
 
+	@SuppressWarnings("rawtypes")
 	@ObjectDiffProperty(ignore = true)
 	@JsonIgnore
-	@SuppressWarnings("unchecked")
 	public List<String> getCorrelators() {
 		// MOVED from ProcessSchemaGenerator
 		List<String> correlators = new ArrayList<String>();
@@ -311,6 +321,20 @@
 		Object o = fieldContainer.get(XSLSHEETS);
 		return o == null ? null : (HashMap<URI, OXslSheet>)o;
 	}
+	
+	@SuppressWarnings("unchecked")
+	@JsonIgnore
+	public Set<OExtension> getDeclaredExtensions() {
+		return (Set<OExtension>) fieldContainer
+				.get(DECLAREDEXTENSIONS);
+	}
+	
+	@SuppressWarnings("unchecked")
+	@JsonIgnore
+	public Set<OExtension> getMustUnderstandExtensions() {
+		return (Set<OExtension>) fieldContainer
+				.get(MUSTUNDERSTANDEXTENSIONS);
+	}
 
 	public void setAllPartnerLinks(Set<OPartnerLink> allPartnerLinks) {
 		if (getAllPartnerLinks() == null) {
@@ -398,6 +422,18 @@
 			fieldContainer.put(XSLSHEETS, xslSheets);
 		}
 	}
+	
+	public void setDeclaredExtensions(Set<OExtension> extensions) {
+		if (getDeclaredExtensions() == null) {
+			fieldContainer.put(DECLAREDEXTENSIONS, extensions);
+		}
+	}
+	
+	public void setMustUnderstandExtensions(Set<OExtension> extensions) {
+		if (getMustUnderstandExtensions() == null) {
+			fieldContainer.put(MUSTUNDERSTANDEXTENSIONS, extensions);
+		}
+	}
 
 	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
 		ois.defaultReadObject();
@@ -535,6 +571,42 @@
 		}
 
 	}
+	
+	public static class OExtension extends OBase implements Serializable {
+		public static final long serialVersionUID = -1L  ;
+        
+        private static final String NAMESPACE = "namespaceURI";
+		private static final String MUSTUNDERSTAND = "mustUnderstand";
+        
+        @JsonCreator
+		public OExtension(){}
+        
+        public OExtension(OProcess process) { super(process); }
+        
+        @JsonIgnore
+		public String getNamespace() {
+			Object o = fieldContainer.get(NAMESPACE);
+			return o == null ? null : (String)o;
+		}
+
+		@JsonIgnore
+		public boolean isMustUnderstand() {
+			Object o = fieldContainer.get(MUSTUNDERSTAND);
+			return o == null ? false : (Boolean)o;
+		}
+		
+		public void setNamespace(String namespaceURI) {
+			fieldContainer.put(NAMESPACE, namespaceURI);
+		}
+
+		public void setMustUnderstand(boolean mustUnderstand) {
+			fieldContainer.put(MUSTUNDERSTAND, mustUnderstand);
+		}
+
+        public String toString() {
+            return "{OExtension " + getNamespace() + (isMustUnderstand() ? " mustUnderstand" : "") + "}";
+        }
+    }
 
 	/**
 	 * custom deserializer of OProcess.
diff --git a/bpel-obj/src/main/java/org/apache/ode/bpel/o/OAssign.java b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OAssign.java
index 64248a3..5212a13 100644
--- a/bpel-obj/src/main/java/org/apache/ode/bpel/o/OAssign.java
+++ b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OAssign.java
@@ -26,12 +26,13 @@
 
 import org.apache.ode.bpel.o.OScope.Variable;
 import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.SerializableElement;
 import org.w3c.dom.Document;
 
 public class OAssign extends OActivity {
     static final long serialVersionUID = -1L  ;
 
-    public final List<Copy> copy = new ArrayList<Copy>();
+    public final List<OAssignOperation> operations = new ArrayList<OAssignOperation>();
 
     public OAssign(OProcess owner, OActivity parent) {
         super(owner, parent);
@@ -41,11 +42,26 @@
     public String toString() {
         return "{OAssign : " + name + ", joinCondition=" + joinCondition + "}";
     }
+    
+    /** 
+     * Base class for assign operations.
+     */
+    public static abstract class OAssignOperation extends OBase {
+		private static final long serialVersionUID = -3042873658302758854L;
+
+		public enum Type { Copy, ExtensionOperation }
+
+    	public OAssignOperation(OProcess owner) {
+    		super(owner);
+    	}
+    	
+    	public abstract Type getType();
+    }
 
     /**
      * Assignmenet copy entry, i.e. what the assignment consits of.
      */
-    public static class Copy extends OBase {
+    public static class Copy extends OAssignOperation {
         private static final long serialVersionUID = 1L;
         public LValue to;
         public RValue from;
@@ -68,6 +84,38 @@
             to = null;
             from = null;
         }
+        
+        public Type getType() {
+        	return Type.Copy;
+        }
+    }
+    
+    /**
+     * Assignment extension operation entry, i.e. what the assignment consists of.
+     */
+    public static class ExtensionAssignOperation extends OAssignOperation {
+        private static final long serialVersionUID = 1L;
+        public SerializableElement nestedElement;
+        public QName extensionName;
+
+        public ExtensionAssignOperation(OProcess owner) {
+            super(owner);
+        }
+
+        public String toString() {
+            return "{OExtensionAssignOperation; " + nestedElement.getElement().getTagName() + "}";
+        }
+        
+        @Override
+		public void dehydrate() {
+			super.dehydrate();
+			nestedElement = null;
+			extensionName = null;
+		}
+
+        public Type getType() {
+			return Type.ExtensionOperation;
+		}
     }
 
     public interface LValue {
@@ -255,8 +303,12 @@
     @Override
     public void dehydrate() {
         super.dehydrate();
-        for (Copy copy : this.copy) {
-            copy.dehydrate();
+		for (OAssignOperation operation : this.operations) {
+			if (operation.getType().equals(OAssignOperation.Type.Copy)) {
+				((Copy)operation).dehydrate();
+			} else if (operation.getType().equals(OAssignOperation.Type.ExtensionOperation)) {
+				((ExtensionAssignOperation)operation).dehydrate();
+			}
         }
     }
 }
diff --git a/bpel-obj/src/main/java/org/apache/ode/bpel/o/OExtensionActivity.java b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OExtensionActivity.java
new file mode 100644
index 0000000..deb73cf
--- /dev/null
+++ b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OExtensionActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.o;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ode.utils.SerializableElement;
+
+/**
+ * Compiled representation of the BPEL <code>&lt;extensionActivity&gt;</code>
+ * activity.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class OExtensionActivity extends OActivity {
+
+	static final long serialVersionUID = -1L;
+	public final List<OActivity> children = new ArrayList<OActivity>();
+	public SerializableElement nestedElement;
+	public QName extensionName;
+
+	public OExtensionActivity(OProcess owner, OActivity parent) {
+		super(owner, parent);
+	}
+	
+}
diff --git a/bpel-obj/src/main/java/org/apache/ode/bpel/o/OProcess.java b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OProcess.java
index 717b9e2..7b95919 100644
--- a/bpel-obj/src/main/java/org/apache/ode/bpel/o/OProcess.java
+++ b/bpel-obj/src/main/java/org/apache/ode/bpel/o/OProcess.java
@@ -76,6 +76,12 @@
 
     public final HashMap<URI, OXslSheet> xslSheets = new HashMap<URI, OXslSheet>();
 
+    /** All declared extensions in the process. **/
+    public final Set<OExtension> declaredExtensions = new HashSet<OExtension>();
+
+    /** All must-understand extensions in the process. **/
+    public final Set<OExtension> mustUnderstandExtensions = new HashSet<OExtension>();
+
     public OProcess(String bpelVersion) {
         super(null);
         this.version = bpelVersion;
@@ -114,12 +120,12 @@
         return processName;
     }
 
-    @SuppressWarnings("unchecked")
-    public Collection getExpressionLanguages() {
+    @SuppressWarnings("rawtypes")
+	public Collection getExpressionLanguages() {
         throw new UnsupportedOperationException(); // TODO: implement me!
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     public List<String> getCorrelators() {
         // MOVED from ProcessSchemaGenerator
         List<String> correlators = new ArrayList<String>();
@@ -186,6 +192,18 @@
         }
 
     }
+    
+    public static class OExtension extends OBase {
+        static final long serialVersionUID = -1L  ;
+        public String namespaceURI;
+        public boolean mustUnderstand;
+        
+        public OExtension(OProcess process) { super(process); }
+
+        public String toString() {
+            return "{OExtension " + namespaceURI + (mustUnderstand ? " mustUnderstand" : "") + "}";
+        }
+    }
 
     public QName getQName() {
         return new QName(targetNamespace, processName);
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelProcess.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelProcess.java
index 0150c97..9208136 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelProcess.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelProcess.java
@@ -19,7 +19,6 @@
 package org.apache.ode.bpel.engine;
 
 import java.io.File;
-import java.io.InputStream;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -52,6 +51,7 @@
 import org.apache.ode.bpel.evt.ProcessInstanceEvent;
 import org.apache.ode.bpel.explang.ConfigurationException;
 import org.apache.ode.bpel.explang.EvaluationException;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
 import org.apache.ode.bpel.iapi.BpelEngineException;
 import org.apache.ode.bpel.iapi.Endpoint;
 import org.apache.ode.bpel.iapi.EndpointReference;
@@ -131,6 +131,9 @@
     private ReplacementMap _replacementMap;
     final ProcessConf _pconf;
 
+	Set<String> _mustUnderstandExtensions;
+	Map<String, ExtensionBundleRuntime> _extensionRegistry;
+    
     /** {@link MessageExchangeInterceptor}s registered for this process. */
     private final List<MessageExchangeInterceptor> _mexInterceptors = new ArrayList<MessageExchangeInterceptor>();
 
@@ -588,6 +591,10 @@
         return routed;
     }
 
+	public void setExtensionRegistry(Map<String, ExtensionBundleRuntime> extensionRegistry) {
+		_extensionRegistry = extensionRegistry;
+	}
+    
     private void setRoles(OProcess oprocess) {
         _partnerRoles = new HashMap<OPartnerLink, PartnerLinkPartnerRoleImpl>();
         _myRoles = new HashMap<OPartnerLink, PartnerLinkMyRoleImpl>();
@@ -959,6 +966,7 @@
 //            }
             _replacementMap = null;
             _expLangRuntimeRegistry = null;
+	    _extensionRegistry = null;
         }
 
         private void doHydrate() {
@@ -1000,6 +1008,25 @@
             _expLangRuntimeRegistry = new ExpressionLanguageRuntimeRegistry();
             registerExprLang(_oprocess);
 
+			// Checking for registered extension bundles, throw an exception when
+			// a "mustUnderstand" extension is not available
+			_mustUnderstandExtensions = new HashSet<String>();
+			for (OProcess.OExtension extension : _oprocess.getDeclaredExtensions()) {
+				if (extension.isMustUnderstand()) {
+					if (_extensionRegistry.get(extension.getNamespace()) == null) {
+						String msg = __msgs.msgExtensionMustUnderstandError(_pconf.getProcessId(),
+								extension.getNamespace());
+						__log.error(msg);
+						throw new BpelEngineException(msg);
+					} else {
+						_mustUnderstandExtensions.add(extension.getNamespace());
+					}
+				} else {
+					__log.warn("The process declares the extension namespace " + extension.getNamespace()
+							+ " that is unkown to the engine");
+				}
+			}
+
             setRoles(_oprocess);
             initExternalVariables();
 
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelRuntimeContextImpl.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelRuntimeContextImpl.java
index f4c9fec..1457a80 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelRuntimeContextImpl.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelRuntimeContextImpl.java
@@ -60,6 +60,8 @@
 import org.apache.ode.bpel.evt.ScopeEvent;
 import org.apache.ode.bpel.evt.ScopeFaultEvent;
 import org.apache.ode.bpel.evt.ScopeStartEvent;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
+import org.apache.ode.bpel.extension.ExtensionOperation;
 import org.apache.ode.bpel.iapi.BpelEngineException;
 import org.apache.ode.bpel.iapi.ContextException;
 import org.apache.ode.bpel.iapi.Endpoint;
@@ -1531,4 +1533,18 @@
     public void forceFlush() {
         _forceFlush = true;
     }
+
+	public ExtensionOperation createExtensionActivityImplementation(QName name) {
+		if (name == null) return null;
+        ExtensionBundleRuntime bundle = _bpelProcess._extensionRegistry.get(name.getNamespaceURI());
+        if (bundle == null) {
+            return null;
+        } else {
+            try {
+                return bundle.getExtensionOperationInstance(name.getLocalPart());
+            } catch (Exception e) {
+                return null;
+            }
+        }
+	}
 }
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelServerImpl.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelServerImpl.java
index 3966fc1..ffb805c 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelServerImpl.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/BpelServerImpl.java
@@ -44,6 +44,7 @@
 import org.apache.ode.bpel.engine.migration.MigrationHandler;
 import org.apache.ode.bpel.evar.ExternalVariableModule;
 import org.apache.ode.bpel.evt.BpelEvent;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
 import org.apache.ode.bpel.iapi.BindingContext;
 import org.apache.ode.bpel.iapi.BpelEngine;
 import org.apache.ode.bpel.iapi.BpelEngineException;
@@ -175,6 +176,15 @@
         }
     }
 
+    public void registerExtensionBundle(ExtensionBundleRuntime bundle) {
+        _contexts.extensionRegistry.put(bundle.getNamespaceURI(), bundle);
+        bundle.registerExtensionActivities();
+    }
+
+    public void unregisterExtensionBundle(String nsURI) {
+        _contexts.extensionRegistry.remove(nsURI);
+    }
+
     public void registerExternalVariableEngine(ExternalVariableModule eve) {
         _contexts.externalVariableEngines.put(eve.getName(), eve);
     }
@@ -317,6 +327,8 @@
             __log.debug("Registering process " + conf.getProcessId() + " with server.");
 
             BpelProcess process = createBpelProcess(conf);
+            
+            process.setExtensionRegistry(_contexts.extensionRegistry);
             process._classLoader = Thread.currentThread().getContextClassLoader();
 
             _engine.registerProcess(process);
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Contexts.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Contexts.java
index a965d58..ce4edd9 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Contexts.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Contexts.java
@@ -29,9 +29,12 @@
 import org.apache.ode.bpel.intercept.MessageExchangeInterceptor;
 import org.apache.ode.bpel.engine.cron.CronScheduler;
 import org.apache.ode.bpel.evar.ExternalVariableModule;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
 
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.xml.namespace.QName;
@@ -67,4 +70,7 @@
     
     public CustomProcessProperties customProcessProperties = new CustomProcessProperties(); 
 
+    /** Global extension bundle registry **/
+    final Map<String, ExtensionBundleRuntime> extensionRegistry = new ConcurrentHashMap<String, ExtensionBundleRuntime>();
+
 }
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Messages.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Messages.java
index 20f0fd8..35dac34 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Messages.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/Messages.java
@@ -191,4 +191,9 @@
         return format("Scheduled job failed; jobDetail={0}", jobDetail);
     }
 
+    public String msgExtensionMustUnderstandError(QName name, String extensionUri) {
+        return format("Deployment of process \"{0}\" failed. The process model requires the " +
+        		"engine to understand language extensions defined by {1}. No extension bundle " +
+        		"has been registered for this namespace.", name, extensionUri);
+    }
 }
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ASSIGN.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ASSIGN.java
index 0f442b9..ca442a0 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ASSIGN.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ASSIGN.java
@@ -26,6 +26,7 @@
 import org.apache.ode.bpel.evt.VariableModificationEvent;
 import org.apache.ode.bpel.explang.EvaluationContext;
 import org.apache.ode.bpel.explang.EvaluationException;
+import org.apache.ode.bpel.extension.ExtensionOperation;
 import org.apache.ode.bpel.obj.OAssign;
 import org.apache.ode.bpel.obj.OAssign.DirectRef;
 import org.apache.ode.bpel.obj.OAssign.LValueExpression;
@@ -36,10 +37,13 @@
 import org.apache.ode.bpel.obj.OLink;
 import org.apache.ode.bpel.obj.OMessageVarType;
 import org.apache.ode.bpel.obj.OMessageVarType.Part;
+import org.apache.ode.bpel.obj.OProcess;
 import org.apache.ode.bpel.obj.OProcess.OProperty;
 import org.apache.ode.bpel.obj.OScope;
 import org.apache.ode.bpel.obj.OScope.Variable;
 import org.apache.ode.bpel.runtime.channels.FaultData;
+import org.apache.ode.bpel.runtime.common.extension.ExtensibilityQNames;
+import org.apache.ode.bpel.runtime.common.extension.ExtensionContext;
 import org.apache.ode.utils.DOMUtils;
 import org.apache.ode.utils.Namespaces;
 import org.apache.ode.utils.msg.MessageBundle;
@@ -82,23 +86,36 @@
 
         FaultData faultData = null;
 
-        for (OAssign.Copy aCopy : oassign.getCopy()) {
+		for (OAssign.OAssignOperation operation : oassign.getOperations()) {
             try {
-                copy(aCopy);
+                if (operation instanceof OAssign.Copy) {
+					copy((OAssign.Copy) operation);
+				} else if (operation instanceof OAssign.ExtensionAssignOperation) {
+					invokeExtensionAssignOperation((OAssign.ExtensionAssignOperation) operation);
+				}
             } catch (FaultException fault) {
-                if (aCopy.isIgnoreMissingFromData()) {
-                    if (fault.getQName().equals(getOAsssign().getOwner().getConstants().getQnSelectionFailure()) &&
-                            (fault.getCause() != null && "ignoreMissingFromData".equals(fault.getCause().getMessage()))) {
-                    continue;
-                    }
-                }
-                if (aCopy.isIgnoreUninitializedFromVariable()) {
-                    if (fault.getQName().equals(getOAsssign().getOwner().getConstants().getQnUninitializedVariable()) &&
-                            (fault.getCause() == null || !"throwUninitializedToVariable".equals(fault.getCause().getMessage()))) {
-                    continue;
-                    }
-                }
-                faultData = createFault(fault.getQName(), aCopy, fault
+            	if (operation instanceof OAssign.Copy) {
+					if (((OAssign.Copy) operation).isIgnoreMissingFromData()) {
+						if (fault
+								.getQName()
+								.equals(getOAsssign().getOwner().getConstants().getQnSelectionFailure())
+								&& (fault.getCause() != null && "ignoreMissingFromData"
+										.equals(fault.getCause().getMessage()))) {
+							continue;
+						}
+					}
+					if (((OAssign.Copy) operation).isIgnoreUninitializedFromVariable()) {
+						if (fault
+								.getQName()
+								.equals(getOAsssign().getOwner().getConstants().getQnUninitializedVariable())
+								&& (fault.getCause() == null || !"throwUninitializedToVariable"
+										.equals(fault.getCause().getMessage()))) {
+							continue;
+						}
+					}
+				}
+                
+                faultData = createFault(fault.getQName(), operation, fault
                         .getMessage());
                 break;
             } catch (ExternalVariableModuleException e) {
@@ -655,6 +672,35 @@
         return data;
     }
 
+	private void invokeExtensionAssignOperation(OAssign.ExtensionAssignOperation eao) throws FaultException {
+        final ExtensionContext context = new ExtensionContextImpl(this, getBpelRuntimeContext());
+
+        try {
+            ExtensionOperation ea = getBpelRuntimeContext().createExtensionActivityImplementation(eao.getExtensionName());
+            if (ea == null) {
+                for (OProcess.OExtension oe : eao.getOwner().getMustUnderstandExtensions()) {
+                    if (eao.getExtensionName().getNamespaceURI().equals(oe.getNamespace())) {
+                        __log.warn("Lookup of extension assign operation " + eao.getExtensionName() + " failed.");
+                        throw new FaultException(ExtensibilityQNames.UNKNOWN_EA_FAULT_NAME, "Lookup of extension assign operation " + eao.getExtensionName() + " failed. No implementation found.");
+                    }
+                }
+                // act like <empty> - do nothing
+                context.complete();
+                return;
+            }
+
+            ea.run(context, DOMUtils.stringToDOM(eao.getNestedElement()));
+        } catch (FaultException fault) {
+            context.completeWithFault(fault);
+        } catch (SAXException e) {
+        	FaultException fault = new FaultException(ExtensibilityQNames.INVALID_EXTENSION_ELEMENT, "The nested element of extension assign operation '" + eao.getExtensionName() + "' is no valid XML.");
+        	context.completeWithFault(fault);
+		} catch (IOException e) {
+			FaultException fault = new FaultException(ExtensibilityQNames.INVALID_EXTENSION_ELEMENT, "The nested element of extension assign operation '" + eao.getExtensionName() + "' is no valid XML.");
+			context.completeWithFault(fault);
+		}
+    }
+
     private class EvaluationContextProxy implements EvaluationContext {
 
         private Variable _var;
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ActivityTemplateFactory.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ActivityTemplateFactory.java
index 1942328..16ece33 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ActivityTemplateFactory.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ActivityTemplateFactory.java
@@ -43,6 +43,7 @@
     if (type instanceof OWhile) return new WHILE(ai, scopeFrame, linkFrame);
     if (type instanceof OForEach) return new FOREACH(ai, scopeFrame, linkFrame);
     if (type instanceof ORepeatUntil) return new REPEATUNTIL(ai,scopeFrame,linkFrame);
+    if (type instanceof OExtensionActivity) return new EXTENSIONACTIVITY(ai, scopeFrame, linkFrame);
 
     throw new IllegalArgumentException("Unknown type: " + type);
   }
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelRuntimeContext.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelRuntimeContext.java
index 448af9a..8aad3ec 100644
--- a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelRuntimeContext.java
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/BpelRuntimeContext.java
@@ -28,6 +28,7 @@
 import org.apache.ode.bpel.common.CorrelationKey;
 import org.apache.ode.bpel.common.FaultException;
 import org.apache.ode.bpel.evt.ProcessInstanceEvent;
+import org.apache.ode.bpel.extension.ExtensionOperation;
 import org.apache.ode.bpel.obj.OPartnerLink;
 import org.apache.ode.bpel.obj.OProcess;
 import org.apache.ode.bpel.obj.OScope;
@@ -311,4 +312,13 @@
     ClassLoader getProcessClassLoader();
     
     void checkInvokeExternalPermission();
+    
+    /**
+     * Create a new extension operation based on the given qualified name.
+     * 
+     * @param name The qualified name for which a corresponding extension operation should be created.
+     * 
+     * @return The created extension operation or NULL if no extension bundle registered a corresponding extension operation for the given qualified name.
+     */
+    ExtensionOperation createExtensionActivityImplementation(QName name);
 }
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/EXTENSIONACTIVITY.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/EXTENSIONACTIVITY.java
new file mode 100644
index 0000000..7c61035
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/EXTENSIONACTIVITY.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime;
+
+import java.io.IOException;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.apache.ode.bpel.extension.ExtensionOperation;
+import org.apache.ode.bpel.obj.OExtensionActivity;
+import org.apache.ode.bpel.obj.OProcess;
+import org.apache.ode.bpel.runtime.common.extension.AbstractSyncExtensionOperation;
+import org.apache.ode.bpel.runtime.common.extension.ExtensibilityQNames;
+import org.apache.ode.bpel.runtime.common.extension.ExtensionContext;
+import org.apache.ode.utils.DOMUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * JacobRunnable that delegates the work of the <code>extensionActivity</code>
+ * activity to a registered extension implementation.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class EXTENSIONACTIVITY extends ACTIVITY {
+	private static final long serialVersionUID = 1L;
+	private static final Logger __log = LoggerFactory
+			.getLogger(EXTENSIONACTIVITY.class);
+
+	public EXTENSIONACTIVITY(ActivityInfo self, ScopeFrame scopeFrame,
+			LinkFrame linkFrame) {
+		super(self, scopeFrame, linkFrame);
+	}
+
+	public final void run() {
+		final ExtensionContext context = new ExtensionContextImpl(this,
+				getBpelRuntimeContext());
+		final OExtensionActivity oea = (OExtensionActivity) _self.o;
+
+		try {
+			ExtensionOperation ea = getBpelRuntimeContext()
+					.createExtensionActivityImplementation(oea.getExtensionName());
+			if (ea == null) {
+				for (OProcess.OExtension oe : oea.getOwner().getMustUnderstandExtensions()) {
+					if (oea.getExtensionName().getNamespaceURI().equals(
+							oe.getNamespace())) {
+						__log.warn("Lookup of extension activity "
+								+ oea.getExtensionName() + " failed.");
+						throw new FaultException(
+								ExtensibilityQNames.UNKNOWN_EA_FAULT_NAME,
+								"Lookup of extension activity "
+										+ oea.getExtensionName()
+										+ " failed. No implementation found.");
+					}
+				}
+				// act like <empty> - do nothing
+				context.complete();
+				return;
+			}
+
+			ea.run(context, DOMUtils.stringToDOM(oea.getNestedElement()));
+
+			// Complete the context for sync extension operations. Asynchronous
+			// operations have to control their completion themselves.
+			if (ea instanceof AbstractSyncExtensionOperation) {
+				context.complete();
+			}
+		} catch (FaultException fault) {
+			__log.error("Execution of extension activity caused an exception.",
+					fault);
+			context.completeWithFault(fault);
+		} catch (SAXException e) {
+        	FaultException fault = new FaultException(ExtensibilityQNames.INVALID_EXTENSION_ELEMENT, "The nested element of extension activity '" + oea.getName() + "' for extension '" + oea.getExtensionName() + "' is no valid XML.");
+        	context.completeWithFault(fault);
+		} catch (IOException e) {
+			FaultException fault = new FaultException(ExtensibilityQNames.INVALID_EXTENSION_ELEMENT, "The nested element of extension activity '" + oea.getName() + "' for extension '" + oea.getExtensionName() + "' is no valid XML.");
+			context.completeWithFault(fault);
+		}
+
+	}
+
+}
\ No newline at end of file
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ExtensionContextImpl.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ExtensionContextImpl.java
new file mode 100644
index 0000000..4117c7e
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/ExtensionContextImpl.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.apache.ode.bpel.evar.ExternalVariableModuleException;
+import org.apache.ode.bpel.evt.ScopeEvent;
+import org.apache.ode.bpel.evt.VariableModificationEvent;
+import org.apache.ode.bpel.obj.OActivity;
+import org.apache.ode.bpel.obj.OPartnerLink;
+import org.apache.ode.bpel.obj.OProcess;
+import org.apache.ode.bpel.obj.OScope;
+import org.apache.ode.bpel.runtime.channels.FaultData;
+import org.apache.ode.bpel.runtime.common.extension.ExtensionContext;
+import org.apache.ode.utils.Namespaces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+
+/**
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public class ExtensionContextImpl implements ExtensionContext {
+	private static final Logger __log = LoggerFactory.getLogger(ExtensionContextImpl.class);
+
+	private BpelRuntimeContext _context;
+	private ACTIVITY _activity;
+	private ActivityInfo _activityInfo;
+	
+	private boolean hasCompleted = false;
+
+	//@hahnml: Changed to ACTIVITY to get the whole stuff with one parameter
+	public ExtensionContextImpl(ACTIVITY activity, BpelRuntimeContext context) {
+		_activityInfo = activity._self;
+		_context = context;
+		_activity = activity;
+	}
+	
+	public Long getProcessId() {
+		return _context.getPid();
+	}
+
+	public Map<String, OScope.Variable> getVisibleVariables()
+			throws FaultException {
+		Map<String, OScope.Variable> visVars = new HashMap<String, OScope.Variable>();
+
+		OActivity current = _activity._scopeFrame.oscope;
+		while (current != null) {
+			if (current instanceof OScope) {
+				for (String varName : ((OScope) current).getVariables().keySet()) {
+					if (!visVars.containsKey(varName)) {
+						visVars.put(varName,
+								((OScope) current).getVariables().get(varName));
+					}
+				}
+			}
+			current = current.getParent();
+		}
+
+		return visVars;
+	}
+
+	public String readMessageProperty(OScope.Variable variable,
+			OProcess.OProperty property) throws FaultException {
+		VariableInstance vi = _activity._scopeFrame.resolve(variable);
+		return _context.readProperty(vi, property);
+	}
+
+	public Node readVariable(OScope.Variable variable) throws FaultException {
+		VariableInstance vi = _activity._scopeFrame.resolve(variable);
+		
+		return _activity._scopeFrame.fetchVariableData(_context, vi, false);
+	}
+
+	public void writeVariable(String variableName, Node value)
+			throws FaultException, ExternalVariableModuleException {
+		OScope.Variable var = getVisibleVariable(variableName);
+		if (var == null) {
+			throw new RuntimeException("Variable '" + variableName
+					+ "' not visible.");
+		}
+		writeVariable(var, value);
+	}
+
+	public Node readVariable(String variableName) throws FaultException {
+		OScope.Variable var = getVisibleVariable(variableName);
+		if (var == null) {
+			throw new RuntimeException("Variable '" + variableName
+					+ "' not visible.");
+		}
+
+		return readVariable(var);
+	}
+
+	public void writeVariable(OScope.Variable variable, Node value)
+			throws FaultException, ExternalVariableModuleException {
+		VariableInstance vi = _activity._scopeFrame.resolve(variable);
+		_activity._scopeFrame.initializeVariable(_context, vi, value);
+		VariableModificationEvent vme = new VariableModificationEvent(
+				variable.getName());
+		vme.setNewValue(value);
+		sendEvent(vme);
+	}
+
+	public OScope.Variable getVisibleVariable(String varName) {
+		return _activity._scopeFrame.oscope.getVisibleVariable(varName);
+	}
+
+	public boolean isVariableVisible(String varName) {
+		return _activity._scopeFrame.oscope.getVisibleVariable(varName) != null;
+	}
+
+	public String getActivityName() {
+		return _activityInfo.o.getName();
+	}
+
+	public OActivity getOActivity() {
+		return _activityInfo.o;
+	}
+
+	public void sendEvent(ScopeEvent event) {
+		if (event.getLineNo() == -1 && _activityInfo.o.getDebugInfo() != null) {
+			event.setLineNo(_activityInfo.o.getDebugInfo().getStartLine());
+		}
+		_activity._scopeFrame.fillEventInfo(event);
+		
+		_context.sendEvent(event);
+	}
+
+	public void complete() {
+		if (!hasCompleted) {
+			
+			_activityInfo.parent
+					.completed(null, CompensationHandler.emptySet());
+			hasCompleted = true;
+		} else {
+			if (__log.isWarnEnabled()) {
+				__log.warn("Activity '" + _activityInfo.o.getName()
+						+ "' has already been completed.");
+			}
+		}
+	}
+
+	public void completeWithFault(Throwable t) {
+		if (!hasCompleted) {
+			StringWriter sw = new StringWriter();
+			t.printStackTrace(new PrintWriter(sw));
+			FaultData fault = new FaultData(new QName(
+					Namespaces.WSBPEL2_0_FINAL_EXEC,
+					"subLanguageExecutionFault"), _activityInfo.o, sw
+					.getBuffer().toString());
+			_activityInfo.parent.completed(fault,
+					CompensationHandler.emptySet());
+			hasCompleted = true;
+		} else {
+			if (__log.isWarnEnabled()) {
+				__log.warn("Activity '" + _activityInfo.o.getName()
+						+ "' has already been completed.");
+			}
+		}
+	}
+
+	public void completeWithFault(FaultException ex) {
+		if (!hasCompleted) {
+			FaultData fault = new FaultData(ex.getQName(), _activityInfo.o,
+					ex.getMessage());
+			_activityInfo.parent.completed(fault,
+					CompensationHandler.emptySet());
+			hasCompleted = true;
+		} else {
+			if (__log.isWarnEnabled()) {
+				__log.warn("Activity '" + _activityInfo.o.getName()
+						+ "' has already been completed.");
+			}
+		}
+
+	}
+	
+	public BpelRuntimeContext getRuntimeInstance() {
+		return _context;
+	}
+
+	public URI getDUDir() {
+		return _context.getBaseResourceURI();
+	}
+
+	public void printToConsole(String msg) {
+		LoggerFactory.getLogger("org.apache.ode.extension.Console").info(msg);
+	}
+
+	public PartnerLinkInstance resolvePartnerLinkInstance(OPartnerLink pl) {
+		return _activity._scopeFrame.resolve(pl);
+	}
+}
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractAsyncExtensionOperation.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractAsyncExtensionOperation.java
new file mode 100644
index 0000000..a3c61df
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractAsyncExtensionOperation.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime.common.extension;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.apache.ode.bpel.extension.ExtensionOperation;
+import org.w3c.dom.Element;
+
+/**
+ * Base class for creating new asynchronous extension implementations.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public abstract class AbstractAsyncExtensionOperation implements
+		ExtensionOperation {
+
+	public abstract void run(Object context, Element element)
+			throws FaultException;
+
+}
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractExtensionBundle.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractExtensionBundle.java
new file mode 100644
index 0000000..e4e1857
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractExtensionBundle.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime.common.extension;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
+import org.apache.ode.bpel.extension.ExtensionBundleValidation;
+import org.apache.ode.bpel.extension.ExtensionOperation;
+import org.apache.ode.bpel.extension.ExtensionValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class that bundles and registers
+ * <code>&lt;extensionActivity&gt;</code> and
+ * <code>&lt;extensionAssignOperation&gt;</code> implementations related to a
+ * particular namespace.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public abstract class AbstractExtensionBundle implements
+		ExtensionBundleRuntime, ExtensionBundleValidation {
+
+	private static Logger __log = LoggerFactory.getLogger(AbstractExtensionBundle.class);
+	private Map<String, Class<? extends ExtensionOperation>> extensionsByName = new HashMap<String, Class<? extends ExtensionOperation>>();
+
+	/**
+	 * Returns the extension namespace this bundle provides implementations for.
+	 * 
+	 * @return
+	 */
+	public abstract String getNamespaceURI();
+
+	/**
+	 * Register extension operations.
+	 */
+	public abstract void registerExtensionActivities();
+
+	/**
+	 * Register an {@link org.apache.ode.bpel.extension.ExtensionOperation}
+	 * implementation as <code>&lt;extensionActivity&gt;</code>.
+	 * 
+	 * @param localName
+	 * @param activity
+	 */
+	protected final void registerExtensionOperation(String localName,
+			Class<? extends ExtensionOperation> operation) {
+		extensionsByName.put(localName, operation);
+	}
+
+	/**
+	 * Returns a list of the local names of registered extension operations.
+	 */
+	public final Set<String> getExtensionOperationNames() {
+		return Collections.unmodifiableSet(extensionsByName.keySet());
+	}
+
+	public final Class<? extends ExtensionOperation> getExtensionOperationClass(
+			String localName) {
+		return extensionsByName.get(localName);
+	}
+
+	public final ExtensionOperation getExtensionOperationInstance(
+			String localName) throws InstantiationException,
+			IllegalAccessException {
+		return getExtensionOperationClass(localName).newInstance();
+	}
+
+	public final Map<QName, ExtensionValidator> getExtensionValidators() {
+		Map<QName, ExtensionValidator> result = new HashMap<QName, ExtensionValidator>();
+		String ns = getNamespaceURI();
+		for (String localName : extensionsByName.keySet()) {
+			if (ExtensionValidator.class.isAssignableFrom(extensionsByName
+					.get(localName))) {
+				try {
+					result.put(
+							new QName(ns, localName),
+							(ExtensionValidator) getExtensionOperationInstance(localName));
+				} catch (Exception e) {
+					__log.warn("Could not instantiate extension validator for '{"
+							+ ns + "}" + localName);
+				}
+			}
+		}
+		return result;
+	}
+}
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractSyncExtensionOperation.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractSyncExtensionOperation.java
new file mode 100644
index 0000000..65420c4
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/AbstractSyncExtensionOperation.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime.common.extension;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.apache.ode.bpel.extension.ExtensionOperation;
+import org.w3c.dom.Element;
+
+/**
+ * Base class for creating new extension implementations.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public abstract class AbstractSyncExtensionOperation implements
+		ExtensionOperation {
+
+	protected abstract void runSync(ExtensionContext context, Element element)
+			throws FaultException;
+
+	public void run(Object contexto, Element element) throws FaultException {
+		ExtensionContext context = (ExtensionContext) contexto;
+		try {
+			runSync(context, element);
+		} catch (FaultException f) {
+			throw f;
+		}
+	}
+	
+}
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensibilityQNames.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensibilityQNames.java
new file mode 100644
index 0000000..ed238ad
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensibilityQNames.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime.common.extension;
+
+import javax.xml.namespace.QName;
+
+public abstract class ExtensibilityQNames {
+	/*
+	 * Activity Recovery extensibility elements.
+	 */
+	public static final String NS_ACTIVITY_RECOVERY = "http://ode.apache.org/activityRecovery";
+	public static final QName FAILURE_HANDLING = new QName(
+			NS_ACTIVITY_RECOVERY, "failureHandling");
+	public static final QName FAILURE_HANDLING_RETRY_FOR = new QName(
+			NS_ACTIVITY_RECOVERY, "retryFor");
+	public static final QName FAILURE_HANDLING_RETRY_DELAY = new QName(
+			NS_ACTIVITY_RECOVERY, "retryDelay");
+	public static final QName FAILURE_HANDLING_FAULT_ON = new QName(
+			NS_ACTIVITY_RECOVERY, "faultOnFailure");
+
+	public static final String NS_BPEL_EXTENSIBILITY = "http://ode.apache.org/bpelExtensibility";
+	
+	public static final QName UNKNOWN_EA_FAULT_NAME = new QName(
+			NS_BPEL_EXTENSIBILITY, "unknownExtensionImplementation");
+	
+	public static final QName INVALID_EXTENSION_ELEMENT = new QName(
+			NS_BPEL_EXTENSIBILITY, "invalidExtensionElement");
+	
+	//
+	// External variables
+	//
+	/** Namespace for external variables. */
+	private static final String EXTVAR_NS = "http://ode.apache.org/externalVariables";
+
+	/** Attribute name for external variable id. */
+	public static final QName EXTVAR_ATTR = new QName(EXTVAR_NS, "id");
+
+	/** Attribute holding the name of the "related" variable. */
+	public static final QName EXTVAR_RELATED = new QName(EXTVAR_NS,
+			"relates-to");
+
+}
diff --git a/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensionContext.java b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensionContext.java
new file mode 100644
index 0000000..61da3aa
--- /dev/null
+++ b/bpel-runtime/src/main/java/org/apache/ode/bpel/runtime/common/extension/ExtensionContext.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ode.bpel.runtime.common.extension;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.ode.bpel.common.FaultException;
+import org.apache.ode.bpel.evar.ExternalVariableModuleException;
+import org.apache.ode.bpel.obj.OActivity;
+import org.apache.ode.bpel.obj.OPartnerLink;
+import org.apache.ode.bpel.obj.OProcess;
+import org.apache.ode.bpel.obj.OScope;
+import org.apache.ode.bpel.runtime.BpelRuntimeContext;
+import org.apache.ode.bpel.runtime.PartnerLinkInstance;
+import org.w3c.dom.Node;
+
+/**
+ * Context for executing extension activities or extension assign operations.
+ * Implementations of the
+ * {@link org.apache.ode.bpel.extension.ExtensionOperation} class use this
+ * interface to access BPEL variables, property sets and link status.
+ * 
+ * All <code>ExtensionOperation</code> implementations must complete with
+ * <code>complete()</code>, <code>completeWithFault(...)</code>.
+ * 
+ * @author Tammo van Lessen (University of Stuttgart)
+ */
+public interface ExtensionContext {
+
+	/**
+	 * Returns a list of variables visible in the current scope.
+	 * 
+	 * @return an unmodifiable list of visible variables.
+	 * @throws FaultException
+	 */
+	Map<String, OScope.Variable> getVisibleVariables() throws FaultException;
+
+	/**
+	 * Returns whether a variable is visible in the current scope or not.
+	 * 
+	 * @param variableName
+	 *            name of the variable.
+	 * @return true if the variable is visible.
+	 * @throws FaultException
+	 */
+	boolean isVariableVisible(String variableName);
+
+	/**
+	 * Read the value of a BPEL variable.
+	 * 
+	 * @param variable
+	 *            variable to read
+	 * @return the value of the variable, wrapped in a <code>Node</code>
+	 */
+	Node readVariable(OScope.Variable variable) throws FaultException;
+
+	/**
+	 * Read the value of a BPEL variable.
+	 * 
+	 * @param variableName
+	 *            variable to read
+	 * @return the value of the variable, wrapped in a <code>Node</code>
+	 */
+	Node readVariable(String variableName) throws FaultException;
+
+	/**
+	 * Write the value into a BPEL variable.
+	 * 
+	 * @param variable
+	 *            variable to write
+	 * @param value
+	 *            the value to be stored into the variable
+	 * @return the value of the variable, wrapped in a <code>Node</code>
+	 */
+	void writeVariable(OScope.Variable variable, Node value)
+			throws FaultException, ExternalVariableModuleException;
+
+	/**
+	 * Write the value into a BPEL variable.
+	 * 
+	 * @param variableName
+	 *            variable to write
+	 * @param value
+	 *            the value to be stored into the variable
+	 * @return the value of the variable, wrapped in a <code>Node</code>
+	 */
+	void writeVariable(String variableName, Node value) throws FaultException,
+			ExternalVariableModuleException;
+
+	/**
+	 * Read the value of a BPEL property.
+	 * 
+	 * @param variable
+	 *            variable containing property
+	 * @param property
+	 *            property to read
+	 * @return value of the property
+	 */
+	String readMessageProperty(OScope.Variable variable,
+			OProcess.OProperty property) throws FaultException;
+
+	/**
+	 * Reads the current process instance id.
+	 * 
+	 * @return instance id
+	 */
+	Long getProcessId();
+
+	/**
+	 * Returns the name of the invoking activity.
+	 * 
+	 * @return activity name
+	 */
+	String getActivityName();
+
+	/**
+	 * Returns the location of the deployment bundle of the executed process.
+	 * 
+	 * @return URI of the deployment bundle.
+	 */
+	URI getDUDir();
+
+	/**
+	 * Allows printing debug output to the console. Output will be redirected to
+	 * the logger associated with <code>org.apache.ode.extension.Console</code>.
+	 * The target log level is INFO.
+	 */
+	void printToConsole(String msg);
+
+	/**
+	 * Marks the currently executed activity as successfully completed.
+	 */
+	void complete();
+
+	/**
+	 * Marks the currently executed activity as faulted.
+	 * 
+	 * @param t
+	 *            an exception to be reported as the fault cause.
+	 */
+	void completeWithFault(Throwable t);
+
+	/**
+	 * Marks the currently executed activity as faulted.
+	 * 
+	 * @param fault
+	 *            a fault.
+	 */
+	void completeWithFault(FaultException fault);
+
+	/*
+	 * Low-level-methods
+	 */
+
+	/**
+	 * Returns the OActivity object.
+	 */
+	OActivity getOActivity();
+
+	/**
+	 * Returns ODE's runtime instance.
+	 */
+	BpelRuntimeContext getRuntimeInstance();
+
+	/**
+	 * Returns an instance of the given OPartnerLink object
+	 * 
+	 * @param pl
+	 *            the partner link model object
+	 * @return the related partner link instance
+	 */
+	PartnerLinkInstance resolvePartnerLinkInstance(OPartnerLink pl);
+}
diff --git a/bpel-runtime/src/test/java/org/apache/ode/bpel/elang/xpath20/runtime/MockCompilerContext.java b/bpel-runtime/src/test/java/org/apache/ode/bpel/elang/xpath20/runtime/MockCompilerContext.java
index 1c4acb9..348ba28 100644
--- a/bpel-runtime/src/test/java/org/apache/ode/bpel/elang/xpath20/runtime/MockCompilerContext.java
+++ b/bpel-runtime/src/test/java/org/apache/ode/bpel/elang/xpath20/runtime/MockCompilerContext.java
@@ -35,6 +35,7 @@
 import org.apache.ode.bpel.compiler.bom.BpelObject;
 import org.apache.ode.bpel.compiler.bom.Expression;
 import org.apache.ode.bpel.compiler.bom.ScopeLikeActivity;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.obj.OActivity;
 import org.apache.ode.bpel.obj.OElementVarType;
 import org.apache.ode.bpel.obj.OExpression;
@@ -249,4 +250,15 @@
     public NSContext tryCacheNamespaceContext(NSContext nsContext) {
         return nsContext;
     }
+
+    public boolean isExtensionDeclared(String namespace) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+    
+	@Override
+	public ExtensionValidator getExtensionValidator(QName extensionElementName) {
+		// TODO Auto-generated method stub
+		return null;
+	}
 }
diff --git a/bpel-runtime/src/test/java/org/apache/ode/bpel/runtime/CoreBpelTest.java b/bpel-runtime/src/test/java/org/apache/ode/bpel/runtime/CoreBpelTest.java
index 456c1cf..3ae8f6f 100644
--- a/bpel-runtime/src/test/java/org/apache/ode/bpel/runtime/CoreBpelTest.java
+++ b/bpel-runtime/src/test/java/org/apache/ode/bpel/runtime/CoreBpelTest.java
@@ -34,6 +34,7 @@
 import org.apache.ode.bpel.common.FaultException;
 import org.apache.ode.bpel.evar.ExternalVariableModuleException;
 import org.apache.ode.bpel.evt.ProcessInstanceEvent;
+import org.apache.ode.bpel.extension.ExtensionOperation;
 import org.apache.ode.bpel.iapi.ProcessConf.PartnerRoleConfig;
 import org.apache.ode.bpel.obj.OCatch;
 import org.apache.ode.bpel.obj.OEmpty;
@@ -480,4 +481,20 @@
 
     public void checkInvokeExternalPermission() {}
 
+    public Node initializeVariable(VariableInstance var, ScopeFrame scopeFrame,
+			Node val) throws ExternalVariableModuleException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public Node fetchVariableData(VariableInstance variable,
+			ScopeFrame scopeFrame, boolean forWriting) throws FaultException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public ExtensionOperation createExtensionActivityImplementation(QName name) {
+		// TODO Auto-generated method stub
+		return null;
+	}
 }
diff --git a/bpel-store/src/main/java/org/apache/ode/store/DeploymentUnitDir.java b/bpel-store/src/main/java/org/apache/ode/store/DeploymentUnitDir.java
index b8a6d16..c36d4b1 100644
--- a/bpel-store/src/main/java/org/apache/ode/store/DeploymentUnitDir.java
+++ b/bpel-store/src/main/java/org/apache/ode/store/DeploymentUnitDir.java
@@ -49,6 +49,7 @@
 import org.apache.ode.bpel.dd.DeployDocument;
 import org.apache.ode.bpel.dd.TDeployment;
 import org.apache.ode.bpel.dd.TDeployment.Process;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.iapi.ContextException;
 import org.apache.ode.bpel.obj.OProcess;
 import org.apache.ode.bpel.obj.serde.DeSerializer;
@@ -84,6 +85,8 @@
     private volatile DeployDocument _dd;
     private volatile DocumentRegistry _docRegistry;
 
+    private Map<QName, ExtensionValidator> _extensionValidators;
+
     private long _version = -1;
 
     private static final FileFilter _wsdlFilter = new FileFilter() {
@@ -199,6 +202,7 @@
             bpelc.setProcessWSDL(bpel11wsdl.toURI());
 
         bpelc.setCompileProperties(prepareCompileProperties(bpelFile));
+        bpelc.setExtensionValidators(_extensionValidators);
         bpelc.setBaseDirectory(_duDirectory);
         // Create process such that immutable objects are intern'ed.
         InternPool.runBlock(new InternableBlock() {
@@ -348,6 +352,10 @@
         return result;
     }
 
+    public void setExtensionValidators(Map<QName, ExtensionValidator> extensionValidators) {
+    	_extensionValidators = extensionValidators;
+    }
+
     public final class CBPInfo {
         final QName processName;
         final String guid;
diff --git a/bpel-store/src/main/java/org/apache/ode/store/ProcessStoreImpl.java b/bpel-store/src/main/java/org/apache/ode/store/ProcessStoreImpl.java
index 00a7c14..87927fe 100644
--- a/bpel-store/src/main/java/org/apache/ode/store/ProcessStoreImpl.java
+++ b/bpel-store/src/main/java/org/apache/ode/store/ProcessStoreImpl.java
@@ -23,6 +23,7 @@
 import org.apache.ode.bpel.compiler.api.CompilationException;
 import org.apache.ode.bpel.dd.DeployDocument;
 import org.apache.ode.bpel.dd.TDeployment;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.iapi.*;
 import org.apache.ode.il.config.OdeConfigProperties;
 import org.apache.ode.store.DeploymentUnitDir.CBPInfo;
@@ -88,7 +89,7 @@
 
     protected File _configDir;
 
-
+    private Map<QName, ExtensionValidator> _extensionValidators = new HashMap<QName, ExtensionValidator>();
 
     /**
      * Executor used to process DB transactions. Allows us to isolate the TX context, and to ensure that only one TX gets executed a
@@ -189,6 +190,7 @@
 
         // Create the DU and compile/scan it before acquiring lock.
         final DeploymentUnitDir du = new DeploymentUnitDir(deploymentUnitDirectory);
+        du.setExtensionValidators(_extensionValidators);
         if( duName != null ) {
             // Override the package name if given from the parameter
             du.setName(duName);
@@ -927,4 +929,13 @@
         }
         return undeployed;
     }
+
+    public void setExtensionValidators(
+			Map<QName, ExtensionValidator> extensionValidators) {
+		_extensionValidators = extensionValidators;
+	}
+	
+	public Map<QName, ExtensionValidator> getExtensionValidators() {
+		return _extensionValidators;
+	}
 }
diff --git a/jbi/src/main/java/org/apache/ode/jbi/OdeLifeCycle.java b/jbi/src/main/java/org/apache/ode/jbi/OdeLifeCycle.java
index 950d47e..3a789a1 100644
--- a/jbi/src/main/java/org/apache/ode/jbi/OdeLifeCycle.java
+++ b/jbi/src/main/java/org/apache/ode/jbi/OdeLifeCycle.java
@@ -26,6 +26,9 @@
 import org.apache.ode.bpel.dao.BpelDAOConnectionFactoryJDBC;
 import org.apache.ode.bpel.engine.BpelServerImpl;
 import org.apache.ode.bpel.engine.ProcessAndInstanceManagementMBean;
+import org.apache.ode.bpel.extension.ExtensionBundleRuntime;
+import org.apache.ode.bpel.extension.ExtensionBundleValidation;
+import org.apache.ode.bpel.extension.ExtensionValidator;
 import org.apache.ode.bpel.extvar.jdbc.JdbcExternalVariableModule;
 import org.apache.ode.bpel.iapi.BpelEventListener;
 import org.apache.ode.bpel.intercept.MessageExchangeInterceptor;
@@ -135,6 +138,8 @@
 
             registerMexInterceptors();
 
+            registerExtensionActivityBundles();
+
             registerMBean();
 
             __log.debug("Starting JCA connector.");
@@ -367,6 +372,61 @@
             }
         }
     }
+    
+    // @hahnml: Added support for extension bundles based on ODE 2.0 alpha branch
+    private void registerExtensionActivityBundles() {
+		String extensionsRTStr = _ode._config.getExtensionActivityBundlesRT();
+		String extensionsValStr = _ode._config
+				.getExtensionActivityBundlesValidation();
+		if (extensionsRTStr != null) {
+			// TODO replace StringTokenizer by regex
+			for (StringTokenizer tokenizer = new StringTokenizer(
+					extensionsRTStr, ",;"); tokenizer.hasMoreTokens();) {
+				String bundleCN = tokenizer.nextToken();
+				
+				//@hahnml: Remove any whitespaces
+				bundleCN = bundleCN.replaceAll(" ", "");
+				
+				try {
+					// instantiate bundle
+					ExtensionBundleRuntime bundleRT = (ExtensionBundleRuntime) Class
+							.forName(bundleCN).newInstance();
+					// register extension bundle (BPEL server)
+					_ode._server.registerExtensionBundle(bundleRT);
+				} catch (Exception e) {
+					__log.warn("Couldn't register the extension bundle runtime "
+							+ bundleCN
+							+ ", the class couldn't be "
+							+ "loaded properly.");
+				}
+			}
+		}
+		if (extensionsValStr != null) {
+			Map<QName, ExtensionValidator> validators = new HashMap<QName, ExtensionValidator>();
+			for (StringTokenizer tokenizer = new StringTokenizer(
+					extensionsValStr, ",;"); tokenizer.hasMoreTokens();) {
+				String bundleCN = tokenizer.nextToken();
+				
+				//@hahnml: Remove any whitespaces
+				bundleCN = bundleCN.replaceAll(" ", "");
+				
+				try {
+					// instantiate bundle
+					ExtensionBundleValidation bundleVal = (ExtensionBundleValidation) Class
+							.forName(bundleCN).newInstance();
+					// add validators
+					validators.putAll(bundleVal.getExtensionValidators());
+				} catch (Exception e) {
+					__log.warn("Couldn't register the extension bundle validator "
+							+ bundleCN
+							+ ", the class couldn't be "
+							+ "loaded properly.");
+				}
+			}
+			// register extension bundle (BPEL store)
+			_ode._store.setExtensionValidators(validators);
+        }
+    }
 
     public synchronized void start() throws JBIException {
         if (_started)
diff --git a/utils/src/main/java/org/apache/ode/utils/DOMUtils.java b/utils/src/main/java/org/apache/ode/utils/DOMUtils.java
index 854a8bc..dc91e6f 100644
--- a/utils/src/main/java/org/apache/ode/utils/DOMUtils.java
+++ b/utils/src/main/java/org/apache/ode/utils/DOMUtils.java
@@ -701,6 +701,10 @@
         }
         return true;
     }
+    
+    public static QName getElementQName(Element el) {
+        return new QName(el.getNamespaceURI(),el.getLocalName());
+    }
 
     public static QName getNodeQName(Node el) {
         String localName = el.getLocalName();