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.burlap;
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 BurlapHandleEncoder 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 BurlapHandleEncoder(String serverId, Class primaryKeyClass)
055: 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:
068: public BurlapHandleEncoder(AbstractServer server, String serverId,
069: Class primaryKeyClass) throws ConfigException {
070: this (serverId, primaryKeyClass);
071:
072: setServer(server);
073: }
074:
075: /**
076: * Creates a home handle given the server id.
077: */
078: public AbstractHomeHandle createHomeHandle() {
079: try {
080: return new BurlapHomeHandle(getServer().getEJBHome(),
081: getServerId());
082: } catch (Throwable e) {
083: return new BurlapHomeHandle(getServerId());
084: }
085: }
086:
087: /**
088: * Creates a handle given the server id and the object id.
089: */
090: public AbstractHandle createHandle(String objectId) {
091: String url = getURL(objectId);
092:
093: try {
094: return new BurlapHandle(url, getServer().getEJBObject(
095: objectId));
096: } catch (Throwable e) {
097: return new BurlapHandle(url);
098: }
099: }
100:
101: /**
102: * Creates a random string key which hashes to this server.
103: */
104: public String createRandomStringKey() {
105: String originalKey = super .createRandomStringKey();
106:
107: int srun = 0;
108: int tail = calculateHash(originalKey) * 65521;
109:
110: CharBuffer cb = CharBuffer.allocate();
111: cb.append(originalKey);
112:
113: int d1 = (64 + srun - tail) & 0x3f;
114: cb.append(serverEncode64[d1]);
115:
116: return cb.close();
117: }
118:
119: /**
120: * Returns the hash of a string for load-balancing.
121: */
122: private int calculateHash(String key) {
123: int hash = 137;
124: int len = key.length();
125: for (int i = 0; i < len; i++) {
126: char ch = key.charAt(i);
127: hash = 65521 * hash + serverHash64[ch & 0xff];
128: }
129:
130: return hash;
131: }
132:
133: /**
134: * Converts a string object id to the correct key.
135: */
136: public Object objectIdToKey(Object objectKey) {
137: String objectId = (String) objectKey;
138:
139: if (_primaryKeyClass == null)
140: return objectId;
141: else if (_primaryKeyClass.equals(String.class))
142: return objectId;
143: else if (_primaryKeyClass.equals(Integer.class)
144: || _primaryKeyClass.equals(int.class))
145: return new Integer(objectId);
146: else if (_primaryKeyClass.equals(Long.class)
147: || _primaryKeyClass.equals(long.class))
148: return new Long(objectId);
149: else if (_primaryKeyClass.equals(Float.class)
150: || _primaryKeyClass.equals(float.class))
151: return new Float(objectId);
152: else if (_primaryKeyClass.equals(Double.class)
153: || _primaryKeyClass.equals(double.class))
154: return new Double(objectId);
155: else if (Character.class.equals(_primaryKeyClass)
156: || char.class.equals(_primaryKeyClass))
157: return objectId;
158: else if (_fields != null) {
159: Object obj;
160:
161: try {
162: obj = _primaryKeyClass.newInstance();
163:
164: int length = objectId.length();
165: int j = 0;
166:
167: CharBuffer cb = new CharBuffer();
168: for (int i = 0; i < _fields.length; i++) {
169: cb.clear();
170: for (; j < length && objectId.charAt(j) != ','; j++)
171: cb.append(objectId.charAt(j));
172:
173: j++;
174:
175: String field = cb.toString();
176: Class fieldClass = _fields[i].getType();
177:
178: if (fieldClass.equals(String.class))
179: _fields[i].set(obj, field);
180: else if (fieldClass.equals(int.class))
181: _fields[i].setInt(obj, Integer.parseInt(field));
182: else if (fieldClass.equals(Integer.class))
183: _fields[i].set(obj, new Integer(field));
184: else if (fieldClass.equals(long.class))
185: _fields[i].setLong(obj, Long.parseLong(field));
186: else if (fieldClass.equals(Long.class))
187: _fields[i].set(obj, new Long(field));
188: else if (fieldClass.equals(float.class))
189: _fields[i].setFloat(obj, (float) Double
190: .parseDouble(field));
191: else if (fieldClass.equals(Float.class))
192: _fields[i].set(obj, new Float(field));
193: else if (fieldClass.equals(double.class))
194: _fields[i].setDouble(obj, Double
195: .parseDouble(field));
196: else if (fieldClass.equals(Double.class))
197: _fields[i].set(obj, new Double(field));
198: else if (char.class.equals(fieldClass))
199: _fields[i].setChar(obj, field.charAt(0));
200: else if (Character.class.equals(fieldClass))
201: _fields[i].set(obj, new Character(field
202: .charAt(0)));
203: else
204: throw new RuntimeException();
205: }
206:
207: j++;
208: } catch (Exception e) {
209: throw EJBExceptionWrapper.create(e);
210: }
211:
212: return obj;
213: } else
214: throw new EJBException("bad primary key class");
215: }
216:
217: /**
218: * Initialize the server encoding hash.
219: */
220: static {
221: serverEncode64 = new char[64];
222: for (int i = 0; i < 26; i++) {
223: serverEncode64[i] = (char) ('a' + i);
224: serverEncode64[i + 26] = (char) ('A' + i);
225: }
226: for (int i = 0; i < 10; i++)
227: serverEncode64[i + 52] = (char) ('0' + i);
228: serverEncode64[62] = '-';
229: serverEncode64[63] = '_';
230:
231: serverHash64 = new int[256];
232:
233: for (int i = 0; i < 26; i++) {
234: serverHash64['a' + i] = i;
235: serverHash64['A' + i] = i + 26;
236: }
237: for (int i = 0; i < 10; i++)
238: serverHash64['0' + i] = 52 + i;
239: serverHash64['-'] = 62;
240: serverHash64['_'] = 63;
241:
242: int j = 64;
243: for (int i = 0; i < 256; i++) {
244: if (serverHash64[i] == 0)
245: serverHash64[i] = j++;
246: }
247:
248: serverEncodeH2 = new char[64];
249: j = 0;
250: for (int i = 0; i < 64; i++) {
251: serverEncodeH2[j] = serverEncode64[i];
252: j = (j + 49) % 64;
253: }
254: }
255: }
|