/*
Tango - Personal Media Center
Copyright (C) 2021 Ulrich Hilger
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.uhilger.tango.api;
import com.google.gson.Gson;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.tango.App;
import static de.uhilger.tango.App.RB_EP_LISTE;
import static de.uhilger.tango.App.RB_EP_LISTE_ALLES;
import de.uhilger.tango.Server;
import de.uhilger.tango.entity.Ablageort;
import de.uhilger.tango.store.FileStorage;
import de.uhilger.tango.entity.Entity;
import de.uhilger.tango.entity.Geraet;
import static de.uhilger.tango.store.FileStorage.ST_ABLAGEORT;
import static de.uhilger.tango.store.FileStorage.ST_GERAET;
import de.uhilger.tango.store.Storage;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.util.ArrayList;
/**
* HttpHandler fuer die Verwaltung von Entitaeten der Mediazentrale
*
* GET /mz/api/store/[typname]/[name]
* GET /mz/api/store/[typname]/liste
* GET /mz/api/store/[typname]/listealles (nur Typ Geraet)
*
* @author Ulrich Hilger
* @version 1, 5.4.2021
*/
public class StorageHandler extends AbstractHandler {
private static final Logger logger = Logger.getLogger(StorageHandler.class.getName());
@Override
protected String put(HttpExchange e) throws IOException {
String path = e.getRequestURI().toString();
String[] elems = path.split(Server.SLASH);
String type = elems[elems.length - 2];
String elemName = elems[elems.length - 1]; // alter Name, wenn Aenderung
if(!elemName.equalsIgnoreCase(App.getRs(RB_EP_LISTE))) {
FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
Gson gson = new Gson();
logger.log(Level.FINE, "type: {0}, token: {1}", new Object[]{type, fs.typeFromName(type).getType().getTypeName()});
Object o = gson.fromJson(bodyLesen(e), fs.typeFromName(type).getType());
if(o instanceof Entity) {
Entity entity = (Entity) o;
if(fs.exists(type, elemName)) { // Aenderung
fs.delete(type, elemName);
// wenn Ablageort, hier noch alten Kontext entfernen
if(type.equalsIgnoreCase(FileStorage.ST_ABLAGEORT)) {
Entity aoe = fs.read(type, elemName);
if(aoe instanceof Ablageort) {
Ablageort ablageort = (Ablageort) aoe;
App.getServer().ablageortEntfernen(ablageort.getUrl());
}
}
fs.write(entity, true);
// wenn Ablageort, hier noch neuen Kontext anlegen
if(type.equalsIgnoreCase(FileStorage.ST_ABLAGEORT)) {
if(entity instanceof Ablageort) {
Ablageort ablageort = (Ablageort) entity;
App.getServer().ablageortHinzufuegen(ablageort);
}
}
} else { // Neu
fs.write(entity, false);
// wenn Ablageort, hier noch neuen Kontext anlegen
if(type.equalsIgnoreCase(FileStorage.ST_ABLAGEORT)) {
if(entity instanceof Ablageort) {
Ablageort ablageort = (Ablageort) entity;
App.getServer().ablageortHinzufuegen(ablageort);
}
}
}
return type + Server.SLASH + entity.getName();
} else {
return "Ungueltiges Objekt im Body.";
}
} else {
return "Ungueltiger Elementname: " + App.getRs(RB_EP_LISTE);
}
}
private boolean loeschen(HttpExchange e) {
String path = e.getRequestURI().toString();
String[] elems = path.split(Server.SLASH);
String type = elems[elems.length - 2];
String elemName = elems[elems.length - 1];
FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
if(type.equalsIgnoreCase(FileStorage.ST_ABLAGEORT)) {
// im laufenden Server den Context entfernen
Entity entity = fs.read(type, elemName);
if(entity instanceof Ablageort) {
Ablageort ablageort = (Ablageort) entity;
App.getServer().ablageortEntfernen(ablageort.getUrl());
}
}
return fs.delete(type, elemName);
}
private String lesen(HttpExchange e) throws IOException, InterruptedException {
String path = e.getRequestURI().toString();
String[] elems = path.split(Server.SLASH);
FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
if(path.endsWith(Server.SLASH)) {
List list = null;
if(elems[elems.length - 1].equalsIgnoreCase(App.getRs(RB_EP_LISTE_ALLES))) {
String type = elems[elems.length - 2];
logger.fine(type);
if(type.equalsIgnoreCase(ST_GERAET)) {
list = collectDeviceStatus(fs, type);
Gson gson = new Gson();
Object o = gson.fromJson(bodyLesen(e), fs.typeFromName(type).getType());
return gson.toJson(list);
}
} else if(elems[elems.length - 1].equalsIgnoreCase(App.getRs(RB_EP_LISTE))) {
String type = elems[elems.length - 2];
logger.fine(type);
list = fs.list(type);
if(type.equalsIgnoreCase(ST_ABLAGEORT)) {
list.add("Livestreams");
}
} else {
String type = elems[elems.length - 1];
logger.fine(type);
list = fs.listObjects(type);
}
return jsonWithEnclosingType(list);
} else {
String type = elems[elems.length - 2];
String elemName = elems[elems.length - 1];
return fs.readJson(type, elemName);
}
}
@Override
public String get(HttpExchange e) {
try {
return lesen(e);
} catch (IOException | InterruptedException ex) {
Logger.getLogger(StorageHandler.class.getName()).log(Level.SEVERE, null, ex);
return ex.getLocalizedMessage();
}
}
@Override
public String post(HttpExchange e) {
return "nicht unterstuetzt";
}
@Override
public boolean delete(HttpExchange e) {
return loeschen(e);
}
private List collectDeviceStatus(Storage fs, String type) throws IOException, InterruptedException {
List list = fs.listObjects(type);
List newList = new ArrayList();
Iterator i = list.iterator();
while (i.hasNext()) {
Entity entity = i.next();
if (entity instanceof Geraet) {
Geraet g = (Geraet) entity;
String statusurl = g.getStatusUrl();
logger.info(statusurl);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(statusurl))
.build();
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
//.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
//.authenticator(Authenticator.getDefault())
.build();
HttpResponse response = client.send(request, BodyHandlers.ofString());
logger.finer(Integer.toString(response.statusCode()));
logger.finer(response.body());
// {"ison":false,"has_timer":false,"overpower":false}
String[] parts = response.body().split(",")[0].split(":");
logger.finer("ison: " + parts[1]);
g.setStatus(Boolean.parseBoolean(parts[1]));
newList.add(g);
}
}
return newList;
}
}