release version 1.10.0

This commit is contained in:
2024-12-14 04:07:49 +03:00
parent a5088587f7
commit c6b3d793c4
1916 changed files with 254306 additions and 0 deletions

View File

@ -0,0 +1,211 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.platform.base.support;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SimpleFileWatcher implements Runnable {
public static interface WatcherCallback {
default void directoryCreated(WatchEvent<?> event, Path directory) {};
default void directoryModified(WatchEvent<?> event, Path directory) {};
default void directoryDeleted(WatchEvent<?> event, Path directory) {};
default void fileCreated(WatchEvent<?> event, Path directory) {};
default void fileModified(WatchEvent<?> event, Path directory) {};
default void fileDeleted(WatchEvent<?> event, Path directory) {};
}
private static final Logger LOG = LoggerFactory.getLogger(SimpleFileWatcher.class);
protected static final WatcherCallback NULL_CALLBACK = new WatcherCallback() {};
protected final WatchService watchService;
protected final Map<WatchKey, Path> keys;
protected WatcherCallback watcherCallback = null;
/**
* Creates a WatchService and registers the given directory
*/
public SimpleFileWatcher(Path dir) throws IOException {
this.watchService = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey, Path>();
walkAndRegisterDirectories(dir);
}
/**
* Register the given directory with the WatchService; This function will be called by
* FileVisitor
*/
private void registerDirectory(Path dir) throws IOException {
WatchKey key = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
keys.put(key, dir);
}
/**
* Register the given directory, and all its sub-directories, with the WatchService.
*/
private void walkAndRegisterDirectories(final Path start) throws IOException {
// register directory and sub-directories
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerDirectory(dir);
return FileVisitResult.CONTINUE;
}
});
}
public void setWatcherCallback(WatcherCallback watcherCallback) {
this.watcherCallback = watcherCallback;
}
protected WatcherCallback getActiveCallback() {
return watcherCallback == null ? NULL_CALLBACK : watcherCallback;
}
/**
* Process all events for keys queued to the watchService
*/
@Override
public void run() {
WatchKey key = null;
try {
while ((key = watchService.take()) != null) {
Path dir = keys.get(key);
if (dir == null) {
System.err.println("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
@SuppressWarnings("rawtypes")
WatchEvent.Kind kind = event.kind();
// Context for directory entry event is the file name of entry
@SuppressWarnings("unchecked")
Path name = ((WatchEvent<Path>) event).context();
Path child = dir.resolve(name);
// print out event
LOG.debug("{}: {}\n", event.kind().name(), child);
// if directory is created, and watching recursively, then register it and its
// sub-directories
if (kind == ENTRY_CREATE) {
try {
if (Files.isDirectory(child)) {
walkAndRegisterDirectories(child);
getActiveCallback().directoryCreated(event, dir);
} else {
LOG.debug("FOUND FILE: {}", child.toString());
getActiveCallback().fileCreated(event, dir);
}
} catch (Exception x) {
LOG.error(String.format("FAILED processing event [%s] for [%s]", kind, child.toString()),
x);
}
} else if (kind == ENTRY_MODIFY) {
try {
if (Files.isDirectory(child)) {
getActiveCallback().directoryModified(event, dir);
} else {
getActiveCallback().fileModified(event, dir);
}
} catch (Exception x) {
LOG.error(String.format("FAILED processing event [%s] for [%s]", kind, child.toString()),
x);
}
} else if (kind == ENTRY_DELETE) {
try {
if (Files.isDirectory(child)) {
getActiveCallback().directoryDeleted(event, dir);
} else {
getActiveCallback().fileDeleted(event, dir);
}
} catch (Exception x) {
LOG.error(String.format("FAILED processing event [%s] for [%s]", kind, child.toString()),
x);
}
}
}
// reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
}
} catch (InterruptedException ignore) {
// NOOP
}
}
public void close() {
try {
for (WatchKey key : keys.keySet())
key.cancel();
this.watchService.close();
} catch (IOException e) {
LOG.error("FAILED closing SimpleFileWatcher", e);
}
}
}

View File

