| /* |
| * 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.common; |
| |
| import java.io.*; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| |
| import org.apache.ode.utils.CollectionUtils; |
| |
| /** |
| * <p> |
| * Message correlation key. Correlation keys are used to match up incoming |
| * messages with a particular process <em>instance</em>. The basic procedure |
| * is to generate and save a correlation key when a <code>receive</code> or |
| * <code>pick</em> activity is activated, and then to match incoming messages |
| * against all correlation keys so saved, finally associating the message with |
| * the process instance that had the matching correlation key. In reality this |
| * process is somewhat more complicated as pains must be taken to avoid race |
| * conditions and to make the matching efficient.</p> |
| * |
| * <p>The correlation keys used in the above process consists of a collection |
| * of name-value pairs, with the name corresponding to a property name (as |
| * defined using the <code><property></code> element of the BPEL process |
| * document) and with the value corresponding to the value of said property as |
| * obtained from a message by means of a property alias (as defined using |
| * the <code><propertyAlias;></code> BPEL process document element). |
| * </p> |
| */ |
| public class CorrelationKey implements Serializable { |
| |
| private static final long serialVersionUID = 1L; |
| |
| /** CorrelationSet name. */ |
| private String _csetName; |
| /** Key values. */ |
| private String _keyValues[]; |
| |
| /** |
| * Constructor. |
| * |
| * @param csetName |
| * correlation set identifier |
| * @param keyValues |
| * correlation key values |
| */ |
| public CorrelationKey(String csetName, String[] keyValues) { |
| _csetName = csetName; |
| _keyValues = keyValues; |
| } |
| |
| public CorrelationKey(String canonicalForm) { |
| int firstTilde = canonicalForm.indexOf('~'); |
| _csetName = canonicalForm.substring(0, firstTilde == -1 ? canonicalForm.length() : firstTilde); |
| |
| if (firstTilde != -1) { |
| List<String> keys = new ArrayList<String>(); |
| char chars[] = canonicalForm.toCharArray(); |
| StringBuffer work = new StringBuffer(); |
| for (int i = firstTilde + 1; i < chars.length; ++i) { |
| boolean isLast = (i == chars.length - 1); |
| if (chars[i] == '~' && !isLast && chars[i + 1] == '~') { |
| work.append(chars[i++]); |
| } else if (chars[i] == '~') { |
| keys.add(work.toString()); |
| work = new StringBuffer(); |
| } else { |
| work.append(chars[i]); |
| } |
| } |
| keys.add(work.toString()); |
| _keyValues = new String[keys.size()]; |
| keys.toArray(_keyValues); |
| } else { |
| _keyValues = new String[0]; |
| } |
| } |
| |
| /** Return the OCorrelation id for the correlation set */ |
| public String getCorrelationSetName() { |
| return _csetName; |
| } |
| |
| /** Return the values for the correlation set */ |
| public String[] getValues() { |
| return _keyValues; |
| } |
| |
| /** |
| * Check if this key matches any member in a set of keys. |
| * |
| * @param keys |
| * set of keys to match against |
| * |
| * @return <code>true</code> if one of the keys in the set |
| * <code>equals(..)</code> this key, <code>false</code> |
| * otherwise |
| */ |
| public boolean isMatch(CorrelationKey[] keys) { |
| for (CorrelationKey key : keys) |
| if (key.equals(this)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Equals comperator method. |
| * |
| * @param o |
| * <code>CorrelationKey</code> object to compare with |
| * |
| * @return <code>true</code> if the given object |
| */ |
| public boolean equals(Object o) { |
| CorrelationKey okey = (CorrelationKey) o; |
| |
| if (okey == null || !okey._csetName.equals(_csetName) || okey._keyValues.length != _keyValues.length) |
| return false; |
| |
| for (int i = 0; i < _keyValues.length; ++i) |
| if (!_keyValues[i].equals(okey._keyValues[i])) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * Generate a hash code from the hash codes of the elements. |
| * |
| * @see HashMap#hashCode |
| * @see Object#hashCode |
| */ |
| public int hashCode() { |
| int hashCode = _csetName.hashCode(); |
| for (String _keyValue : _keyValues) |
| hashCode ^= _keyValue.hashCode(); |
| return hashCode; |
| } |
| |
| /** |
| * @see Object#toString |
| */ |
| public String toString() { |
| StringBuffer buf = new StringBuffer("{CorrelationKey "); |
| buf.append("setId="); |
| buf.append(_csetName); |
| buf.append(", values="); |
| buf.append(CollectionUtils.makeCollection(ArrayList.class, _keyValues)); |
| buf.append('}'); |
| |
| return buf.toString(); |
| } |
| |
| public String toCanonicalString() { |
| StringBuffer buf = new StringBuffer(); |
| buf.append(_csetName); |
| buf.append('~'); |
| for (int i = 0; i < getValues().length; ++i) { |
| if (i != 0) |
| buf.append('~'); |
| escapeTilde(buf, getValues()[i]); |
| } |
| return buf.toString(); |
| } |
| |
| static void escapeTilde(StringBuffer buf, String str) { |
| if (str == null) |
| return; |
| char[] chars = str.toCharArray(); |
| for (char achar : chars) { |
| if (achar == '~') { |
| buf.append("~~"); |
| } else { |
| buf.append(achar); |
| } |
| } |
| } |
| |
| } |