001    /*
002      Copyright (C) 2002 Laurent Martelli <laurent@aopsys.com>, 
003      Julien van Malderen <julien@aopsys.com>
004    
005      This program is free software; you can redistribute it and/or modify
006      it under the terms of the GNU Lesser General Public License as
007      published by the Free Software Foundation; either version 2 of the
008      License, or (at your option) any later version.
009    
010      This program is distributed in the hope that it will be useful, but
011      WITHOUT ANY WARRANTY; without even the implied warranty of
012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013      Lesser General Public License for more details.
014    
015      You should have received a copy of the GNU Lesser General Public
016      License along with this program; if not, write to the Free Software
017      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
018      USA */
019    
020    package org.objectweb.jac.aspects.persistence;
021    
022    import org.apache.log4j.Logger;
023    import org.objectweb.jac.core.ACManager;
024    import org.objectweb.jac.core.rtti.ClassRepository;
025    import org.objectweb.jac.util.Base64;
026    import org.objectweb.jac.util.Log;
027    
028    /**
029     * General converter from and to String for all Objects.
030     *
031     * <p>It converts Objects into Strings to store them for persistence,
032     * and converts stored Strings into their original form for new
033     * use. OIDs are converted to <localId>@<storage_id></p>
034     */
035    public class ValueConverter
036    {
037        static Logger logger = Logger.getLogger("persistence.converter");
038    
039        /**
040         * Returns a string representation of a value so that it can be
041         * stored.<p>
042         *
043         * @param currentStorage the current storage. OID values from this
044         * storage will be converted to a string which does not contain
045         * the storage id.
046         * @param obj a persistent or primitive object
047         * @return a ready to store string representation 
048         *
049         * @see stringToObject(Storage,String)
050         */
051        static public String objectToString(Storage currentStorage, Object obj)
052        {
053            if (obj == null) 
054                return "null";
055            Class lClass = obj.getClass();
056            String className = lClass.getName();
057            String value;
058          
059            StringConverter converter = (StringConverter)ClassRepository.get()
060                .getClass(className).getAttribute(PersistenceAC.VALUE_CONVERTER);
061    
062            if (obj instanceof OID) {
063                OID oid = (OID)obj;
064                if (oid.getStorage()==currentStorage)
065                    value = ((OID)obj).localId();
066                else
067                    value = ((OID)obj).localId()+'@'+oid.getStorage().getId();
068            } else {
069                if (lClass == java.lang.String.class) {
070                    value = (String)obj; 
071                } else if (converter != null) {
072                    value = converter.objectToString(obj);
073                } else if (lClass.isArray() &&
074                           (lClass.getComponentType()==byte.class)) {
075                    // array of bytes
076                    value = Base64.encodeToString((byte[])obj);
077                } else {
078                    value = obj.toString();
079                }
080                value = className+":"+value;
081            }
082            return value;
083        }
084    
085        /**
086         * Returns an object from a string, depending on the needed type.<p>
087         *
088         * @param currentStorage the current storage. OID values with no
089         * storage id will be attributed to this storage.
090         * @param str the type and value in a string format (type:value)
091         * @return an object value deduced from the string representation
092         * and from the needed type 
093         *
094         * @see objectToString(Storage,Object)
095         */
096        static public Object stringToObject(Storage currentStorage, String str)
097        {
098            logger.debug("stringToObject("+str+")");
099            if (str.equals("null")) 
100                return null;
101            char firstChar = str.charAt(0);
102            if (Character.isDigit(firstChar)) {
103                Storage storage;
104                int index = str.indexOf('@');
105                if (index==-1) {
106                    storage = currentStorage;
107                    return new LongOID(storage,Long.parseLong(str));
108                } else {
109                    PersistenceAC ac = (PersistenceAC)ACManager.getACM().getAC("persistence");
110                    String storageName = str.substring(index+1);
111                    storage = ac.getStorage(storageName.equals("null")?null:storageName);
112                    return new LongOID(storage,Long.parseLong(str.substring(0,index)));
113                }
114            } else {
115                int separator = str.indexOf(":");
116                String type = str.substring(0,separator);
117                str = str.substring(separator+1);
118                logger.debug("type = "+type+" ; value = "+str);
119    
120                StringConverter converter = (StringConverter)ClassRepository.get()
121                    .getClass(type).getAttribute(PersistenceAC.VALUE_CONVERTER);
122    
123                if (type.equals("java.lang.String")) {
124                    return str;
125                } else if (converter != null) {
126                    return converter.stringToObject(str);
127                } else if (type.equals("boolean") ||
128                           type.equals("java.lang.Boolean")) {
129                    if (str.equals("true"))
130                        return Boolean.TRUE;
131                    else if (str.equals("false"))
132                        return Boolean.FALSE;
133                    else {
134                        logger.error("BAD BOOLEAN VALUE "+str);
135                        return null;
136                    }
137                } else if (type.equals("java.io.File")) {
138                    return new java.io.File(str);
139                } else if (type.equals("org.objectweb.jac.util.File")) {
140                    return new org.objectweb.jac.util.File(str);
141                } else if (type.equals("int") || type.equals("java.lang.Integer")) {
142                    return new Integer(str);
143                } else if (type.equals("long") || type.equals("java.lang.Long")) {
144                    return new Long(str);
145                } else if (type.equals("float") || type.equals("java.lang.Float")) {
146                    return new Float(str);
147                } else if (type.equals("double") || type.equals("java.lang.Double")) {
148                    return new Double(str);
149                } else if (type.equals("byte") || type.equals("java.lang.Byte")) {
150                    return new Byte(str);
151                } else if (type.equals("[B")) {
152                    return Base64.decode(str);
153                }
154                else {
155                    logger.error("Unhandled type for value `"+str+"' : "+type);
156                    throw new Error("Unhandled type for value `"+str+"' : "+type);
157                }
158            }
159        }
160    
161    }