@ -0,0 +1,96 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
import org.jline.utils.AttributedStringBuilder;
/**
* Colored support for column.
*/
public class AnsiColumnExt extends ColExt {
private int color;
private boolean bold;
public AnsiColumnExt(String header, int color, boolean bold) {
super(header);
this.color = color;
this.bold = bold;
}
public String getContent(ShellTableExt.CellData cellData) {
String in = super.getContent(cellData);
AttributedStringBuilder sb = new AttributedStringBuilder();
sb.style(sb.style().foreground(color));
if (bold)
sb.style(sb.style().bold());
sb.append(in);
if (bold)
sb.style(sb.style().boldOff());
sb.style(sb.style().foregroundOff());
return sb.toAnsi();
}
@Override
@Deprecated
public String getContent(String content) {
String in = super.getContent(content);
AttributedStringBuilder sb = new AttributedStringBuilder();
sb.style(sb.style().foreground(color));
if (bold)
sb.style(sb.style().bold());
sb.append(in);
if (bold)
sb.style(sb.style().boldOff());
sb.style(sb.style().foregroundOff());
return sb.toAnsi();
}
}

View File

@ -0,0 +1,381 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.karaf.shell.support.ansi.SimpleAnsi;
/**
* Column definition.
*/
public class ColExt {
// This is kept here only for backwards compatibility
// and is used in cyan(boolean) method
private static final Function<String, String> COLOR_CYAN =
(cellContent) -> SimpleAnsi.COLOR_CYAN;
Function<String, String> colorProvider;
Function<ShellTableExt.CellData, String> colorProviderExt;
protected ShellTableExt ownerTable = null;
/**
* Column header.
*/
private String header;
/**
* Maximum size of this column. The default -1 means the column may grow indefinitely
*/
int maxSize = -1;
int size = 0;
boolean wrap;
boolean bold;
boolean cyan;
Boolean splitLists = null;
/**
* Alignment
*/
private HAlignExt align = HAlignExt.left;
public ColExt(String header) {
this.header = header;
}
public ColExt align(HAlignExt align) {
this.align = align;
return this;
}
public ColExt alignLeft() {
this.align = HAlignExt.left;
return this;
}
public ColExt alignRight() {
this.align = HAlignExt.right;
return this;
}
public ColExt alignCenter() {
this.align = HAlignExt.center;
return this;
}
public ColExt maxSize(int maxSize) {
this.maxSize = maxSize;
return this;
}
public ColExt splitLists() {
return splitLists(true);
}
public ColExt splitLists(boolean value) {
this.splitLists = value;
return this;
}
public ColExt wrap() {
return wrap(true);
}
public ColExt wrap(boolean wrap) {
this.wrap = wrap;
return this;
}
public ColExt bold() {
return bold(true);
}
public ColExt bold(boolean bold) {
this.bold = bold;
return this;
}
public ColExt cyan() {
return cyan(true);
}
public ColExt cyan(boolean cyan) {
if (cyan)
colorProvider(COLOR_CYAN);
// Only remove colorProvider if argument is false and
// member equals COLOR_CYAN
else if (this.colorProvider == COLOR_CYAN)
colorProvider(null);
return this;
}
public int getSize() {
return size;
}
public ColExt colorProvider(Function<String, String> colorProvider) {
this.colorProvider = colorProvider;
return this;
}
public ColExt colorProviderExt(Function<ShellTableExt.CellData, String> colorProvider) {
this.colorProviderExt = colorProvider;
return this;
}
protected void updateSize(int cellSize) {
if (this.size <= cellSize) {
this.size = getClippedSize(cellSize);
}
}
private int getClippedSize(int cellSize) {
return this.maxSize == -1 ? cellSize : Math.min(cellSize, this.maxSize);
}
/*
String format(Object cellData) {
if (cellData == null) {
cellData = "";
}
String fullContent = String.format("%s", cellData);
if (fullContent.length() == 0) {
return "";
}
String finalContent = cut(fullContent, getClippedSize(fullContent.length()));
updateSize(finalContent.length());
return finalContent;
}
*/
protected boolean isSplitLists() {
if (this.splitLists != null)
return this.splitLists;
if (ownerTable != null)
return ownerTable.isSplitLists();
return false;
}
/*
@ENTAXY_FIX:
when calculating cell size we must take into account not LENGTH, but WIDTH of the data
'cause data may contain "\n" so the LENGTH of data won't be equal to it's WIDTH
*/
@SuppressWarnings("unchecked")
public String format(Object cellData) {
if (cellData == null) {
cellData = "";
}
String fullContent = String.format("%s", cellData);
if (isSplitLists() && (cellData instanceof List)) {
fullContent = (String) ((List) cellData).stream().map(v -> v == null ? "" : v.toString())
.collect(Collectors.joining("\n"));
}
if (fullContent.length() == 0) {
return "";
}
String finalContent = cut(fullContent, getClippedSize(fullContent.length()));
int finalContentWidth = 0;
for (String s : Arrays.asList(finalContent.split("\n")))
finalContentWidth = Math.max(finalContentWidth, s.length());
updateSize(finalContentWidth);
return finalContent;
}
String getHeader() {
return header;
}
String getContent(ShellTableExt.CellData cellData) {
String content = cellData.cellContent;
List<String> lines = new ArrayList<>();
lines.addAll(Arrays.asList(content.split("\n")));
if (wrap) {
List<String> wrapped = new ArrayList<>();
for (String line : lines) {
wrapped.addAll(wrap(line));
}
lines = wrapped;
}
String color = null;
if (colorProviderExt != null) {
color = colorProviderExt.apply(cellData);
} else if (colorProvider != null) {
color = colorProvider.apply(content);
}
StringBuilder sb = new StringBuilder();
for (String line : lines) {
if (sb.length() > 0) {
sb.append("\n");
}
line = this.align.position(cut(line, size), this.size);
if (bold) {
line = SimpleAnsi.INTENSITY_BOLD + line + SimpleAnsi.INTENSITY_NORMAL;
}
if (color != null)
sb.append(color);
sb.append(line);
if (color != null)
sb.append(SimpleAnsi.COLOR_DEFAULT);
}
return sb.toString();
}
@Deprecated
String getContent(String content) {
List<String> lines = new ArrayList<>();
lines.addAll(Arrays.asList(content.split("\n")));
if (wrap) {
List<String> wrapped = new ArrayList<>();
for (String line : lines) {
wrapped.addAll(wrap(line));
}
lines = wrapped;
}
String color = null;
if (colorProvider != null) {
color = colorProvider.apply(content);
}
StringBuilder sb = new StringBuilder();
for (String line : lines) {
if (sb.length() > 0) {
sb.append("\n");
}
line = this.align.position(cut(line, size), this.size);
if (bold) {
line = SimpleAnsi.INTENSITY_BOLD + line + SimpleAnsi.INTENSITY_NORMAL;
}
if (color != null)
sb.append(color);
sb.append(line);
if (color != null)
sb.append(SimpleAnsi.COLOR_DEFAULT);
}
return sb.toString();
}
/*
protected String cut(String content, int size) {
if (content.length() <= size) {
return content;
} else {
return content.substring(0, Math.max(0, size - 1));
}
}
*/
protected String cut0(String content, int size) {
if (content.length() <= size) {
return content;
} else {
return content.substring(0, Math.max(0, size - 1));
}
}
protected String cut(String content, int size) {
if (content.length() <= size) {
return content;
} else {
String[] contentSplitted = content.split("\n");
for (int i = 0; i < contentSplitted.length; i++)
contentSplitted[i] = cut0(contentSplitted[i], size);
if (contentSplitted.length == 1)
return contentSplitted[0];
return Arrays.asList(contentSplitted).stream().collect(Collectors.joining("\n"));
}
}
protected List<String> wrap(String str) {
List<String> result = new ArrayList<>();
Pattern wrap = Pattern.compile("(\\S\\S{" + size + ",}|.{1," + size + "})(\\s+|$)");
int cur = 0;
while (cur >= 0) {
int lst = str.indexOf('\n', cur);
String s = (lst >= 0) ? str.substring(cur, lst) : str.substring(cur);
if (s.length() == 0) {
result.add(s);
} else {
Matcher m = wrap.matcher(s);
while (m.find()) {
result.add(m.group());
}
}
if (lst >= 0) {
cur = lst + 1;
} else {
break;
}
}
return result;
}
}

View File

@ -0,0 +1,93 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
import static ru.entaxy.platform.base.support.karaf.shell.StringUtil.length;
import static ru.entaxy.platform.base.support.karaf.shell.StringUtil.repeat;
/**
* Enumeration type which contains all possible horizontal alignments.
*/
public enum HAlignExt {
/**
* Center align.
*/
center {
@Override
public String position(String text, int colWidth) {
int width = colWidth - length(text);
text = repeat(" ", width / 2) + text + repeat(" ", width / 2);
if (length(text) < colWidth) {
// if colWidth is odd we add space at the end.
text += " ";
}
return text;
}
},
/**
* Left align.
*/
left {
@Override
public String position(String text, int colWidth) {
return text + repeat(" ", colWidth - length(text));
}
},
/**
* Right align.
*/
right {
@Override
public String position(String text, int colWidth) {
return repeat(" ", colWidth - length(text)) + text;
}
};
/**
* Calculate text position.
*
* @param text the text to align.
* @param colWidth the column width.
* @return the string at the given position.
*/
public abstract String position(String text, int colWidth);
}

View File

@ -0,0 +1,132 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RowExt {
protected List<Object> data;
protected List<String> content;
protected Object dataObject = null;
RowExt() {
data = new ArrayList<>();
content = new ArrayList<>();
}
RowExt(Object dataObject) {
data = new ArrayList<>();
content = new ArrayList<>();
this.dataObject = dataObject;
}
RowExt(List<ColExt> cols) {
this();
for (ColExt col : cols) {
data.add(col.getHeader());
}
}
public void addContent(List<Object> data) {
this.data = data;
}
public void addContent(Object... cellDataAr) {
data.addAll(Arrays.asList(cellDataAr));
}
void formatContent(List<ColExt> cols) {
content.clear();
int c = 0;
for (ColExt col : cols) {
content.add(col.format(data.get(c)));
c++;
}
}
String getContent(List<ColExt> cols, String separator) {
if (cols.size() != content.size()) {
throw new RuntimeException("Number of columns and number of content elements do not match");
}
List<String[]> contents = new ArrayList<>();
int lines = 0;
for (int col = 0; col < cols.size(); col++) {
// String[] cnt = cols.get(col).getContent(content.get(col)).split("\n");
String[] cnt = cols.get(col).getContent(new ShellTableExt.CellData(dataObject, content.get(col))).split("\n");
lines = Math.max(lines, cnt.length);
contents.add(cnt);
}
StringBuilder st = new StringBuilder();
for (int line = 0; line < lines; line++) {
if (line > 0) {
st.append("\n");
}
StringBuilder st2 = new StringBuilder();
for (int col = 0; col < cols.size(); col++) {
String[] strings = contents.get(col);
if (col > 0) {
st2.append(separator);
}
if (line < strings.length) {
st2.append(strings[line]);
} else {
st2.append(StringUtil.repeat(" ", cols.get(col).getSize()));
}
}
while (st2.charAt(st2.length() - 1) == ' ') {
st2.setLength(st2.length() - 1);
}
st.append(st2);
}
return st.toString();
}
public Object getDataObject() {
return dataObject;
}
public void setDataObject(Object dataObject) {
this.dataObject = dataObject;
}
}

