View Javadoc
1   /*
2    * Copyright (c) 2006-present the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.gmaven.adapter.impl;
17  
18  import java.util.EventObject;
19  import java.util.Map;
20  
21  import javax.annotation.Nullable;
22  
23  import groovy.lang.Binding;
24  import groovy.lang.GroovyClassLoader;
25  import groovy.ui.Console;
26  import org.codehaus.gmaven.adapter.ConsoleWindow;
27  import org.codehaus.gmaven.adapter.ResourceLoader;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  import static com.google.common.base.Preconditions.checkNotNull;
32  
33  /**
34   * Default {@link ConsoleWindow} implementation.
35   *
36   * @since 2.0
37   */
38  public class ConsoleWindowImpl
39      implements ConsoleWindow
40  {
41    private final Logger log = LoggerFactory.getLogger(getClass());
42  
43    private final GroovyRuntimeImpl runtime;
44  
45    private final Object lock = new Object();
46  
47    ConsoleWindowImpl(final GroovyRuntimeImpl runtime) {
48      this.runtime = checkNotNull(runtime);
49    }
50  
51    @Override
52    public WindowHandle open(final ClassLoader classLoader,
53                             final ResourceLoader resourceLoader,
54                             final Map<String, Object> context,
55                             final @Nullable Map<String, Object> options)
56        throws Exception
57    {
58      checkNotNull(classLoader);
59      checkNotNull(resourceLoader);
60      checkNotNull(context);
61  
62      log.trace("Opening; class-loader: {}, resource-loader: {}, context: {}",
63          classLoader, resourceLoader, context);
64  
65      final GroovyClassLoader gcl = runtime.createGroovyClassLoader(classLoader, resourceLoader);
66      Binding binding = runtime.createBinding(context);
67  
68      // FIXME: Sort out how we can avoid IDEA from thinking a sub-class of this needs to have additional overrides
69      // FIXME: Its complaining about the synthetic methods which are dynamically added to GroovyObject instances
70      // FIXME: Perhaps we can install exit lock notification via an event listener instead?
71  
72      final Console console = new Console(gcl, binding)
73      {
74        public void exit(final EventObject event) {
75          try {
76            super.exit(event);
77          }
78          finally {
79            synchronized (lock) {
80              lock.notifyAll();
81            }
82          }
83        }
84      };
85  
86      if (options != null) {
87        configureOptions(console, options);
88      }
89  
90      log.trace("Opening");
91      console.run();
92  
93      return new WindowHandle()
94      {
95        @Override
96        public void close() {
97          log.trace("Closing");
98          console.exit();
99          cleanup();
100       }
101 
102       @Override
103       public void await() throws InterruptedException {
104         log.trace("Waiting");
105         synchronized (lock) {
106           lock.wait();
107         }
108         cleanup();
109       }
110 
111       private void cleanup() {
112         gcl.clearCache();
113       }
114     };
115   }
116 
117   private void configureOptions(final Console console, final Map<String, Object> options) {
118     // TODO
119   }
120 }