/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.uima.analysis_engine.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.uima.cas.TypeSystem;

/**
 * Implements a globally shared weak-reference map between
 *   types &amp; features to the corresponding Full Feature name
 * Used to avoid creating new full feature names when compiling
 *   result feature specs.
 * Indexable for features via a 2 step index: typeName (weak) and shortFeatName
 *
 */
public class RsFullFeatNames {
  
  private static class TypeFeats {
    private Map<String, String> short2Full = null;  // null till used 
  }
  
  private static final Map<String, TypeFeats> typeName2TypeFeats = new WeakHashMap<String, TypeFeats>(); 
  
  
  public static String getFullFeatName(String typeName, String shortFeatName) {
    synchronized (typeName2TypeFeats) {
      TypeFeats tf = typeName2TypeFeats.get(typeName);
      if (null == tf) {
        tf = new TypeFeats();
        typeName2TypeFeats.put(typeName, tf);
      }
      if (null == tf.short2Full) {
        tf.short2Full = new HashMap<String, String>(3);
      } else {
        String s = tf.short2Full.get(shortFeatName);
        if (null != s) {
          return s;
        }
      }
      String fullFeatName = makeFullFeatName(typeName, shortFeatName);
      tf.short2Full.put(shortFeatName, fullFeatName);
      return fullFeatName;
    } 
  }
  
  private static String makeFullFeatName(String typeName, String shortFeatName) {
    StringBuilder sb = new StringBuilder(typeName.length() + 1 + shortFeatName.length());
    return sb.append(typeName).append(TypeSystem.FEATURE_SEPARATOR).append(shortFeatName).toString();
  }

}

@@ -893,62 +893,29 @@
 til.
-HashMap;%0D%0Aimport java.util.Map;%0D%0Aimport java.util.Weak
+concurrent.Concurrent
 Hash
@@ -1246,15 +1246,8 @@
 Name
- (weak)
  and
@@ -1268,164 +1268,215 @@
 %0D%0A *
+ 
 %0D%0A *
-/%0D%0Apublic class RsFullFeatNames %7B%0D%0A  %0D%0A  private static class TypeFeats %7B%0D%0A    private Map%3CString, String%3E short2Full = null;  // null till used 
+ NOTE: this static table ends up holding on to string representations of all types,%0D%0A * all features, and all valid full feature names; there's no %22cleanup%22.%0D%0A *%0D%0A */%0D%0Apublic class RsFullFeatNames %7B
 %0D%0A  
-%7D%0D%0A
   %0D%0A
@@ -1502,92 +1502,165 @@
 nal 
-Map%3CString, TypeFeats%3E typeName2TypeFeats = new WeakHashMap%3CString, TypeFeats
+ConcurrentHashMap%3CString, ConcurrentHashMap%3CString, String%3E%3E typeName2TypeFeats = %0D%0A      new ConcurrentHashMap%3CString, ConcurrentHashMap%3CString, String%3E
 %3E();
- %0D%0A
   %0D%0A
@@ -1752,60 +1752,47 @@
     
-synchronized (typeName2TypeFeats) %7B%0D%0A      TypeFeats
+%0D%0A    ConcurrentHashMap%3CString, String%3E
  tf 
@@ -1821,29 +1821,36 @@
 et(typeName)
+, tfOther
 ;%0D%0A
-  
     if (null
@@ -1870,40 +1870,17 @@
     
-  tf = new TypeFeats();%0D%0A       
+tfOther =
  typ
@@ -1898,16 +1898,24 @@
 eats.put
+IfAbsent
 (typeNam
@@ -1923,85 +1923,25 @@
 , tf
-);%0D%0A      %7D%0D%0A      if (null == tf.short2Full) %7B%0D%0A        tf.short2Full = new 
+ = new Concurrent
 Hash
@@ -1964,9 +1964,9 @@
 ng%3E(
-3
+)
 );%0D%0A
@@ -1975,22 +1975,56 @@
     
-%7D else %7B
+tf = (tfOther != null) ? tfOther : tf; 
 %0D%0A    
+%7D%0D%0A
     
@@ -2037,27 +2037,16 @@
  s = tf.
-short2Full.
 get(shor
@@ -2055,23 +2055,27 @@
 eatName)
-;%0D%0A    
+, otherS;%0D%0A
     if (
@@ -2079,17 +2079,17 @@
 f (null 
-!
+=
 = s) %7B%0D%0A
@@ -2098,68 +2098,45 @@
     
-    return s;%0D%0A        %7D%0D%0A      %7D%0D%0A      String full
+otherS = tf.putIfAbsent(short
 FeatName
  = m
@@ -2131,16 +2131,19 @@
 FeatName
+, s
  = makeF
@@ -2170,32 +2170,33 @@
 , shortFeatName)
+)
 ;%0D%0A      tf.shor
@@ -2192,59 +2192,51 @@
     
-tf.short2Full.put(shortFeatName, fullFeatName)
+s = (otherS != null) ? otherS : s
 ;%0D%0A  
+  %7D%0D%0A
     
@@ -2246,29 +2246,10 @@
 urn 
-fullFeatName;%0D%0A    %7D 
+s;
 %0D%0A  

Remove sync, switch to ConcurrentHashMap