View File

@ -0,0 +1,90 @@
/*-
* ~~~~~~licensing~~~~~~
* platform-manager-core
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.platform.base.support.karaf.shell;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.apache.karaf.shell.support.table.Col;
public class ShellTableColFixed extends Col {
protected int maxSizeLocal = -1;
public ShellTableColFixed(String header) {
super(header);
}
@Override
protected String cut(String content, int size) {
if (content.length() <= size) {
return content;
} else {
String[] contentSplitted = content.split("\n");
for (int i=0; i<contentSplitted.length; i++)
contentSplitted[i] = super.cut(contentSplitted[i], size);
if (contentSplitted.length == 1)
return contentSplitted[0];
return Arrays.asList(contentSplitted).stream().collect(Collectors.joining("\n"));
}
}
@Override
public ShellTableColFixed maxSize(int maxSize) {
this.maxSizeLocal = maxSize;
return (ShellTableColFixed)super.maxSize(maxSize);
}
private int getClippedSize(int cellSize) {
return this.maxSizeLocal == -1 ? cellSize : Math.min(cellSize, this.maxSizeLocal);
}
/*
@ENTAXY_FIX:
when calculating cell size we must take into account not LENGTH, but WIDTH of the data
'cause data may contain "\n" so the LENGTH of data won't be equal to it's WIDTH
*/
public String format(Object cellData) {
if (cellData == null) {
cellData = "";
}
String fullContent = String.format("%s", cellData);
if (fullContent.length() == 0) {
return "";
}
String finalContent = cut(fullContent, getClippedSize(fullContent.length()));
int finalContentWidth = 0;
for (String s: Arrays.asList(finalContent.split("\n")))
finalContentWidth = Math.max(finalContentWidth, s.length());
updateSize(finalContentWidth);
return finalContent;
}
}

