/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang.beam;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.ericsson.otp.erlang.OtpAuthException;
import com.ericsson.otp.erlang.OtpConnection;
import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBinary;
import com.ericsson.otp.erlang.OtpErlangExit;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.ericsson.otp.erlang.OtpPeer;
import com.ericsson.otp.erlang.OtpSelf;
import erjang.ETuple;
public class ErlangBeamDisLoader extends BeamLoader {
static Logger log = Logger.getLogger("erjang.beam");
/** For transition phase from external to internal beam file reader */
final boolean TRY_NATIVE_LOADER = true;
String myid = "JVM2@localhost";
OtpConnection conn;
private OtpSelf self;
private OtpPeer peer;
// {'$gen_call', {To, Tag}, {call, Mod, Fun, Args, User}}
public ErlangBeamDisLoader() throws OtpAuthException, IOException {
self = new OtpSelf(myid);
peer = new OtpPeer("beam_loader@localhost");
conn = self.connect(peer);
}
@Override
public BeamFileData load(File file) throws IOException {
sendGEN(conn, "beam_loader", new OtpErlangTuple(
new OtpErlangObject[] {
new OtpErlangAtom("disasm"),
new OtpErlangString(file.getAbsolutePath()) }));
try {
OtpErlangObject reply = conn.receiveRPC();
return new SymbolicBeamFileData(check((ETuple)OtpConverter.convert(reply), file));
} catch (OtpErlangExit e) {
throw new RuntimeException("external beam_loader died", e);
} catch (OtpAuthException e) {
throw new RuntimeException("external beam_loader auth", e);
}
}
@Override
public BeamFileData load(byte[] data) throws IOException {
sendGEN(conn, "beam_loader", new OtpErlangTuple(
new OtpErlangObject[] {
new OtpErlangAtom("disasm"),
new OtpErlangBinary(data) }));
try {
OtpErlangObject reply = conn.receiveRPC();
return new SymbolicBeamFileData(check((ETuple)OtpConverter.convert(reply), data));
} catch (OtpErlangExit e) {
throw new RuntimeException("external beam_loader died", e);
} catch (OtpAuthException e) {
throw new RuntimeException("external beam_loader auth", e);
}
}
public void sendGEN(final OtpConnection conn, String server, final OtpErlangObject request) throws IOException {
final OtpErlangObject[] gen = new OtpErlangObject[3];
final OtpErlangObject[] reply = new OtpErlangObject[2];
/* {self, { call, Mod, Fun, Args, user}} */
reply[0] = self.pid();
reply[1] = self.createRef();
gen[0] = new OtpErlangAtom("$gen_call");
gen[1] = new OtpErlangTuple(reply);
gen[2] = request;
conn.send(server, new OtpErlangTuple(gen));
}
protected ETuple check(ETuple dis1, File file) throws IOException {
if (!TRY_NATIVE_LOADER) return dis1;
ETuple dis2 = erjang.beam.loader.BeamLoader.read(file.getAbsolutePath()).toSymbolic();
return check(dis1, dis2);
}
protected ETuple check(ETuple dis1, byte[] data) throws IOException {
if (!TRY_NATIVE_LOADER) return dis1;
ETuple dis2 = erjang.beam.loader.BeamLoader.parse(data).toSymbolic();
return check(dis1, dis2);
}
protected ETuple check(ETuple dis1, ETuple dis2) {
log.fine("DB| loader-cmp: ");
boolean eq = false;
try {eq = dis1.equals(dis2);} catch (RuntimeException re) {
log.log(Level.WARNING, "failed to compare tuples", re);
}
if (eq) log.fine("OK");
else { if (log.isLoggable(Level.FINE)) { log.fine("DIFF:\n"+dis1+"\nvs\n"+dis2); }}
return dis1;
}
}