Java tutorial
/* * Source code in 3rd-party is licensed and owned by their respective * copyright holders. * * All other source code is copyright Tresys Technology and licensed as below. * * Copyright (c) 2012 Tresys Technology LLC, Columbia, Maryland, USA * * This software was developed by Tresys Technology LLC * with U.S. Government sponsorship. * * 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.tresys.jalop.utils.jnltest; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.xml.soap.MimeHeaders; import org.apache.log4j.Logger; import org.beepcore.beep.core.BEEPException; import org.json.simple.parser.ParseException; import com.tresys.jalop.jnl.ConnectAck; import com.tresys.jalop.jnl.ConnectNack; import com.tresys.jalop.jnl.Connection; import com.tresys.jalop.jnl.ConnectionHandler; import com.tresys.jalop.jnl.ConnectionRequest; import com.tresys.jalop.jnl.DigestPair; import com.tresys.jalop.jnl.DigestStatus; import com.tresys.jalop.jnl.Publisher; import com.tresys.jalop.jnl.PublisherSession; import com.tresys.jalop.jnl.RecordInfo; import com.tresys.jalop.jnl.RecordType; import com.tresys.jalop.jnl.Role; import com.tresys.jalop.jnl.Session; import com.tresys.jalop.jnl.SourceRecord; import com.tresys.jalop.jnl.SubscribeRequest; import com.tresys.jalop.jnl.Subscriber; import com.tresys.jalop.jnl.SubscriberSession; import com.tresys.jalop.jnl.exceptions.JNLException; import com.tresys.jalop.jnl.impl.ContextImpl; import com.tresys.jalop.utils.jnltest.Config.Config; import com.tresys.jalop.utils.jnltest.Config.ConfigurationException; import com.tresys.jalop.utils.jnltest.Config.PeerConfig; /** * Main class for JNLTest */ public class JNLTest implements Subscriber, Publisher, ConnectionHandler { /** Logger for this class */ private static final Logger logger = Logger.getLogger(JNLTest.class); /** * Configuration for this instance of JNLTest. */ private final Config config; /** * From Sessions to associated {@link SubscriberImpl} */ private final Map<Session, Map<RecordType, SubscriberImpl>> sessMap = new HashMap<Session, Map<RecordType, SubscriberImpl>>(); /** * From Sessions to associated {@link PublisherImpl} */ private final Map<Session, Map<RecordType, PublisherImpl>> pubSessMap = new HashMap<Session, Map<RecordType, PublisherImpl>>(); /** * ConnectionHandler implementation */ private ConnectionHandler connectionHandler; /** * Counter to keep track of the last used serial Id for log records */ private long latestLogSID; /** * Counter to keep track of the last used serial Id for audit records */ private long latestAuditSID; /** * Counter to keep track of the last used serial Id for journal records */ private long latestJournalSID; /** * Create a JNLTest object based on the specified configuration. * * @param config * A {@link Config} */ public JNLTest(final Config config) { this.config = config; } /** * @return the latestLogSID */ public long getLatestLogSID() { return latestLogSID; } /** * @param latestLogSID the latestLogSID to set */ public void setLatestLogSID(final long latestLogSID) { this.latestLogSID = latestLogSID; } /** * @return the latestAuditSID */ public long getLatestAuditSID() { return latestAuditSID; } /** * @param latestAuditSID the latestAuditSID to set */ public void setLatestAuditSID(final long latestAuditSID) { this.latestAuditSID = latestAuditSID; } /** * @return the latestJournalSID */ public long getLatestJournalSID() { return latestJournalSID; } /** * @param latestJournalSID the latestJournalSID to set */ public void setLatestJournalSID(final long latestJournalSID) { this.latestJournalSID = latestJournalSID; } /** * Main entry point for the JNLTest program. This takes a single argument, * the full path to a configuration file to use. * * @param args * The command line arguments * @throws BEEPException * @throws JNLException */ public static void main(final String[] args) throws JNLException, BEEPException { if (args.length != 1) { System.err.println("Must specify exactly one argument that is " + " the configuration file to use"); System.exit(1); } Config config; try { config = Config.parse(args[0]); } catch (final IOException e) { System.err.println("Caught IO exception: " + e.getMessage()); System.exit(1); throw new RuntimeException("Failed to call exit()"); } catch (final ParseException e) { System.err.print(e.toString()); System.exit(1); throw new RuntimeException("Failed to call exit()"); } catch (final ConfigurationException e) { System.err.println("Exception processing the config file: " + e.getMessage()); System.exit(1); throw new RuntimeException("Failed to call exit()"); } final JNLTest jt = new JNLTest(config); System.out.println("Started Connections"); jt.start(); } /** * Once a {@link JNLTest} object has a config, call this method to connect to the * remotes, or wait for incoming connections. * @throws BEEPException * @throws JNLException */ private void start() throws JNLException, BEEPException { if (!this.config.isListener()) { if (this.config.getRole() == Role.Subscriber) { final ContextImpl contextImpl = new ContextImpl(null, this, null, this.config.getPendingDigestTimeout(), config.getPendingDigestMax(), "agent", null, null, config.getSslConfiguration()); contextImpl.subscribe(this.config.getAddress(), this.config.getPort(), this.config.getRecordTypes().toArray(new RecordType[0])); } else if (this.config.getRole() == Role.Publisher) { final ContextImpl contextImpl = new ContextImpl(this, null, null, this.config.getPendingDigestTimeout(), config.getPendingDigestMax(), "agent", null, null, config.getSslConfiguration()); contextImpl.publish(this.config.getAddress(), this.config.getPort(), this.config.getRecordTypes().toArray(new RecordType[0])); } this.logger.info("Waiting: " + config.getSessionTimeout()); synchronized (this) { try { this.wait(config.getSessionTimeout().getTime()); } catch (final InterruptedException e) { this.logger.info("Someone woke us up"); } } } else { this.connectionHandler = new ConnectionHandlerImpl(this.config.getPeerConfigs()); Publisher publisher = null; Subscriber subscriber = null; for (final InetAddress add : this.config.getPeerConfigs().keySet()) { final PeerConfig pc = this.config.getPeerConfigs().get(add); if (!pc.getPublishAllow().isEmpty()) { publisher = this; } if (!pc.getSubscribeAllow().isEmpty()) { subscriber = this; } } final ContextImpl contextImpl = new ContextImpl(publisher, subscriber, this, this.config.getPendingDigestTimeout(), this.config.getPendingDigestMax(), "agent", null, null, config.getSslConfiguration()); contextImpl.listen(this.config.getAddress(), this.config.getPort()); } } @Override public SubscribeRequest getSubscribeRequest(final SubscriberSession sess) { // TODO: All the code here to manage the maps should really be happening in the // connection handler callbacks, but the library isn't generating those events // quite yet. Map<RecordType, SubscriberImpl> map; synchronized (this.sessMap) { map = this.sessMap.get(sess); if (map == null) { map = new HashMap<RecordType, SubscriberImpl>(); this.sessMap.put(sess, map); } } SubscriberImpl sub; synchronized (map) { sub = map.get(sess.getRecordType()); if (sub == null) { sub = new SubscriberImpl(sess.getRecordType(), this.config.getOutputPath(), sess.getAddress(), this); map.put(sess.getRecordType(), sub); } } return sub.getSubscribeRequest(sess); } @Override public boolean notifySysMetadata(final SubscriberSession sess, final RecordInfo recordInfo, final InputStream sysMetaData) { return this.sessMap.get(sess).get(sess.getRecordType()).notifySysMetadata(sess, recordInfo, sysMetaData); } @Override public boolean notifyAppMetadata(final SubscriberSession sess, final RecordInfo recordInfo, final InputStream appMetaData) { return this.sessMap.get(sess).get(sess.getRecordType()).notifyAppMetadata(sess, recordInfo, appMetaData); } @Override public boolean notifyPayload(final SubscriberSession sess, final RecordInfo recordInfo, final InputStream payload) { return this.sessMap.get(sess).get(sess.getRecordType()).notifyPayload(sess, recordInfo, payload); } @Override public boolean notifyDigest(final SubscriberSession sess, final RecordInfo recordInfo, final byte[] digest) { return this.sessMap.get(sess).get(sess.getRecordType()).notifyDigest(sess, recordInfo, digest); } @Override public boolean notifyDigestResponse(final SubscriberSession sess, final Map<String, DigestStatus> statuses) { return this.sessMap.get(sess).get(sess.getRecordType()).notifyDigestResponse(sess, statuses); } @Override public SourceRecord getNextRecord(final PublisherSession sess, final String lastSerialId) { return this.pubSessMap.get(sess).get(sess.getRecordType()).getNextRecord(sess, lastSerialId); } @Override public SourceRecord onJournalResume(final PublisherSession sess, final String serialId, final long offset, final MimeHeaders headers) { setPubMap(sess); return this.pubSessMap.get(sess).get(sess.getRecordType()).onJournalResume(sess, serialId, offset, headers); } @Override public boolean onSubscribe(final PublisherSession sess, final String serialId, final MimeHeaders headers) { setPubMap(sess); return this.pubSessMap.get(sess).get(sess.getRecordType()).onSubscribe(sess, serialId, headers); } private void setPubMap(final PublisherSession sess) { // TODO: All the code here to manage the maps should really be happening in the // connection handler callbacks, but the library isn't generating those events // quite yet. Map<RecordType, PublisherImpl> map; synchronized (this.pubSessMap) { map = this.pubSessMap.get(sess); if (map == null) { map = new HashMap<RecordType, PublisherImpl>(); this.pubSessMap.put(sess, map); } } synchronized (map) { if (map.get(sess.getRecordType()) == null) { map.put(sess.getRecordType(), new PublisherImpl(this.config.getInputPath(), sess.getRecordType())); } } } @Override public boolean onRecordComplete(final PublisherSession sess, final String serailId, final SourceRecord record) { return this.pubSessMap.get(sess).get(sess.getRecordType()).onRecordComplete(sess, serailId, record); } @Override public boolean sync(final PublisherSession sess, final String serialId, final MimeHeaders headers) { return this.pubSessMap.get(sess).get(sess.getRecordType()).sync(sess, serialId, headers); } @Override public void notifyDigest(final PublisherSession sess, final String serialId, final byte[] digest) { this.pubSessMap.get(sess).get(sess.getRecordType()).notifyDigest(sess, serialId, digest); } @Override public void notifyPeerDigest(final PublisherSession sess, final Map<String, DigestPair> digestPairs) { this.pubSessMap.get(sess).get(sess.getRecordType()).notifyPeerDigest(sess, digestPairs); } @Override public Set<ConnectError> handleConnectionRequest(final boolean rejecting, final ConnectionRequest connRequest) { return this.connectionHandler.handleConnectionRequest(rejecting, connRequest); } @Override public void sessionClosed(final Session sess) { this.connectionHandler.sessionClosed(sess); } @Override public void connectionClosed(final Connection conn) { this.connectionHandler.connectionClosed(conn); } @Override public void connectAck(final Session sess, final ConnectAck ack) { this.connectionHandler.connectAck(sess, ack); } @Override public void connectNack(final Session sess, final ConnectNack nack) { this.connectionHandler.connectNack(sess, nack); } }