~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 
 * contributor license agreements.  See the NOTICE file distributed with
4
 
 * this work for additional information regarding copyright ownership.
5
 
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 
 * (the "License"); you may not use this file except in compliance with
7
 
 * the License.  You may obtain a copy of the License at
8
 
 *
9
 
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 
 *
11
 
 * Unless required by applicable law or agreed to in writing, software
12
 
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 
 * See the License for the specific language governing permissions and
15
 
 * limitations under the License.
16
 
 */
17
 
 
18
 
package org.apache.solr.core;
19
 
 
20
 
import java.io.BufferedReader;
21
 
import java.io.File;
22
 
import java.io.FileFilter;
23
 
import java.io.FileInputStream;
24
 
import java.io.IOException;
25
 
import java.io.InputStream;
26
 
import java.io.InputStreamReader;
27
 
import java.net.MalformedURLException;
28
 
import java.net.URL;
29
 
import java.net.URLClassLoader;
30
 
import java.util.*;
31
 
import java.util.concurrent.ConcurrentHashMap;
32
 
 
33
 
import org.slf4j.Logger;
34
 
import org.slf4j.LoggerFactory;
35
 
 
36
 
import java.nio.charset.CharacterCodingException;
37
 
import java.nio.charset.Charset;
38
 
import java.nio.charset.CodingErrorAction;
39
 
import java.lang.reflect.Constructor;
40
 
 
41
 
import javax.naming.Context;
42
 
import javax.naming.InitialContext;
43
 
import javax.naming.NamingException;
44
 
import javax.naming.NoInitialContextException;
45
 
 
46
 
import org.apache.solr.analysis.CharFilterFactory;
47
 
import org.apache.solr.analysis.TokenFilterFactory;
48
 
import org.apache.solr.analysis.TokenizerFactory;
49
 
import org.apache.solr.common.util.FileUtils;
50
 
import org.apache.solr.common.ResourceLoader;
51
 
import org.apache.solr.common.SolrException;
52
 
import org.apache.solr.handler.component.SearchComponent;
53
 
import org.apache.solr.request.SolrRequestHandler;
54
 
import org.apache.solr.response.QueryResponseWriter;
55
 
import org.apache.solr.schema.FieldType;
56
 
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
57
 
import org.apache.solr.util.plugin.ResourceLoaderAware;
58
 
import org.apache.solr.util.plugin.SolrCoreAware;
59
 
import org.apache.solr.search.QParserPlugin;
60
 
 
61
 
/**
62
 
 * @since solr 1.3
63
 
 */ 
64
 
public class SolrResourceLoader implements ResourceLoader
65
 
