📄 cmsrfsfileviewer.java
字号:
skip -= skipped;
maxSkipTries--;
}
LineNumberReader lineReader = new LineNumberReader(reader);
StringBuffer result = new StringBuffer();
String read = lineReader.readLine();
// logfile treatment is different
// we invert the lines: latest come first
if (m_isLogfile) {
// java hall of shame candidate... but standard
Stack inverter = new Stack();
for (int i = m_windowSize; i > 0 && read != null; i--) {
inverter.push(read);
read = lineReader.readLine();
}
// pop-off:
while (!inverter.isEmpty()) {
result.append(inverter.pop());
result.append('\n');
}
} else {
for (int i = m_windowSize; i > 0 && read != null; i--) {
result.append(read);
result.append('\n');
read = lineReader.readLine();
}
}
return CmsEncoder.escapeXml(result.toString());
} catch (IOException ioex) {
CmsRfsException ex = new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_ACCESS_1,
m_filePath), ioex);
throw ex;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
LOG.error(e);
}
}
}
} else {
return Messages.get().getBundle().key(Messages.GUI_FILE_VIEW_NO_PREVIEW_0);
}
}
/**
* Set the boolean that decides if the view to the underlying file via
* <code>{@link #readFilePortion()}</code> is enabled.<p>
*
* @param preview the boolean that decides if the view to the underlying file via
* <code>{@link #readFilePortion()}</code> is enabled
*/
public void setEnabled(boolean preview) {
m_enabled = preview;
}
/**
* Set the character encoding of the underlying file.<p>
*
* The given String has to match a valid charset name (canonical or alias)
* of one of the system's supported <code>{@link Charset}</code> instances
* (see <code>{@link Charset#forName(java.lang.String)}</code>).<p>
*
* This setting will be used for transcoding the file when portions
* of it are read via <code>{@link CmsRfsFileViewer#readFilePortion()}</code>
* to a String. This enables to correctly display files with text in various encodings
* in UIs.<p>
*
* @param fileEncoding the character encoding of the underlying file to set.
*/
public void setFileEncoding(String fileEncoding) {
checkFrozen();
try {
m_fileEncoding = Charset.forName(fileEncoding);
} catch (IllegalCharsetNameException icne) {
throw new CmsIllegalArgumentException(Messages.get().container(
Messages.ERR_CHARSET_ILLEGAL_NAME_1,
fileEncoding));
} catch (UnsupportedCharsetException ucse) {
throw new CmsIllegalArgumentException(Messages.get().container(
Messages.ERR_CHARSET_UNSUPPORTED_1,
fileEncoding));
}
}
/**
* Set the path in the real file system that points to the file
* that should be displayed.<p>
*
* This method will only suceed if the file specified by the <code>path</code>
* argument is valid within the file system, no folder and may be read by the
* OpenCms process on the current platform.<p>
*
* @param path the path in the real file system that points to the file that should be displayed to set
*
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* @throws CmsRfsException if the given path is invalid, does not point to a file or cannot be accessed
*/
public void setFilePath(String path) throws CmsRfsException, CmsRuntimeException {
checkFrozen();
expireIndices();
if (path != null) {
// leading whitespace from CmsComboWidget causes exception
path = path.trim();
}
if (CmsStringUtil.isEmpty(path)) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_EMPTY_1,
new Object[] {String.valueOf(path)}));
}
try {
// just for validation :
File file = new File(path);
if (file.isDirectory()) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_IS_FOLDER_1,
new Object[] {String.valueOf(path)}));
} else if (!file.isFile()) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_NOT_FOUND_1,
new Object[] {String.valueOf(path)}));
} else if (!file.canRead()) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_NOT_READ_1,
new Object[] {String.valueOf(path)}));
} else {
// avoid that the indexing thread is inited but before he opens m_filepath this is changed by a further call.
synchronized (this) {
m_filePath = file.getCanonicalPath();
if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) {
// early indexing.
initIndexer(m_filePath);
// scroll to last window:
if (m_isLogfile) {
scrollToFileEnd();
}
}
}
}
} catch (FileNotFoundException fnfe) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_NOT_FOUND_1,
new Object[] {String.valueOf(path)}), fnfe);
} catch (IOException ioex) {
throw new CmsRfsException(Messages.get().container(
Messages.ERR_FILE_ARG_ACCESS_1,
new Object[] {String.valueOf(path)}), ioex);
}
}
/**
* Package friendly access that allows the <code>{@link org.opencms.workplace.CmsWorkplaceManager}</code>
* to "freeze" this instance within the system-wide assignment in it's
* <code>{@link org.opencms.workplace.CmsWorkplaceManager#setFileViewSettings(org.opencms.file.CmsObject, CmsRfsFileViewer)}</code> method.<p>
*
* @param frozen if true this instance will freeze and throw <code>CmsRuntimeExceptions</code> upon setter invocations
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* ({@link #setFrozen(boolean)})
*
*/
public void setFrozen(boolean frozen) throws CmsRuntimeException {
m_frozen = frozen;
}
/**
* Set if the internal file is in standard logfile format (true) or not (false).<p>
*
* If set to true the file might be
* treated / displayed in a more convenient format than standard files in future.<p>
*
* @param isLogfile determines if the internal file is in standard logfile format (true) or not (false)
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* ({@link #setFrozen(boolean)})
*/
public void setIsLogfile(boolean isLogfile) throws CmsRuntimeException {
checkFrozen();
m_isLogfile = isLogfile;
}
/**
* Sets the start position of the current display.<p>
*
* This is a count of "windows" that
* consist of viewable text with "windowSize" lines of text (for a non-standard log file) or
* log-entries (for a standard log file).<p>
*
* @param windowPos the start position of the current display to set
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* ({@link #setFrozen(boolean)})
*/
public void setWindowPos(int windowPos) throws CmsRuntimeException {
checkFrozen();
m_windowPos = windowPos;
}
/**
* Set the amount of lines (or entries depending on wether a standard log file is shown)
* to display per page.<p>
*
* @param windowSize the amount of lines to display per page
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* ({@link #setFrozen(boolean)})
*
*/
public void setWindowSize(int windowSize) throws CmsRuntimeException {
checkFrozen();
m_windowSize = windowSize;
// go to last window (nice for logfiles)
if (CmsStringUtil.isNotEmpty(m_filePath)) {
if (m_isLogfile) {
scrollToFileEnd();
}
}
}
/**
* Return a line number index for the given file path.<p>
*
* Implementation allows control of eventual caching of line number indexes
* for files. <p>
*
* This method should never called from outside. It's visibility is set only
* for unit tests concerning the indexing mechanism.<p>
*
* This compilation unit uses indices (indexes) for fast reading / skipping of files that have
* to be dropped to free memory. Threads had to be avoided so this method will
* also check on all other remaining indices expiration time to drop them.<p>
*
*
* @param filePath the String denoting a valid path to a file in the real file system
* @return a line number index for the given file path
*/
protected CmsRfsFileLineIndexInfo initIndexer(String filePath) {
synchronized (m_fileName2lineIndex) {
CmsRfsFileLineIndexInfo result = (CmsRfsFileLineIndexInfo)m_fileName2lineIndex.get(filePath);
if (result != null) {
// nop
} else {
// create a new instance, this will be slow:
result = new CmsRfsFileLineIndexInfo(new File(filePath));
m_fileName2lineIndex.put(filePath, result);
}
return result;
}
}
/**
* Internal helper that throws a <code>{@link CmsRuntimeException}</code> if the
* configuration of this instance has been frozen ({@link #setFrozen(boolean)}).<p>
*
* @throws CmsRuntimeException if the configuration of this instance has been frozen
* ({@link #setFrozen(boolean)})
*/
private void checkFrozen() throws CmsRuntimeException {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_FILE_VIEW_SETTINGS_FROZEN_0));
}
}
/**
* Checks the internal cache of line number indices for expiration and
* drops those which are too old.<p>
*/
private void expireIndices() {
synchronized (m_fileName2lineIndex) {
CmsRfsFileLineIndexInfo index;
// cannot use valkues().iterator() because we need remove support on map.
Iterator it = m_fileName2lineIndex.entrySet().iterator();
Map.Entry entry;
long time = System.currentTimeMillis();
while (it.hasNext()) {
entry = (Map.Entry)it.next();
index = (CmsRfsFileLineIndexInfo)entry.getValue();
// expired?
if (time - index.m_creationTime > index.m_maxIndexAge) {
it.remove();
}
}
}
}
/**
* Internally sets the member <code>m_windowPos</code> to the last available
* window of <code>m_windowSize</code> windows to let further calls to
* <code>{@link #readFilePortion()}</code> display the end of the file. <p>
*
* This method is triggered when a new file is chosen
* (<code>{@link #setFilePath(String)}</code>) because the amount of lines changes.
* This method is also triggered when a different window size is chosen
* (<code>{@link #setWindowSize(int)}</code>) because the amount of lines to display change.
*
*
*/
private void scrollToFileEnd() {
if (OpenCms.getRunLevel() < OpenCms.RUNLEVEL_3_SHELL_ACCESS) {
// no scrolling if system not yet fully initialized
return;
}
CmsRfsFileLineIndexInfo lineInfo = initIndexer(m_filePath);
// shift the window position to the end of the file:
float lines = lineInfo.lineCount();
// if 11.75 windows are available, we don't want to end on window nr. 10
int availWindows = (int)Math.ceil(lines / m_windowSize);
// availWindows are available but m_windowPos starts with window nr. zero.
m_windowPos = availWindows - 1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -