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    
018    package org.apache.geronimo.deployment.service;
019    
020    import java.beans.PropertyEditorSupport;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.HashSet;
024    import java.util.Iterator;
025    import java.util.LinkedHashSet;
026    import java.util.List;
027    import java.util.Set;
028    
029    import javax.xml.namespace.QName;
030    
031    import org.apache.geronimo.common.DeploymentException;
032    import org.apache.geronimo.common.propertyeditor.PropertyEditorException;
033    import org.apache.geronimo.deployment.xbeans.ArtifactType;
034    import org.apache.geronimo.deployment.xbeans.ClassFilterType;
035    import org.apache.geronimo.deployment.xbeans.DependenciesType;
036    import org.apache.geronimo.deployment.xbeans.EnvironmentDocument;
037    import org.apache.geronimo.deployment.xbeans.EnvironmentType;
038    import org.apache.geronimo.deployment.xbeans.ImportType;
039    import org.apache.geronimo.deployment.xbeans.DependencyType;
040    import org.apache.geronimo.kernel.repository.Artifact;
041    import org.apache.geronimo.kernel.repository.Dependency;
042    import org.apache.geronimo.kernel.repository.Environment;
043    import org.apache.xmlbeans.XmlException;
044    import org.apache.xmlbeans.XmlObject;
045    import org.apache.xmlbeans.XmlOptions;
046    
047    /**
048     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
049     */
050    public class EnvironmentBuilder extends PropertyEditorSupport implements XmlAttributeBuilder {
051        private final static QName QNAME = EnvironmentDocument.type.getDocumentElementName();
052        private final static String NAMESPACE = QNAME.getNamespaceURI();
053    
054        public static Environment buildEnvironment(EnvironmentType environmentType) {
055            Environment environment = new Environment();
056            if (environmentType != null) {
057                if (environmentType.isSetModuleId()) {
058                    environment.setConfigId(toArtifact(environmentType.getModuleId(), null));
059                }
060    
061                if (environmentType.isSetDependencies()) {
062                    DependencyType[] dependencyArray = environmentType.getDependencies().getDependencyArray();
063                    LinkedHashSet dependencies = toDependencies(dependencyArray);
064                    environment.setDependencies(dependencies);
065                }
066                environment.setInverseClassLoading(environmentType.isSetInverseClassloading());
067                environment.setSuppressDefaultEnvironment(environmentType.isSetSuppressDefaultEnvironment());
068                environment.setHiddenClasses(toFilters(environmentType.getHiddenClasses()));
069                environment.setNonOverrideableClasses(toFilters(environmentType.getNonOverridableClasses()));
070            }
071    
072            return environment;
073        }
074    
075        public static void mergeEnvironments(Environment environment, Environment additionalEnvironment) {
076            if (additionalEnvironment != null) {
077                //TODO merge configIds??
078                if (environment.getConfigId() == null) {
079                    environment.setConfigId(additionalEnvironment.getConfigId());
080                }
081                environment.addDependencies(additionalEnvironment.getDependencies());
082                environment.setInverseClassLoading(environment.isInverseClassLoading() || additionalEnvironment.isInverseClassLoading());
083                environment.setSuppressDefaultEnvironment(environment.isSuppressDefaultEnvironment() || additionalEnvironment.isSuppressDefaultEnvironment());
084                environment.addHiddenClasses(additionalEnvironment.getHiddenClasses());
085                environment.addNonOverrideableClasses(additionalEnvironment.getNonOverrideableClasses());
086            }
087        }
088    
089        public static Environment buildEnvironment(EnvironmentType environmentType, Environment defaultEnvironment) {
090            Environment environment = buildEnvironment(environmentType);
091            if (!environment.isSuppressDefaultEnvironment()) {
092                mergeEnvironments(environment, defaultEnvironment);
093            }
094            return environment;
095        }
096    
097        public static EnvironmentType buildEnvironmentType(Environment environment) {
098            EnvironmentType environmentType = EnvironmentType.Factory.newInstance();
099            if (environment.getConfigId() != null) {
100                ArtifactType configId = toArtifactType(environment.getConfigId());
101                environmentType.setModuleId(configId);
102            }
103    
104            List dependencies = toDependencyTypes(environment.getDependencies());
105            DependencyType[] dependencyTypes = (DependencyType[]) dependencies.toArray(new DependencyType[dependencies.size()]);
106            DependenciesType dependenciesType = environmentType.addNewDependencies();
107            dependenciesType.setDependencyArray(dependencyTypes);
108            if (environment.isInverseClassLoading()) {
109                environmentType.addNewInverseClassloading();
110            }
111            if (environment.isSuppressDefaultEnvironment()) {
112                environmentType.addNewSuppressDefaultEnvironment();
113            }
114            environmentType.setHiddenClasses(toFilterType(environment.getHiddenClasses()));
115            environmentType.setNonOverridableClasses(toFilterType(environment.getNonOverrideableClasses()));
116            return environmentType;
117        }
118    
119        private static ClassFilterType toFilterType(Set filters) {
120            String[] classFilters = (String[]) filters.toArray(new String[filters.size()]);
121            ClassFilterType classFilter = ClassFilterType.Factory.newInstance();
122            classFilter.setFilterArray(classFilters);
123            return classFilter;
124        }
125    
126        private static List toDependencyTypes(Collection artifacts) {
127            List dependencies = new ArrayList();
128            for (Iterator iterator = artifacts.iterator(); iterator.hasNext();) {
129                Dependency dependency = (Dependency) iterator.next();
130                ArtifactType artifactType = toDependencyType(dependency);
131                dependencies.add(artifactType);
132            }
133            return dependencies;
134        }
135    
136        private static ArtifactType toArtifactType(Artifact artifact) {
137            ArtifactType artifactType = ArtifactType.Factory.newInstance();
138            fillArtifactType(artifact, artifactType);
139            return artifactType;
140        }
141    
142        private static void fillArtifactType(Artifact artifact, ArtifactType artifactType) {
143            if (artifact.getGroupId() != null) {
144                artifactType.setGroupId(artifact.getGroupId());
145            }
146            if (artifact.getArtifactId() != null) {
147                artifactType.setArtifactId(artifact.getArtifactId());
148            }
149            if (artifact.getVersion() != null) {
150                artifactType.setVersion(artifact.getVersion().toString());
151            }
152            if (artifact.getType() != null) {
153                artifactType.setType(artifact.getType());
154            }
155        }
156    
157        private static DependencyType toDependencyType(Dependency dependency) {
158            DependencyType dependencyType = DependencyType.Factory.newInstance();
159            fillArtifactType(dependency.getArtifact(), dependencyType);
160    
161            org.apache.geronimo.kernel.repository.ImportType importType = dependency.getImportType();
162            if (importType == org.apache.geronimo.kernel.repository.ImportType.CLASSES) {
163                dependencyType.setImport(ImportType.CLASSES);
164            } else if (importType == org.apache.geronimo.kernel.repository.ImportType.SERVICES) {
165                dependencyType.setImport(ImportType.SERVICES);
166            }
167    
168            return dependencyType;
169        }
170    
171        private static Set toFilters(ClassFilterType filterType) {
172            Set filters = new HashSet();
173            if (filterType != null) {
174                String[] filterArray = filterType.getFilterArray();
175                for (int i = 0; i < filterArray.length; i++) {
176                    String filter = filterArray[i].trim();
177                    filters.add(filter);
178                }
179            }
180            return filters;
181        }
182    
183        //package level for testing
184        static LinkedHashSet toArtifacts(ArtifactType[] artifactTypes) {
185            LinkedHashSet artifacts = new LinkedHashSet();
186            for (int i = 0; i < artifactTypes.length; i++) {
187                ArtifactType artifactType = artifactTypes[i];
188                Artifact artifact = toArtifact(artifactType, "jar");
189                artifacts.add(artifact);
190            }
191            return artifacts;
192        }
193    
194        private static LinkedHashSet toDependencies(DependencyType[] dependencyArray) {
195            LinkedHashSet dependencies = new LinkedHashSet();
196            for (int i = 0; i < dependencyArray.length; i++) {
197                DependencyType artifactType = dependencyArray[i];
198                Dependency dependency = toDependency(artifactType);
199                dependencies.add(dependency);
200            }
201            return dependencies;
202        }
203    
204        private static Dependency toDependency(DependencyType dependencyType) {
205            Artifact artifact = toArtifact(dependencyType, null);
206            if (ImportType.CLASSES.equals(dependencyType.getImport())) {
207                return new Dependency(artifact, org.apache.geronimo.kernel.repository.ImportType.CLASSES);
208            } else if (ImportType.SERVICES.equals(dependencyType.getImport())) {
209                return new Dependency(artifact, org.apache.geronimo.kernel.repository.ImportType.SERVICES);
210            } else if (dependencyType.getImport() == null) {
211                return new Dependency(artifact, org.apache.geronimo.kernel.repository.ImportType.ALL);
212            } else {
213                throw new IllegalArgumentException("Unknown import type: " + dependencyType.getImport());
214            }
215        }
216    
217        private static Artifact toArtifact(ArtifactType artifactType, String defaultType) {
218            String groupId = artifactType.isSetGroupId() ? trim(artifactType.getGroupId()) : null;
219            String type = artifactType.isSetType() ? trim(artifactType.getType()) : defaultType;
220            String artifactId = trim(artifactType.getArtifactId());
221            String version = artifactType.isSetVersion() ? trim(artifactType.getVersion()) : null;
222            return new Artifact(groupId, artifactId, version, type);
223        }
224    
225        private static String trim(String string) {
226            if (string == null || string.length() == 0) {
227            return null;
228            }
229            return string.trim();
230        }
231    
232    
233        public String getNamespace() {
234            return NAMESPACE;
235        }
236    
237        public Object getValue(XmlObject xmlObject, String type, ClassLoader cl) throws DeploymentException {
238    
239            EnvironmentType environmentType;
240            if (xmlObject instanceof EnvironmentType) {
241                environmentType = (EnvironmentType) xmlObject;
242            } else {
243                environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type);
244            }
245            try {
246                XmlOptions xmlOptions = new XmlOptions();
247                xmlOptions.setLoadLineNumbers();
248                Collection errors = new ArrayList();
249                xmlOptions.setErrorListener(errors);
250                if (!environmentType.validate(xmlOptions)) {
251                    throw new XmlException("Invalid deployment descriptor: " + errors + "\nDescriptor: " + environmentType.toString(), null, errors);
252                }
253            } catch (XmlException e) {
254                throw new DeploymentException(e);
255            }
256    
257            return buildEnvironment(environmentType);
258        }
259    
260        public String getAsText() {
261            Environment environment = (Environment) getValue();
262            EnvironmentType environmentType = buildEnvironmentType(environment);
263            XmlOptions xmlOptions = new XmlOptions();
264            xmlOptions.setSaveSyntheticDocumentElement(QNAME);
265            xmlOptions.setSavePrettyPrint();
266            return environmentType.xmlText(xmlOptions);
267        }
268    
269        public void setAsText(String text) {
270            try {
271                EnvironmentDocument environmentDocument = EnvironmentDocument.Factory.parse(text);
272                EnvironmentType environmentType = environmentDocument.getEnvironment();
273                Environment environment = (Environment) getValue(environmentType, null, null);
274                setValue(environment);
275    
276            } catch (XmlException e) {
277                throw new PropertyEditorException(e);
278            } catch (DeploymentException e) {
279                throw new PropertyEditorException(e);
280            }
281        }
282    
283    
284        //This is added by hand to the xmlAttributeBuilders since it is needed to bootstrap the ServiceConfigBuilder.
285    }