{
66
 
  public static final Logger log = LoggerFactory.getLogger(SolrResourceLoader.class);
67
 
 
68
 
  static final String project = "solr";
69
 
  static final String base = "org.apache" + "." + project;
70
 
  static final String[] packages = {"","analysis.","schema.","handler.","search.","update.","core.","response.","request.","update.processor.","util.", "spelling.", "handler.component.", "handler.dataimport." };
71
 
 
72
 
  private URLClassLoader classLoader;
73
 
  private final String instanceDir;
74
 
  private String dataDir;
75
 
  
76
 
  private final List<SolrCoreAware> waitingForCore = Collections.synchronizedList(new ArrayList<SolrCoreAware>());
77
 
  private final List<SolrInfoMBean> infoMBeans = Collections.synchronizedList(new ArrayList<SolrInfoMBean>());
78
 
  private final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
79
 
  private static final Charset UTF_8 = Charset.forName("UTF-8");
80
 
 
81
 
  private final Properties coreProperties;
82
 
 
83
 
  private volatile boolean live;
84
 
 
85
 
  /**
86
 
   * <p>
87
 
   * This loader will delegate to the context classloader when possible,
88
 
   * otherwise it will attempt to resolve resources using any jar files
89
 
   * found in the "lib/" directory in the specified instance directory.
90
 
   * If the instance directory is not specified (=null), SolrResourceLoader#locateInstanceDir will provide one.
91
 
   * <p>
92
 
   */
93
 
  public SolrResourceLoader( String instanceDir, ClassLoader parent, Properties coreProperties )
94
 
  {
95
 
    if( instanceDir == null ) {
96
 
      this.instanceDir = SolrResourceLoader.locateSolrHome();
97
 
    } else{
98
 
      this.instanceDir = normalizeDir(instanceDir);
99
 
    }
100
 
    log.info("Solr home set to '" + this.instanceDir + "'");
101
 
    
102
 
    this.classLoader = createClassLoader(null, parent);
103
 
    addToClassLoader("./lib/", null);
104
 
    
105
 
    this.coreProperties = coreProperties;
106
 
  }
107
 
 
108
 
  /**
109
 
   * <p>
110
 
   * This loader will delegate to the context classloader when possible,
111
 
   * otherwise it will attempt to resolve resources using any jar files
112
 
   * found in the "lib/" directory in the specified instance directory.
113
 
   * If the instance directory is not specified (=null), SolrResourceLoader#locateInstanceDir will provide one.
114
 
   * <p>
115
 
   */
116
 
  public SolrResourceLoader( String instanceDir, ClassLoader parent )
117
 
  {
118
 
    this(instanceDir, parent, null);
119
 
  }
120
 
 
121
 
  /**
122
 
   * Adds every file/dir found in the baseDir which passes the specified Filter
123
 
   * to the ClassLoader used by this ResourceLoader.  This method <b>MUST</b>
124
 
   * only be called prior to using this ResourceLoader to get any resources, otherwise
125
 
   * it's behavior will be non-deterministic.
126
 
   *
127
 
   * @param baseDir base directory whose children (either jars or directories of
128
 
   *                classes) will be in the classpath, will be resolved relative
129
 
   *                the instance dir.
130
 
   * @param filter The filter files must satisfy, if null all files will be accepted.
131
 
   */
132
 
  void addToClassLoader(final String baseDir, final FileFilter filter) {
133
 
    File base = FileUtils.resolvePath(new File(getInstanceDir()), baseDir);
134
 
    this.classLoader = replaceClassLoader(classLoader, base, filter);
135
 
  }
136
 
  
137
 
  /**
138
 
   * Adds the specific file/dir specified to the ClassLoader used by this
139
 
   * ResourceLoader.  This method <b>MUST</b>
140
 
   * only be called prior to using this ResourceLoader to get any resources, otherwise
141
 
   * it's behavior will be non-deterministic.
142
 
   *
143
 
   * @param path A jar file (or directory of classes) to be added to the classpath,
144
 
   *             will be resolved relative the instance dir.
145
 
   */
146
 
  void addToClassLoader(final String path) {
147
 
    final File file = FileUtils.resolvePath(new File(getInstanceDir()), path);
148
 
    if (file.canRead()) {
149
 
      this.classLoader = replaceClassLoader(classLoader, file.getParentFile(),
150
 
                                            new FileFilter() {
151
 
                                              public boolean accept(File pathname) {
152
 
                                                return pathname.equals(file);
153
 
                                              }
154
 
                                            });
155
 
    } else {
156
 
      log.error("Can't find (or read) file to add to classloader: " + file);
157
 
    }
158
 
  }
159
 
  
160
 
  private static URLClassLoader replaceClassLoader(final URLClassLoader oldLoader,
161
 
                                                   final File base,
162
 
                                                   final FileFilter filter) {
163
 
    if (null != base && base.canRead() && base.isDirectory()) {
164
 
      File[] files = base.listFiles(filter);
165
 
      
166
 
      if (null == files || 0 == files.length) return oldLoader;
167
 
      
168
 
      URL[] oldElements = oldLoader.getURLs();
169
 
      URL[] elements = new URL[oldElements.length + files.length];
170
 
      System.arraycopy(oldElements, 0, elements, 0, oldElements.length);
171
 
      
172
 
      for (int j = 0; j < files.length; j++) {
173
 
        try {
174
 
          URL element = files[j].toURI().normalize().toURL();
175
 
          log.info("Adding '" + element.toString() + "' to classloader");
176
 
          elements[oldElements.length + j] = element;
177
 
        } catch (MalformedURLException e) {
178
 
          SolrException.log(log, "Can't add element to classloader: " + files[j], e);
179
 
        }
180
 
      }
181
 
      return URLClassLoader.newInstance(elements, oldLoader.getParent());
182
 
    }
183
 
    // are we still here?
184
 
    return oldLoader;
185
 
  }
186
 
  
187
 
  /**
188
 
   * Convenience method for getting a new ClassLoader using all files found
189
 
   * in the specified lib directory.
190
 
   */
191
 
  static URLClassLoader createClassLoader(final File libDir, ClassLoader parent) {
192
 
    if ( null == parent ) {
193
 
      parent = Thread.currentThread().getContextClassLoader();
194
 
    }
195
 
    return replaceClassLoader(URLClassLoader.newInstance(new URL[0], parent),
196
 
                              libDir, null);
197
 
  }
198
 
  
199
 
  public SolrResourceLoader( String instanceDir )
200
 
  {
201
 
    this( instanceDir, null, null );
202
 
  }
203
 
  
204
 
  /** Ensures a directory name always ends with a '/'. */
205
 
  public  static String normalizeDir(String path) {
206
 
    return ( path != null && (!(path.endsWith("/") || path.endsWith("\\"))) )? path + File.separator : path;
207
 
  }
208
 
 
209
 
  public String getConfigDir() {
210
 
    return instanceDir + "conf/";
211
 
  }
212
 
  
213
 
  public String getDataDir()    {
214
 
    return dataDir;
215
 
  }
216
 
 
217
 
  public Properties getCoreProperties() {
218
 
    return coreProperties;
219
 
  }
220
 
 
221
 
  /** Opens a schema resource by its name.
222
 
   * Override this method to customize loading schema resources.
223
 
   *@return the stream for the named schema
224
 
   */
225
 
  public InputStream openSchema(String name) {
226
 
    return openResource(name);
227
 
  }
228
 
  
229
 
  /** Opens a config resource by its name.
230
 
   * Override this method to customize loading config resources.
231
 
   *@return the stream for the named configuration
232
 
   */
233
 
  public InputStream openConfig(String name) {
234
 
    return openResource(name);
235
 
  }
236
 
  
237
 
  /** Opens any resource by its name.
238
 
   * By default, this will look in multiple locations to load the resource:
239
 
   * $configDir/$resource (if resource is not absolute)
240
 
   * $CWD/$resource
241
 
   * otherwise, it will look for it in any jar accessible through the class loader.
242
 
   * Override this method to customize loading resources.
243
 
   *@return the stream for the named resource
244
 
   */
245
 
  public InputStream openResource(String resource) {
246
 
    InputStream is=null;
247
 
    try {
248
 
      File f0 = new File(resource);
249
 
      File f = f0;
250
 
      if (!f.isAbsolute()) {
251
 
        // try $CWD/$configDir/$resource
252
 
        f = new File(getConfigDir() + resource);
253
 
      }
254
 
      if (f.isFile() && f.canRead()) {
255
 
        return new FileInputStream(f);
256
 
      } else if (f != f0) { // no success with $CWD/$configDir/$resource
257
 
        if (f0.isFile() && f0.canRead())
258
 
          return new FileInputStream(f0);
259
 
      }
260
 
      // delegate to the class loader (looking into $INSTANCE_DIR/lib jars)
261
 
      is = classLoader.getResourceAsStream(resource);
262
 
      if (is == null)
263
 
        is = classLoader.getResourceAsStream(getConfigDir() + resource);
264
 
    } catch (Exception e) {
265
 
      throw new RuntimeException("Error opening " + resource, e);
266
 
    }
267
 
    if (is==null) {
268
 
      throw new RuntimeException("Can't find resource '" + resource + "' in classpath or '" + getConfigDir() + "', cwd="+System.getProperty("user.dir"));
269
 
    }
270
 
    return is;
271
 
  }
272
 
 
273
 
  /**
274
 
   * Accesses a resource by name and returns the (non comment) lines
275
 
   * containing data.
276
 
   *
277
 
   * <p>
278
 
   * A comment line is any line that starts with the character "#"
279
 
   * </p>
280
 
   *
281
 
   * @param resource
282
 
   * @return a list of non-blank non-comment lines with whitespace trimmed
283
 
   * from front and back.
284
 
   * @throws IOException
285
 
   */
286
 
  public List<String> getLines(String resource) throws IOException {
287
 
    return getLines(resource, UTF_8);
288
 
  }
289
 
 
290
 
  /**
291
 
   * Accesses a resource by name and returns the (non comment) lines containing
292
 
   * data using the given character encoding.
293
 
   *
294
 
   * <p>
295
 
   * A comment line is any line that starts with the character "#"
296
 
   * </p>
297
 
   *
298
 
   * @param resource the file to be read
299
 
   * @param encoding
300
 
   * @return a list of non-blank non-comment lines with whitespace trimmed
301
 
   * @throws IOException
302
 
   */
303
 
  public List<String> getLines(String resource,
304
 
      String encoding) throws IOException {
305
 
    return getLines(resource, Charset.forName(encoding));
306
 
  }
307
 
 
308
 
 
309
 
  public List<String> getLines(String resource, Charset charset) throws IOException{
310
 
    BufferedReader input = null;
311
 
    ArrayList<String> lines;
312
 
    try {
313
 
      input = new BufferedReader(new InputStreamReader(openResource(resource),
314
 
          charset.newDecoder()
315
 
          .onMalformedInput(CodingErrorAction.REPORT)
316
 
          .onUnmappableCharacter(CodingErrorAction.REPORT)));
317
 
 
318
 
      lines = new ArrayList<String>();
319
 
      for (String word=null; (word=input.readLine())!=null;) {
320
 
        // skip initial bom marker
321
 
        if (lines.isEmpty() && word.length() > 0 && word.charAt(0) == '\uFEFF')
322
 
          word = word.substring(1);
323
 
        // skip comments
324
 
        if (word.startsWith("#")) continue;
325
 
        word=word.trim();
326
 
        // skip blank lines
327
 
        if (word.length()==0) continue;
328
 
        lines.add(word);
329
 
      }
330
 
    } catch (CharacterCodingException ex) {
331
 
      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, 
332
 
          "Error loading resource (wrong encoding?): " + resource, ex);
333
 
    } finally {
334
 
      if (input != null)
335
 
        input.close();
336
 
    }
337
 
    return lines;
338
 
  }