View File

@ -0,0 +1,284 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.felix.gogo.runtime.threadio.ThreadPrintStream;
import org.apache.felix.service.command.Job;
import org.jline.terminal.Terminal;
public class ShellTableExt {
private static final char SEP_HORIZONTAL = '─';
private static final char SEP_VERTICAL = '│';
private static final char SEP_CROSS = '┼';
private static final char SEP_HORIZONTAL_ASCII = '-';
private static final char SEP_VERTICAL_ASCII = '|';
private static final char SEP_CROSS_ASCII = '+';
private static final String DEFAULT_SEPARATOR = " " + SEP_VERTICAL + " ";
private static final String DEFAULT_SEPARATOR_ASCII = " " + SEP_VERTICAL_ASCII + " ";
private static final String DEFAULT_SEPARATOR_NO_FORMAT = "\t";
private List<ColExt> cols = new ArrayList<>();
private List<RowExt> rows = new ArrayList<>();
private boolean showHeaders = true;
private String separator = DEFAULT_SEPARATOR;
private int size;
private String emptyTableText;
private boolean forceAscii;
private boolean splitLists = false;
public ShellTableExt() {
}
public ShellTableExt noHeaders() {
this.showHeaders = false;
return this;
}
public ShellTableExt separator(String separator) {
this.separator = separator;
return this;
}
public ShellTableExt size(int size) {
this.size = size;
return this;
}
public boolean isSplitLists() {
return splitLists;
}
public ShellTableExt splitLists() {
return splitLists(true);
}
public ShellTableExt splitLists(boolean value) {
this.splitLists = value;
return this;
}
public ShellTableExt column(ColExt colunmn) {
cols.add(colunmn);
colunmn.ownerTable = this;
return this;
}
public ColExt column(String header) {
ColExt col = new ColExt(header);
col.ownerTable = this;
cols.add(col);
return col;
}
public RowExt addRow() {
RowExt row = new RowExt();
rows.add(row);
return row;
}
public RowExt addRow(Object dataObject) {
RowExt row = addRow();
row.setDataObject(dataObject);
return row;
}
public ShellTableExt forceAscii() {
forceAscii = true;
return this;
}
/**
* Set text to display if there are no rows in the table.
*
* @param text the text to display when the table is empty.
* @return the shell table.
*/
public ShellTableExt emptyTableText(String text) {
this.emptyTableText = text;
return this;
}
public void print(PrintStream out) {
print(out, true);
}
public void print(PrintStream out, boolean format) {
print(out, null, format);
}
public void print(PrintStream out, Charset charset, boolean format) {
boolean unicode = supportsUnicode(out, charset);
String separator = unicode ? this.separator : DEFAULT_SEPARATOR_ASCII;
// "normal" table rendering, with borders
RowExt headerRow = new RowExt(cols);
headerRow.formatContent(cols);
for (RowExt row : rows) {
row.formatContent(cols);
}
if (size > 0) {
adjustSize();
}
if (format && showHeaders) {
String headerLine = headerRow.getContent(cols, separator);
out.println(headerLine);
int iCol = 0;
for (ColExt col : cols) {
if (iCol++ == 0) {
out.print(underline(col.getSize(), false, unicode));
} else {
out.print(underline(col.getSize() + 3, true, unicode));
}
iCol++;
}
out.println();
}
for (RowExt row : rows) {
if (!format) {
if (separator == null || separator.equals(DEFAULT_SEPARATOR))
out.println(row.getContent(cols, DEFAULT_SEPARATOR_NO_FORMAT));
else
out.println(row.getContent(cols, separator));
} else {
out.println(row.getContent(cols, separator));
}
}
if (format && rows.size() == 0 && emptyTableText != null) {
out.println(emptyTableText);
}
}
private boolean supportsUnicode(PrintStream out, Charset charset) {
if (forceAscii) {
return false;
}
if (charset == null) {
charset = getEncoding(out);
}
if (charset == null) {
return false;
}
CharsetEncoder encoder = charset.newEncoder();
return encoder.canEncode(separator)
&& encoder.canEncode(SEP_HORIZONTAL)
&& encoder.canEncode(SEP_CROSS);
}
private Charset getEncoding(PrintStream ps) {
if (ps.getClass() == ThreadPrintStream.class) {
try {
return ((Terminal) Job.Utils.current().session().get(".jline.terminal")).encoding();
} catch (Throwable t) {
// ignore
}
try {
ps = (PrintStream) ps.getClass().getMethod("getCurrent").invoke(ps);
} catch (Throwable t) {
// ignore
}
}
try {
Field f = ps.getClass().getDeclaredField("charOut");
f.setAccessible(true);
OutputStreamWriter osw = (OutputStreamWriter) f.get(ps);
return Charset.forName(osw.getEncoding());
} catch (Throwable t) {
// ignore
}
return null;
}
private void adjustSize() {
int currentSize = 0;
for (ColExt col : cols) {
currentSize += col.size + separator.length();
}
currentSize -= separator.length();
int sizeToGrow = size - currentSize;
for (int i = cols.size() - 1; i >= 0; i--) {
ColExt col = cols.get(i);
if (col.maxSize == -1) {
col.size = Math.max(0, col.size + sizeToGrow);
return;
}
}
}
private String underline(int length, boolean crossAtBeg, boolean supported) {
char[] exmarks = new char[length];
Arrays.fill(exmarks, supported ? SEP_HORIZONTAL : SEP_HORIZONTAL_ASCII);
if (crossAtBeg) {
exmarks[1] = supported ? SEP_CROSS : SEP_CROSS_ASCII;
}
return new String(exmarks);
}
public static class CellData {
public Object dataObject;
public String cellContent;
public CellData(Object dataObject, String cellContent) {
this.dataObject = dataObject;
this.cellContent = cellContent;
}
}
}

