All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.predic8.membrane.core.exchangestore.FileExchangeStore Maven / Gradle / Ivy

There is a newer version: 5.6.0
Show newest version
/* Copyright 2009, 2012 predic8 GmbH, www.predic8.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.predic8.membrane.core.exchangestore;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import com.predic8.membrane.annot.MCAttribute;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.core.Constants;
import com.predic8.membrane.core.exchange.AbstractExchange;
import com.predic8.membrane.core.http.AbstractBody;
import com.predic8.membrane.core.http.Message;
import com.predic8.membrane.core.http.MessageObserver;
import com.predic8.membrane.core.interceptor.Interceptor.Flow;
import com.predic8.membrane.core.rules.Rule;
import com.predic8.membrane.core.rules.RuleKey;
import com.predic8.membrane.core.rules.StatisticCollector;
import com.predic8.membrane.core.util.TextUtil;

/**
 * The output file is UTF-8 encoded.
 */
@MCElement(name="fileExchangeStore")
public class FileExchangeStore extends AbstractExchangeStore {

	private static Logger log = LoggerFactory.getLogger(FileExchangeStore.class
			.getName());

	private static AtomicInteger counter = new AtomicInteger();

	private static final String DATE_FORMAT = "'h'HH'm'mm's'ss'ms'SSS";

	private static final ThreadLocal dateFormat = new ThreadLocal();

	private static final String separator = System
			.getProperty("file.separator");

	public static final String MESSAGE_FILE_PATH = "message.file.path";

	private String dir;

	private File directory;

	private boolean raw = false;
	private boolean saveBodyOnly = false;
	private int maxDays = -1;

	private Timer oldFilesCleanupTimer;