339
 
 
340
 
  /*
341
 
   * A static map of short class name to fully qualified class name 
342
 
   */
343
 
  private static Map<String, String> classNameCache = new ConcurrentHashMap<String, String>();
344
 
 
345
 
  /**
346
 
   * This method loads a class either with it's FQN or a short-name (solr.class-simplename or class-simplename).
347
 
   * It tries to load the class with the name that is given first and if it fails, it tries all the known
348
 
   * solr packages. This method caches the FQN of a short-name in a static map in-order to make subsequent lookups
349
 
   * for the same class faster. The caching is done only if the class is loaded by the webapp classloader and it
350
 
   * is loaded using a shortname.
351
 
   *
352
 
   * @param cname The name or the short name of the class.
353
 
   * @param subpackages the packages to be tried if the cnams starts with solr.
354
 
   * @return the loaded class. An exception is thrown if it fails
355
 
   */
356
 
  public Class findClass(String cname, String... subpackages) {
357
 
    if (subpackages == null || subpackages.length == 0 || subpackages == packages) {
358
 
      subpackages = packages;
359
 
      String  c = classNameCache.get(cname);
360
 
      if(c != null) {
361
 
        try {
362
 
          return Class.forName(c, true, classLoader);
363
 
        } catch (ClassNotFoundException e) {
364
 
          //this is unlikely
365
 
          log.error("Unable to load cached class-name :  "+ c +" for shortname : "+cname + e);
366
 
        }
367
 
 
368
 
      }
369
 
    }
370
 
    Class clazz = null;
371
 
    // first try cname == full name
372
 
    try {
373
 
      return Class.forName(cname, true, classLoader);
374
 
    } catch (ClassNotFoundException e) {
375
 
      String newName=cname;
376
 
      if (newName.startsWith(project)) {
377
 
        newName = cname.substring(project.length()+1);
378
 
      }
379
 
      for (String subpackage : subpackages) {
380
 
        try {
381
 
          String name = base + '.' + subpackage + newName;
382
 
          log.trace("Trying class name " + name);
383
 
          return clazz = Class.forName(name,true,classLoader);
384
 
        } catch (ClassNotFoundException e1) {
385
 
          // ignore... assume first exception is best.
386
 
        }
387
 
      }
388
 
  
389
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Error loading class '" + cname + "'", e, false);
390
 
    }finally{
391
 
      //cache the shortname vs FQN if it is loaded by the webapp classloader  and it is loaded
392
 
      // using a shortname
393
 
      if ( clazz != null &&
394
 
              clazz.getClassLoader() == SolrResourceLoader.class.getClassLoader() &&
395
 
              !cname.equals(clazz.getName()) &&
396
 
              (subpackages.length == 0 || subpackages == packages)) {
397
 
        //store in the cache
398
 
        classNameCache.put(cname, clazz.getName());
399
 
      }
400
 
    }
401
 
  }
402
 
 
403
 
  public Object newInstance(String cname, String ... subpackages) {
404
 
    Class clazz = findClass(cname,subpackages);
405
 
    if( clazz == null ) {
406
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
407
 
          "Can not find class: "+cname + " in " + classLoader, false);
408
 
    }
409
 
    
410
 
    Object obj = null;
411
 
    try {
412
 
      obj = clazz.newInstance();
413
 
    } 
414
 
    catch (Exception e) {
415
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
416
 
          "Error instantiating class: '" + clazz.getName()+"'", e, false );
417
 
    }
418
 
 
419
 
    if (!live) {
420
 
      if( obj instanceof SolrCoreAware ) {
421
 
        assertAwareCompatibility( SolrCoreAware.class, obj );
422
 
        waitingForCore.add( (SolrCoreAware)obj );
423
 
      }
424
 
      if( obj instanceof ResourceLoaderAware ) {
425
 
        assertAwareCompatibility( ResourceLoaderAware.class, obj );
426
 
        waitingForResources.add( (ResourceLoaderAware)obj );
427
 
      }
428
 
      if (obj instanceof SolrInfoMBean){
429
 
        //TODO: Assert here?
430
 
        infoMBeans.add((SolrInfoMBean) obj);
431
 
      }
432
 
    }
433
 
    return obj;
434
 
  }
435
 
 
436
 
  public Object newAdminHandlerInstance(final CoreContainer coreContainer, String cname, String ... subpackages) {
437
 
    Class clazz = findClass(cname,subpackages);
438
 
    if( clazz == null ) {
439
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
440
 
          "Can not find class: "+cname + " in " + classLoader, false);
441
 
    }
442
 
    
443
 
    Object obj = null;
444
 
    try {
445
 
      Constructor ctor = clazz.getConstructor(CoreContainer.class);
446
 
       obj = ctor.newInstance(coreContainer);
447
 
    } 
448
 
    catch (Exception e) {
449
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
450
 
          "Error instantiating class: '" + clazz.getName()+"'", e, false );
451
 
    }
452
 
 
453
 
    if (!live) {
454
 
      //TODO: Does SolrCoreAware make sense here since in a multi-core context
455
 
      // which core are we talking about ?
456
 
      if( obj instanceof ResourceLoaderAware ) {
457
 
        assertAwareCompatibility( ResourceLoaderAware.class, obj );
458
 
        waitingForResources.add( (ResourceLoaderAware)obj );
459
 
      }
460
 
    }
461
 
 
462
 
    return obj;
463
 
  }
464
 
 
465
 
 
466
 
 
467
 
  public Object newInstance(String cName, String [] subPackages, Class[] params, Object[] args){
468
 
    Class clazz = findClass(cName,subPackages);
469
 
    if( clazz == null ) {
470
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
471
 
          "Can not find class: "+cName + " in " + classLoader, false);
472
 
    }
473
 
 
474
 
    Object obj = null;
475
 
    try {
476
 
 
477
 
      Constructor constructor = clazz.getConstructor(params);
478
 
      obj = constructor.newInstance(args);
479
 
    }
480
 
    catch (Exception e) {
481
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
482
 
          "Error instantiating class: '" + clazz.getName()+"'", e, false );