View File

@ -0,0 +1,48 @@
/*-
* ~~~~~~licensing~~~~~~
* platform-manager-core
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.platform.base.support.karaf.shell;
import org.apache.karaf.shell.support.table.ShellTable;
/**
* @deprecated use {@link ru.entaxy.platform.base.support.karaf.shell.ShellTableExt} instead
*/
@Deprecated
public class ShellTableFixed extends ShellTable {
@Override
public ShellTableColFixed column(String header) {
ShellTableColFixed col = new ShellTableColFixed(header);
column(col);
return col;
}
public ShellTableFixed column(ShellTableColFixed colunmn) {
super.column(colunmn);
return this;
}
}

View File

@ -0,0 +1,68 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/*
* 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 ru.entaxy.platform.base.support.karaf.shell;
public class StringUtil {
/**
* Returns length of the string.
*
* @param string String.
* @return Length.
*/
public static int length(String string) {
return string == null ? 0 : string.length();
}
/**
* Utility method to repeat string.
*
* @param string String to repeat.
* @param times Number of times.
* @return Repeat string.
*/
public static String repeat(String string, int times) {
if (times <= 0) {
return "";
} else if (times % 2 == 0) {
return repeat(string + string, times / 2);
} else {
return string + repeat(string + string, times / 2);
}
}
}

View File

