View | Details | Raw Unified | Return to bug 50213
Collapse All | Expand All

(-)src/main/java/org/apache/log4j/spi/NOPLogger.java (-2 / +4 lines)
Lines 167-177 Link Here
167
167
168
168
169
    /** {@inheritDoc} */
169
    /** {@inheritDoc} */
170
    public void removeAppender(Appender appender) {
170
    public boolean removeAppender(Appender appender) {
171
        return false;
171
    }
172
    }
172
173
173
    /** {@inheritDoc} */
174
    /** {@inheritDoc} */
174
    public void removeAppender(final String name) {
175
    public boolean removeAppender(final String name) {
176
        return false;
175
    }
177
    }
176
178
177
    /** {@inheritDoc} */
179
    /** {@inheritDoc} */
(-)src/main/java/org/apache/log4j/spi/AppenderAttachable.java (-2 / +2 lines)
Lines 62-75 Link Here
62
  /**
62
  /**
63
     Remove the appender passed as parameter from the list of appenders.
63
     Remove the appender passed as parameter from the list of appenders.
64
  */
64
  */
65
   void removeAppender(Appender appender);
65
   boolean removeAppender(Appender appender);
66
66
67
67
68
 /**
68
 /**
69
    Remove the appender with the name passed as parameter from the
69
    Remove the appender with the name passed as parameter from the
70
    list of appenders.  
70
    list of appenders.  
71
  */
71
  */
72
 void
72
 boolean
73
 removeAppender(String name);   
73
 removeAppender(String name);   
74
}
74
}
75
75
(-)src/main/java/org/apache/log4j/Category.java (-34 / +20 lines)
Lines 123-129 Link Here
123
  protected LoggerRepository repository;
123
  protected LoggerRepository repository;
124
124
125
125
126
  AppenderAttachableImpl aai;
126
  AppenderAttachableImpl aai = new AppenderAttachableImpl();
127
127
128
  /** Additivity is set to true by default, that is children inherit
128
  /** Additivity is set to true by default, that is children inherit
129
      the appenders of their ancestors by default. If this variable is
129
      the appenders of their ancestors by default. If this variable is
Lines 155-166 Link Here
155
     <p>If <code>newAppender</code> is already in the list of
155
     <p>If <code>newAppender</code> is already in the list of
156
     appenders, then it won't be added again.
156
     appenders, then it won't be added again.
157
  */
157
  */
158
  synchronized
158
  
159
  public
159
  public
160
  void addAppender(Appender newAppender) {
160
  void addAppender(Appender newAppender) {
161
    if(aai == null) {
162
      aai = new AppenderAttachableImpl();
163
    }
164
    aai.addAppender(newAppender);
161
    aai.addAppender(newAppender);
165
    repository.fireAddAppenderEvent(this, newAppender);
162
    repository.fireAddAppenderEvent(this, newAppender);
166
  }
163
  }
Lines 200-214 Link Here
200
    int writes = 0;
197
    int writes = 0;
201
198
202
    for(Category c = this; c != null; c=c.parent) {
199
    for(Category c = this; c != null; c=c.parent) {
203
      // Protected against simultaneous call to addAppender, removeAppender,...
204
      synchronized(c) {
205
	if(c.aai != null) {
206
	  writes += c.aai.appendLoopOnAppenders(event);
200
	  writes += c.aai.appendLoopOnAppenders(event);
207
	}
201
	  if(!c.additive) {
208
	if(!c.additive) {
202
	    break;
209
	  break;
203
	  }
210
	}
211
      }
212
    }
204
    }