483
 
    }
484
 
 
485
 
    if (!live) {
486
 
      if( obj instanceof SolrCoreAware ) {
487
 
        assertAwareCompatibility( SolrCoreAware.class, obj );
488
 
        waitingForCore.add( (SolrCoreAware)obj );
489
 
      }
490
 
      if( obj instanceof ResourceLoaderAware ) {
491
 
        assertAwareCompatibility( ResourceLoaderAware.class, obj );
492
 
        waitingForResources.add( (ResourceLoaderAware)obj );
493
 
      }
494
 
      if (obj instanceof SolrInfoMBean){
495
 
        //TODO: Assert here?
496
 
        infoMBeans.add((SolrInfoMBean) obj);
497
 
      }
498
 
    }
499
 
 
500
 
    return obj;
501
 
  }
502
 
 
503
 
  
504
 
  /**
505
 
   * Tell all {@link SolrCoreAware} instances about the SolrCore
506
 
   */
507
 
  public void inform(SolrCore core) 
508
 
  {
509
 
    this.dataDir = core.getDataDir();
510
 
 
511
 
    // make a copy to avoid potential deadlock of a callback calling newInstance and trying to
512
 
    // add something to waitingForCore.
513
 
    SolrCoreAware[] arr;
514
 
 
515
 
    while (waitingForCore.size() > 0) {
516
 
      synchronized (waitingForCore) {
517
 
        arr = waitingForCore.toArray(new SolrCoreAware[waitingForCore.size()]);
518
 
        waitingForCore.clear();
519
 
      }
520
 
 
521
 
      for( SolrCoreAware aware : arr) {
522
 
        aware.inform( core );
523
 
      }
524
 
    }
525
 
 
526
 
    // this is the last method to be called in SolrCore before the latch is released.
527
 
    live = true;
528
 
  }
529
 
  
530
 
  /**
531
 
   * Tell all {@link ResourceLoaderAware} instances about the loader
532
 
   */
533
 
  public void inform( ResourceLoader loader ) 
534
 
  {
535
 
 
536
 
     // make a copy to avoid potential deadlock of a callback adding to the list
537
 
    ResourceLoaderAware[] arr;
538
 
 
539
 
    while (waitingForResources.size() > 0) {
540
 
      synchronized (waitingForResources) {
541
 
        arr = waitingForResources.toArray(new ResourceLoaderAware[waitingForResources.size()]);
542
 
        waitingForResources.clear();
543
 
      }
544
 
 
545
 
      for( ResourceLoaderAware aware : arr) {
546
 
        aware.inform(loader);
547
 
      }
548
 
    }
549
 
  }
550
 
 
551
 
  /**
552
 
   * Register any {@link org.apache.solr.core.SolrInfoMBean}s
553
 
   * @param infoRegistry The Info Registry
554
 
   */
555
 
  public void inform(Map<String, SolrInfoMBean> infoRegistry) {
556
 
    // this can currently happen concurrently with requests starting and lazy components
557
 
    // loading.  Make sure infoMBeans doesn't change.
558
 
 
559
 
    SolrInfoMBean[] arr;
560
 
    synchronized (infoMBeans) {
561
 
      arr = infoMBeans.toArray(new SolrInfoMBean[infoMBeans.size()]);
562
 
      waitingForResources.clear();
563
 
    }
564
 
 
565
 
 
566
 
    for (SolrInfoMBean bean : arr) {
567
 
      infoRegistry.put(bean.getName(), bean);
568
 
    }
569
 
  }
570
 
  
571
 
  /**
572
 
   * Determines the solrhome from the environment.
573
 
   * Tries JNDI (java:comp/env/solr/home) then system property (solr.solr.home);
574
 
   * if both fail, defaults to solr/
575
 
   * @return the instance directory name
576
 
   */
577
 
  /**
578
 
   * Finds the solrhome based on looking up the value in one of three places:
579
 
   * <ol>
580
 
   *  <li>JNDI: via java:comp/env/solr/home</li>
581
 
   *  <li>The system property solr.solr.home</li>
582
 
   *  <li>Look in the current working directory for a solr/ directory</li> 
583
 
   * </ol>
584
 
   *
585
 
   * The return value is normalized.  Normalization essentially means it ends in a trailing slash.
586
 
   * @return A normalized solrhome
587
 
   * @see #normalizeDir(String)
588
 
   */
