/**
* Copyright 2015 StreamSets Inc.
*
* Licensed under 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 com.streamsets.pipeline.lib.io;
import com.streamsets.pipeline.api.impl.Utils;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.Comparator;
// trick to be able to use 'private' constants in the enum
class LogRollModeConstants {
private static final String YYYY_REGEX = "\\.[0-9]{4}";
static final String YYYY_WW_REGEX = YYYY_REGEX + "-[0-9]{2}";
static final String YYYY_MM_REGEX = YYYY_REGEX + "-(01|02|03|04|05|06|07|09|10|11|12)";
static final String YYYY_MM_DD_REGEX = YYYY_MM_REGEX + "-[0-9]{2}";
static final String YYYY_MM_DD_HH_REGEX = YYYY_MM_DD_REGEX + "-[0-9]{2}";
static final String YYYY_MM_DD_HH_MM_REGEX = YYYY_MM_DD_HH_REGEX + "-[0-9]{2}";
private LogRollModeConstants() {}
}
/**
* Set of {@link RollMode} for Log4j and log files in general where the live log file is renamed upon
* 'archival' and a new live log file is created.
* <p/>
* The assumption for all these roll modes is that the live file name is always the same.
*/
public enum LogRollModeFactory implements RollModeFactory {
REVERSE_COUNTER(ReverseCounterComparator.class, "regex:", "\\.[0-9]+$"),
DATE_YYYY_MM(StringComparator.class, "regex:", LogRollModeConstants.YYYY_MM_REGEX + "$"),
DATE_YYYY_MM_DD(StringComparator.class, "regex:", LogRollModeConstants.YYYY_MM_DD_REGEX + "$"),
DATE_YYYY_MM_DD_HH(StringComparator.class, "regex:", LogRollModeConstants.YYYY_MM_DD_HH_REGEX + "$"),
DATE_YYYY_MM_DD_HH_MM(StringComparator.class, "regex:", LogRollModeConstants.YYYY_MM_DD_HH_MM_REGEX + "$"),
DATE_YYYY_WW(StringComparator.class, "regex:", LogRollModeConstants.YYYY_WW_REGEX + "$"),
ALPHABETICAL(StringComparator.class, "glob:", ".*"),
;
private final String patternPrefix;
private final String patternPostfix;
private final Class comparatorClass;
LogRollModeFactory(Class comparatorClass, String patternPrefix, String patternPostfix) {
this.comparatorClass = comparatorClass;
this.patternPrefix = patternPrefix;
this.patternPostfix = patternPostfix;
}
@Override
public String getTokenForPattern() {
return "";
}
@Override
public RollMode get(String fileName, String periodicPattern) {
return new LogRollMode(patternPrefix, patternPostfix, comparatorClass, fileName);
}
private class LogRollMode implements RollMode {
private final String patternPrefix;
private final String patternPostfix;
private final Class comparatorClass;
private final String liveFileName;
private LogRollMode(String patternPrefix, String patternPostfix, Class comparatorClass, String liveFileName) {
this.patternPrefix = patternPrefix;
this.patternPostfix = patternPostfix;
this.comparatorClass = comparatorClass;
this.liveFileName = liveFileName;
}
@Override
public String getLiveFileName() {
Utils.checkNotNull(liveFileName, "liveFileName");
Utils.checkArgument(!liveFileName.isEmpty(), "liveFileName cannot be empty");
return liveFileName;
}
@Override
public boolean isFirstAcceptable(String firstFileName) {
Utils.checkNotNull(liveFileName, "liveFileName");
return firstFileName == null || firstFileName.isEmpty() || firstFileName.startsWith(liveFileName + ".");
}
@Override
public boolean isCurrentAcceptable(String currentName) {
return !liveFileName.equals(currentName);
}
@Override
public boolean isFileRolled(LiveFile currentFile) {
return !liveFileName.equals(currentFile.getPath().getFileName().toString());
}
@Override
@SuppressWarnings("unchecked")
public Comparator<Path> getComparator() {
try {
Object obj = comparatorClass.newInstance();
((LiveFileNameSetter) obj).setName(liveFileName);
return (Comparator<Path>) obj;
} catch (Exception ex) {
throw new RuntimeException(Utils.format("Unexpected exception: {}", ex.toString()), ex);
}
}
@Override
public String getPattern() {
return patternPrefix + liveFileName + patternPostfix;
}
@Override
public String toString() {
return name();
}
}
private interface LiveFileNameSetter {
void setName(String name);
}
static class StringComparator implements Comparator<Path>, LiveFileNameSetter, Serializable {
private int liveNameLength;
@Override
public void setName(String liveFileName) {
this.liveNameLength = liveFileName.length() + 1;
}
@Override
public int compare(Path o1, Path o2) {
String rd1 = o1.getFileName().toString().substring(liveNameLength);
String rd2 = o2.getFileName().toString().substring(liveNameLength);
return rd1.compareTo(rd2);
}
}
static class ReverseCounterComparator implements Comparator<Path>, LiveFileNameSetter, Serializable {
private int liveNameLength;
@Override
public void setName(String liveFileName) {
this.liveNameLength = liveFileName.length() + 1;
}
@Override
public int compare(Path o1, Path o2) {
String rd1 = o1.getFileName().toString().substring(liveNameLength);
String rd2 = o2.getFileName().toString().substring(liveNameLength);
return Integer.parseInt(rd2) - Integer.parseInt(rd1);
}
}
}