001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.kernel.config.xstream;
018    
019    import java.util.Iterator;
020    import java.util.Map;
021    import java.util.Set;
022    import java.util.LinkedHashSet;
023    import java.util.LinkedHashMap;
024    import java.net.URI;
025    
026    import com.thoughtworks.xstream.converters.Converter;
027    import com.thoughtworks.xstream.converters.MarshallingContext;
028    import com.thoughtworks.xstream.converters.UnmarshallingContext;
029    import com.thoughtworks.xstream.converters.ConversionException;
030    import com.thoughtworks.xstream.io.HierarchicalStreamReader;
031    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
032    import com.thoughtworks.xstream.mapper.Mapper;
033    
034    import org.apache.geronimo.crypto.EncryptionManager;
035    import org.apache.geronimo.gbean.AbstractName;
036    import org.apache.geronimo.gbean.GBeanData;
037    import org.apache.geronimo.gbean.GBeanInfo;
038    import org.apache.geronimo.gbean.ReferencePatterns;
039    
040    /**
041     * @version $Rev: 889880 $ $Date: 2009-12-12 10:45:24 +0800 (Sat, 12 Dec 2009) $
042     */
043    public class GBeanDataConverter implements Converter {
044        private final Mapper mapper;
045    
046        public GBeanDataConverter(Mapper mapper) {
047            this.mapper = mapper;
048        }
049    
050        public boolean canConvert(Class clazz) {
051            return GBeanData.class.isAssignableFrom(clazz);
052        }
053    
054        public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) {
055            GBeanData gbeanData = (GBeanData) object;
056    
057            // name
058            AbstractName abstractName = gbeanData.getAbstractName();
059            if (abstractName != null) {
060                writer.addAttribute("name", abstractName.toString());
061            }
062    
063            // gbeanInfo
064            GBeanInfo gbeanInfo = gbeanData.getGBeanInfo();
065            String sourceClass = gbeanInfo.getSourceClass();
066            if (sourceClass != null) {
067                writer.addAttribute("sourceClass", sourceClass);
068            } else {
069                writer.startNode("gbean-info");
070                marshallingContext.convertAnother(gbeanInfo);
071                writer.endNode();
072            }
073    
074            // dependencies Set<ReferencePatterns>
075            Set dependencies = gbeanData.getDependencies();
076            for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
077                ReferencePatterns referencePatterns = (ReferencePatterns) iterator.next();
078                writer.startNode("dependency");
079                marshallingContext.convertAnother(referencePatterns);
080                writer.endNode();
081            }
082    
083            // attributes Map<String, Object>
084            Map attributes = gbeanData.getAttributes();
085            for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
086                Map.Entry entry = (Map.Entry) iterator.next();
087                String attributeName = (String) entry.getKey();
088                Object attributeValue = entry.getValue();
089                if (gbeanInfo.getAttribute(attributeName).isEncrypted()
090                        && attributeValue != null) {
091                    attributeValue = EncryptionManager
092                            .encrypt((String) attributeValue);
093                }
094                if (attributeValue != null) {
095                    writer.startNode("attribute");
096                    writer.addAttribute("name", attributeName);
097    
098                    writer.startNode(mapper.serializedClass(attributeValue.getClass()));
099                    marshallingContext.convertAnother(attributeValue);
100                    writer.endNode();
101    
102                    writer.endNode();
103                }
104            }
105            // references Map<String, ReferencePatterns>
106            Map references = gbeanData.getReferences();
107            for (Iterator iterator = references.entrySet().iterator(); iterator.hasNext();) {
108                Map.Entry entry = (Map.Entry) iterator.next();
109                String referenceName = (String) entry.getKey();
110                ReferencePatterns referencePatterns = (ReferencePatterns) entry.getValue();
111                writer.startNode("reference");
112                writer.addAttribute("name", referenceName);
113                marshallingContext.convertAnother(referencePatterns);
114                writer.endNode();
115            }
116        }
117    
118        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext unmarshallingContext) {
119            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
120            if (classLoader == null) {
121                classLoader = this.getClass().getClassLoader();
122            }
123    
124            // name
125            String gbeanName = reader.getAttribute("name");
126            AbstractName abstractName = null;
127            if (gbeanName != null) {
128                abstractName = new AbstractName(URI.create(gbeanName));
129            }
130    
131            // gbeanInfo
132            GBeanInfo gbeanInfo = null;
133            String sourceClass = reader.getAttribute("sourceClass");
134            if (sourceClass != null) {
135                gbeanInfo = GBeanInfo.getGBeanInfo(sourceClass, classLoader);
136            }
137    
138            Set dependencies = new LinkedHashSet();
139            Map attributes = new LinkedHashMap();
140            Map references = new LinkedHashMap();
141            while (reader.hasMoreChildren()) {
142                reader.moveDown();
143    
144                String nodeName = reader.getNodeName();
145                if (nodeName.equals("gbean-info")) {
146                    if (gbeanInfo != null) {
147                        throw new ConversionException("GBean info declared more than once in gbean " + abstractName);
148                    }
149                    gbeanInfo = (GBeanInfo) unmarshallingContext.convertAnother(reader, GBeanInfo.class);
150                } else if (nodeName.equals("dependency")) {
151                    ReferencePatterns referencePatterns = (ReferencePatterns) unmarshallingContext.convertAnother(reader, ReferencePatterns.class);
152                    dependencies.add(referencePatterns);
153                } else if (nodeName.equals("attribute")) {
154                    String attributeName = reader.getAttribute("name");
155    
156                    reader.moveDown();
157                    String classAttribute = reader.getAttribute(mapper.attributeForImplementationClass());
158                    Class type;
159                    if (classAttribute == null) {
160                        type = mapper.realClass(reader.getNodeName());
161                    } else {
162                        type = mapper.realClass(classAttribute);
163                    }
164                    Object attributeValue = unmarshallingContext.convertAnother(reader, type);
165                    reader.moveUp();
166    
167                    attributes.put(attributeName, attributeValue);
168                } else if (nodeName.equals("reference")) {
169                    String referenceName = reader.getAttribute("name");
170                    ReferencePatterns referencePatterns = (ReferencePatterns) unmarshallingContext.convertAnother(reader, ReferencePatterns.class);
171                    references.put(referenceName, referencePatterns);
172                } else {
173                    throw new ConversionException("Unknown nested node in GBean: " + nodeName);
174                }
175    
176                reader.moveUp();
177            }
178    
179            if (gbeanInfo == null) {
180                throw new ConversionException("GBean info not declared in gbean " + abstractName);
181            }
182    
183            GBeanData gbeanData = new GBeanData(abstractName, gbeanInfo);
184            gbeanData.setDependencies(dependencies);
185            for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
186                Map.Entry entry = (Map.Entry) iterator.next();
187                String attributeName = (String) entry.getKey();
188                Object attributeValue = entry.getValue();
189                gbeanData.setAttribute(attributeName, attributeValue);
190            }
191            for (Iterator iterator = references.entrySet().iterator(); iterator.hasNext();) {
192                Map.Entry entry = (Map.Entry) iterator.next();
193                String referenceName = (String) entry.getKey();
194                ReferencePatterns referencePatterns = (ReferencePatterns) entry.getValue();
195                gbeanData.setReferencePatterns(referenceName, referencePatterns);
196            }
197    
198            return gbeanData;
199        }
200    }