001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.common;
012:
013: import com.versant.core.jdo.VersantPersistenceManager;
014: import com.versant.core.metadata.*;
015: import com.versant.core.util.classhelper.*;
016:
017: import java.io.*;
018: import java.util.Date;
019: import java.util.Locale;
020: import java.util.Properties;
021:
022: /**
023: * Utility methods.
024: */
025: public class Utils {
026:
027: public static final boolean JDK14;
028:
029: static {
030: String v = System.getProperty("java.version");
031: JDK14 = !v.startsWith("1.3"); // we can ignore 1.2 and older
032: }
033:
034: /**
035: * Safe toString method. If toString on o fails then the toString of the
036: * exception is returned in angle brackets instead. This will also format
037: * a byte[] nicely showing the first few bytes in hex.
038: */
039: public static String toString(Object o) {
040: if (o == null)
041: return "null";
042: try {
043: if (o instanceof byte[]) {
044: byte[] a = (byte[]) o;
045: StringBuffer s = new StringBuffer();
046: s.append("byte[]{");
047: int i = 0;
048: for (; i < a.length && i < 10; i++) {
049: if (i > 0)
050: s.append(", ");
051: s.append("0x");
052: s.append(Integer.toHexString(a[i]));
053: }
054: if (i < a.length)
055: s.append("..." + a.length + " bytes");
056: s.append('}');
057: return s.toString();
058: }
059: return o.toString();
060: } catch (Throwable e) {
061: return "<toString failed: " + e + ">";
062: }
063: }
064:
065: /**
066: * Write a UTF8 String that can be bigger than 64K. This code was cut and
067: * pasted from ObjectOutputStream.
068: *
069: * @see #readLongUTF8(java.io.DataInput)
070: */
071: public static void writeLongUTF8(String s, DataOutput out)
072: throws IOException {
073: byte[] buf = new byte[1024];
074: int len = s.length();
075: int bufmax = buf.length - 3;
076: out.writeInt(len);
077: int pos = 0;
078: for (int i = 0; i < len; i++) {
079: char c = s.charAt(i);
080: if (c <= 0x007F && c != 0) {
081: buf[pos++] = (byte) c;
082: } else if (c > 0x07FF) {
083: buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
084: buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
085: buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
086: pos += 3;
087: } else {
088: buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
089: buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
090: pos += 2;
091: }
092: if (pos >= bufmax) {
093: out.write(buf, 0, pos);
094: pos = 0;
095: }
096: }
097: if (pos > 0)
098: out.write(buf, 0, pos);
099: }
100:
101: /**
102: * Read a UTF8 String previously written with writeLongUTF8. This code
103: * was cut and pasted from ObjectInputStream. This method will be slow
104: * if in is not buffered.
105: *
106: * @see #writeLongUTF8(String, DataOutput)
107: */
108: public static String readLongUTF8(DataInput in) throws IOException {
109: int len = in.readInt();
110: if (len == 0)
111: return "";
112: char[] cbuf = new char[len];
113: for (int i = 0; i < len; i++) {
114: int b1, b2, b3;
115: b1 = in.readUnsignedByte();
116: switch (b1 >> 4) {
117: case 0:
118: case 1:
119: case 2:
120: case 3:
121: case 4:
122: case 5:
123: case 6:
124: case 7: // 1 byte format: 0xxxxxxx
125: cbuf[i] = (char) b1;
126: break;
127:
128: case 12:
129: case 13: // 2 byte format: 110xxxxx 10xxxxxx
130: b2 = in.readUnsignedByte();
131: if ((b2 & 0xC0) != 0x80) {
132: throw new UTFDataFormatException();
133: }
134: cbuf[i] = (char) (((b1 & 0x1F) << 6) | ((b2 & 0x3F) << 0));
135: break;
136:
137: case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
138: b2 = in.readUnsignedByte();
139: b3 = in.readUnsignedByte();
140: if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
141: throw new UTFDataFormatException();
142: }
143: cbuf[i] = (char) (((b1 & 0x0F) << 12)
144: | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0));
145: break;
146:
147: default: // 10xx xxxx, 1111 xxxx
148: throw new UTFDataFormatException();
149: }
150: }
151: return new String(cbuf);
152: }
153:
154: /**
155: * Util method that is responsible to check if a 'VersantObjectNotFoundException'
156: * must be thrown. This is determined from the classmetadata of the oid.
157: */
158: public static void checkToThrowRowNotFound(OID oid,
159: ModelMetaData jmd) {
160: final ClassMetaData cmd = oid.getAvailableClassMetaData();
161: if (cmd.returnNullForRowNotFound == ClassMetaData.NULL_NO_ROW_FALSE) {
162: throw BindingSupportImpl
163: .getInstance()
164: .objectNotFound(
165: "No row for "
166: + oid.getAvailableClassMetaData().storeClass
167: + " " + oid.toSString());
168: }
169: }
170:
171: /**
172: * @see #checkToThrowRowNotFound(com.versant.core.common.OID, com.versant.core.metadata.ModelMetaData)
173: */
174: public static void checkToThrowRowNotFound(OID refFrom, OID oid,
175: ModelMetaData jmd) {
176: final ClassMetaData refFromCmd = refFrom.getClassMetaData();
177: final ClassMetaData cmd = oid.getAvailableClassMetaData();
178: if (cmd.returnNullForRowNotFound == ClassMetaData.NULL_NO_ROW_FALSE
179: || (cmd.returnNullForRowNotFound == ClassMetaData.NULL_NO_ROW_PASSON && jmd.returnNullForRowNotFound)) {
180: throw BindingSupportImpl
181: .getInstance()
182: .objectNotFound(
183: "No row for "
184: + oid.getAvailableClassMetaData().storeClass
185: + " " + oid.toSString()
186: + " as referenced from "
187: + refFromCmd.storeClass + " "
188: + refFrom.toSString());
189: }
190: }
191:
192: /**
193: * Writes the correct primitive or wrapper to the output stream
194: */
195: public static void writeSimple(int type, DataOutput os,
196: Object toWrite) throws IOException {
197: if (toWrite == null) {
198: os.writeInt(0);
199: } else {
200: os.writeInt(1);
201: switch (type) {
202: case MDStatics.INTW:
203: case MDStatics.INT:
204: os.writeInt(((Integer) toWrite).intValue());
205: break;
206: case MDStatics.SHORTW:
207: case MDStatics.SHORT:
208: os.writeShort(((Short) toWrite).shortValue());
209: break;
210: case MDStatics.STRING:
211: os.writeUTF((String) toWrite);
212: break;
213: case MDStatics.BOOLEANW:
214: case MDStatics.BOOLEAN:
215: os.writeBoolean(((Boolean) toWrite).booleanValue());
216: break;
217: case MDStatics.BYTEW:
218: case MDStatics.BYTE:
219: os.writeByte(((Byte) toWrite).byteValue());
220: break;
221: case MDStatics.DOUBLEW:
222: case MDStatics.DOUBLE:
223: os.writeDouble(((Double) toWrite).doubleValue());
224: break;
225: case MDStatics.FLOATW:
226: case MDStatics.FLOAT:
227: os.writeFloat(((Float) toWrite).floatValue());
228: break;
229: case MDStatics.LONGW:
230: case MDStatics.LONG:
231: os.writeLong(((Long) toWrite).longValue());
232: break;
233: case MDStatics.DATE:
234: os.writeLong(((Date) toWrite).getTime());
235: break;
236: case MDStatics.BIGDECIMAL:
237: os.writeUTF(toWrite.toString());
238: case MDStatics.LOCALE:
239: final Locale l = (Locale) toWrite;
240: os.writeUTF(l.getLanguage());
241: os.writeUTF(l.getCountry());
242: os.writeUTF(l.getVariant());
243: break;
244: default:
245: throw BindingSupportImpl.getInstance().internal(
246: "writeSimpleField for '"
247: + MDStaticUtils.toSimpleName(type)
248: + "' is not supported");
249: }
250: }
251: }
252:
253: public static Object[] getObjectsById(Object[] objects, int count,
254: VersantPersistenceManager pm, FieldMetaData fmd,
255: boolean isPC) {
256: // Clone data into an object[] and convert OIDs to PC instances.
257: // TODO should be possible to avoid the clone in future
258: Object[] data;
259: if (objects == null) {
260: data = null;
261: } else {
262: Object[] a = objects;
263: data = new Object[count];
264: if (isPC) {
265: pm.getObjectsById(a, count, data, fmd.stateFieldNo,
266: fmd.classMetaData.index);
267: } else {
268: System.arraycopy(a, 0, data, 0, count);
269: }
270: }
271: return data;
272: }
273:
274: /**
275: * Load resourceName as a Properties file using loader.
276: */
277: public static Properties loadProperties(String resourceName,
278: ClassLoader loader) {
279: Properties p = new Properties();
280: InputStream in = null;
281: try {
282: try {
283: in = loader.getResourceAsStream(resourceName);
284: if (in == null) {
285: throw BindingSupportImpl.getInstance().runtime(
286: "Resource not found: " + resourceName);
287: }
288: p.load(in);
289: } finally {
290: if (in != null)
291: in.close();
292: }
293: } catch (IOException e) {
294: throw BindingSupportImpl.getInstance().runtime(
295: "Error loading resource '" + resourceName + "': "
296: + e.getClass().getName() + ": "
297: + e.getMessage(), e);
298: }
299: return p;
300: }
301:
302: /**
303: * Is the database type Versant?
304: */
305: public static boolean isVersantDatabaseType(String dbt) {
306: return "versant".equals(dbt) || "vds".equals(dbt);
307: }
308:
309: /**
310: * Is the URL a Versant URL?
311: */
312: public static boolean isVersantURL(String url) {
313: return url != null
314: && (url.startsWith("vds:") || url
315: .startsWith("versant:"));
316: }
317:
318: public static boolean isStringEmpty(String str) {
319: return str == null || str.trim().length() == 0;
320: }
321:
322: public static boolean isDataSource(String className,
323: ClassLoader loader) {
324: Class driverClass;
325: try {
326: driverClass = ClassHelper.get().classForName(className,
327: false, loader);
328: } catch (ClassNotFoundException cnfe) {
329: try {
330: driverClass = Class.forName(className);
331: } catch (ClassNotFoundException e) {
332: return false;
333: }
334: }
335:
336: if ((java.sql.Driver.class).isAssignableFrom(driverClass)) {
337: return false;
338:
339: } else if ((javax.sql.DataSource.class)
340: .isAssignableFrom(driverClass)) {
341: return true;
342:
343: } else {
344: return false;
345: }
346:
347: }
348:
349: }
|