001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.appender.rolling; 018 019import java.io.File; 020import java.io.FileOutputStream; 021import java.io.IOException; 022import java.io.OutputStream; 023import java.io.Serializable; 024import java.nio.ByteBuffer; 025import java.util.Collection; 026import java.util.concurrent.ArrayBlockingQueue; 027import java.util.concurrent.ExecutorService; 028import java.util.concurrent.Semaphore; 029import java.util.concurrent.ThreadPoolExecutor; 030import java.util.concurrent.TimeUnit; 031import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; 032 033import org.apache.logging.log4j.core.Layout; 034import org.apache.logging.log4j.core.LifeCycle; 035import org.apache.logging.log4j.core.LifeCycle2; 036import org.apache.logging.log4j.core.LogEvent; 037import org.apache.logging.log4j.core.LoggerContext; 038import org.apache.logging.log4j.core.appender.ConfigurationFactoryData; 039import org.apache.logging.log4j.core.appender.FileManager; 040import org.apache.logging.log4j.core.appender.ManagerFactory; 041import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction; 042import org.apache.logging.log4j.core.appender.rolling.action.Action; 043import org.apache.logging.log4j.core.config.Configuration; 044import org.apache.logging.log4j.core.util.Constants; 045import org.apache.logging.log4j.core.util.FileUtils; 046import org.apache.logging.log4j.core.util.Log4jThreadFactory; 047 048/** 049 * The Rolling File Manager. 050 */ 051public class RollingFileManager extends FileManager { 052 053 private static RollingFileManagerFactory factory = new RollingFileManagerFactory(); 054 private static final int MAX_TRIES = 3; 055 private static final int MIN_DURATION = 100; 056 057 protected long size; 058 private long initialTime; 059 private volatile PatternProcessor patternProcessor; 060 private final Semaphore semaphore = new Semaphore(1); 061 private final Log4jThreadFactory threadFactory = Log4jThreadFactory.createThreadFactory("RollingFileManager"); 062 private volatile TriggeringPolicy triggeringPolicy; 063 private volatile RolloverStrategy rolloverStrategy; 064 private volatile boolean renameEmptyFiles = false; 065 private volatile boolean initialized = false; 066 private volatile String fileName; 067 private final FileExtension fileExtension; 068 069 /* This executor pool will create a new Thread for every work async action to be performed. Using it allows 070 us to make sure all the Threads are completed when the Manager is stopped. */ 071 private final ExecutorService asyncExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 0, TimeUnit.MILLISECONDS, 072 new EmptyQueue(), threadFactory); 073 074 private static final AtomicReferenceFieldUpdater<RollingFileManager, TriggeringPolicy> triggeringPolicyUpdater = 075 AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, TriggeringPolicy.class, "triggeringPolicy"); 076 077 private static final AtomicReferenceFieldUpdater<RollingFileManager, RolloverStrategy> rolloverStrategyUpdater = 078 AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, RolloverStrategy.class, "rolloverStrategy"); 079 080 private static final AtomicReferenceFieldUpdater<RollingFileManager, PatternProcessor> patternProcessorUpdater = 081 AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, PatternProcessor.class, "patternProcessor"); 082 083 @Deprecated 084 protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, 085 final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, 086 final RolloverStrategy rolloverStrategy, final String advertiseURI, 087 final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) { 088 this(fileName, pattern, os, append, size, time, triggeringPolicy, rolloverStrategy, advertiseURI, layout, 089 writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE])); 090 } 091 092 @Deprecated 093 protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, 094 final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, 095 final RolloverStrategy rolloverStrategy, final String advertiseURI, 096 final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { 097 super(fileName, os, append, false, advertiseURI, layout, writeHeader, buffer); 098 this.size = size; 099 this.initialTime = time; 100 this.triggeringPolicy = triggeringPolicy; 101 this.rolloverStrategy = rolloverStrategy; 102 this.patternProcessor = new PatternProcessor(pattern); 103 this.patternProcessor.setPrevFileTime(time); 104 this.fileName = fileName; 105 this.fileExtension = FileExtension.lookupForFile(pattern); 106 } 107 108 @Deprecated 109 protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os, 110 final boolean append, final boolean createOnDemand, final long size, final long time, 111 final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy, 112 final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { 113 super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, writeHeader, buffer); 114 this.size = size; 115 this.initialTime = time; 116 this.triggeringPolicy = triggeringPolicy; 117 this.rolloverStrategy = rolloverStrategy; 118 this.patternProcessor = new PatternProcessor(pattern); 119 this.patternProcessor.setPrevFileTime(time); 120 this.fileName = fileName; 121 this.fileExtension = FileExtension.lookupForFile(pattern); 122 } 123 124 /** 125 * @since 2.9 126 */ 127 protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os, 128 final boolean append, final boolean createOnDemand, final long size, final long time, 129 final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy, 130 final String advertiseURI, final Layout<? extends Serializable> layout, 131 final String filePermissions, final String fileOwner, final String fileGroup, 132 final boolean writeHeader, final ByteBuffer buffer) { 133 super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, 134 filePermissions, fileOwner, fileGroup, writeHeader, buffer); 135 this.size = size; 136 this.initialTime = time; 137 this.triggeringPolicy = triggeringPolicy; 138 this.rolloverStrategy = rolloverStrategy; 139 this.patternProcessor = new PatternProcessor(pattern); 140 this.patternProcessor.setPrevFileTime(time); 141 this.fileName = fileName; 142 this.fileExtension = FileExtension.lookupForFile(pattern); 143 } 144 145 public void initialize() { 146 147 if (!initialized) { 148 LOGGER.debug("Initializing triggering policy {}", triggeringPolicy); 149 initialized = true; 150 triggeringPolicy.initialize(this); 151 if (triggeringPolicy instanceof LifeCycle) { 152 ((LifeCycle) triggeringPolicy).start(); 153 } 154 } 155 } 156 157 /** 158 * Returns a RollingFileManager. 159 * @param fileName The file name. 160 * @param pattern The pattern for rolling file. 161 * @param append true if the file should be appended to. 162 * @param bufferedIO true if data should be buffered. 163 * @param policy The TriggeringPolicy. 164 * @param strategy The RolloverStrategy. 165 * @param advertiseURI the URI to use when advertising the file 166 * @param layout The Layout. 167 * @param bufferSize buffer size to use if bufferedIO is true 168 * @param immediateFlush flush on every write or not 169 * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) 170 * @param filePermissions File permissions 171 * @param fileOwner File owner 172 * @param fileGroup File group 173 * @param configuration The configuration. 174 * @return A RollingFileManager. 175 */ 176 public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append, 177 final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy, 178 final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize, 179 final boolean immediateFlush, final boolean createOnDemand, 180 final String filePermissions, final String fileOwner, final String fileGroup, 181 final Configuration configuration) { 182 183 if (strategy instanceof DirectWriteRolloverStrategy && fileName != null) { 184 LOGGER.error("The fileName attribute must not be specified with the DirectWriteRolloverStrategy"); 185 return null; 186 } 187 final String name = fileName == null ? pattern : fileName; 188 return narrow(RollingFileManager.class, getManager(name, new FactoryData(fileName, pattern, append, 189 bufferedIO, policy, strategy, advertiseURI, layout, bufferSize, immediateFlush, createOnDemand, 190 filePermissions, fileOwner, fileGroup, configuration), factory)); 191 } 192 193 /** 194 * Returns the name of the File being managed. 195 * @return The name of the File being managed. 196 */ 197 @Override 198 public String getFileName() { 199 if (rolloverStrategy instanceof DirectFileRolloverStrategy) { 200 fileName = ((DirectFileRolloverStrategy) rolloverStrategy).getCurrentFileName(this); 201 } 202 return fileName; 203 } 204 205 public FileExtension getFileExtension() { 206 return fileExtension; 207 } 208 209 // override to make visible for unit tests 210 @Override 211 protected synchronized void write(final byte[] bytes, final int offset, final int length, 212 final boolean immediateFlush) { 213 super.write(bytes, offset, length, immediateFlush); 214 } 215 216 @Override 217 protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) { 218 size += length; 219 super.writeToDestination(bytes, offset, length); 220 } 221 222 public boolean isRenameEmptyFiles() { 223 return renameEmptyFiles; 224 } 225 226 public void setRenameEmptyFiles(final boolean renameEmptyFiles) { 227 this.renameEmptyFiles = renameEmptyFiles; 228 } 229 230 /** 231 * Returns the current size of the file. 232 * @return The size of the file in bytes. 233 */ 234 public long getFileSize() { 235 return size + byteBuffer.position(); 236 } 237 238 /** 239 * Returns the time the file was created. 240 * @return The time the file was created. 241 */ 242 public long getFileTime() { 243 return initialTime; 244 } 245 246 /** 247 * Determines if a rollover should occur. 248 * @param event The LogEvent. 249 */ 250 public synchronized void checkRollover(final LogEvent event) { 251 if (triggeringPolicy.isTriggeringEvent(event)) { 252 rollover(); 253 } 254 } 255 256 @Override 257 public boolean releaseSub(final long timeout, final TimeUnit timeUnit) { 258 LOGGER.debug("Shutting down RollingFileManager {}" + getName()); 259 boolean stopped = true; 260 if (triggeringPolicy instanceof LifeCycle2) { 261 stopped &= ((LifeCycle2) triggeringPolicy).stop(timeout, timeUnit); 262 } else if (triggeringPolicy instanceof LifeCycle) { 263 ((LifeCycle) triggeringPolicy).stop(); 264 stopped &= true; 265 } 266 final boolean status = super.releaseSub(timeout, timeUnit) && stopped; 267 asyncExecutor.shutdown(); 268 try { 269 // Allow at least the minimum interval to pass so async actions can complete. 270 final long millis = timeUnit.toMillis(timeout); 271 final long waitInterval = MIN_DURATION < millis ? millis : MIN_DURATION; 272 273 for (int count = 1; count <= MAX_TRIES && !asyncExecutor.isTerminated(); ++count) { 274 asyncExecutor.awaitTermination(waitInterval * count, TimeUnit.MILLISECONDS); 275 } 276 if (asyncExecutor.isTerminated()) { 277 LOGGER.debug("All asynchronous threads have terminated"); 278 } else { 279 asyncExecutor.shutdownNow(); 280 try { 281 asyncExecutor.awaitTermination(timeout, timeUnit); 282 if (asyncExecutor.isTerminated()) { 283 LOGGER.debug("All asynchronous threads have terminated"); 284 } else { 285 LOGGER.debug("RollingFileManager shutting down but some asynchronous services may not have completed"); 286 } 287 } catch (final InterruptedException inner) { 288 LOGGER.warn("RollingFileManager stopped but some asynchronous services may not have completed."); 289 } 290 } 291 } catch (final InterruptedException ie) { 292 asyncExecutor.shutdownNow(); 293 try { 294 asyncExecutor.awaitTermination(timeout, timeUnit); 295 if (asyncExecutor.isTerminated()) { 296 LOGGER.debug("All asynchronous threads have terminated"); 297 } 298 } catch (final InterruptedException inner) { 299 LOGGER.warn("RollingFileManager stopped but some asynchronous services may not have completed."); 300 } 301 // Preserve interrupt status 302 Thread.currentThread().interrupt(); 303 } 304 LOGGER.debug("RollingFileManager shutdown completed with status {}", status); 305 return status; 306 } 307 308 public synchronized void rollover() { 309 if (!hasOutputStream()) { 310 return; 311 } 312 if (rollover(rolloverStrategy)) { 313 try { 314 size = 0; 315 initialTime = System.currentTimeMillis(); 316 createFileAfterRollover(); 317 } catch (final IOException e) { 318 logError("Failed to create file after rollover", e); 319 } 320 } 321 } 322 323 protected void createFileAfterRollover() throws IOException { 324 setOutputStream(createOutputStream()); 325 } 326 327 /** 328 * Returns the pattern processor. 329 * @return The PatternProcessor. 330 */ 331 public PatternProcessor getPatternProcessor() { 332 return patternProcessor; 333 } 334 335 public void setTriggeringPolicy(final TriggeringPolicy triggeringPolicy) { 336 triggeringPolicy.initialize(this); 337 final TriggeringPolicy policy = this.triggeringPolicy; 338 int count = 0; 339 boolean policyUpdated = false; 340 do { 341 ++count; 342 } while (!(policyUpdated = triggeringPolicyUpdater.compareAndSet(this, this.triggeringPolicy, triggeringPolicy)) 343 && count < MAX_TRIES); 344 if (policyUpdated) { 345 if (triggeringPolicy instanceof LifeCycle) { 346 ((LifeCycle) triggeringPolicy).start(); 347 } 348 if (policy instanceof LifeCycle) { 349 ((LifeCycle) policy).stop(); 350 } 351 } else { 352 if (triggeringPolicy instanceof LifeCycle) { 353 ((LifeCycle) triggeringPolicy).stop(); 354 } 355 } 356 } 357 358 public void setRolloverStrategy(final RolloverStrategy rolloverStrategy) { 359 rolloverStrategyUpdater.compareAndSet(this, this.rolloverStrategy, rolloverStrategy); 360 } 361 362 public void setPatternProcessor(final PatternProcessor patternProcessor) { 363 patternProcessorUpdater.compareAndSet(this, this.patternProcessor, patternProcessor); 364 } 365 366 /** 367 * Returns the triggering policy. 368 * @param <T> TriggeringPolicy type 369 * @return The TriggeringPolicy 370 */ 371 @SuppressWarnings("unchecked") 372 public <T extends TriggeringPolicy> T getTriggeringPolicy() { 373 // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here. 374 return (T) this.triggeringPolicy; 375 } 376 377 /** 378 * Returns the rollover strategy. 379 * @return The RolloverStrategy 380 */ 381 public RolloverStrategy getRolloverStrategy() { 382 return this.rolloverStrategy; 383 } 384 385 private boolean rollover(final RolloverStrategy strategy) { 386 387 boolean releaseRequired = false; 388 try { 389 // Block until the asynchronous operation is completed. 390 semaphore.acquire(); 391 releaseRequired = true; 392 } catch (final InterruptedException e) { 393 logError("Thread interrupted while attempting to check rollover", e); 394 return false; 395 } 396 397 boolean success = true; 398 399 try { 400 final RolloverDescription descriptor = strategy.rollover(this); 401 if (descriptor != null) { 402 writeFooter(); 403 closeOutputStream(); 404 if (descriptor.getSynchronous() != null) { 405 LOGGER.debug("RollingFileManager executing synchronous {}", descriptor.getSynchronous()); 406 try { 407 success = descriptor.getSynchronous().execute(); 408 } catch (final Exception ex) { 409 success = false; 410 logError("Caught error in synchronous task", ex); 411 } 412 } 413 414 if (success && descriptor.getAsynchronous() != null) { 415 LOGGER.debug("RollingFileManager executing async {}", descriptor.getAsynchronous()); 416 asyncExecutor.execute(new AsyncAction(descriptor.getAsynchronous(), this)); 417 releaseRequired = false; 418 } 419 return true; 420 } 421 return false; 422 } finally { 423 if (releaseRequired) { 424 semaphore.release(); 425 } 426 } 427 428 } 429 430 /** 431 * Performs actions asynchronously. 432 */ 433 private static class AsyncAction extends AbstractAction { 434 435 private final Action action; 436 private final RollingFileManager manager; 437 438 /** 439 * Constructor. 440 * @param act The action to perform. 441 * @param manager The manager. 442 */ 443 public AsyncAction(final Action act, final RollingFileManager manager) { 444 this.action = act; 445 this.manager = manager; 446 } 447 448 /** 449 * Executes an action. 450 * 451 * @return true if action was successful. A return value of false will cause 452 * the rollover to be aborted if possible. 453 * @throws java.io.IOException if IO error, a thrown exception will cause the rollover 454 * to be aborted if possible. 455 */ 456 @Override 457 public boolean execute() throws IOException { 458 try { 459 return action.execute(); 460 } finally { 461 manager.semaphore.release(); 462 } 463 } 464 465 /** 466 * Cancels the action if not already initialized or waits till completion. 467 */ 468 @Override 469 public void close() { 470 action.close(); 471 } 472 473 /** 474 * Determines if action has been completed. 475 * 476 * @return true if action is complete. 477 */ 478 @Override 479 public boolean isComplete() { 480 return action.isComplete(); 481 } 482 483 @Override 484 public String toString() { 485 final StringBuilder builder = new StringBuilder(); 486 builder.append(super.toString()); 487 builder.append("[action="); 488 builder.append(action); 489 builder.append(", manager="); 490 builder.append(manager); 491 builder.append(", isComplete()="); 492 builder.append(isComplete()); 493 builder.append(", isInterrupted()="); 494 builder.append(isInterrupted()); 495 builder.append("]"); 496 return builder.toString(); 497 } 498 } 499 500 /** 501 * Factory data. 502 */ 503 private static class FactoryData extends ConfigurationFactoryData { 504 private final String fileName; 505 private final String pattern; 506 private final boolean append; 507 private final boolean bufferedIO; 508 private final int bufferSize; 509 private final boolean immediateFlush; 510 private final boolean createOnDemand; 511 private final TriggeringPolicy policy; 512 private final RolloverStrategy strategy; 513 private final String advertiseURI; 514 private final Layout<? extends Serializable> layout; 515 private final String filePermissions; 516 private final String fileOwner; 517 private final String fileGroup; 518 519 /** 520 * Creates the data for the factory. 521 * @param pattern The pattern. 522 * @param append The append flag. 523 * @param bufferedIO The bufferedIO flag. 524 * @param advertiseURI 525 * @param layout The Layout. 526 * @param bufferSize the buffer size 527 * @param immediateFlush flush on every write or not 528 * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) 529 * @param filePermissions File permissions 530 * @param fileOwner File owner 531 * @param fileGroup File group 532 * @param configuration The configuration 533 */ 534 public FactoryData(final String fileName, final String pattern, final boolean append, final boolean bufferedIO, 535 final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, 536 final Layout<? extends Serializable> layout, final int bufferSize, final boolean immediateFlush, 537 final boolean createOnDemand, final String filePermissions, final String fileOwner, final String fileGroup, 538 final Configuration configuration) { 539 super(configuration); 540 this.fileName = fileName; 541 this.pattern = pattern; 542 this.append = append; 543 this.bufferedIO = bufferedIO; 544 this.bufferSize = bufferSize; 545 this.policy = policy; 546 this.strategy = strategy; 547 this.advertiseURI = advertiseURI; 548 this.layout = layout; 549 this.immediateFlush = immediateFlush; 550 this.createOnDemand = createOnDemand; 551 this.filePermissions = filePermissions; 552 this.fileOwner = fileOwner; 553 this.fileGroup = fileGroup; 554 } 555 556 public TriggeringPolicy getTriggeringPolicy() { 557 return this.policy; 558 } 559 560 public RolloverStrategy getRolloverStrategy() { 561 return this.strategy; 562 } 563 564 public String getPattern() { 565 return pattern; 566 } 567 568 @Override 569 public String toString() { 570 final StringBuilder builder = new StringBuilder(); 571 builder.append(super.toString()); 572 builder.append("[pattern="); 573 builder.append(pattern); 574 builder.append(", append="); 575 builder.append(append); 576 builder.append(", bufferedIO="); 577 builder.append(bufferedIO); 578 builder.append(", bufferSize="); 579 builder.append(bufferSize); 580 builder.append(", policy="); 581 builder.append(policy); 582 builder.append(", strategy="); 583 builder.append(strategy); 584 builder.append(", advertiseURI="); 585 builder.append(advertiseURI); 586 builder.append(", layout="); 587 builder.append(layout); 588 builder.append(", filePermissions="); 589 builder.append(filePermissions); 590 builder.append(", fileOwner="); 591 builder.append(fileOwner); 592 builder.append("]"); 593 return builder.toString(); 594 } 595 } 596 597 @Override 598 public void updateData(final Object data) { 599 final FactoryData factoryData = (FactoryData) data; 600 setRolloverStrategy(factoryData.getRolloverStrategy()); 601 setTriggeringPolicy(factoryData.getTriggeringPolicy()); 602 setPatternProcessor(new PatternProcessor(factoryData.getPattern(), getPatternProcessor())); 603 } 604 605 /** 606 * Factory to create a RollingFileManager. 607 */ 608 private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> { 609 610 /** 611 * Creates a RollingFileManager. 612 * @param name The name of the entity to manage. 613 * @param data The data required to create the entity. 614 * @return a RollingFileManager. 615 */ 616 @Override 617 public RollingFileManager createManager(final String name, final FactoryData data) { 618 long size = 0; 619 boolean writeHeader = !data.append; 620 File file = null; 621 if (data.fileName != null) { 622 file = new File(data.fileName); 623 // LOG4J2-1140: check writeHeader before creating the file 624 writeHeader = !data.append || !file.exists(); 625 626 try { 627 FileUtils.makeParentDirs(file); 628 final boolean created = data.createOnDemand ? false : file.createNewFile(); 629 LOGGER.trace("New file '{}' created = {}", name, created); 630 } catch (final IOException ioe) { 631 LOGGER.error("Unable to create file " + name, ioe); 632 return null; 633 } 634 size = data.append ? file.length() : 0; 635 } 636 637 try { 638 final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE; 639 final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]); 640 final OutputStream os = data.createOnDemand || data.fileName == null ? null : 641 new FileOutputStream(data.fileName, data.append); 642 final long time = data.createOnDemand || file == null ? 643 System.currentTimeMillis() : file.lastModified(); // LOG4J2-531 create file first so time has valid value 644 645 final RollingFileManager rm = new RollingFileManager(data.getLoggerContext(), data.fileName, data.pattern, os, 646 data.append, data.createOnDemand, size, time, data.policy, data.strategy, data.advertiseURI, 647 data.layout, data.filePermissions, data.fileOwner, data.fileGroup, writeHeader, buffer); 648 if (os != null && rm.isAttributeViewEnabled()) { 649 rm.defineAttributeView(file.toPath()); 650 } 651 652 return rm; 653 } catch (final IOException ex) { 654 LOGGER.error("RollingFileManager (" + name + ") " + ex, ex); 655 } 656 return null; 657 } 658 } 659 660 private static class EmptyQueue extends ArrayBlockingQueue<Runnable> { 661 662 /** 663 * 664 */ 665 private static final long serialVersionUID = 1L; 666 667 EmptyQueue() { 668 super(1); 669 } 670 671 @Override 672 public int remainingCapacity() { 673 return 0; 674 } 675 676 @Override 677 public boolean add(final Runnable runnable) { 678 throw new IllegalStateException("Queue is full"); 679 } 680 681 @Override 682 public void put(final Runnable runnable) throws InterruptedException { 683 /* No point in going into a permanent wait */ 684 throw new InterruptedException("Unable to insert into queue"); 685 } 686 687 @Override 688 public boolean offer(final Runnable runnable, final long timeout, final TimeUnit timeUnit) throws InterruptedException { 689 Thread.sleep(timeUnit.toMillis(timeout)); 690 return false; 691 } 692 693 @Override 694 public boolean addAll(final Collection<? extends Runnable> collection) { 695 if (collection.size() > 0) { 696 throw new IllegalArgumentException("Too many items in collection"); 697 } 698 return false; 699 } 700 701 } 702 703}