001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.ejb.hessian;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.ejb.AbstractServer;
033: import com.caucho.ejb.EJBExceptionWrapper;
034: import com.caucho.ejb.protocol.AbstractHandle;
035: import com.caucho.ejb.protocol.AbstractHomeHandle;
036: import com.caucho.ejb.protocol.HandleEncoder;
037: import com.caucho.util.CharBuffer;
038:
039: import javax.ejb.EJBException;
040: import java.lang.reflect.Field;
041:
042: /**
043: * Encodes and decodes handles.
044: */
045: public class HessianHandleEncoder extends HandleEncoder {
046: private static char[] _serverEncode64;
047: private static int[] _serverHash64;
048: private static char[] _serverEncodeH2;
049:
050: private Class _primaryKeyClass;
051: private Field[] _fields;
052: private int[] _fieldTypes;
053:
054: public HessianHandleEncoder(AbstractServer server, String serverId,
055: Class primaryKeyClass) throws ConfigException {
056: super (serverId);
057:
058: _primaryKeyClass = primaryKeyClass;
059:
060: if (_primaryKeyClass == null || _primaryKeyClass.isPrimitive()
061: || _primaryKeyClass.getName().startsWith("java.lang."))
062: return;
063:
064: _fields = _primaryKeyClass.getFields();
065: _fieldTypes = new int[_fields.length];
066:
067: for (int i = 0; i < _fields.length; i++)
068: _fields[i].setAccessible(true);
069:
070: setServer(server);
071: }
072:
073: /**
074: * Creates a home handle given the server id.
075: */
076: public AbstractHomeHandle createHomeHandle() {
077: try {
078: return new HessianHomeHandle(getServer().getEJBHome(),
079: getServerId());
080: } catch (Throwable e) {
081: return new HessianHomeHandle(getServerId());
082: }
083: }
084:
085: /**
086: * Creates a handle given the server id and the object id.
087: */
088: public AbstractHandle createHandle(String objectId) {
089: HessianHandle handle = new HessianHandle(getURL(objectId),
090: objectId);
091:
092: return handle;
093: }
094:
095: /**
096: * Creates a random string key which hashes to this server.
097: */
098: public String createRandomStringKey() {
099: String originalKey = super .createRandomStringKey();
100:
101: int srun = 0;
102: int tail = calculateHash(originalKey) * 65521;
103:
104: CharBuffer cb = CharBuffer.allocate();
105: cb.append(originalKey);
106:
107: int d1 = (64 + srun - tail) & 0x3f;
108: cb.append(_serverEncode64[d1]);
109:
110: return cb.close();
111: }
112:
113: /**
114: * Returns the hash of a string for load-balancing.
115: */
116: private int calculateHash(String key) {
117: int hash = 137;
118: int len = key.length();
119: for (int i = 0; i < len; i++) {
120: char ch = key.charAt(i);
121: hash = 65521 * hash + _serverHash64[ch & 0xff];
122: }
123:
124: return hash;
125: }
126:
127: /**
128: * Converts a string object id to the correct key.
129: */
130: public Object objectIdToKey(Object objectKey) {
131: String objectId = (String) objectKey;
132:
133: if (_primaryKeyClass == null)
134: return objectId;
135: else if (_primaryKeyClass.equals(String.class))
136: return objectId;
137: else if (_primaryKeyClass.equals(Integer.class)
138: || _primaryKeyClass.equals(int.class))
139: return new Integer(objectId);
140: else if (_primaryKeyClass.equals(Long.class)
141: || _primaryKeyClass.equals(long.class))
142: return new Long(objectId);
143: else if (_primaryKeyClass.equals(Float.class)
144: || _primaryKeyClass.equals(float.class))
145: return new Float(objectId);
146: else if (_primaryKeyClass.equals(Double.class)
147: || _primaryKeyClass.equals(double.class))
148: return new Double(objectId);
149: else if (_fields != null) {
150: Object obj;
151:
152: try {
153: obj = _primaryKeyClass.newInstance();
154:
155: int length = objectId.length();
156: int j = 0;
157:
158: CharBuffer cb = new CharBuffer();
159: for (int i = 0; i < _fields.length; i++) {
160: cb.clear();
161: for (; j < length && objectId.charAt(j) != ','; j++)
162: cb.append(objectId.charAt(j));
163:
164: j++;
165:
166: String field = cb.toString();
167: Class fieldClass = _fields[i].getType();
168:
169: if (fieldClass.equals(String.class))
170: _fields[i].set(obj, field);
171: else if (fieldClass.equals(int.class))
172: _fields[i].setInt(obj, Integer.parseInt(field));
173: else if (fieldClass.equals(Integer.class))
174: _fields[i].set(obj, new Integer(field));
175: else if (fieldClass.equals(long.class))
176: _fields[i].setLong(obj, Long.parseLong(field));
177: else if (fieldClass.equals(Long.class))
178: _fields[i].set(obj, new Long(field));
179: else if (fieldClass.equals(float.class))
180: _fields[i].setFloat(obj, (float) Double
181: .parseDouble(field));
182: else if (fieldClass.equals(Float.class))
183: _fields[i].set(obj, new Float(field));
184: else if (fieldClass.equals(double.class))
185: _fields[i].setDouble(obj, Double
186: .parseDouble(field));
187: else if (fieldClass.equals(Double.class))
188: _fields[i].set(obj, new Double(field));
189: else
190: throw new RuntimeException();
191: }
192:
193: j++;
194: } catch (Exception e) {
195: throw EJBExceptionWrapper.create(e);
196: }
197:
198: return obj;
199: } else
200: throw new EJBException("bad primary key class");
201: }
202:
203: /**
204: * Initialize the server encoding hash.
205: */
206: static {
207: _serverEncode64 = new char[64];
208: for (int i = 0; i < 26; i++) {
209: _serverEncode64[i] = (char) ('a' + i);
210: _serverEncode64[i + 26] = (char) ('A' + i);
211: }
212: for (int i = 0; i < 10; i++)
213: _serverEncode64[i + 52] = (char) ('0' + i);
214: _serverEncode64[62] = '-';
215: _serverEncode64[63] = '_';
216:
217: _serverHash64 = new int[256];
218:
219: for (int i = 0; i < 26; i++) {
220: _serverHash64['a' + i] = i;
221: _serverHash64['A' + i] = i + 26;
222: }
223: for (int i = 0; i < 10; i++)
224: _serverHash64['0' + i] = 52 + i;
225: _serverHash64['-'] = 62;
226: _serverHash64['_'] = 63;
227:
228: int j = 64;
229: for (int i = 0; i < 256; i++) {
230: if (_serverHash64[i] == 0)
231: _serverHash64[i] = j++;
232: }
233:
234: _serverEncodeH2 = new char[64];
235: j = 0;
236: for (int i = 0; i < 64; i++) {
237: _serverEncodeH2[j] = _serverEncode64[i];
238: j = (j + 49) % 64;
239: }
240: }
241: }
|