395 lines
17 KiB
Java
395 lines
17 KiB
Java
package _VisualDVM.Repository.Server;
|
||
import Common.Database.Database;
|
||
import Common.Database.Objects.DBObject;
|
||
import Common.Database.Objects.riDBObject;
|
||
import Common.Database.RepositoryRefuseException;
|
||
import Common.Utils.InterruptThread;
|
||
import Common.Utils.Utils_;
|
||
import _VisualDVM.Constants;
|
||
import _VisualDVM.Passes.Server.RepositoryPass;
|
||
import _VisualDVM.Repository.EmailMessage;
|
||
import _VisualDVM.Utils;
|
||
import javafx.util.Pair;
|
||
import sun.misc.SignalHandler;
|
||
|
||
import javax.activation.DataHandler;
|
||
import javax.activation.DataSource;
|
||
import javax.activation.FileDataSource;
|
||
import javax.mail.*;
|
||
import javax.mail.internet.InternetAddress;
|
||
import javax.mail.internet.MimeBodyPart;
|
||
import javax.mail.internet.MimeMessage;
|
||
import javax.mail.internet.MimeMultipart;
|
||
import java.io.*;
|
||
import java.net.ServerSocket;
|
||
import java.net.Socket;
|
||
import java.util.Date;
|
||
import java.util.LinkedHashMap;
|
||
import java.util.Properties;
|
||
import java.util.Vector;
|
||
public abstract class RepositoryServer<D extends Database> {
|
||
protected static FileWriter Log;
|
||
protected static boolean printOn = true;
|
||
public abstract String getServerFileName();
|
||
public abstract String getServerHomeName();
|
||
//-
|
||
public D db;
|
||
protected Socket clientSocket; //сокет для общения
|
||
protected ServerSocket server; // серверсокет
|
||
protected ObjectInputStream in; // поток чтения из сокета
|
||
protected ObjectOutputStream out; // поток записи в сокет
|
||
protected ServerExchangeUnit_2021 request;
|
||
protected ServerExchangeUnit_2021 response;
|
||
//-
|
||
protected ServerCode code;
|
||
protected long count = 0; //для отладки.
|
||
protected Thread interruptThread = new InterruptThread(10000,
|
||
() -> {
|
||
System.exit(0);
|
||
return null;
|
||
});
|
||
Class<D> d_class;
|
||
//-----------RECURSION ->
|
||
SignalHandler signalHandler = signal -> {
|
||
};
|
||
public RepositoryServer(Class<D> d_class_in) {
|
||
d_class = d_class_in;
|
||
}
|
||
protected static void ResetLog() {
|
||
if (printOn) {
|
||
try {
|
||
Log = new FileWriter("Log.txt", false);
|
||
Log.close();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
protected static void Print(String message) {
|
||
if (printOn) {
|
||
try {
|
||
Log = new FileWriter("Log.txt", true);
|
||
String dmessage = Utils_.Brackets("SESSION -> ") + new Date() +
|
||
" " + message;
|
||
Log.write(dmessage + "\n");
|
||
Log.close();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
//-DVMTestingChecker
|
||
public abstract int getPort();
|
||
protected void Session() throws Exception {};
|
||
protected void UnsafeSession() throws Exception {}
|
||
protected void startAdditionalThreads() {
|
||
}
|
||
public void ActivateDB() {
|
||
try {
|
||
db = d_class.newInstance();
|
||
db.Activate();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
}
|
||
public void Email(EmailMessage message_in, String address_in) throws Exception {
|
||
Thread thread = new Thread(() -> {
|
||
try {
|
||
Properties props = new Properties();
|
||
props.put("mail.smtp.host", Constants.SMTPHost);
|
||
props.put("mail.smtp.auth", "true");
|
||
props.put("mail.smtp.port", String.valueOf(Constants.SMTPPort));
|
||
props.put("mail.smtp.socketFactory.port", String.valueOf(Constants.MailSocketPort));
|
||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||
props.put("mail.smtp.connectiontimeout", String.valueOf(15000));
|
||
props.put("mail.smtp.timeout", String.valueOf(15000));
|
||
props.put("mail.smtp.writetimeout", String.valueOf(15000));
|
||
//------------------------------
|
||
LinkedHashMap<String, File> innerFiles = new LinkedHashMap<>();
|
||
for (String aName : message_in.files.keySet()) {
|
||
File f = Utils.getTempFileName(aName);
|
||
Utils_.bytesToFile(message_in.files.get(aName), f);
|
||
innerFiles.put(aName, f);
|
||
}
|
||
//------------------------------
|
||
Session session = Session.getDefaultInstance(props,
|
||
new Authenticator() {
|
||
@Override
|
||
protected PasswordAuthentication getPasswordAuthentication() {
|
||
return new PasswordAuthentication(
|
||
Constants.MailAddress,
|
||
Constants.MailPassword);
|
||
}
|
||
});
|
||
try {
|
||
MimeMessage message = new MimeMessage(session);
|
||
message.setFrom(new InternetAddress(Constants.MailAddress));
|
||
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(address_in));
|
||
message.setSubject(message_in.subject);
|
||
Multipart multipart = new MimeMultipart();
|
||
MimeBodyPart textBodyPart = new MimeBodyPart();
|
||
textBodyPart.setText(message_in.text);
|
||
multipart.addBodyPart(textBodyPart);
|
||
for (String aName : innerFiles.keySet()) {
|
||
MimeBodyPart attachmentBodyPart = new MimeBodyPart();
|
||
DataSource source = new FileDataSource(innerFiles.get(aName));
|
||
attachmentBodyPart.setDataHandler(new DataHandler(source));
|
||
attachmentBodyPart.setFileName(aName);
|
||
multipart.addBodyPart(attachmentBodyPart);
|
||
}
|
||
message.setContent(multipart);
|
||
Transport.send(message);
|
||
} catch (Exception ex) {
|
||
System.out.println("Исключение во время отправки сообщения абоненту " + Utils_.Brackets(address_in));
|
||
ex.printStackTrace();
|
||
Utils_.sleep(1000);
|
||
}
|
||
} catch (Exception ex) {
|
||
System.out.println("Исключение во время выполнения рассылки.");
|
||
ex.printStackTrace();
|
||
}
|
||
});
|
||
thread.start();
|
||
}
|
||
public boolean canDelete(DBObject object) throws Exception {
|
||
return true;
|
||
}
|
||
public void StartAction() throws Exception {
|
||
}
|
||
public void Start() throws Exception {
|
||
DiagnosticSignalHandler.install("TERM", signalHandler);
|
||
DiagnosticSignalHandler.install("INT", signalHandler);
|
||
DiagnosticSignalHandler.install("ABRT", signalHandler);
|
||
interruptThread.start();
|
||
startAdditionalThreads();
|
||
server = new ServerSocket(getPort());
|
||
StartAction();
|
||
while (true) {
|
||
try {
|
||
clientSocket = server.accept();
|
||
ResetLog();
|
||
Print((count++) + " клиент присоединился, IP=" + clientSocket.getInetAddress());
|
||
code = ServerCode.Undefined;
|
||
out = new ObjectOutputStream(clientSocket.getOutputStream());
|
||
in = new ObjectInputStream(clientSocket.getInputStream());
|
||
//->
|
||
DBObject dbObject = null;
|
||
Pair<Class, Object> p = null;
|
||
Print("Ожидание команды от клиента...");
|
||
Object transport = in.readObject();
|
||
Print("Команда прочитана.");
|
||
//-->
|
||
if (transport instanceof ServerExchangeUnit_2021) {
|
||
request = (ServerExchangeUnit_2021) transport;
|
||
response = new ServerExchangeUnit_2021(ServerCode.OK);
|
||
Print("клиент: <- " + (request.codeName));
|
||
//--
|
||
try {
|
||
code = request.getCode();
|
||
//--
|
||
if (transport instanceof SafeServerExchangeUnit){
|
||
SafeServerExchangeUnit safe_request= (SafeServerExchangeUnit) transport;
|
||
if (safe_request.version!=Constants.version){
|
||
//версия не совпала. не даем работать.
|
||
throw new RepositoryRefuseException("Версия клиента не совпадает с версией сервера!");
|
||
}
|
||
//БЕЗОПАСНАЯ СЕССИЯ
|
||
switch (code) {
|
||
case Email:
|
||
Email();
|
||
break;
|
||
case EditObject:
|
||
EditObject();
|
||
break;
|
||
case GetObjectCopyByPK:
|
||
GetObjectCopyByPK();
|
||
break;
|
||
case GetObjectsCopiesByPK:
|
||
GetObjectsCopiesByPK();
|
||
break;
|
||
case PublishObject:
|
||
PublishObject();
|
||
break;
|
||
case PublishObjects:
|
||
PublishObjects();
|
||
break;
|
||
case DeleteObjectByPK:
|
||
DeleteObjectByPK();
|
||
break;
|
||
case DeleteObjectsByPK:
|
||
DeleteObjectsByPK();
|
||
break;
|
||
case CloneObjectByPK:
|
||
CloneObject();
|
||
break;
|
||
default:
|
||
Session();
|
||
break;
|
||
}
|
||
}else {
|
||
//ОПАСНАЯ СЕССИЯ
|
||
switch (code){
|
||
case Ping:
|
||
Ping();
|
||
break;
|
||
case ReceiveFile:
|
||
ReceiveFile();
|
||
break;
|
||
case Email:
|
||
Email();
|
||
break;
|
||
default:
|
||
UnsafeSession();
|
||
break;
|
||
}
|
||
}
|
||
} catch (Exception ex) {
|
||
response = new ServerExchangeUnit_2021(ServerCode.FAIL, "Исключение сервера", ex);
|
||
} finally {
|
||
Print("сервер: -> " + response.codeName);
|
||
out.writeObject(response);
|
||
Print("Ответ отправлен.");
|
||
}
|
||
}
|
||
Print("Соединение с клиентом завершено.");
|
||
//->
|
||
} catch (Exception ex) {
|
||
Print("Исключение.Соединение с клиентом завершено.");
|
||
} finally {
|
||
//->
|
||
try {
|
||
if (clientSocket != null)
|
||
clientSocket.close();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
// потоки тоже хорошо бы закрыть
|
||
try {
|
||
if (in != null)
|
||
in.close();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
try {
|
||
if (out != null)
|
||
out.close();
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
Print("Сервер ждет следующего клиента.");
|
||
}
|
||
}
|
||
}
|
||
//--
|
||
void Ping() {}
|
||
public boolean PingFromClient() {
|
||
RepositoryPass pingPass = new RepositoryPass(this) {
|
||
boolean success;
|
||
@Override
|
||
protected boolean needsAnimation() {
|
||
return true;
|
||
}
|
||
@Override
|
||
protected boolean canStart(Object... args) throws Exception {
|
||
success = false;
|
||
return true;
|
||
}
|
||
@Override
|
||
public String getDescription() {
|
||
return "Ping";
|
||
}
|
||
@Override
|
||
protected void body() throws Exception {
|
||
try {
|
||
super.body();
|
||
success = true;
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
}
|
||
@Override
|
||
protected void ServerAction() throws Exception {
|
||
unsafe_command(new ServerExchangeUnit_2021(ServerCode.Ping));
|
||
}
|
||
@Override
|
||
protected boolean validate() {
|
||
return success;
|
||
}
|
||
};
|
||
return pingPass.Do();
|
||
}
|
||
void ReceiveFile() throws Exception {
|
||
File file = new File(request.arg);
|
||
response.object = file.exists() ? Utils_.fileToBytes(file) : null;
|
||
}
|
||
void Email() throws Exception {
|
||
Email((EmailMessage) request.object, request.arg);
|
||
}
|
||
//----
|
||
void PublishObject() throws Exception {
|
||
DBObject dbObject = (DBObject) request.object;
|
||
beforePublishAction(dbObject);
|
||
response.object = (Serializable) db.InsertS(dbObject).getPK();
|
||
afterPublishAction(dbObject);
|
||
}
|
||
void PublishObjects() throws Exception {
|
||
Vector<DBObject> objects = (Vector<DBObject>) request.object;
|
||
for (DBObject dbObject : objects) {
|
||
beforePublishAction(dbObject);
|
||
response.object = (Serializable) db.InsertS(dbObject).getPK();
|
||
afterPublishAction(dbObject);
|
||
}
|
||
}
|
||
void CloneObject() throws Exception {
|
||
Pair<Class, Object> to_clone = (Pair<Class, Object>) request.object;
|
||
Object pk = to_clone.getValue();
|
||
if (db.getTable(to_clone.getKey()).containsKey(to_clone.getValue())) {
|
||
riDBObject src = (riDBObject) db.getTable(to_clone.getKey()).get(to_clone.getValue());
|
||
riDBObject dst = (riDBObject) to_clone.getKey().newInstance();
|
||
dst.SynchronizeFields(src);
|
||
//единственное отличие клона - текущий автор
|
||
dst.description += " копия";
|
||
String[] packed = request.arg.split("\n");
|
||
dst.sender_name = packed[0];
|
||
dst.sender_address = packed[1];
|
||
db.Insert(dst);
|
||
afterCloneAction(src, dst);
|
||
response.object = (Serializable) dst.getPK();
|
||
}
|
||
}
|
||
void GetObjectCopyByPK() throws Exception {
|
||
Pair<Class, Object> p = (Pair<Class, Object>) request.object;
|
||
DBObject dbObject = db.getObjectCopyByPK(p.getKey(), p.getValue());
|
||
response.object = dbObject;
|
||
}
|
||
void GetObjectsCopiesByPK() throws Exception {
|
||
Pair<Class, Object> p = (Pair<Class, Object>) request.object;
|
||
response.object = db.getObjectsCopies(p.getKey(), (Vector<Object>) p.getValue());
|
||
}
|
||
void EditObject() throws Exception {
|
||
DBObject new_object = (DBObject) request.object;
|
||
db.UpdateWithCheck(new_object);
|
||
afterEditAction(new_object);
|
||
}
|
||
void DeleteObjectByPK() throws Exception {
|
||
Pair<Class, Object> to_delete = (Pair<Class, Object>) request.object;
|
||
afterDeleteAction(db.DeleteByPK(to_delete.getKey(), to_delete.getValue()));
|
||
}
|
||
void DeleteObjectsByPK() throws Exception {
|
||
Pair<Class, Vector<Object>> to_delete = (Pair<Class, Vector<Object>>) request.object;
|
||
for (Object object : to_delete.getValue()) {
|
||
afterDeleteAction(db.DeleteByPK(to_delete.getKey(), object));
|
||
}
|
||
}
|
||
protected void afterCloneAction(riDBObject src, riDBObject dst) throws Exception {
|
||
}
|
||
protected void beforePublishAction(DBObject object) throws Exception {
|
||
}
|
||
protected void afterPublishAction(DBObject object) throws Exception {
|
||
}
|
||
protected void afterEditAction(DBObject object) throws Exception {
|
||
}
|
||
protected void afterDeleteAction(DBObject object) throws Exception {
|
||
}
|
||
}
|