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;
018
019 import java.io.Serializable;
020 import java.io.IOException;
021 import java.io.ObjectInputStream;
022 import java.io.ByteArrayInputStream;
023 import java.io.EOFException;
024 import java.io.ByteArrayOutputStream;
025 import java.io.ObjectOutputStream;
026 import java.util.List;
027 import java.util.ArrayList;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.Iterator;
031
032 import org.apache.geronimo.gbean.GBeanData;
033 import org.apache.geronimo.gbean.GBeanInfo;
034 import org.apache.geronimo.gbean.AbstractName;
035 import org.apache.geronimo.kernel.Naming;
036 import org.apache.geronimo.kernel.ObjectInputStreamExt;
037 import org.apache.geronimo.kernel.repository.Environment;
038
039 /**
040 * @version $Rev: 510752 $ $Date: 2007-02-22 20:27:16 -0500 (Thu, 22 Feb 2007) $
041 */
042 public class SerializedGBeanState implements GBeanState, Serializable {
043 private static final long serialVersionUID = 6015138334529564307L;
044
045 /**
046 * GBeans contained in this configuration.
047 */
048 private final List gbeans = new ArrayList();
049
050 /**
051 * The serialized form of the gbeans. Once this is set on more gbeans can be added.
052 */
053 private byte[] gbeanState;
054
055 public SerializedGBeanState(Collection gbeans) {
056 if (gbeans != null){
057 this.gbeans.addAll(gbeans);
058 }
059 }
060
061 public List getGBeans(ClassLoader classLoader) throws InvalidConfigException {
062 if (gbeanState == null) {
063 return Collections.unmodifiableList(gbeans);
064 }
065 gbeans.addAll(loadGBeans(gbeanState, classLoader));
066 return Collections.unmodifiableList(gbeans);
067 }
068
069 public void addGBean(GBeanData gbeanData) {
070 if (gbeanState != null) {
071 throw new IllegalStateException("GBeans have been serialized, so no more GBeans can be added");
072 }
073
074 gbeans.add(gbeanData);
075 }
076
077 public GBeanData addGBean(String name, GBeanInfo gbeanInfo, Naming naming, Environment environment) {
078 if (gbeanState != null) {
079 throw new IllegalStateException("GBeans have been serialized, so no more GBeans can be added");
080 }
081
082 String j2eeType = gbeanInfo.getJ2eeType();
083 if (j2eeType == null) j2eeType = "GBean";
084 AbstractName abstractName = naming.createRootName(environment.getConfigId(), name, j2eeType);
085 GBeanData gBeanData = new GBeanData(abstractName, gbeanInfo);
086 addGBean(gBeanData);
087 return gBeanData;
088 }
089
090 private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
091 if (gbeanState == null) {
092 gbeanState = storeGBeans(gbeans);
093 gbeans.clear();
094 }
095
096 stream.defaultWriteObject();
097 }
098
099 private static List loadGBeans(byte[] gbeanState, ClassLoader classLoader) throws InvalidConfigException {
100 List gbeans = new ArrayList();
101 if (gbeanState != null && gbeanState.length > 0) {
102 // Set the thread context classloader so deserializing classes can grab the cl from the thread
103 ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
104 try {
105 Thread.currentThread().setContextClassLoader(classLoader);
106
107 ObjectInputStream ois = new ObjectInputStreamExt(new ByteArrayInputStream(gbeanState), classLoader);
108 try {
109 while (true) {
110 GBeanData gbeanData = new GBeanData();
111 gbeanData.readExternal(ois);
112 gbeans.add(gbeanData);
113 }
114 } catch (EOFException e) {
115 // ok
116 } finally {
117 ois.close();
118 }
119 } catch (ClassNotFoundException e) {
120 throw new InvalidConfigException("Class not loadable in classloader: " + classLoader, e);
121 } catch (NoClassDefFoundError e) {
122 throw new InvalidConfigException("Class not loadable in classloader: " + classLoader, e);
123 } catch (Exception e) {
124 throw new InvalidConfigException("Unable to deserialize GBeanState in classloader: " + classLoader, e);
125 } finally {
126 Thread.currentThread().setContextClassLoader(oldCl);
127 }
128 }
129 return gbeans;
130 }
131
132 private static byte[] storeGBeans(List gbeans) throws IOException {
133 ByteArrayOutputStream baos = new ByteArrayOutputStream();
134 ObjectOutputStream oos;
135 try {
136 oos = new ObjectOutputStream(baos);
137 } catch (IOException e) {
138 throw (AssertionError) new AssertionError("Unable to initialize ObjectOutputStream").initCause(e);
139 }
140 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
141 GBeanData gbeanData = (GBeanData) iterator.next();
142 try {
143 gbeanData.writeExternal(oos);
144 } catch (Exception e) {
145 throw (IOException) new IOException("Unable to serialize GBeanData for " + gbeanData.getAbstractName()).initCause(e);
146 }
147 }
148 try {
149 oos.flush();
150 } catch (IOException e) {
151 throw (AssertionError) new AssertionError("Unable to flush ObjectOutputStream").initCause(e);
152 }
153 return baos.toByteArray();
154 }
155 }