@ -0,0 +1,69 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.platform.base.support.osgi.feature;
import java.util.List;
import org.apache.karaf.features.Capability;
import org.apache.karaf.features.Feature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.platform.base.support.osgi.bundle.CapabilityDescriptorImpl;
import ru.entaxy.platform.base.support.osgi.bundle.CapabilityHelper;
public class FeatureCapabilityHelper extends CapabilityHelper {
private static final Logger LOG = LoggerFactory.getLogger(FeatureCapabilityHelper.class);
protected Feature feature;
public FeatureCapabilityHelper(Feature feature) {
super();
setMultipleNamespacesSupported(true);
this.feature = feature;
load();
}
@Override
protected void load() {
super.load();
List<? extends Capability> featureCapabilities = feature.getCapabilities();
for (Capability c : featureCapabilities) {
String[] caps = c.getValue().split(",");
for (String cap : caps)
try {
CapabilityDescriptorImpl descriptor = parseCapability(cap);
if (descriptor != null)
addProvidedCapability(descriptor);
} catch (Exception e) {
LOG.error(String.format("Error parsing capability [%s] for feature [%s/%s]", cap, feature.getName(),
feature.getVersion()), e);
}
}
}
}

View File

@ -0,0 +1,164 @@
/*-
* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.platform.base.support.osgi.feature;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.karaf.bundle.core.BundleService;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.platform.base.support.CommonUtils;
public class FeaturesUtils {
public static class FeaturesHelper {
private static final Logger LOG = LoggerFactory.getLogger(FeaturesUtils.FeaturesHelper.class);
public static FeaturesHelper create() {
return new FeaturesHelper();
}
public static FeaturesHelper create(BundleContext bundleContext) {
return create().bundleContext(bundleContext);
}
protected BundleContext bundleContext = FrameworkUtil.getBundle(FeaturesUtils.class).getBundleContext();
protected String capabilityNamespace = null;
protected boolean installedOnly = false;
protected Bundle bundle = null;
protected FeaturesHelper() {
super();
}
public List<Feature> find() throws Exception {
ServiceReference<FeaturesService> ref = bundleContext.getServiceReference(FeaturesService.class);
FeaturesService featuresService = bundleContext.getService(ref);
Feature[] featureArray =
isInstalledOnly() ? featuresService.listInstalledFeatures() : featuresService.listFeatures();
List<Feature> features = Arrays.asList(featureArray);
if (bundle != null) {
ServiceReference<BundleService> ref0 = bundleContext.getServiceReference(BundleService.class);
BundleService bundleService = bundleContext.getService(ref0);
final String location = bundleService.getInfo(bundle).getUpdateLocation();
bundleContext.ungetService(ref0);
features = features.stream().filter(
f -> (f.getBundles().stream().filter(bi -> bi.getLocation().equals(location))
.count() > 0))
.collect(Collectors.toList());
}
if (CommonUtils.isValid(capabilityNamespace)) {
features = features.stream()
.filter(f -> (new FeatureCapabilityHelper(f).isCapabilityProvided(capabilityNamespace)))
.collect(Collectors.toList());
}
bundleContext.ungetService(ref);
return features;
}
public FeaturesUtils.FeaturesHelper bundleContext(BundleContext BundleContextValue) {
this.setBundleContext(BundleContextValue);
return this;
}
public FeaturesUtils.FeaturesHelper withCapabilityNamespace(String capabilityNamespaceValue) {
this.setCapabilityNamespace(capabilityNamespaceValue);
return this;
};
public FeaturesUtils.FeaturesHelper installedOnly() {
this.setInstalledOnly(true);
return this;
};
public FeaturesUtils.FeaturesHelper installedOnly(boolean InstalledOnlyValue) {
this.setInstalledOnly(InstalledOnlyValue);
return this;
};
public FeaturesUtils.FeaturesHelper containingBundle(Bundle bundleValue) {
this.setBundle(bundleValue);
return this;
};
public BundleContext getBundleContext() {
return bundleContext;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public String getCapabilityNamespace() {
return capabilityNamespace;
}
public void setCapabilityNamespace(String capabilityNamespace) {
this.capabilityNamespace = capabilityNamespace;
}
public boolean isInstalledOnly() {
return installedOnly;
}
public void setInstalledOnly(boolean installedOnly) {
this.installedOnly = installedOnly;
}
public Bundle getBundle() {
return bundle;
}
public void setBundle(Bundle bundle) {
this.bundle = bundle;
};
}
}