View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.gshell.wisdom.application;
21  
22  import org.apache.geronimo.gshell.application.Application;
23  import org.apache.geronimo.gshell.application.ApplicationConfiguration;
24  import org.apache.geronimo.gshell.application.ApplicationManager;
25  import org.apache.geronimo.gshell.application.ClassPath;
26  import org.apache.geronimo.gshell.application.model.ApplicationModel;
27  import org.apache.geronimo.gshell.artifact.Artifact;
28  import org.apache.geronimo.gshell.artifact.ArtifactResolver;
29  import org.apache.geronimo.gshell.chronos.StopWatch;
30  import org.apache.geronimo.gshell.event.EventPublisher;
31  import org.apache.geronimo.gshell.shell.Shell;
32  import org.apache.geronimo.gshell.shell.ShellContext;
33  import org.apache.geronimo.gshell.shell.ShellContextHolder;
34  import org.apache.geronimo.gshell.spring.BeanContainer;
35  import org.apache.geronimo.gshell.spring.BeanContainerAware;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  import java.io.File;
40  import java.lang.reflect.InvocationHandler;
41  import java.lang.reflect.InvocationTargetException;
42  import java.lang.reflect.Method;
43  import java.lang.reflect.Proxy;
44  import java.net.URL;
45  import java.util.Collection;
46  
47  /**
48   * Default implementation of the {@link ApplicationManager} component.
49   *
50   * @version $Rev: 721408 $ $Date: 2008-11-28 10:56:57 +0100 (Fri, 28 Nov 2008) $
51   */
52  public class ApplicationManagerImpl
53      implements ApplicationManager, BeanContainerAware
54  {
55      private final Logger log = LoggerFactory.getLogger(getClass());
56  
57      private final EventPublisher eventPublisher;
58  
59      private ArtifactResolver artifactResolver;
60  
61      private BeanContainer container;
62  
63      private BeanContainer applicationContainer;
64  
65      private Application application;
66  
67      public ApplicationManagerImpl(final EventPublisher eventPublisher, final ArtifactResolver artifactResolver) {
68          assert eventPublisher != null;
69          this.eventPublisher = eventPublisher;
70  
71          assert artifactResolver != null;
72          this.artifactResolver = artifactResolver;
73      }
74  
75      public void setBeanContainer(final BeanContainer container) {
76          assert container != null;
77          
78          this.container = container;
79      }
80  
81      public Application getApplication() {
82          if (application == null) {
83              throw new IllegalStateException("Application has not been configured");
84          }
85  
86          return application;
87      }
88  
89      public void configure(final ApplicationConfiguration config) throws Exception {
90          assert config != null;
91  
92          log.trace("Configuring; config: {}", config);
93  
94          // Validate the configuration
95          config.validate();
96  
97          application = loadApplication(config);
98  
99          log.debug("Application configured");
100         
101         eventPublisher.publish(new ApplicationConfiguredEvent(application));
102     }
103 
104     private ApplicationImpl loadApplication(final ApplicationConfiguration config) throws Exception {
105         assert config != null;
106 
107         StopWatch watch = new StopWatch(true);
108 
109         ApplicationImpl app = new ApplicationImpl(config);
110         ApplicationModel model = app.getModel();
111 
112         log.debug("Loading application: {}", app.getId());
113         log.trace("Application model: {}", model);
114 
115         ClassPath classPath = loadClassPath(model);
116         app.initClassPath(classPath);
117 
118         BeanContainer child = container.createChild(classPath.getUrls());
119         log.debug("Application container: {}", child);
120 
121         child.loadBeans(new String[] {
122             "classpath*:META-INF/gshell/components.xml"
123         });
124         
125         applicationContainer = child;
126 
127         log.debug("Application loaded in: {}", watch);
128 
129         return app;
130     }
131 
132     private ClassPath loadClassPath(final ApplicationModel model) throws Exception {
133         assert model != null;
134 
135         // FIXME: Get basedir from application
136         Artifact artifact = model.getArtifact();
137         ClassPathCache cache = new ClassPathCache(new File(new File(System.getProperty("gshell.home")), "var/" + artifact.getGroup() + "/" + artifact.getName() + "/classpath.ser"));
138                 
139         ClassPath classPath = cache.get();
140 
141         if (classPath == null) {
142             Collection<Artifact> artifacts = resolveArtifacts(model);
143             classPath = new ClassPathImpl(artifacts);
144             cache.set(classPath);
145         }
146         
147         if (log.isDebugEnabled()) {
148             log.debug("Application classpath:");
149 
150             for (URL url : classPath.getUrls()) {
151                 log.debug("    {}", url);
152             }
153         }
154         
155         return classPath;
156     }
157 
158     private Collection<Artifact> resolveArtifacts(final ApplicationModel model) throws Exception {
159         assert model != null;
160 
161         log.debug("Resolving application artifacts");
162 
163         ArtifactResolver.Request request = new ArtifactResolver.Request();
164 
165         request.filter = new ApplicationArtifactFilter();
166         request.artifact = model.getArtifact();
167         request.artifacts = model.getDependencies();
168 
169         ArtifactResolver.Result result = artifactResolver.resolve(request);
170 
171         return result.artifacts;
172     }
173 
174     //
175     // ShellFactory
176     //
177 
178     public Shell create() throws Exception {
179         // Make sure that we have a valid context
180         getApplication();
181 
182         final Shell shell = applicationContainer.getBean(Shell.class);
183 
184         final ShellContext context = shell.getContext();
185 
186         log.debug("Created shell instance: {}", shell);
187 
188         InvocationHandler handler = new InvocationHandler() {
189             //
190             // FIXME: Need to resolve how to handle the security manager for the application,
191             //        the SM is not thread-specific, but VM specific... so not sure this is
192             //        the right approache at all :-(
193             //
194 
195             //
196             // FIXME: This SM actually causes some icky problems when trying to shutdown thread pools, which makes for ugly crap when using ssh
197             //
198 
199             //
200             // FIXME: Disable our custom security stuff for now, not sure how to make this work well... yet.
201             //
202             // private final ApplicationSecurityManager sm = new ApplicationSecurityManager();
203 
204             public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
205                 assert proxy != null;
206                 assert method != null;
207                 // args may be null
208 
209                 if (method.getDeclaringClass() == Object.class) {
210                     return method.invoke(this, args);
211                 }
212 
213                 final ShellContext prevContext = ShellContextHolder.get(true);
214                 ShellContextHolder.set(context);
215 
216                 // final SecurityManager prevSM = System.getSecurityManager();
217                 // System.setSecurityManager(sm);
218 
219                 try {
220                     return method.invoke(shell, args);
221                 }
222                 catch (InvocationTargetException e) {
223                     throw e.getTargetException();
224                 }
225                 finally {
226                     // System.setSecurityManager(prevSM);
227                     ShellContextHolder.set(prevContext);
228                 }
229             }
230         };
231 
232         ClassLoader cl = Thread.currentThread().getContextClassLoader();
233         Shell proxy = (Shell) Proxy.newProxyInstance(cl, new Class[] { Shell.class }, handler);
234 
235         log.debug("Create shell proxy: {}", proxy);
236 
237         eventPublisher.publish(new ShellCreatedEvent(proxy));
238         
239         return proxy;
240     }
241 }