Programmatically changing the level of the Appender reference of a Logger in log4j2 - log4j2

I tested the solution to a similar question
How can I change the AppenderRef Level in log4j2 programmatically?
But the solution is not working for the latest version of log4j2.xml - 2.17.0 .
Usecase is slight different than the question referred to . I am configuring Log4J programmatically, through a configuration factory :
package test.config;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.*;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import simplica.util.CommonUtils;
import java.io.File;
import java.net.URI;
/**
* Configuration Factory to configure the Log4J2 Configuration programmatically
*
* #version 1.0
* #author Vishwanath Washimkar
*
*/
#Plugin(
name = "CustomConfigurationFactory",
category = ConfigurationFactory.CATEGORY)
#Order(50)
public class CustomConfigurationFactory extends ConfigurationFactory {
private LayoutComponentBuilder layoutBuilder;
private String logDirPath;
private EmailAppender emailAppender;
private String debugLoglevel;
private AppConfig appConfig;
private static ConfigurationBuilder<BuiltConfiguration> builder;
public static LoggerComponentBuilder labwareLogger;
/**
* Related to FileAppenders
*/
private final static String APPN_LAYOUT_PATTERN = "%d{MM-dd#HH:mm:ss}%-4r %-5p [%t] %37c %3x - %m%n";
public CustomConfigurationFactory(){
builder = newConfigurationBuilder();
appConfig = AppConfig.getInstance();
if(appConfig != null){
logDirPath = appConfig.getWeblimsLogPath();
emailAppender = appConfig.getEmailAppender();
}
}
#Override
protected String[] getSupportedTypes() {
return new String[] { "*" };
}
#Override
public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
return null;
}
#Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
return createConfiguration();
}
public Configuration createConfiguration() {
builder.setStatusLevel(Level.WARN);
builder.setConfigurationName("Test");
builder.setMonitorInterval("5");
layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", APPN_LAYOUT_PATTERN);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
if (CommonUtils.isValue(logDirPath)) {
File file = new File(logDirPath);
if (file.isDirectory() && file.canWrite()) {
configureWithFileAppender(builder, rootLogger);
} else {
configureWithConsoleAppender(builder, rootLogger);
}
} else {
//this is the last re course as every other configuration has failed
configureWithConsoleAppender(builder,rootLogger);
}
if(emailAppender != null){
if(!emailAppender.getEnabled()){
//add and enable email appender
configureEmailAppender(builder,rootLogger);
}
}
builder.add(rootLogger);
return builder.build();
}
private void configureEmailAppender(ConfigurationBuilder<BuiltConfiguration> builder, RootLoggerComponentBuilder rootLogger) {
String emailAppenderName = "emailAppender";
AppenderComponentBuilder smtpBuilder = builder.newAppender("emailAppender", "SMTP")//
.addAttribute("smtpUsername", emailAppender.getSMTPUsername())
.addAttribute("smtpPassword", emailAppender.getSMTPPassword())
.addAttribute("smtpProtocol", emailAppender.getSmtpProtocol())
.addAttribute("smtpHost", emailAppender.getSMTPHost())
.addAttribute("to", emailAppender.getTo())
.addAttribute("subject", emailAppender.getSubject())
.addAttribute("Cc", emailAppender.getCc())
.addAttribute("Bcc", emailAppender.getBcc())
.add(layoutBuilder);
builder.add(smtpBuilder);
if(emailAppender.getEnabled()){
rootLogger.add(builder.newAppenderRef(emailAppenderName));
}
}
private void configureWithConsoleAppender(ConfigurationBuilder<BuiltConfiguration> builder, RootLoggerComponentBuilder rootLogger) {
if(builder == null) throw new IllegalArgumentException("builder cannot be null");
// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("console", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(layoutBuilder);
builder.add(appenderBuilder);
rootLogger.add(builder.newAppenderRef("console"));
}
private void configureWithFileAppender(ConfigurationBuilder<BuiltConfiguration> builder, RootLoggerComponentBuilder rootLogger) {
if(builder == null) throw new IllegalArgumentException("builder cannot be null");
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("TimeBasedTriggeringPolicy").addAttribute("interval", "1"));
AppenderComponentBuilder debugLogBuilder = builder.newAppender("debugLog", "RollingFile")
.addAttribute("fileName", logDirPath + "\\" + "debug.log")
.addAttribute("filePattern", logDirPath + "\\" + "debug%d{MM-dd-yy}.log.gz")
.add(layoutBuilder)
.addComponent(triggeringPolicy);
AppenderComponentBuilder errorLogBuilder = builder.newAppender("errorLog", "RollingFile")
.addAttribute("fileName", logDirPath + "\\" + "error.log")
.addAttribute("filePattern", logDirPath + "\\" + "error-%d{MM-dd-yy}.log.gz")
.add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(debugLogBuilder);
builder.add(errorLogBuilder);
labwareLogger = builder.newLogger("test", Level.DEBUG );
labwareLogger.add(builder.newAppenderRef("debugLog").addAttribute("level", getDebugLogLevel()));
labwareLogger.add(builder.newAppenderRef("errorLog").addAttribute("level", Level.ERROR));
builder.add(labwareLogger);
rootLogger.add(builder.newAppenderRef("debugLog").addAttribute("level", Level.WARN));
rootLogger.add(builder.newAppenderRef("errorLog").addAttribute("level", Level.ERROR));
}
private Level getDebugLogLevel() {
String logLevel = appConfig.getDebugLogLevel();
if("DEBUG".equalsIgnoreCase(logLevel)){
return Level.DEBUG;
}
if("INFO".equalsIgnoreCase(logLevel)){
return Level.INFO;
}
if("ERROR".equalsIgnoreCase(logLevel)){
return Level.ERROR;
}
if("WARN".equalsIgnoreCase(logLevel)){
return Level.WARN;
}
if("FATAL".equalsIgnoreCase(logLevel)){
return Level.FATAL;
}
if("TRACE".equalsIgnoreCase(logLevel)){
return Level.TRACE;
}
if("ALL".equalsIgnoreCase(logLevel)){
return Level.ALL;
}
//at the end lets just return the
return Level.WARN;
}
}
Then I am trying to change the logging level for appenderRef in a servlet.
package com.example.testwebapp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import java.io.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
#WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;
public void init() {
message = "Hello World! from Vish";
}
int i =0;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
if(i > 2) {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configuration config = context.getConfiguration();
LoggerConfig labware = config.getLoggerConfig("labware");
labware.removeAppender("debugLog");
labware.addAppender(config.getAppender("debugLog"), Level.DEBUG, null);
// This causes all Loggers to refetch information from their LoggerConfig.
context.updateLoggers();
}
i++;
response.setContentType("text/html");
getLog().debug("DEBUG log entryc 11111 ");
getLog().info("INFO log entry ");
getLog().error("ERROR log entry ");
getLog().warn("############# WAR log entry ");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + " World </h1>");
out.println("</body></html>");
}
public void destroy() {
}
/**
* #return The logger for the class.
*/
private static Log getLog() {
return LogFactory.getLog(HelloServlet.class);
}
}

Related

Snowflake SDKTest: Error:(137, 49) java: cannot find symbol variable PublicKeyReader location: class net.snowflake.ingest.example.SDKTest

I am not able to run the SDKTest class following this documentation:
https://docs.snowflake.net/manuals/user-guide/data-load-snowpipe-rest-load.html
I am using IntelliJ and Java SDK 12.0.
Error:(137, 49) java: cannot find symbol
symbol: variable PublicKeyReader
location: class net.snowflake.ingest.example.SDKTest
Can anybody help me with this?
BR,
Here is the running copy of SDK Test code :
package com.snowflake.SalesforceTestCases;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import net.snowflake.ingest.SimpleIngestManager;
import net.snowflake.ingest.connection.HistoryRangeResponse;
import net.snowflake.ingest.connection.HistoryResponse;
public class SDKTest {
private static final String PRIVATE_KEY_FILE = "<Path to your p8 file>/rsa_key.p8";
public static class PrivateKeyReader {
public static PrivateKey get(String filename) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String encrypted = new String(keyBytes);
String passphrase = "Snowflake";
encrypted = encrypted.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
encrypted = encrypted.replace("-----END ENCRYPTED PRIVATE KEY-----", "");
EncryptedPrivateKeyInfo pkInfo = new EncryptedPrivateKeyInfo(Base64.getMimeDecoder().decode(encrypted));
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray());
SecretKeyFactory pbeKeyFactory = SecretKeyFactory.getInstance(pkInfo.getAlgName());
PKCS8EncodedKeySpec encodedKeySpec = pkInfo.getKeySpec(pbeKeyFactory.generateSecret(keySpec));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey encryptedPrivateKey = keyFactory.generatePrivate(encodedKeySpec);
return encryptedPrivateKey;
}
}
private static HistoryResponse waitForFilesHistory(final SimpleIngestManager manager, Set<String> files)
throws Exception {
ExecutorService service = Executors.newSingleThreadExecutor();
class GetHistory implements Callable<HistoryResponse> {
private Set<String> filesWatchList;
GetHistory(Set<String> files) {
this.filesWatchList = files;
}
String beginMark = null;
public HistoryResponse call() throws Exception {
HistoryResponse filesHistory = null;
while (true) {
Thread.sleep(5000);
HistoryResponse response = manager.getHistory(null, null, beginMark);
if (response.getNextBeginMark() != null) {
beginMark = response.getNextBeginMark();
}
if (response != null && response.files != null) {
for (HistoryResponse.FileEntry entry : response.files) {
// if we have a complete file that we've
// loaded with the same name..
String filename = entry.getPath();
if (entry.getPath() != null && entry.isComplete() && filesWatchList.contains(filename)) {
if (filesHistory == null) {
filesHistory = new HistoryResponse();
filesHistory.setPipe(response.getPipe());
}
filesHistory.files.add(entry);
filesWatchList.remove(filename);
// we can return true!
if (filesWatchList.isEmpty()) {
return filesHistory;
}
}
}
}
}
}
}
GetHistory historyCaller = new GetHistory(files);
// fork off waiting for a load to the service
Future<HistoryResponse> result = service.submit(historyCaller);
HistoryResponse response = result.get(2, TimeUnit.MINUTES);
return response;
}
public static void main(String[] args) {
final String account = "<Snowflake Account Name >";
final String hostName = "<Snowflake Account URL>";
final String user = "<Snowflake Account Username>";
final String pipe = "<Snowflake Pipe Path>";
try {
final long oneHourMillis = 1000 * 3600L;
String startTime = Instant.ofEpochMilli(System.currentTimeMillis() - 4 * oneHourMillis).toString();
PrivateKey privateKey = PrivateKeyReader.get(PRIVATE_KEY_FILE);
//PublicKey publicKey = PublicKeyReader.get(PUBLIC_KEY_FILE);
#SuppressWarnings("deprecation")
SimpleIngestManager manager = new SimpleIngestManager(account, user, pipe, privateKey, "https", hostName, 443);
Set<String> files = new TreeSet<>();
files.add("<filename>");
manager.ingestFiles(manager.wrapFilepaths(files), null);
HistoryResponse history = waitForFilesHistory(manager, files);
System.out.println("Received history response: " + history.toString());
String endTime = Instant.ofEpochMilli(System.currentTimeMillis()).toString();
HistoryRangeResponse historyRangeResponse = manager.getHistoryRange(null, startTime, endTime);
System.out.println("Received history range response: " + historyRangeResponse.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
My understanding of the error is that the compiler does not know what the variable PublicKeyReader references. Perhaps the variable was declared incorrectly in the code or there was a misspelling? There is a sample Java program in the documentation you mentioned, but there is also a sample program here if it helps:
https://github.com/snowflakedb/snowflake-ingest-java
References for Error:
What does a "Cannot find symbol" compilation error mean?
https://www.thoughtco.com/error-message-cannot-find-symbol-2034060

Custom extension element in Stanza for Smack 4.1.4

I am moving my android application from asmack-android library to Smack 4.1.4. I have some PacketExtensions in the asmack version of Smack, which uses PacketExtension and PacketExtensionProvider classes to handle. Since the PacketExtension is deprecated in Smack 4.1.4, I am confused among the classes and interfaces ExtensionElement, DataPacketExtension, ExtensionElementProvider , DefaultExtensionElement. Could any one of you give me an example of creating an extension which can be added with stanza and parse back...https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware /smack/packet/DefaultExtensionElement.htmlhttps://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware /smack/provider/ExtensionElementProvider.html
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
Log.e("message --->", message.toXML().toString());
This will produce the following stanza
<message id='923442621149' type='chat'><body>shanraisshan</body></message>
1. CUSTOM EXTENSION STANZA TYPE-1
In order to generate below custom extension stanza
<message id='923442621149' type='chat'><body>shanraisshan</body>
<reply xmlns='shayan:reply' rText='this is custom attribute'/>
</message>
where reply is a custom extension, which contains
Element (reply)
Namespace (shayan:reply)
the list of default xmpp namespaces are available at Official XMPP website
Do following steps
1. Add ReplyExtension.java in your project
ReplyExtension.java
package com.xmpp.extensions;
import org.jivesoftware.smack.packet.DefaultExtensionElement;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.List;
import java.util.Map;
/**
* Shayan Rais (http://shanraisshan.com)
* created on 9/7/2016
*/
public class ReplyExtension implements ExtensionElement {
public static final String NAMESPACE = "shayan:reply";
public static final String ELEMENT = "reply";
String rText = null;
static final String ATTRIBUTE_REPLY_TEXT = "rText";
#Override
public String getElementName() {
return ELEMENT;
}
#Override
public String getNamespace() {
return NAMESPACE;
}
#Override
public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder(this);
xml.attribute(ATTRIBUTE_REPLY_TEXT, getReplyText());
xml.closeEmptyElement();
return xml;
}
//__________________________________________________________________________________________________
public void setReplyText(String _rText) {
rText = _rText;
}
public String getReplyText() {
return rText;
}
//__________________________________________________________________________________________________
public static class Provider extends EmbeddedExtensionProvider<ReplyExtension> {
#Override
protected ReplyExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) {
ReplyExtension repExt = new ReplyExtension();
repExt.setReplyText(attributeMap.get(ATTRIBUTE_REPLY_TEXT));
return repExt;
}
}
}
2. Register ReplyExtension in your Provider Manager
ProviderManager.addExtensionProvider(ReplyExtension.ELEMENT, ReplyExtension.NAMESPACE, new ReplyExtension.Provider());
FOR SENDING MESSAGES
You can generate the custom extension stanza TYPE-1 by using following code
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
//adding custom reply extension
ReplyExtension repExt = new ReplyExtension();
repExt.setReplyText("this is custom attribute");
message.addExtension(repExt);
Log.e("message --->", message.toXML().toString());
DURING RECEIVING MESSAGES
Now during receiving custom extension stanzas, you need to cast the extension to get attribute values.
//check for message with reply extension
ExtensionElement packetExtension = message.getExtension(ReplyExtension.NAMESPACE);
ReplyExtension repExt = (ReplyExtension)packetExtension;
if(repExt!=null) {
Log.e("--->", " --- LOG REPLY EXTENSION ---");
Log.e("--->", repExt.toXML() + "");
Log.e("--->", repExt.getReplyText() + ""); //this is custom attribute
}
_______________________________________________________
2. CUSTOM EXTENSION STANZA TYPE-2
In order to generate below custom extension stanza
<message id='923442621149' type='chat'><body>shanraisshan</body>
<reply xmlns='shayan:reply'><rText>this is custom attribute</rText></reply>
</message>
FOR SENDING MESSAGES
You can generate the custom extension stanza TYPE-2 by using following code
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
//adding custom reply extension
DefaultExtensionElement repExt = new DefaultExtensionElement("reply", "shayan:reply");
repExt.setValue("rText", "this is custom attribute");
message.addExtension(repExt);
Log.e("message --->", message.toXML().toString());
DURING RECEIVING MESSAGES
DefaultExtensionElement repExt = (DefaultExtensionElement) message.getExtension("shayan:reply");
if(repExt!=null) {
Log.e("--->", " --- LOG REPLY EXTENSION ---");
Log.e(getClass().getSimpleName(), repExt.getValue("rText"));
}
Finally figured it out.... Here is the solution for it...
import org.jivesoftware.smack.packet.DefaultExtensionElement;
public class IM_FileSharing_Extension extends DefaultExtensionElement implements
IM_Commons_Extension_FileSharing {
private String fileUrl;
private String fileType;
private String base64preview;
private String fileId;
private String fileSize;
public IM_FileSharing_Extension(String fileUrl, String fileType,
String base64preview, String fileId, String fileSize) {
super(FILE_TAG, XMLNS);
this.fileUrl = fileUrl;
this.fileType = fileType;
this.base64preview = base64preview;
this.fileId = fileId;
this.fileSize = fileSize;
}
#Override
public String toXML() {
StringBuilder sb = new StringBuilder("<" + FILE_TAG + " xmlns=\""
+ XMLNS + "\" ");
sb.append(FILE_URL + "=\"" + fileUrl + "\" ");
sb.append(FILE_ID + "=\"" + fileId + "\" ");
sb.append(FILE_TYPE + "=\"" + fileType + "\" ");
sb.append(FILE_SIZE + "=\"" + fileSize + "\">");
sb.append("<" + FILE_PREVIEW_TAG + ">" + base64preview + "</"
+ FILE_PREVIEW_TAG + ">");
sb.append("</" + FILE_TAG + ">");
return sb.toString();
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
public String getBase64preview() {
return base64preview;
}
public void setBase64preview(String base64preview) {
this.base64preview = base64preview;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public String getFileSize() {
return fileSize;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
}
Provider for the above extension is as follows...
import java.io.IOException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Log;
public class IM_FileSharingExtension_Provider extends
ExtensionElementProvider<IM_FileSharing_Extension> implements
IM_Commons_Extension_FileSharing {
static final String TAG = "file_extension";
#Override
public IM_FileSharing_Extension parse(XmlPullParser parser, int initialDepth)
throws XmlPullParserException, IOException, SmackException {
IM_FileSharing_Extension fileExtension = null;
boolean stop = false;
String n = null;
int evtType;
String fileUrl = null;
String fileType = null;
String fileId = null;
String fileSize = null;
while (!stop) {
evtType = parser.getEventType();
n = parser.getName();
Log.d(TAG, "n:" + n + " evt:" + evtType);
switch (evtType) {
case XmlPullParser.START_TAG:
if (FILE_TAG.equals(n)) {
fileUrl = parser.getAttributeValue("", FILE_URL);
fileType = parser.getAttributeValue("", FILE_TYPE);
fileId = parser.getAttributeValue("", FILE_ID);
fileSize = parser.getAttributeValue("", FILE_SIZE);
evtType = parser.next();
}
if (FILE_PREVIEW_TAG.equals(parser.getName())) {
String basePreview = parser.nextText();
fileExtension = new IM_FileSharing_Extension(fileUrl,
fileType, basePreview, fileId, fileSize);
}
evtType = parser.next();
break;
case XmlPullParser.END_TAG:
if (parser.getName().equals(FILE_TAG)) {
return fileExtension;
}
evtType = parser.next();
}
}
return null;
}
}
And should be added in Provider manager as following....
ProviderManager.addExtensionProvider(
IM_Commons_Extension_FileSharing.FILE_TAG,
IM_Commons_Extension_FileSharing.XMLNS,
new IM_FileSharingExtension_Provider());

Log4j2 Custom RolloverStrategy

Is there a way to write a custom RolloverStrategy in log4j2? I want to delete old files over 14 days and log4j2 currently doesn't support it (https://issues.apache.org/jira/browse/LOG4J2-524).
I wrote a custom Strategy and tried to implement RolloverStrategy interface but I don't see it being triggered on file rollover.
I got it working...I had to annotate my class with #Plugin as shown below:
#org.apache.logging.log4j.core.config.plugins.Plugin(name = "DeleteMaxAgeFilesStrategy", category = "Core", printObject = true)
public class DeleteMaxAgeFilesStrategy implements RolloverStrategy {
private static final Logger logger = LoggerFactory.getLogger(DeleteMaxAgeFilesStrategy.class);
private static final int DEFAULT_MAX_AGE = 14;
private final int maxAgeIndex;
public DeleteMaxAgeFilesStrategy(int maxAgeIndex) {
this.maxAgeIndex = maxAgeIndex;
}
#Override public RolloverDescription rollover(RollingFileManager manager) throws SecurityException {
purgeMaxAgeFiles(maxAgeIndex, manager);
return null;
}
#PluginFactory
public static DeleteMaxAgeFilesStrategy createStrategy(
#PluginAttribute("maxAge") final String maxAge) {
int maxAgeIndex = DEFAULT_MAX_AGE;
if (maxAge != null) {
maxAgeIndex = Integer.parseInt(maxAge);
}
return new DeleteMaxAgeFilesStrategy(maxAgeIndex);
}
/**
* Purge files older than defined maxAge. If file older than current date - maxAge delete them or else keep it.
*
* #param maxAgeIndex maxAge Index
* #param manager The RollingFileManager
*/
private void purgeMaxAgeFiles(final int maxAgeIndex, final RollingFileManager manager) {
String filename = manager.getFileName();
File file = new File(filename);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -maxAgeIndex);
Date cutoffDate = cal.getTime();
if (file.getParentFile().exists()) {
filename = file.getName().replaceAll("\\..*", "");
File[] files = file.getParentFile().listFiles(
new StartsWithFileFilter(filename, false));
for (int i = 0; i < files.length; i++) {
try {
BasicFileAttributes attr = Files.readAttributes(files[i].toPath(), BasicFileAttributes.class);
if (new Date(attr.creationTime().toMillis()).before(cutoffDate)) {
files[i].delete();
}
} catch (Exception e) {
logger.error("Unable to delete old log files at rollover", e);
}
}
}
}
class StartsWithFileFilter implements FileFilter {
private final String startsWith;
private final boolean inclDirs;
public StartsWithFileFilter(String startsWith, boolean includeDirectories) {
super();
this.startsWith = startsWith.toUpperCase();
inclDirs = includeDirectories;
}
/*
* (non-Javadoc)
*
* #see java.io.FileFilter#accept(java.io.File)
*/
public boolean accept(File pathname) {
if (!inclDirs && pathname.isDirectory()) {
return false;
} else
return pathname.getName().toUpperCase().startsWith(startsWith);
}
}
}
and here's my log4j2.xml config:
<RollingFile name="FileOut" fileName="${sys:application.log.path}/restly-api.log"
filePattern="${sys:application.log.path}/restly-api-%d{yyyy-MM-dd}.gz">
<PatternLayout pattern="%date{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%t] [%logger{36}] %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
<DeleteMaxAgeFilesStrategy maxAge="14"/>
</RollingFile>
Note: Log4j2 has implemented this feature in 2.6 release

Primefaces dataExporter - inline PDF in new window without footer

I'm trying to use Primefaces's dataExporter component. I have two problems with it (for now):
In column footers of datatable I have a p:commandButton. What happens to me is that when I export datatable with dataExporter to PDF I can see that it added column footers to PDF and wrote something like this: javax.faces.component.UIPanel#9e08b9 (it just called toString of UIComponent I suppose). Is there any way to instruct dataExporter to ignore column footers?
I want to try to somehow open new window with generated PDF and show that PDF inline on a new page. I don't wont to see Download file prompt. Is this possible?
After some time, and coding I finally succeeded to make this work. Primefaces doesn't have this functions included so I have to override default behavior little bit.
First I created custom PDFExporter to skip footer printing:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.export.PDFExporter;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfPTable;
public class CustomPDFExporter extends PDFExporter {
#Override
protected void addColumnFacets(DataTable table, PdfPTable pdfTable,
ColumnType columnType) {
if (columnType == ColumnType.HEADER) {
super.addColumnFacets(table, pdfTable, columnType);
}
}
#Override
protected void writePDFToResponse(ExternalContext externalContext,
ByteArrayOutputStream baos, String fileName) throws IOException,
DocumentException {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("reportBytes", baos.toByteArray());
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("reportName", fileName);
}
}
As you can see, report data is added in session.
Now DataExporter of Primefaces should be rewriten:
import java.io.IOException;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.export.CSVExporter;
import org.primefaces.component.export.Exporter;
import org.primefaces.component.export.ExporterType;
import org.primefaces.component.export.XMLExporter;
import org.primefaces.context.RequestContext;
import asw.iis.common.ui.beans.DatatableBackingBean;
public class CustomDataExporter implements ActionListener, StateHolder {
private ValueExpression target;
private ValueExpression type;
private ValueExpression fileName;
private ValueExpression encoding;
private MethodExpression preProcessor;
private MethodExpression postProcessor;
private DatatableBackingBean<?> datatableBB;
public CustomDataExporter() {}
public CustomDataExporter(ValueExpression target, ValueExpression type, ValueExpression fileName, ValueExpression encoding,
MethodExpression preProcessor, MethodExpression postProcessor, DatatableBackingBean<?> datatableBB) {
this.target = target;
this.type = type;
this.fileName = fileName;
this.encoding = encoding;
this.preProcessor = preProcessor;
this.postProcessor = postProcessor;
this.datatableBB = datatableBB;
}
public void processAction(ActionEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
try {
datatableBB.stampaPreProcess();
ELContext elContext = context.getELContext();
String tableId = (String) target.getValue(elContext);
String exportAs = (String) type.getValue(elContext);
String outputFileName = (String) fileName.getValue(elContext);
String encodingType = "UTF-8";
if(encoding != null) {
encodingType = (String) encoding.getValue(elContext);
}
try {
Exporter exporter;
ExporterType exporterType = ExporterType.valueOf(exportAs.toUpperCase());
switch(exporterType) {
case XLS:
exporter = new ExcelExporter();
break;
case PDF:
exporter = new CustomPDFExporter();
break;
case CSV:
exporter = new CSVExporter();
break;
case XML:
exporter = new XMLExporter();
break;
default:
exporter = new CustomPDFExporter();
break;
}
UIComponent component = event.getComponent().findComponent(tableId);
if(component == null) {
throw new FacesException("Cannot find component \"" + tableId + "\" in view.");
}
if(!(component instanceof DataTable)) {
throw new FacesException("Unsupported datasource target:\"" + component.getClass().getName() + "\", exporter must target a PrimeFaces DataTable.");
}
DataTable table = (DataTable) component;
exporter.export(context, table, outputFileName, false, false, encodingType, preProcessor, postProcessor);
if ("pdf".equals(exportAs)) {
String path = ((ServletContext)(FacesContext.getCurrentInstance().getExternalContext().getContext())).getContextPath();
RequestContext.getCurrentInstance().execute("window.open('" + path + "/report.pdf', '_blank', 'dependent=yes, menubar=no, toolbar=no')");
} else {
context.responseComplete();
}
}
catch (IOException e) {
throw new FacesException(e);
}
}
finally {
((HttpServletRequest) context.getExternalContext().getRequest()).removeAttribute("vrstaStampe");
datatableBB.stampaPostProcess();
}
}
public boolean isTransient() {
return false;
}
public void setTransient(boolean value) {
}
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
target = (ValueExpression) values[0];
type = (ValueExpression) values[1];
fileName = (ValueExpression) values[2];
preProcessor = (MethodExpression) values[3];
postProcessor = (MethodExpression) values[4];
encoding = (ValueExpression) values[5];
datatableBB = (DatatableBackingBean<?>) values[6];
}
public Object saveState(FacesContext context) {
Object values[] = new Object[7];
values[0] = target;
values[1] = type;
values[2] = fileName;
values[3] = preProcessor;
values[4] = postProcessor;
values[5] = encoding;
values[6] = datatableBB;
return ((Object[]) values);
}
}
Main job here is to instantiate CustomPDFExporter, and open new window in case when report type is PDF.
Now I wrote simple Servlet to handle this request and print report data:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
byte[] b = (byte[]) req.getSession().getAttribute("reportBytes");
if (b == null) {
b = new byte[0];
}
resp.setContentType("application/pdf");
resp.setContentLength(b.length);
resp.getOutputStream().write(b);
req.getSession().removeAttribute("reportBytes");
}
}
This will configure HTTP header, and print bytes of report to output stream. Also it removes report bytes from session.
Finally, as I handle this printing from dynamically created menu button I add this action listener in code:
MenuItem item = ...;
ELContext el = FacesContext.getCurrentInstance().getELContext();
ExpressionFactory ef = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
ValueExpression typeEL = ef.createValueExpression(el, "#{startBean.reportType}", String.class);
ValueExpression fileEL = ef.createValueExpression(el, datasource, String.class);
ValueExpression targetEL = ef.createValueExpression(el, ":" + datatableId + ":datatableForm:datatable", String.class);
ValueExpression encodingEL = ef.createValueExpression(el, "ISO-8859-2", String.class);
CustomDataExporter de = new CustomDataExporter(targetEL, typeEL, fileEL, encodingEL, null, null, this);
item.setAjax(true);
item.addActionListener(de);

smart gwt required xml file structure

code is working properly.but i am not able to display the final data which is from "setDataURL("ds/test_data/employees.data.xml".so tel me where shud i create dis file and how to create.
package com.smartgwt.sample.showcase.client;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.fields.DataSourceFloatField;
import com.smartgwt.client.data.fields.DataSourceIntegerField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.tree.TreeGrid;
import com.smartgwt.client.widgets.tree.TreeGridField;
import com.google.gwt.i18n.client.NumberFormat;
import com.smartgwt.sample.showcase.shared.FieldVerifier;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Showcase implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);
/**
* This is the entry point method.
*/
public void onModuleLoad() {
RootPanel.get().add(getViewPanel());
}
public Canvas getViewPanel() {
EmployeeXmlDS employeesDS = EmployeeXmlDS.getInstance();
TreeGrid treeGrid = new TreeGrid();
treeGrid.setCanEdit(true);
treeGrid.setLoadDataOnDemand(false);
treeGrid.setWidth(500);
treeGrid.setHeight(400);
treeGrid.setDataSource(employeesDS);
treeGrid.setNodeIcon("icons/16/person.png");
treeGrid.setFolderIcon("icons/16/person.png");
treeGrid.setShowOpenIcons(false);
treeGrid.setShowDropIcons(false);
treeGrid.setClosedIconSuffix("");
treeGrid.setAutoFetchData(true);
TreeGridField nameField = new TreeGridField("Name");
TreeGridField jobField = new TreeGridField("Job");
TreeGridField salaryField = new TreeGridField("Salary");
salaryField.setCellFormatter(new CellFormatter() {
public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
if (value != null) {
NumberFormat nf = NumberFormat.getFormat("#,##0");
try {
return "$" + nf.format(((Number) value).longValue());
} catch (Exception e) {
return value.toString();
}
} else {
return null;
}
}
});
treeGrid.setFields(nameField, jobField, salaryField);
return treeGrid;
}
}
class EmployeeXmlDS extends DataSource {
private static EmployeeXmlDS instance = null;
public static EmployeeXmlDS getInstance() {
if (instance == null) {
instance = new EmployeeXmlDS("employeesDS");
}
return instance;
}
public EmployeeXmlDS(String id) {
setID(id);
setTitleField("Name");
setRecordXPath("/List/employee");
DataSourceTextField nameField = new DataSourceTextField("Name", "Name", 128);
DataSourceIntegerField employeeIdField = new DataSourceIntegerField("EmployeeId", "Employee ID");
employeeIdField.setPrimaryKey(true);
employeeIdField.setRequired(true);
DataSourceIntegerField reportsToField = new DataSourceIntegerField("ReportsTo", "Manager");
reportsToField.setRequired(true);
reportsToField.setForeignKey(id + ".EmployeeId");
reportsToField.setRootValue("1");
DataSourceTextField jobField = new DataSourceTextField("Job", "Title", 128);
DataSourceTextField emailField = new DataSourceTextField("Email", "Email", 128);
DataSourceTextField statusField = new DataSourceTextField("EmployeeStatus", "Status", 40);
DataSourceFloatField salaryField = new DataSourceFloatField("Salary", "Salary");
DataSourceTextField orgField = new DataSourceTextField("OrgUnit", "Org Unit", 128);
DataSourceTextField genderField = new DataSourceTextField("Gender", "Gender", 7);
genderField.setValueMap("male", "female");
DataSourceTextField maritalStatusField = new DataSourceTextField("MaritalStatus",
"Marital Status", 10);
setFields(nameField, employeeIdField, reportsToField, jobField, emailField, statusField,
salaryField, orgField, genderField, maritalStatusField);
setDataURL("ds/test_data/employees.data.xml");
setClientOnly(true);
}
}

Resources