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;
019    
020    import java.io.ByteArrayInputStream;
021    import java.io.File;
022    import java.io.FileOutputStream;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.OutputStream;
026    import java.net.URI;
027    import java.net.URISyntaxException;
028    import java.net.URL;
029    import java.util.ArrayList;
030    import java.util.Collection;
031    import java.util.Collections;
032    import java.util.HashSet;
033    import java.util.LinkedHashMap;
034    import java.util.LinkedHashSet;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Set;
038    import java.util.StringTokenizer;
039    import java.util.jar.Attributes;
040    import java.util.jar.JarFile;
041    import java.util.jar.Manifest;
042    import java.util.zip.ZipEntry;
043    import java.util.zip.ZipFile;
044    
045    import org.apache.geronimo.common.DeploymentException;
046    import org.apache.geronimo.deployment.util.DeploymentUtil;
047    import org.apache.geronimo.gbean.AbstractName;
048    import org.apache.geronimo.gbean.AbstractNameQuery;
049    import org.apache.geronimo.gbean.GBeanData;
050    import org.apache.geronimo.gbean.GBeanInfo;
051    import org.apache.geronimo.gbean.GReferenceInfo;
052    import org.apache.geronimo.gbean.ReferencePatterns;
053    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
054    import org.apache.geronimo.kernel.GBeanNotFoundException;
055    import org.apache.geronimo.kernel.Naming;
056    import org.apache.geronimo.kernel.config.Configuration;
057    import org.apache.geronimo.kernel.config.ConfigurationData;
058    import org.apache.geronimo.kernel.config.ConfigurationManager;
059    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
060    import org.apache.geronimo.kernel.config.NoSuchConfigException;
061    import org.apache.geronimo.kernel.repository.Artifact;
062    import org.apache.geronimo.kernel.repository.Environment;
063    
064    /**
065     * @version $Rev:385232 $ $Date: 2007-07-23 21:41:35 -0400 (Mon, 23 Jul 2007) $
066     */
067    public class DeploymentContext {
068        private final File baseDir;
069        private final File inPlaceConfigurationDir;
070        private final ResourceContext resourceContext;
071        private final byte[] buffer = new byte[4096];
072        private final Map<String, ConfigurationData> childConfigurationDatas = new LinkedHashMap<String, ConfigurationData>();
073        private final ConfigurationManager configurationManager;
074        private final Configuration configuration;
075        private final Naming naming;
076        private final List<ConfigurationData> additionalDeployment = new ArrayList<ConfigurationData>();
077        protected final AbstractName moduleName;
078    
079        public DeploymentContext(File baseDir, File inPlaceConfigurationDir, Environment environment, AbstractName moduleName, ConfigurationModuleType moduleType, Naming naming, ConfigurationManager configurationManager, Collection repositories) throws DeploymentException {
080            this(baseDir, inPlaceConfigurationDir, environment, moduleName, moduleType, naming, createConfigurationManager(configurationManager, repositories));
081        }
082    
083        public DeploymentContext(File baseDir, File inPlaceConfigurationDir, Environment environment, AbstractName moduleName, ConfigurationModuleType moduleType, Naming naming, ConfigurationManager configurationManager) throws DeploymentException {
084            if (baseDir == null) throw new NullPointerException("baseDir is null");
085            if (environment == null) throw new NullPointerException("environment is null");
086            if (moduleType == null) throw new NullPointerException("type is null");
087            if (configurationManager == null) throw new NullPointerException("configurationManager is null");
088    
089            if (!baseDir.exists()) {
090                baseDir.mkdirs();
091            }
092            this.baseDir = baseDir;
093    
094            this.inPlaceConfigurationDir = inPlaceConfigurationDir;
095    
096            this.moduleName = moduleName;
097    
098            this.naming = naming;
099    
100            this.configuration = createTempConfiguration(environment, moduleType, baseDir, inPlaceConfigurationDir, configurationManager, naming);
101    
102            this.configurationManager = configurationManager;
103    
104            if (null == inPlaceConfigurationDir) {
105                resourceContext = new CopyResourceContext(configuration, baseDir);
106            } else {
107                resourceContext = new InPlaceResourceContext(configuration, inPlaceConfigurationDir);
108            }
109        }
110    
111        private static ConfigurationManager createConfigurationManager(ConfigurationManager configurationManager, Collection repositories) {
112            return new DeploymentConfigurationManager(configurationManager, repositories);
113        }
114    
115        private static Configuration createTempConfiguration(Environment environment, ConfigurationModuleType moduleType, File baseDir, File inPlaceConfigurationDir, ConfigurationManager configurationManager, Naming naming) throws DeploymentException {
116            try {
117                configurationManager.loadConfiguration(new ConfigurationData(moduleType, null, null, null, environment, baseDir, inPlaceConfigurationDir, naming));
118                return configurationManager.getConfiguration(environment.getConfigId());
119            } catch (Exception e) {
120                throw new DeploymentException("Unable to create configuration for deployment", e);
121            }
122        }
123    
124        public ConfigurationManager getConfigurationManager() {
125            return configurationManager;
126        }
127    
128        public Artifact getConfigID() {
129            return configuration.getId();
130        }
131    
132        public File getBaseDir() {
133            return baseDir;
134        }
135    
136        public File getInPlaceConfigurationDir() {
137            return inPlaceConfigurationDir;
138        }
139    
140        public Naming getNaming() {
141            return naming;
142        }
143    
144        public GBeanData addGBean(String name, GBeanInfo gbeanInfo) throws GBeanAlreadyExistsException {
145            if (name == null) throw new NullPointerException("name is null");
146            if (gbeanInfo == null) throw new NullPointerException("gbean is null");
147            GBeanData gbean = new GBeanData(gbeanInfo);
148            configuration.addGBean(name, gbean);
149            return gbean;
150        }
151    
152        public void addGBean(GBeanData gbean) throws GBeanAlreadyExistsException {
153            if (gbean == null) throw new NullPointerException("gbean is null");
154            if (gbean.getAbstractName() == null) throw new NullPointerException("gbean.getAbstractName() is null");
155            configuration.addGBean(gbean);
156        }
157    
158        public void removeGBean(AbstractName name) throws GBeanNotFoundException {
159            if (name == null) throw new NullPointerException("name is null");
160            configuration.removeGBean(name);
161        }
162    
163        public Set<AbstractName> getGBeanNames() {
164            return new HashSet<AbstractName>(configuration.getGBeans().keySet());
165        }
166    
167        /**
168         * @deprecated use findGBeans(pattern)
169         * @param pattern Search for gbeans whose name matches pattern.
170         * @return the set of gbeans whose name matches the pattern.
171         */
172        public Set<AbstractName> listGBeans(AbstractNameQuery pattern) {
173            return findGBeans(pattern);
174        }
175    
176        public AbstractName findGBean(AbstractNameQuery pattern) throws GBeanNotFoundException {
177            return configuration.findGBean(pattern);
178        }
179    
180        public AbstractName findGBean(Set<AbstractNameQuery> patterns) throws GBeanNotFoundException {
181            return configuration.findGBean(patterns);
182        }
183    
184        public LinkedHashSet<AbstractName> findGBeans(AbstractNameQuery pattern) {
185            return configuration.findGBeans(pattern);
186        }
187    
188        public LinkedHashSet<GBeanData> findGBeanDatas(Configuration configuration, AbstractNameQuery pattern) {
189            return configuration.findGBeanDatas(configuration, Collections.singleton(pattern));
190        }
191    
192        public LinkedHashSet<AbstractName> findGBeans(Set<AbstractNameQuery> patterns) {
193            return configuration.findGBeans(patterns);
194        }
195    
196        public GBeanData getGBeanInstance(AbstractName name) throws GBeanNotFoundException {
197            Map gbeans = configuration.getGBeans();
198            GBeanData gbeanData = (GBeanData) gbeans.get(name);
199            if (gbeanData == null) {
200                throw new GBeanNotFoundException(name);
201            }
202            return gbeanData;
203        }
204    
205        /**
206         * Add a packed jar file into the deployment context and place it into the
207         * path specified in the target path.  The newly added packed jar is added
208         * to the classpath of the configuration.
209         *
210         * @param targetPath where the packed jar file should be placed
211         * @param jarFile    the jar file to copy
212         * @throws IOException if there's a problem copying the jar file
213         */
214        public void addIncludeAsPackedJar(URI targetPath, JarFile jarFile) throws IOException {
215            resourceContext.addIncludeAsPackedJar(targetPath, jarFile);
216        }
217    
218        /**
219         * Add a ZIP file entry into the deployment context and place it into the
220         * path specified in the target path.  The newly added entry is added
221         * to the classpath of the configuration.
222         *
223         * @param targetPath where the ZIP file entry should be placed
224         * @param zipFile    the ZIP file
225         * @param zipEntry   the ZIP file entry
226         * @throws IOException if there's a problem copying the ZIP entry
227         */
228        public void addInclude(URI targetPath, ZipFile zipFile, ZipEntry zipEntry) throws IOException {
229            resourceContext.addInclude(targetPath, zipFile, zipEntry);
230        }
231    
232        /**
233         * Add a file into the deployment context and place it into the
234         * path specified in the target path.  The newly added file is added
235         * to the classpath of the configuration.
236         *
237         * @param targetPath where the file should be placed
238         * @param source     the URL of file to be copied
239         * @throws IOException if there's a problem copying the ZIP entry
240         */
241        public void addInclude(URI targetPath, URL source) throws IOException {
242            resourceContext.addInclude(targetPath, source);
243        }
244    
245        /**
246         * Add a file into the deployment context and place it into the
247         * path specified in the target path.  The newly added file is added
248         * to the classpath of the configuration.
249         *
250         * @param targetPath where the file should be placed
251         * @param source     the file to be copied
252         * @throws IOException if there's a problem copying the ZIP entry
253         */
254        public void addInclude(URI targetPath, File source) throws IOException {
255            resourceContext.addInclude(targetPath, source);
256        }
257    
258        interface JarFileFactory {
259            JarFile newJarFile(URI relativeURI) throws IOException;
260    
261            String getManifestClassPath(JarFile jarFile) throws IOException;
262        }
263    
264        private class DefaultJarFileFactory implements JarFileFactory {
265    
266            public JarFile newJarFile(URI relativeURI) throws IOException {
267                File targetFile = getTargetFile(relativeURI);
268                try {
269                    return new JarFile(targetFile);
270                } catch (IOException e) {
271                    throw (IOException)new IOException("Could not create JarFile for file: " + targetFile).initCause(e);
272                }
273            }
274    
275            public String getManifestClassPath(JarFile jarFile) throws IOException {
276                Manifest manifest = jarFile.getManifest();
277                if (manifest == null) {
278                    return null;
279                }
280                return manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
281            }
282        }
283    
284        public void getCompleteManifestClassPath(JarFile moduleFile, URI moduleBaseUri, URI resolutionUri, ClassPathList classpath, ModuleList exclusions) throws DeploymentException {
285            List<DeploymentException> problems = new ArrayList<DeploymentException>();
286            getCompleteManifestClassPath(moduleFile, moduleBaseUri, resolutionUri, classpath, exclusions, new DefaultJarFileFactory(), problems);
287            if (!problems.isEmpty()) {
288                if (problems.size() == 1) {
289                    throw problems.get(0);
290                }
291                throw new DeploymentException("Determining complete manifest classpath unsuccessful:", problems);
292            }
293        }
294    
295        /**
296         * Recursively construct the complete set of paths in the ear for the manifest classpath of the supplied modulefile.
297         * Used only in PersistenceUnitBuilder to figure out if a persistence.xml relates to the starting module.  Having a classloader for
298         * each ejb module would eliminate the need for this and be more elegant.
299         *
300         * @param moduleFile    the module that we start looking at classpaths at, in the car.
301         * @param moduleBaseUri where the moduleFile is inside the car file.  For an (unpacked) war this ends with / which means we also need:
302         * @param resolutionUri the uri to resolve all entries against. For a module such as an ejb jar that is part of the
303         *                      root ear car it is ".".  For a sub-configuration such as a war it is the "reverse" of the path to the war file in the car.
304         *                      For instance, if the war file is foo/bar/myweb.war, the resolutionUri is "../../..".
305         * @param classpath     the classpath list we are constructing.
306         * @param exclusions    the paths to not investigate.  These are typically the other modules in the ear/car file: they will have their contents processed for themselves.
307         * @param factory       the factory for constructing JarFiles and the way to extract the manifest classpath from a JarFile. Introduced to make
308         *                      testing plausible, but may be useful for in-IDE deployment.
309         * @param problems      List to save all the problems we encounter.
310         * @throws org.apache.geronimo.common.DeploymentException
311         *          if something goes wrong.
312         */
313        public void getCompleteManifestClassPath(JarFile moduleFile, URI moduleBaseUri, URI resolutionUri, ClassPathList classpath, ModuleList exclusions, JarFileFactory factory, List<DeploymentException> problems) throws DeploymentException {
314            String manifestClassPath;
315            try {
316                manifestClassPath = factory.getManifestClassPath(moduleFile);
317            } catch (IOException e) {
318                problems.add(new DeploymentException(printInfo("Could not read manifest: " + moduleBaseUri, moduleBaseUri, classpath, exclusions), e));
319                return;
320            }
321    
322            if (manifestClassPath == null) {
323                return;
324            }
325    
326            for (StringTokenizer tokenizer = new StringTokenizer(manifestClassPath, " "); tokenizer.hasMoreTokens();) {
327                String path = tokenizer.nextToken();
328    
329                URI pathUri;
330                try {
331                    pathUri = new URI(path);
332                } catch (URISyntaxException e) {
333                    problems.add(new DeploymentException(printInfo("Invalid manifest classpath entry, path=" + path, moduleBaseUri, classpath, exclusions)));
334                    return;
335                }
336    
337                if (!pathUri.getPath().endsWith(".jar")) {
338                    problems.add(new DeploymentException(printInfo("Manifest class path entries must end with the .jar extension (J2EE 1.4 Section 8.2): path=" + path, moduleBaseUri, classpath, exclusions)));
339                    return;
340                }
341                if (pathUri.isAbsolute()) {
342                    problems.add(new DeploymentException(printInfo("Manifest class path entries must be relative (J2EE 1.4 Section 8.2): path=" + path, moduleBaseUri, classpath, exclusions)));
343                    return;
344                }
345    
346                URI targetUri = moduleBaseUri.resolve(pathUri);
347                if (targetUri.getPath().endsWith("/")) {
348                    problems.add(new DeploymentException(printInfo("target path must not end with a '/' character: path=" + path + ", resolved to targetURI=" + targetUri, moduleBaseUri, classpath, exclusions)));
349                    return;
350                }
351                String targetEntry = targetUri.toString();
352                if (exclusions.contains(targetEntry)) {
353                    continue;
354                }
355                URI resolvedUri = resolutionUri.resolve(targetUri);
356                String classpathEntry = resolvedUri.toString();
357                //don't get caught in circular references
358                if (classpath.contains(classpathEntry)) {
359                    continue;
360                }
361                classpath.add(classpathEntry);
362    
363                JarFile classPathJarFile;
364                try {
365                    classPathJarFile = factory.newJarFile(targetUri);
366                } catch (IOException e) {
367                    problems.add(new DeploymentException(printInfo("Manifest class path entries must be a valid jar file (JAVAEE 5 Section 8.2): path=" + path + ", resolved to targetURI=" + targetUri, moduleBaseUri, classpath, exclusions), e));
368                    return;
369                }
370    
371                getCompleteManifestClassPath(classPathJarFile, targetUri, resolutionUri, classpath, exclusions, factory, problems);
372            }
373        }
374    
375        private String printInfo(String message, URI moduleBaseUri, ClassPathList classpath, ModuleList exclusions) {
376            StringBuffer buf = new StringBuffer(message).append("\n");
377            buf.append("    looking at: ").append(moduleBaseUri);
378            buf.append("    current classpath: ").append(classpath);
379            buf.append("    ignoring modules: ").append(exclusions);
380            return buf.toString();
381        }
382    
383        /**
384         * Import the classpath from a jar file's manifest.  The imported classpath
385         * is crafted relative to <code>moduleBaseUri</code>.
386         *
387         * @param moduleFile    the jar file from which the manifest is obtained.
388         * @param moduleBaseUri the base for the imported classpath
389         * @throws DeploymentException if there is a problem with the classpath in
390         *                             the manifest
391         */
392        public void addManifestClassPath(JarFile moduleFile, URI moduleBaseUri) throws DeploymentException {
393            Manifest manifest;
394            try {
395                manifest = moduleFile.getManifest();
396            } catch (IOException e) {
397                throw new DeploymentException("Could not read manifest: " + moduleBaseUri);
398            }
399    
400            if (manifest == null) {
401                return;
402            }
403            String manifestClassPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
404            if (manifestClassPath == null) {
405                return;
406            }
407    
408            for (StringTokenizer tokenizer = new StringTokenizer(manifestClassPath, " "); tokenizer.hasMoreTokens();) {
409                String path = tokenizer.nextToken();
410    
411                URI pathUri;
412                try {
413                    pathUri = new URI(path);
414                } catch (URISyntaxException e) {
415                    throw new DeploymentException("Invalid manifest classpath entry: module=" + moduleBaseUri + ", path=" + path);
416                }
417    
418                if (!pathUri.getPath().endsWith(".jar")) {
419                    throw new DeploymentException("Manifest class path entries must end with the .jar extension (J2EE 1.4 Section 8.2): module=" + moduleBaseUri);
420                }
421                if (pathUri.isAbsolute()) {
422                    throw new DeploymentException("Manifest class path entries must be relative (J2EE 1.4 Section 8.2): moduel=" + moduleBaseUri);
423                }
424    
425                try {
426                    URI targetUri = moduleBaseUri.resolve(pathUri);
427                    if (targetUri.getPath().endsWith("/"))
428                        throw new IllegalStateException("target path must not end with a '/' character: " + targetUri);
429                    configuration.addToClassPath(targetUri.toString());
430                } catch (IOException e) {
431                    throw new DeploymentException(e);
432                }
433            }
434        }
435    
436        public void addClass(URI targetPath, String fqcn, byte[] bytes) throws IOException, URISyntaxException {
437            if (!targetPath.getPath().endsWith("/"))
438                throw new IllegalStateException("target path must end with a '/' character: " + targetPath);
439    
440            String classFileName = fqcn.replace('.', '/') + ".class";
441    
442            File targetFile = getTargetFile(new URI(targetPath.toString() + classFileName));
443            addFile(targetFile, new ByteArrayInputStream(bytes));
444    
445            configuration.addToClassPath(targetPath.toString());
446        }
447    
448        public void addFile(URI targetPath, ZipFile zipFile, ZipEntry zipEntry) throws IOException {
449            resourceContext.addFile(targetPath, zipFile, zipEntry);
450        }
451    
452        public void addFile(URI targetPath, URL source) throws IOException {
453            resourceContext.addFile(targetPath, source);
454        }
455    
456        public void addFile(URI targetPath, File source) throws IOException {
457            resourceContext.addFile(targetPath, source);
458        }
459    
460        public void addFile(URI targetPath, String source) throws IOException {
461            resourceContext.addFile(targetPath, source);
462        }
463    
464        private void addFile(File targetFile, InputStream source) throws IOException {
465            targetFile.getParentFile().mkdirs();
466            OutputStream out = null;
467            try {
468                out = new FileOutputStream(targetFile);
469                int count;
470                while ((count = source.read(buffer)) > 0) {
471                    out.write(buffer, 0, count);
472                }
473            } finally {
474                DeploymentUtil.close(out);
475            }
476        }
477    
478        public File getTargetFile(URI targetPath) {
479            return resourceContext.getTargetFile(targetPath);
480        }
481    
482        public ClassLoader getClassLoader() throws DeploymentException {
483            return configuration.getConfigurationClassLoader();
484        }
485    
486        public Configuration getConfiguration() {
487            return configuration;
488        }
489    
490        public void flush() throws IOException {
491            resourceContext.flush();
492        }
493    
494        public void close() throws IOException, DeploymentException {
495            if (configurationManager != null) {
496                try {
497                    configurationManager.unloadConfiguration(configuration.getId());
498                } catch (NoSuchConfigException ignored) {
499                    //ignore
500                }
501            }
502        }
503    
504        public void addChildConfiguration(String moduleName, ConfigurationData configurationData) {
505            childConfigurationDatas.put(moduleName, configurationData);
506        }
507    
508        public ConfigurationData getConfigurationData() throws DeploymentException {
509            List<String> failures = verify(configuration);
510            if (!failures.isEmpty()) {
511                StringBuffer message = new StringBuffer();
512                for (String failure : failures) {
513                    if (message.length() > 0) message.append("\n");
514                    message.append(failure);
515                }
516                throw new DeploymentException(message.toString());
517            }
518    
519            ArrayList<GBeanData> gbeans = new ArrayList<GBeanData>(configuration.getGBeans().values());
520            Collections.sort(gbeans, new GBeanData.PriorityComparator());
521            ConfigurationData configurationData = new ConfigurationData(configuration.getModuleType(),
522                    new LinkedHashSet<String>(configuration.getClassPath()),
523                    gbeans,
524                    childConfigurationDatas,
525                    configuration.getEnvironment(),
526                    baseDir,
527                    inPlaceConfigurationDir,
528                    naming);
529    
530            for (ConfigurationData ownedConfiguration : additionalDeployment) {
531                configurationData.addOwnedConfigurations(ownedConfiguration.getId());
532            }
533    
534            return configurationData;
535        }
536    
537        public void addAdditionalDeployment(ConfigurationData configurationData) {
538            additionalDeployment.add(configurationData);
539        }
540    
541        public List getAdditionalDeployment() {
542            return additionalDeployment;
543        }
544    
545        public AbstractName getModuleName() {
546            return moduleName;
547        }
548    
549        public List<String> verify(Configuration configuration) throws DeploymentException {
550            List<String> failures = new ArrayList<String>();
551            for (Map.Entry<AbstractName, GBeanData> entry : this.configuration.getGBeans().entrySet()) {
552                AbstractName name = entry.getKey();
553                GBeanData gbean = entry.getValue();
554    
555                for (Map.Entry<String, ReferencePatterns> referenceEntry : gbean.getReferences().entrySet()) {
556                    String referenceName = referenceEntry.getKey();
557                    ReferencePatterns referencePatterns = referenceEntry.getValue();
558    
559                    String failure = verifyReference(gbean, referenceName, referencePatterns, configuration);
560                    if (failure != null) {
561                        failures.add(failure);
562                    }
563                }
564    
565                for (ReferencePatterns referencePatterns : gbean.getDependencies()) {
566                    String failure = verifyDependency(name, referencePatterns, configuration);
567                    if (failure != null) {
568                        failures.add(failure);
569                    }
570                }
571            }
572            return failures;
573        }
574    
575        private String verifyReference(GBeanData gbean, String referenceName, ReferencePatterns referencePatterns, Configuration configuration) {
576            GReferenceInfo referenceInfo = gbean.getGBeanInfo().getReference(referenceName);
577    
578            // if there is no reference info we can't verify
579            if (referenceInfo == null) return null;
580    
581            // A collection valued reference doesn't need to be verified
582            if (referenceInfo.getProxyType().equals(Collection.class.getName())) return null;
583    
584            String message = isVerifyReference(referencePatterns, configuration);
585            if (message != null) {
586                return "Unable to resolve reference \"" + referenceName + "\" in gbean " +
587                        gbean.getAbstractName() + " to a gbean matching the pattern " + referencePatterns.getPatterns() + "due to: " + message;
588            }
589            return null;
590        }
591    
592        private String verifyDependency(AbstractName name, ReferencePatterns referencePatterns, Configuration configuration) {
593            String message = isVerifyReference(referencePatterns, configuration);
594            if (message != null) {
595                return "Unable to resolve dependency in gbean " + name +
596                        " to a gbean matching the pattern " + referencePatterns.getPatterns() + "due to: " + message;
597            }
598    
599            return null;
600        }
601    
602        private String isVerifyReference(ReferencePatterns referencePatterns, Configuration configuration) {
603            // we can't verify a resolved reference since it will have a specific artifact already set...
604            // hopefully the deployer won't generate bad resolved references
605            if (referencePatterns.isResolved()) return null;
606    
607            // Do not verify the reference if it has an explicit depenency on another artifact, because it it likely
608            // that the other artifact is not in the "environment" (if it were you wouldn't use the long form)
609            Set<AbstractNameQuery> patterns = referencePatterns.getPatterns();
610            for (AbstractNameQuery query : patterns) {
611                if (query.getArtifact() != null) return null;
612            }
613    
614            // attempt to find the bean
615            try {
616                configuration.findGBean(patterns);
617                return null;
618            } catch (GBeanNotFoundException e) {
619                //TODO bug!! GERONIMO-3140 Multiple matches may be caused by using an already-loaded configuration rather than reloading one
620                // using the client_artifact_aliases.properties which e.g. remap the server tm to the client tm.
621                if (e.hasMatches()) {
622                    return null;
623                }
624                return e.getMessage();
625            }
626        }
627    }