589
 
  public static String locateSolrHome() {
590
 
    String home = null;
591
 
    // Try JNDI
592
 
    try {
593
 
      Context c = new InitialContext();
594
 
      home = (String)c.lookup("java:comp/env/"+project+"/home");
595
 
      log.info("Using JNDI solr.home: "+home );
596
 
    } catch (NoInitialContextException e) {
597
 
      log.info("JNDI not configured for "+project+" (NoInitialContextEx)");
598
 
    } catch (NamingException e) {
599
 
      log.info("No /"+project+"/home in JNDI");
600
 
    } catch( RuntimeException ex ) {
601
 
      log.warn("Odd RuntimeException while testing for JNDI: " + ex.getMessage());
602
 
    } 
603
 
    
604
 
    // Now try system property
605
 
    if( home == null ) {
606
 
      String prop = project + ".solr.home";
607
 
      home = System.getProperty(prop);
608
 
      if( home != null ) {
609
 
        log.info("using system property "+prop+": " + home );
610
 
      }
611
 
    }
612
 
    
613
 
    // if all else fails, try 
614
 
    if( home == null ) {
615
 
      home = project + '/';
616
 
      log.info(project + " home defaulted to '" + home + "' (could not find system property or JNDI)");
617
 
    }
618
 
    return normalizeDir( home );
619
 
  }
620
 
  @Deprecated
621
 
  public static String locateInstanceDir() {
622
 
    return locateSolrHome();
623
 
  }
624
 
 
625
 
  public String getInstanceDir() {
626
 
    return instanceDir;
627
 
  }
628
 
  
629
 
  /**
630
 
   * Keep a list of classes that are allowed to implement each 'Aware' interface
631
 
   */
632
 
  private static final Map<Class, Class[]> awareCompatibility;
633
 
  static {
634
 
    awareCompatibility = new HashMap<Class, Class[]>();
635
 
    awareCompatibility.put( 
636
 
      SolrCoreAware.class, new Class[] {
637
 
        SolrRequestHandler.class,
638
 
        QueryResponseWriter.class,
639
 
        SearchComponent.class,
640
 
        UpdateRequestProcessorFactory.class
641
 
      }
642
 
    );
643
 
 
644
 
    awareCompatibility.put(
645
 
      ResourceLoaderAware.class, new Class[] {
646
 
        CharFilterFactory.class,
647
 
        TokenFilterFactory.class,
648
 
        TokenizerFactory.class,
649
 
        QParserPlugin.class,
650
 
        FieldType.class
651
 
      }
652
 
    );
653
 
  }
654
 
 
655
 
  /**
656
 
   * Utility function to throw an exception if the class is invalid
657
 
   */
658
 
  void assertAwareCompatibility( Class aware, Object obj )
659
 
  {
660
 
    Class[] valid = awareCompatibility.get( aware );
661
 
    if( valid == null ) {
662
 
      throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
663
 
          "Unknown Aware interface: "+aware );
664
 
    }
665
 
    for( Class v : valid ) {
666
 
      if( v.isInstance( obj ) ) {
667
 
        return;
668
 
      }
669
 
    }
670
 
    StringBuilder builder = new StringBuilder();
671
 
    builder.append( "Invalid 'Aware' object: " ).append( obj );
672
 
    builder.append( " -- ").append( aware.getName() );
673
 
    builder.append(  " must be an instance of: " );
674
 
    for( Class v : valid ) {
675
 
      builder.append( "[" ).append( v.getName() ).append( "] ") ;
676
 
    }
677
 
    throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, builder.toString() );
678
 
  }
679
 
  /**
680
 
  +   * EXPERT
681
 
  +   * <p/>
682
 
  +   * The underlying class loader.  Most applications will not need to use this.
683
 
  +   * @return The {@link ClassLoader}
684
 
  +   */
685
 
  public ClassLoader getClassLoader() {
686
 
      return classLoader;
687
 
    }
688
 
}