213
205
214
    if(writes == 0) {
206
    if(writes == 0) {
Lines 221-227 Link Here
221
     interface.
213
     interface.
222
     @since 1.0
214
     @since 1.0
223
  */
215
  */
224
  synchronized
225
  void closeNestedAppenders() {
216
  void closeNestedAppenders() {
226
    Enumeration enumeration = this.getAllAppenders();
217
    Enumeration enumeration = this.getAllAppenders();
227
    if(enumeration != null) {
218
    if(enumeration != null) {
Lines 406-418 Link Here
406
     is returned.
397
     is returned.
407
398
408
     @return Enumeration An enumeration of the appenders in this category.  */
399
     @return Enumeration An enumeration of the appenders in this category.  */
409
  synchronized
410
  public
400
  public
411
  Enumeration getAllAppenders() {
401
  Enumeration getAllAppenders() {
412
    if(aai == null)
402
    
403
    Enumeration allAppenders = aai.getAllAppenders();
404
    if(allAppenders == null)
413
      return NullEnumeration.getInstance();
405
      return NullEnumeration.getInstance();
414
    else
406
    else
415
      return aai.getAllAppenders();
407
      return allAppenders;
416
  }
408
  }
417
409
418
  /**
410
  /**
Lines 420-429 Link Here
420
412
421
     <p>Return the appender with that name if in the list. Return
413
     <p>Return the appender with that name if in the list. Return
422
     <code>null</code> otherwise.  */
414
     <code>null</code> otherwise.  */
423
  synchronized
424
  public
415
  public
425
  Appender getAppender(String name) {
416
  Appender getAppender(String name) {
426
     if(aai == null || name == null)
417
     if(name == null)
427
      return null;
418
      return null;
428
419
429
     return aai.getAppender(name);
420
     return aai.getAppender(name);
Lines 880-889 Link Here
880
871
881
     <p>This is useful when re-reading configuration information.
872
     <p>This is useful when re-reading configuration information.
882
  */
873
  */
883
  synchronized
884
  public
874
  public
885
  void removeAllAppenders() {
875
  void removeAllAppenders() {
886
    if(aai != null) {
887
      Vector appenders = new Vector();
876
      Vector appenders = new Vector();
888
      for (Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements();) {
877
      for (Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements();) {
889
          appenders.add(iter.nextElement());
878
          appenders.add(iter.nextElement());
Lines 892-899 Link Here
892
      for(Enumeration iter = appenders.elements(); iter.hasMoreElements();) {
881
      for(Enumeration iter = appenders.elements(); iter.hasMoreElements();) {
893
          fireRemoveAppenderEvent((Appender) iter.nextElement());
882
          fireRemoveAppenderEvent((Appender) iter.nextElement());
894
      }
883
      }
895
      aai = null;
896
    }
897
  }
884
  }
898
885
899
886
Lines 902-917 Link Here
902
889
903
     @since 0.8.2
890
     @since 0.8.2
904
  */
891
  */
905
  synchronized
906
  public
892
  public
907
  void removeAppender(Appender appender) {
893
  boolean removeAppender(Appender appender) {
908
    if(appender == null || aai == null)
894
    if(appender == null)
909
      return;
895
      return false;
910
    boolean wasAttached = aai.isAttached(appender);
896
     boolean wasAttached = aai.removeAppender(appender);
911
    aai.removeAppender(appender);
912
    if (wasAttached) {
897
    if (wasAttached) {
913
        fireRemoveAppenderEvent(appender);
898
        fireRemoveAppenderEvent(appender);
914
    }
899
    }
900
    return wasAttached;
915
  }
901
  }
916
902
917
  /**
903
  /**
Lines 919-933 Link Here
919
     list of appenders.
905
     list of appenders.
920
906
921
     @since 0.8.2 */
907
     @since 0.8.2 */
922
  synchronized
923
  public
908
  public
924
  void removeAppender(String name) {
909
  boolean removeAppender(String name) {
925
    if(name == null || aai == null) return;
910
    if(name == null || aai == null) return false;
926
    Appender appender = aai.getAppender(name);
911
    Appender appender = aai.getAppender(name);
927
    aai.removeAppender(name);
912
    boolean wasRemoved = aai.removeAppender(name);
928
    if (appender != null) {
913
    if (wasRemoved) {
929
        fireRemoveAppenderEvent(appender);
914
        fireRemoveAppenderEvent(appender);
930
    }
915
    }
916
    return wasRemoved;
931
  }
917
  }
932
918
933
  /**
919
  /**
(-)src/main/java/org/apache/log4j/AsyncAppender.java (-4 / +4 lines)
Lines 328-336 Link Here
328
   * Removes an appender.
328
   * Removes an appender.
329
   * @param appender appender to remove.
329
   * @param appender appender to remove.
330
   */
330
   */
331
  public void removeAppender(final Appender appender) {
331
  public boolean removeAppender(final Appender appender) {
332
    synchronized (appenders) {
332
    synchronized (appenders) {
333
      appenders.removeAppender(appender);
333
      return appenders.removeAppender(appender);
334
    }
334
    }
335
  }
335
  }
336
336
Lines 338-346 Link Here
338
   * Remove appender by name.
338
   * Remove appender by name.
339
   * @param name name.
339
   * @param name name.
340
   */
340
   */
341
  public void removeAppender(final String name) {
341
  public boolean removeAppender(final String name) {
342
    synchronized (appenders) {
342
    synchronized (appenders) {
343
      appenders.removeAppender(name);
343
      return appenders.removeAppender(name);
344
    }
344
    }
345
  }
345
  }
346
346
(-)src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java (-38 / +112 lines)
Lines 17-68 Link Here
17
17
18
package org.apache.log4j.helpers;
18
package org.apache.log4j.helpers;
19
19
20
import org.apache.log4j.spi.AppenderAttachable;
20
import java.util.ArrayList;
21
import org.apache.log4j.spi.LoggingEvent;
21
import java.util.Collections;
22
import java.util.Enumeration;
23
import java.util.List;
22
24
23
import org.apache.log4j.Appender;
25
import org.apache.log4j.Appender;
24
import java.util.Vector;
26
import org.apache.log4j.spi.AppenderAttachable;
25
import java.util.Enumeration;
27
import org.apache.log4j.spi.LoggingEvent;
26
28
27
/**
29
/**
28
   A straightforward implementation of the {@link AppenderAttachable}
30
   A straightforward implementation of the {@link AppenderAttachable}
29
   interface.
31
   interface.
30
32
   
33
   Modified so that appenderList is immutable. Would use
34
   java.util.concurrent.CopyOnWriteArrayList
35
   but unfortunately we have to maintain compatibility with Java 1.4.
36
   
31
   @author Ceki G&uuml;lc&uuml;
37
   @author Ceki G&uuml;lc&uuml;
38
   @author David Boden
32
   @since version 0.9.1 */
39
   @since version 0.9.1 */
33
public class AppenderAttachableImpl implements AppenderAttachable {
40
public class AppenderAttachableImpl implements AppenderAttachable {
34
  
41
  
35
  /** Array of appenders. */
42
  /** Array of appenders. */
36
  protected Vector  appenderList;
43
  protected List appenderList;
37
44
38
  /**
45
  /**
39
     Attach an appender. If the appender is already in the list in
46
     Attach an appender. If the appender is already in the list in
40
     won't be added again.
47
     won't be added again.
41
  */
48
  */
42
  public
49
  public synchronized
43
  void addAppender(Appender newAppender) {
50
  void addAppender(Appender newAppender) {
44
    // Null values for newAppender parameter are strictly forbidden.
51
    // Null values for newAppender parameter are strictly forbidden.
45
    if(newAppender == null)
52
    if(newAppender == null)
46
      return;
53
      return;
47
    
54
    
55
    List buffer;
56
    
48
    if(appenderList == null) {
57
    if(appenderList == null) {
49
      appenderList = new Vector(1);
58
      buffer = new ArrayList(1);
59
    } else if(appenderList.contains(newAppender)) {
60
      return; //Do nothing if appender is already present 
61
    } else {
62
      buffer = new ArrayList(appenderList);
50
    }
63
    }
51
    if(!appenderList.contains(newAppender))
64
    
52
      appenderList.addElement(newAppender);
65
    buffer.add(newAppender);
66
    //This assignment is guaranteed to be atomic,
67
    //removing the need to synchronise when fetching
68
    //appenderList in getAllAppenders() or getAppender(String)
69
    //This is the only line of this method where appenderList is *written* to
70
    appenderList = Collections.unmodifiableList(buffer);
53
  }
71
  }
54
72
55
  /**
73
  /**
56
     Call the <code>doAppend</code> method on all attached appenders.  */
74
     Call the <code>doAppend</code> method on all attached appenders.  */
57
  public
75
  public
58
  int appendLoopOnAppenders(LoggingEvent event) {
76
  int appendLoopOnAppenders(LoggingEvent event) {
77
    //Get an object reference to appenderList now, so that
78
    //even if the object reference appenderList changes, we have
79
    //a reference to the underlying object that will live for
80
    //the lifetime of this method
81
    List referenceToAppenderList = appenderList;
82
    
59
    int size = 0;
83
    int size = 0;
60
    Appender appender;
84
    Appender appender;
61
85
62
    if(appenderList != null) {
86
    if(referenceToAppenderList != null) {
63
      size = appenderList.size();
87
      size = referenceToAppenderList.size();
64
      for(int i = 0; i < size; i++) {
88
      for(int i = 0; i < size; i++) {
65
	appender = (Appender) appenderList.elementAt(i);
89
	appender = (Appender) referenceToAppenderList.get(i);
66
	appender.doAppend(event);
90
	appender.doAppend(event);
67
      }
91
      }
68
    }    
92
    }    
Lines 78-87 Link Here
78
   */
102
   */
79
  public
103
  public
80
  Enumeration getAllAppenders() {
104
  Enumeration getAllAppenders() {
81
    if(appenderList == null)
105
    //Get an object reference to appenderList now, so that
106
    //even if the object reference appenderList changes, we have
107
    //a reference to the underlying object that will live for
108
    //the lifetime of this method
109
    List referenceToAppenderList = appenderList;
110
    
111
    if(referenceToAppenderList == null)
82
      return null;
112
      return null;
83
    else 
113
    else 
84
      return appenderList.elements();    
114
      return Collections.enumeration(referenceToAppenderList);    
85
  }
115
  }
86
116
87
  /**
117
  /**
Lines 93-105 Link Here
93
   */
123
   */
94
  public
124
  public
95
  Appender getAppender(String name) {
125
  Appender getAppender(String name) {
96
     if(appenderList == null || name == null)
126
     //Get an object reference to appenderList now, so that
127
     //even if the object reference appenderList changes, we have
128
     //a reference to the underlying object that will live for
129
     //the lifetime of this method
130
     List referenceToAppenderList = appenderList;
131
     
132
     if(referenceToAppenderList == null || name == null)
97
      return null;
133
      return null;
98
134
99
     int size = appenderList.size();
135
     int size = referenceToAppenderList.size();
100
     Appender appender;
136
     Appender appender;
101
     for(int i = 0; i < size; i++) {
137
     for(int i = 0; i < size; i++) {
102
       appender = (Appender) appenderList.elementAt(i);
138
       appender = (Appender) referenceToAppenderList.get(i);
103
       if(name.equals(appender.getName()))
139
       if(name.equals(appender.getName()))
104
	  return appender;
140
	  return appender;
105
     }
141
     }
Lines 114-126 Link Here
114
     @since 1.2 */
150
     @since 1.2 */
115
  public 
151
  public 
116
  boolean isAttached(Appender appender) {
152
  boolean isAttached(Appender appender) {
117
    if(appenderList == null || appender == null)
153
    //Get an object reference to appenderList now, so that
154
    //even if the object reference appenderList changes, we have
155
    //a reference to the underlying object that will live for
156
    //the lifetime of this method
157
    List referenceToAppenderList = appenderList;
158
      
159
    if(referenceToAppenderList == null || appender == null)
118
      return false;
160
      return false;
119
161
120
     int size = appenderList.size();
162
     int size = referenceToAppenderList.size();
121
     Appender a;
163
     Appender a;
122
     for(int i = 0; i < size; i++) {
164
     for(int i = 0; i < size; i++) {
123
       a  = (Appender) appenderList.elementAt(i);
165
       a  = (Appender) referenceToAppenderList.get(i);
124
       if(a == appender)
166
       if(a == appender)
125
	  return true;
167
	  return true;
126
     }
168
     }
Lines 132-147 Link Here
132
  /**
174
  /**
133
   * Remove and close all previously attached appenders.
175
   * Remove and close all previously attached appenders.
134
   * */
176
   * */
135
  public
177
  public synchronized
136
  void removeAllAppenders() {
178
  void removeAllAppenders() {
137
    if(appenderList != null) {
179
      //Get an object reference to appenderList now, so that
138
      int len = appenderList.size();      
180
      //even if the object reference appenderList changes, we have
181
      //a reference to the underlying object that will live for
182
      //the lifetime of this method
183
      List referenceToAppenderList = appenderList;
184
      //Null the appender list as early as possible so that any thread
185
      //that is calling a get() method receives null. This reduces
186
      //the possibility of a thread iterating through a list of appenders
187
      //that is in the process of being closed. Unfortunately that
188
      //possibility can't be *eliminated* without locking on read. So,
189
      //that's the compromise! Code may have to deal with closing appenders.
190
      //However, the synchronisation on the appender itself should deal
191
      //with that unlikely scenario.
192
      appenderList = null;
193
      
194
    if(referenceToAppenderList != null) {
195
      int len = referenceToAppenderList.size();      
139
      for(int i = 0; i < len; i++) {
196
      for(int i = 0; i < len; i++) {
140
	Appender a = (Appender) appenderList.elementAt(i);
197
	Appender a = (Appender) referenceToAppenderList.get(i);
141
	a.close();
198
	a.close();
142
      }
199
      }      
143
      appenderList.removeAllElements();
144
      appenderList = null;      
145
    }
200
    }
146
  }
201
  }
147
202
Lines 149-159 Link Here
149
  /**
204
  /**
150
     Remove the appender passed as parameter form the list of attached
205
     Remove the appender passed as parameter form the list of attached
151
     appenders.  */
206
     appenders.  */
152
  public
207
  public synchronized
153
  void removeAppender(Appender appender) {
208
  boolean removeAppender(Appender appender) {
154
    if(appender == null || appenderList == null) 
209
    if(appender == null || appenderList == null) 
155
      return;
210
      return false;
156
    appenderList.removeElement(appender);    
211
    
212
    if(appenderList.contains(appender)) {
213
      List buffer = new ArrayList(appenderList);
214
      buffer.remove(appender);
215
      //This assignment is guaranteed to be atomic,
216
      //removing the need to synchronise when fetching
217
      //appenderList in getAllAppenders() or getAppender(String)
218
      //This is the only line of this method where appenderList is *written* to
219
      appenderList = Collections.unmodifiableList(buffer);
220
      return true;
221
    } else {
222
      return false;
223
    }
157
  }
224
  }
158
225
159
226
Lines 161-176 Link Here
161
    Remove the appender with the name passed as parameter form the
228
    Remove the appender with the name passed as parameter form the
162
    list of appenders.  
229
    list of appenders.  
163
  */
230
  */
164
  public
231
  public synchronized
165
  void removeAppender(String name) {
232
  boolean removeAppender(String name) {
166
    if(name == null || appenderList == null) return;
233
    if(name == null || appenderList == null) return false;
167
    int size = appenderList.size();
234
    int size = appenderList.size();
168
    for(int i = 0; i < size; i++) {
235
    for(int i = 0; i < size; i++) {
169
      if(name.equals(((Appender)appenderList.elementAt(i)).getName())) {
236
      if(name.equals(((Appender)appenderList.get(i)).getName())) {
170
	 appenderList.removeElementAt(i);
237
        List buffer = new ArrayList(appenderList);
171
	 break;
238
        buffer.remove(i);
239
        //This assignment is guaranteed to be atomic,
240
        //removing the need to synchronise when fetching
241
        //appenderList in getAllAppenders() or getAppender(String)
242
        //This is the only line of this method where appenderList is *written* to
243
        appenderList = Collections.unmodifiableList(buffer);
244
	    return true;
172
      }
245
      }
173
    }
246
    }
247
    return false;
174
  }
248
  }
175
249
176
}
250
}

Return to bug 50213