Dear all,
mec_as2 is a very good opensource product compared to other ones that even not handle data compression (I need it !).
The only claim I can do is that mec_as2 is not multi-local site. (I need also it !)
As far the stepstone does not allow this, I read forum about this subject. Some idea for run as Windows service, and some other about using Xvnc on Linux.
I tried with Xvnc and works well, please find attached the /etc/init.d/mec_as2 script for multi local use on Linux.
Example :
/home/mec_as2_1
/home/mec_as2_2
You must create ~/.vnc/passwd for each accound with 'vncpasswd' (for vncviewer clients).
It is obvious that each mec_as2 must use differents ports for all, including AS2 http requests ( 8080, 8081, ...).
A good idea is to NAT http://my.as2.service.com:4080 to
your as2 host in LAN(or DMZ) on 8080, and http://my.as2.service.com:4081 to your as2 host in LAN (or DMZ) on 8081.
Here is the script I can't see as attachment...
#!/bin/bash
#
# chkconfig: - 91 35
# description: Starts and stops vncserver. \
# used to provide remote X administration services.\
# Starts ans stops mec_as2 pseudo multi-local AS2 services
# Source function library.
. /etc/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
# Base directory where mec_as2 is installed in each account (MUST be same in all)
AS2BASEDIR="AS2/"
# Displays and accounts: display1:account1:display2:account2 ...
VNCSERVERS="20:mec_as2_1:21:mec_as2_2"
prog=$"VNC server"
startVnc() {
gprintf "Starting %s: " "$prog"
ulimit -S -c 0 >/dev/null 2>&1
RETVAL=0
for display in ${VNCSERVERS}
do
gprintf "%s " "${display}"
initlog $INITLOG_ARGS -c \
"su ${display##*:} -c \"cd ~${display##*:} && [ -f .vnc/passwd ] && vncserver :${display%%:*}\""
RETVAL=$?
[ "$RETVAL" -ne 0 ] && break
done
[ "$RETVAL" -eq 0 ] && success $"vncserver startup" || \
failure "vncserver start"
echo
[ "$RETVAL" -eq 0 ] && touch /var/lock/subsys/vncserver
}
startAs2() {
gprintf "Starting %s: " "mec_as2"
for display in ${VNCSERVERS}
do
su - ${display##*:} -c "cd ~${display##*:}/$AS2BASEDIR ; ./mec_as2_start.sh >& log/start.log &"
RETVAL=$?
[ "$RETVAL" -ne 0 ] && break
done
[ "$RETVAL" -eq 0 ] && success $"mec_as2 startup" || \
failure "mec_as2 start"
echo
[ "$RETVAL" -eq 0 ] && touch /var/lock/subsys/mec_as2
}
stopVnc() {
gprintf "Shutting down %s: " "$prog"
for display in ${VNCSERVERS}
do
gprintf "%s " "${display}"
unset BASH_ENV ENV
initlog $INITLOG_ARGS -c \
"su ${display##*:} -c \"vncserver -kill :${display%%:*} >& /dev/null\""
done
RETVAL=$?
[ "$RETVAL" -eq 0 ] && success $"vncserver shutdown" || \
failure "vncserver shutdown"
echo
[ "$RETVAL" -eq 0 ] && rm -f /var/lock/subsys/vncserver
}
stopAs2() {
gprintf "Shutting down %s: " "mec_as2"
for display in ${VNCSERVERS}
do
su - ${display##*:} -c "cd ~${display##*:}/$AS2BASEDIR ; ./mec_as2_stop.sh >& log/stop.log"
RETVAL=$?
[ "$RETVAL" -ne 0 ] && break
done
[ "$RETVAL" -eq 0 ] && success $"mec_as2 shutdown" || \
failure "mec_as2 shutdown"
echo
[ "$RETVAL" -eq 0 ] && \rm /var/lock/subsys/mec_as2
}
# See how we were called.
case "$1" in
start)
startVnc && startAs2
;;
stop)
($0 statusas2 && stopAs2); ($0 status && stopVnc)
;;
startas2)
startAs2
;;
stopas2)
($0 statusas2 && stopAs2)
;;
restart|reload)
stop
start
;;
condrestart)
if [ -f /var/lock/subsys/mec_as2 ]; then
stopAs2
if [ -f /var/lock/subsys/vncserver ]; then
stopVnc
startVnc
fi
$0 status && startAs2
fi
;;
status)
status Xvnc
;;
statusas2)
test -f /var/lock/subsys/mec_as2
;;
*)
gprintf "Usage: %s {start|stop|restart|condrestart|status|startas2|stopas2|statusas2}\n" "$0"
exit 1
esac
How to attach mec_as2 consoles
Now your AS2 servers are running in virtual X windows,
you can attach to mec_as2_1 with :
vncviewer your_as2_host:20
and to mec_as2_2 with :
vncviewer your_as2_host:21
typo in the multi-local script
Please read in script :
_____________________________
[...]
restart|reload)
$0 stop
$0 start
;;
[...]
______________________________
instead of :
[...]
restart|reload)
stop
start
;;
[...]
______________________________
I forgot something important
In each mec_as2_start.sh script in all user account,
the DISPLAY must be set up just before java launch
In the example:
mec_as2_1 :
[...]
DISPLAY=localhost:20.0; export DISPLAY
java -Xmx192M -Xms92M -classpath $CLASSPATH de.mendelson.comm.as2.AS2
mec_as2_2 :
[...]
DISPLAY=localhost:21.0; export DISPLAY
java -Xmx192M -Xms92M -classpath $CLASSPATH de.mendelson.comm.as2.AS2
crownedgrouse, superb. Would
crownedgrouse,
superb. Would you mind sending me a document where all this is collected? I would like to add it to the m-e-c as2 documentation, there exists a part "community guides" in the integrated help system. It would be part of the next releases then.
Regards
sh at mendelson dot de
Heller
Sure
Sure, but what kind of format ?
I like docbook.
crownedgrouse, please send
crownedgrouse,
please send it as plain text or html. All our help files are in the directory as2help/html. I will paste your data into the help template and integrate it into the online help for the next release.
Regards
Heller
I dont see where you specify
I dont see where you specify the listening port for the server, I assume this is editing the jetty.xml file ?
I'm looking to do the same as you, i'm going to do it a little different to you, perhaps we can change notes at the end? :-)
yes in jetty.xml
but be aware that you MUST change ports in source code and re-compil for second and other servers :
3333 DB server (HSQL) remote port
16423 JNDI proxy or registry
16023 JNDI proxy or registry
1099 RMI used for sync/blocking client server communication, will be removed once MINA supports sync connections (Milestone1)
1235 MINA client-server communication
I add to the documentation I sent to heller (that may be add to community guide) it would be easier to have an environnement variable to offset all ports of m-e-c AS2 ($MEC_AS2_PORT_OFFSET or somewhat) without any re-compilation.
Good news : Heller tolds me this morning that real multi-local m-e-c AS2 will be done in next release if nothing more urgent would be done !!!
would be better still if it
would be better still if it was held in a properties file (to make implementation a few seconds) or xml files outside of the app (if done the right way) :-)
Oh that's interesting!...
Oh that's interesting!... seems multiple local stations existed back in b10 :-o
http://www.mec-community.com/node/52
Unfortunately the URL on that page no longer works, seems that developer did a lot of work too.
well here are my changes...
in the root of the mec-as2 folder is another folder called config, you need to add this to your class path. It contains ONE file mecpreferences.xml
This file contains ANY key that you want to overload from the PreferencesAS2 class. For example mine looks like this
<xml version="1.0" encoding="UTF-8"?>
<settings>
<serverrmiport>1099</serverrmiport>
<dbport>3333</dbport>
<jndiport>16423</jndiport>
<mqproxyport>16023</mqproxyport>
<clientservercommport>1235</clientservercommport>
</settings>
You (optionally) need an updated build.xml, mine looks like this
<?xml version="1.0" encoding="UTF-8"?>
<!--
mec-as2 build descriptor
$Id: build.xml,v 1.5 2007/01/29 09:16:45 amir Exp $
Author: $Author: amir $
-->
<project name="mecas2" default="build">
<property file="build.properties"/>
<path id="all.classpath">
<fileset dir="${MAIL_HOME}/" includes="*.jar"/>
<fileset dir="${MAIL_HOME}/lib/" includes="*.jar"/>
<fileset dir="${MEC_HOME}/jlib/" includes="*.jar"/>
<fileset dir="${MEC_HOME}/jlib/mina/" includes="*.jar"/>
<fileset dir="${MEC_HOME}/jlib/jms/" includes="*.jar"/>
<fileset dir="${MEC_HOME}/jetty/" includes="*.jar"/>
<fileset dir="${MEC_HOME}/jetty/lib/" includes="*.jar"/>
<fileset dir="${DBCP_HOME}" includes="*.jar"/>
</path>
<target name="init">
<available file="src" property="build.java"/>
</target>
<target name="javadoc">
<javadoc packagenames="de.*"
encoding="8859_1"
sourcepath="src"
classpathref="all.classpath"
defaultexcludes="no"
public="true"
destdir="docs/api"
author="true"
version="true"
use="true"
verbose = "false"
windowtitle="MEC-AS2 Documentation">
</javadoc>
</target>
<target name="build" depends="init,build.java"
description="Build the app">
</target>
<target name="build.java" if="build.java" description="Build any java code">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes"
debug="yes"
encoding="8859_1"
nowarn="true"
verbose="no"
deprecation="false">
<classpath refid="all.classpath"/>
</javac>
<copy todir="build/classes/de/mendelson/comm/as2/client/">
<fileset dir="./src/de/mendelson/comm/as2/client/">
<exclude name="**/*.java"/>
</fileset>
</copy>
<!-- copy images and others files needed at runtime -->
<copy todir="build/classes/de/">
<fileset dir="./src/de/">
<exclude name="**/*.java"/>
<exclude name="**/*.form"/>
</fileset>
</copy>
<mkdir dir="build/WEB-INF/lib"/>
<jar jarfile="build/WEB-INF/lib/${MEC_JAR}"
basedir="build/classes"
compress="false">
</jar>
</target>
<target name="clean" depends="init"
description="Cleans out the generated directories">
<delete dir="build"/>
</target>
<target name="deploy"
depends="build"
description="deploys newly compiled code">
<copy file="build/WEB-INF/lib/${MEC_JAR}" todir="${MEC_HOME}"/>
<copy file="config/mecpreferences.xml" todir="${MEC_HOME}/config"/>
<war update="yes" destfile="${MEC_HOME}/jetty/webapps/${project}.war">
<fileset dir="build"/>
<exclude name="build/classes"/>
</war>
</target>
</project>
Finally you need an updated PreferencesAS2.java file. Currently mine looks like this but I am cleaning it up, should work OK though.
//$Header: /cvsroot/mec-as2/b23/de/mendelson/comm/as2/preferences/PreferencesAS2.java,v 1.1 2008/05/16 11:09:56 heller Exp $
package de.mendelson.comm.as2.preferences;
import de.mendelson.comm.as2.AS2ServerVersion;
import de.mendelson.util.MecResourceBundle;
// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
// SAX
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.prefs.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.awt.*;
import java.io.File;
import java.io.InputStream;
/*
* Copyright (C) mendelson-e-commerce GmbH Berlin Germany
*
* This software is subject to the license agreement set forth in the license.
* Please read and agree to all terms before using this software.
* Other product and brand names are trademarks of their respective owners.
*/
/**
* Class to manage the preferences of the AS2 server
*
* @author S.Heller
* @version $Revision: 1.1 $
*/
public class PreferencesAS2 {
class PreferenceHandler extends DefaultHandler {
StringBuffer textBuffer;
// SAX callback implementations from ContentHandler, ErrorHandler, etc.
//===========================================================
// SAX DocumentHandler methods
//===========================================================
public void startDocument() throws SAXException {
System.out.println("configuration file loaded, starting parse");
}
public void endDocument() throws SAXException {
System.out.println("finished parsing configuration file");
System.out.println(MEC_SETTINGS.toString());
}
public void endElement(String namespaceURI,
String sName,
String qName) throws SAXException {
MEC_SETTINGS.put(qName, textBuffer.toString());
}
public void startElement(String namespaceURI,
String sName,
String qName,
Attributes attrs) throws SAXException {
textBuffer = new StringBuffer();
}
public void characters(char[] buf, int offset, int len)
throws SAXException {
String s = new String(buf, offset, len);
if (null == textBuffer) {
textBuffer = new StringBuffer(s);
} else {
textBuffer.append(s);
}
}
}
// set out version here
public static final long serialVersionUID = 1L;
/**
* Logger.
*/
private static final Logger LOGGER
= Logger.getLogger("PreferencesAS2");
static MecResourceBundle rb;
static {
//load resource bundle
try {
rb = (MecResourceBundle) ResourceBundle.getBundle(
ResourceBundlePreferences.class.getName());
} catch (MissingResourceException e) {
throw new RuntimeException("Oops..resource bundle "
+ e.getClassName()
+ " not found.");
}
}
private final int OS_WIN = 1;
private final int OS_OTHER = 2;
/**
* Error exit code.
*/
private final int INT_ERROR = -1;
/**
* Magic string(s).
*/
private final String STR_EIGHT_HUNDRED = "800";
/**
* Magic string(s).
*/
private final String STR_SIX_HUNDRED = "600";
/**
* Magic string(s).
*/
private final String STR_DE = "de";
/**
* Magic string(s).
*/
private final String STR_EN = "en";
/**
* Magic string(s).
*/
public static final String STR_WIN = "win";
/**
* Position of the client frame X
*/
public static final String FRAME_X = "frameguix";
/**
* Position of the client frame Y
*/
public static final String FRAME_Y = "frameguiy";
/**
* Position of the client frame height
*/
public static final String FRAME_HEIGHT = "frameguiheight";
/**
* Position of the IDE frame WIDTH
*/
public static final String FRAME_WIDTH = "frameguiwidth";
/**
* Language to use for the software localization
*/
public static final String LANGUAGE = "language";
/**
* the actual used server to connect to
*/
public static final String SERVER_HOST = "serverhost";
/**
* The RMI connection port
*/
public static final String SERVER_RMI_PORT = "serverrmiport";
/**
* RMI service
*/
public static final String SERVER_RMI_SERVICE = "rmiservice";
/**
* DB server
*/
public static final String SERVER_DB_PORT = "dbport";
/**
* client server comm port
*/
public static final String CLIENTSERVER_COMM_PORT = "clientservercommport";
/**
* Directory the messageparts are stored in
*/
public static final String DIR_MSG = "dirmsg";
public static final String ASYNC_MDN_TIMEOUT = "asyncmdntimeout";
/**
* keystore for user defined certs in https
*/
public static final String KEYSTORE_HTTPS_SEND = "httpsendkeystore";
/**
* password for user defined certs keystore in https
*/
public static final String
KEYSTORE_HTTPS_SEND_PASS = "httpsendkeystorepass";
/**
* The configuration file.
*/
public static final String DEFAULT_CONFIG = "mecpreferences.xml";
/**
* password for the encryption/signature keystore
*/
public static final String KEYSTORE_PASS = "keystorepass";
public static final String PROXY_HOST = "proxyhost";
public static final String PROXY_PORT = "proxyport";
public static final String AUTH_PROXY_USER = "proxyuser";
public static final String AUTH_PROXY_PASS = "proxypass";
public static final String AUTH_PROXY_USE = "proxyuseauth";
public static final String PROXY_USE = "proxyuse";
public static final String AUTO_MSG_DELETE = "automsgdelete";
public static final String AUTO_MSG_DELETE_OLDERTHAN
= "automsgdeleteolderthan";
public static final String STR_SPACE = " ";
public static final String AUTO_MSG_DELETE_LOG = "automsgdeletelog";
public static final String JNDI_PORT = "jndiport";
public static final String MQ_PROXY_PORT = "mqproxyport";
public static final String RECEIPT_PARTNER_SUBDIR = "receiptpartnersubdir";
public static final String HTTP_SEND_TIMEOUT = "httpsendtimeout";
public static final String ERR_UNABLE_TO_LOAD_XML
= "Unable to load preferences XML file";
/**
* Settings stored for the user
*/
private Preferences preferences = null;
/**
* Magic string(s).
*/
private String STR_USRDIR = "user.dir";
/**
* name of the operation system
*/
private String os = System.getProperty("os.name");
/**
* this is where we save the settings
*/
private static final Map MEC_SETTINGS = new HashMap();
/**
* Initialize the preferences
*/
public PreferencesAS2() {
//on windows systems it is common to use as root.
//On Linux/Unix systems it is ok
//for only one user (lets say user account "mendelson" )
if (OS_WIN == getOS()) {
this.preferences =
Preferences.systemNodeForPackage(AS2ServerVersion.class);
} else {
this.preferences =
Preferences.userNodeForPackage(AS2ServerVersion.class);
}
// load in config on start-up.
if (MEC_SETTINGS.isEmpty())
loadConfig();
}
/**
* loads in the defaults from an XML file.
*/
public void loadConfig() {
// Get SAX Parser Factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// Turn on validation, and turn off namespaces
factory.setValidating(false);
factory.setNamespaceAware(false);
try {
SAXParser parser = factory.newSAXParser();
InputStream stream = getClass().getClassLoader()
.getResourceAsStream(DEFAULT_CONFIG);
parser.parse(stream, new PreferenceHandler());
} catch (Exception e) {
LOGGER.log(Level.SEVERE, ERR_UNABLE_TO_LOAD_XML
+ STR_SPACE
+ DEFAULT_CONFIG);
LOGGER.log(Level.SEVERE, e.getMessage());
System.exit(INT_ERROR);
}
}
/**
* Returns the localized preference
*/
public static String getLocalizedName(final String KEY) {
return rb.getResourceString(KEY);
}
/**
* Returns the default value for the key
*
* @param KEY key to store properties with in the preferences
*/
private String getDefaultValue(final String KEY) {
if (MEC_SETTINGS.containsKey(KEY)) {
return (String) MEC_SETTINGS.get(KEY);
}
if (KEY.equals(FRAME_X)) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dialogSize = new Dimension(
Integer.parseInt(getDefaultValue(FRAME_WIDTH)),
Integer.parseInt(getDefaultValue(FRAME_HEIGHT)));
return (String.valueOf((screenSize.width - dialogSize.width) / 2));
}
if (KEY.equals(FRAME_Y)) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dialogSize = new Dimension(
Integer.parseInt(getDefaultValue(FRAME_WIDTH)),
Integer.parseInt(getDefaultValue(FRAME_HEIGHT)));
return (String.valueOf((screenSize.height - dialogSize.height) / 2));
}
if (KEY.equals(FRAME_WIDTH)) {
return (STR_EIGHT_HUNDRED);
}
if (KEY.equals(FRAME_HEIGHT)) {
return (STR_SIX_HUNDRED);
}
//language used for the localization
if (KEY.equals(this.LANGUAGE)) {
if (Locale.getDefault().equals(Locale.GERMANY)) {
return (STR_DE);
}
//default is always english
return (STR_EN);
}
//RMI port for client-server communication
if (KEY.equals(SERVER_RMI_PORT)) {
return ("1099");
}
//DB port for the server
if (KEY.equals(SERVER_DB_PORT)) {
return ("3333");
}
//RMI service provided by the rmi server
if (KEY.equals(SERVER_RMI_SERVICE)) {
return ("MEC_AS2");
}
//server to connect to by default
if (KEY.equals(SERVER_HOST)) {
return ("localhost");
}
//message part directory
if (KEY.equals(DIR_MSG)) {
return (new File(System.getProperty(STR_USRDIR)).getAbsolutePath()
+ File.separator + "messages");
}
if (KEY.equals(this.KEYSTORE_HTTPS_SEND)) {
return ("jetty/etc/keystore");
}
if (KEY.equals(this.KEYSTORE_HTTPS_SEND_PASS)) {
return ("changeit");
}
if (KEY.equals(this.PROXY_HOST)) {
return ("localhost");
}
if (KEY.equals(this.PROXY_PORT)) {
return ("8118");
}
if (KEY.equals(this.AUTH_PROXY_PASS)) {
return ("mypass");
}
if (KEY.equals(this.AUTH_PROXY_USER)) {
return ("myuser");
}
if (KEY.equals(this.AUTH_PROXY_USE)) {
return ("FALSE");
}
if (KEY.equals(this.PROXY_USE)) {
return ("FALSE");
}
if (KEY.equals(this.KEYSTORE_PASS)) {
return ("test");
}
//30 minutes
if (KEY.equals(this.ASYNC_MDN_TIMEOUT)) {
return ("30");
}
if (KEY.equals(this.AUTO_MSG_DELETE)) {
return ("TRUE");
}
if (KEY.equals(this.AUTO_MSG_DELETE_LOG)) {
return ("TRUE");
}
if (KEY.equals(this.AUTO_MSG_DELETE_OLDERTHAN)) {
return ("5");
}
if (KEY.equals(this.JNDI_PORT)) {
return ("16423");
}
if (KEY.equals(this.MQ_PROXY_PORT)) {
return ("16023");
}
if (KEY.equals(this.RECEIPT_PARTNER_SUBDIR)) {
return ("FALSE");
}
if (KEY.equals(CLIENTSERVER_COMM_PORT)) {
return ("1235");
}
if (KEY.equals(HTTP_SEND_TIMEOUT)) {
return ("5000");
}
throw new IllegalArgumentException("No defaults defined for prefs key "
+ KEY + " in " + this.getClass().getName());
}
/**
* Returns a single string value from the preferences or the default
* if it is not found
*
* @param KEY one of the class internal constants
*/
public String get(final String KEY) {
return (this.preferences.get(KEY, this.getDefaultValue(KEY)));
}
/**
* Stores a value in the preferences. If the passed value is null or an
* empty string the key-value pair will be deleted from the registry.
*
* @param KEY Key as defined in this class
* @param value value to set
*/
public void put(final String KEY, String value) {
if (value == null || value.length() == 0) {
this.preferences.remove(KEY);
} else {
this.preferences.put(KEY, value);
}
try {
this.preferences.flush();
} catch (BackingStoreException ignore) {
}
}
/**
* Puts a value to the preferences and stores the prefs
*
* @param KEY Key as defined in this class
* @param value value to set
*/
public void putInt(final String KEY, int value) {
this.preferences.putInt(KEY, value);
try {
this.preferences.flush();
} catch (BackingStoreException ignore) {
}
}
/**
* Returns the value for the asked key, if noen is defined it returns
* the default value
*/
public int getInt(final String KEY) {
return preferences.getInt(KEY, Integer.parseInt(getDefaultValue(KEY)));
}
/**
* Puts a value to the preferences and stores the prefs
*
* @param KEY Key as defined in this class
* @param value value to set
*/
public void putBoolean(final String KEY, boolean value) {
this.preferences.putBoolean(KEY, value);
try {
this.preferences.flush();
} catch (BackingStoreException ignore) {
}
}
/**
* Returns the value for the asked key.
* if non is defined it returns the default value
*
* @param KEY is the key you want to check
* @return the boolean flag indicating if key exists.
*/
public boolean getBoolean(final String KEY) {
return (this.preferences.getBoolean(KEY,
Boolean.parseBoolean(getDefaultValue(KEY))));
}
/**
* Returns the value for the asked key.
* if there is no match, it returns the second parameter value
*
* @param KEY is the key to look for
* @param
* @return the value or the default
*/
public boolean getBoolean(final String KEY, final boolean defaultValue) {
return (preferences.getBoolean(KEY, defaultValue));
}
/**
* Returns the OS of the actual installation
*/
private int getOS() {
if (this.os.toLowerCase().startsWith(STR_WIN)) {
return (this.OS_WIN);
} else {
return (this.OS_OTHER);
}
}
}
Oh and the name of the
Oh and the name of the element in the XML has to match then name used in the PreferencesAS2 file you want to override exactly.