	public void snap(final AbstractExchange exc, final Flow flow) {
		try {
			Message m = flow == Flow.REQUEST ? exc.getRequest() : exc.getResponse();
			// TODO: [fix me] support multi-snap
			// TODO: [fix me] snap message headers *here*, not in observer
			if (m != null)
				m.addObserver(new MessageObserver() {
					public void bodyRequested(AbstractBody body) {
					}
					public void bodyComplete(AbstractBody body) {
						snapInternal(exc, flow);
					}
				});
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private void snapInternal(AbstractExchange exc, Flow flow) {
		int fileNumber = counter.incrementAndGet();

		StringBuilder buf = getDirectoryNameBuffer(exc.getTime());

		directory = new File(buf.toString());
		directory.mkdirs();
		if (directory.exists() && directory.isDirectory()) {
			buf.append(separator);
			buf.append(getDateFormat().format(exc.getTime().getTime()));
			buf.append("-");
			buf.append(fileNumber);
			exc.setProperty(MESSAGE_FILE_PATH, buf.toString());
			buf.append("-");
			StringBuilder buf2 = new StringBuilder(buf);
			buf.append("Request.msg");
			buf2.append("Response.msg");
			try {
				switch (flow) {
				case REQUEST:
					writeFile(exc.getRequest(), buf.toString());
					break;
				case ABORT:
				case RESPONSE:
					if (exc.getResponse() != null)
						writeFile(exc.getResponse(), buf2.toString());
				}
			} catch (Exception e) {
				log.error("{}",e, e);
			}
		} else {
			log.error("Directory does not exists or file is not a directory: "+ buf.toString());
		}

	}

	private StringBuilder getDirectoryNameBuffer(Calendar time) {
		StringBuilder buf = new StringBuilder();
		buf.append(dir);
		buf.append(separator);
		buf.append(time.get(Calendar.YEAR));
		buf.append(separator);
		buf.append((time.get(Calendar.MONTH) + 1));
		buf.append(separator);
		buf.append(time.get(Calendar.DAY_OF_MONTH));
		return buf;
	}

	private static DateFormat getDateFormat() {
		DateFormat df = dateFormat.get();
		if (df == null) {
			df = new SimpleDateFormat(DATE_FORMAT);
			dateFormat.set(df);
		}
		return df;
	}

	private void writeFile(Message msg, String path) throws Exception {
		File file = new File(path);
		file.createNewFile();

		FileOutputStream os = new FileOutputStream(file);
		try {
			if (raw || !saveBodyOnly) {
				msg.writeStartLine(os);
				msg.getHeader().write(os);
				os.write(Constants.CRLF_BYTES);
			}

			if (msg.isBodyEmpty())
				return;

			if (raw)
				os.write(msg.getBody().getRaw());
			else {
				if (msg.isXML())
					os.write(TextUtil.formatXML(
							new InputStreamReader(msg.getBodyAsStream(), msg
									.getHeader().getCharset()))
									.getBytes(Constants.UTF_8));
				else
					os.write(msg.getBody().getContent());
			}
		} finally {
			os.close();
		}
	}

	public void initializeTimer() {
		if (this.maxDays < 0) {
			return; // don't do anything if this feature is deactivated
		}

		oldFilesCleanupTimer = new Timer("Clean up old log files", true);

		// schedule first run for the night
		Calendar firstRun = Calendar.getInstance();
		firstRun.set(Calendar.HOUR_OF_DAY, 3);
		firstRun.set(Calendar.MINUTE, 14);

		// schedule for the next day if the scheduled execution time is before now
		if (firstRun.before(Calendar.getInstance()))
			firstRun.add(Calendar.DAY_OF_MONTH, 1);

		oldFilesCleanupTimer.scheduleAtFixedRate(
				new TimerTask() {
					@Override
					public void run() {
						try {
							deleteOldFolders(Calendar.getInstance());
						} catch (IOException e) {
							log.error("", e);
						}
					}
				},
				firstRun.getTime(),
				24*60*60*1000		// one day
				);
	}

	public void deleteOldFolders(Calendar now) throws IOException {
		if (this.maxDays < 0) {
			return; // don't do anything if this feature is deactivated
		}

		Calendar threshold = now;
		threshold.add(Calendar.DAY_OF_MONTH, -maxDays);

		ArrayList folders3 = new DepthWalker(3).getDirectories(new File(dir));

		ArrayList deletion = new ArrayList();

		for (File f : folders3) {

			int day =  Integer.parseInt(f.getName());
			int mon =  Integer.parseInt(f.getParentFile().getName());
			int year = Integer.parseInt(f.getParentFile().getParentFile().getName());
			Calendar folderTime = Calendar.getInstance();
			folderTime.clear();
			folderTime.set(year, mon-1, day);
			if (folderTime.before(threshold)) {
				deletion.add(f);
			}
		}

		for (File d : deletion) {
			FileUtils.deleteDirectory(d);
		}
	}

	public AbstractExchange[] getExchanges(RuleKey ruleKey) {
		throw new RuntimeException(
				"Method getExchanges() is not supported by FileExchangeStore");
	}

	public int getNumberOfExchanges(RuleKey ruleKey) {
		throw new RuntimeException(
				"Method getNumberOfExchanges() is not supported by FileExchangeStore");
	}

	public void remove(AbstractExchange exchange) {
		throw new RuntimeException(
				"Method remove() is not supported by FileExchangeStore");
	}

	public void removeAllExchanges(Rule rule) {
		throw new RuntimeException(
				"Method removeAllExchanges() is not supported by FileExchangeStore");
	}

	public StatisticCollector getStatistics(RuleKey ruleKey) {
		return null;
	}

	public Object[] getAllExchanges() {
		return null;
	}

	public Object[] getLatExchanges(int count) {
		return null;
	}

	public List getAllExchangesAsList() {
		return null;
	}

	public void removeAllExchanges(AbstractExchange[] exchanges) {
		// ignore
	}

	public String getDir() {
		return dir;
	}
	/**
	 * @description Directory where the exchanges are saved.
	 * @example logs
	 */
	@Required
	@MCAttribute
	public void setDir(String dir) {
		this.dir = dir;
	}

	public boolean isRaw() {
		return raw;
	}
	/**
	 * @default false
	 * @description If this is true, headers will always be printed (overriding
	 *              saveBodyOnly) and the body of the exchange won't be
	 *              formatted nicely.
	 * @example true
	 */
	@MCAttribute
	public void setRaw(boolean raw) {
		this.raw = raw;
	}

	public boolean isSaveBodyOnly() {
		return saveBodyOnly;
	}
	/**
	 * @default false
	 * @description If this is true, no headers will be written to the exchange
	 *              log files.
	 * @example true
	 */
	@MCAttribute
	public void setSaveBodyOnly(boolean saveBodyOnly) {
		this.saveBodyOnly = saveBodyOnly;
	}

	public int getMaxDays() {
		return maxDays;
	}
	/**
	 * @default -1
	 * @description Number of days for which exchange logs are preserved. A
	 *              value smaller than zero deactivates the deletion of old
	 *              logs.
	 * @example 60
	 */
	@MCAttribute
	public void setMaxDays(int maxDays) {
		this.maxDays = maxDays;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy