Commit 97a65114 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

Version 3.15.0

See merge request !8
parents 99c8f6a8 5950ea5f
Pipeline #10106 passed with stage
in 3 minutes and 15 seconds
package de.hft.stuttgart.citydoctor2.webservice.database;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.hibernate.Session;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.QueryBuilder;
import de.hft.stuttgart.citydoctor2.webservice.model.BuildingReference;
import de.hft.stuttgart.citydoctor2.webservice.model.BuildingReferenceWithErrorIndicator;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
public class BuildingQueries {
private BuildingQueries() {
// only static use
}
public static void persistBuilding(WebBuilding buildingRef, EntityManager manager) {
manager.getTransaction().begin();
try {
manager.persist(buildingRef);
} finally {
manager.getTransaction().commit();
}
}
public static List<BuildingReference> getBuildingsForModel(int from, int modelId, EntityManager manager) {
Session session = manager.unwrap(Session.class);
try {
session.getTransaction().begin();
Query<BuildingReference> query = session.createQuery("SELECT new de.hft.stuttgart.citydoctor2."
+ "webservice.model.BuildingReference(b.id, b.gmlId, b.modelWidth) FROM WebBuilding b WHERE model.id = ?1",
BuildingReference.class);
query.setParameter(1, modelId);
query.setMaxResults(20);
query.setFirstResult(from);
return query.getResultList();
} finally {
session.getTransaction().commit();
}
}
public static List<String> getBuildingsForSearchString(String s, int modelId, EntityManager manager) {
FullTextEntityManager textEntityManager = Search.getFullTextEntityManager(manager);
textEntityManager.getTransaction().begin();
try {
QueryBuilder queryBuilder = textEntityManager.getSearchFactory().buildQueryBuilder().forEntity(WebBuilding.class).get();
org.apache.lucene.search.Query luceneQ = queryBuilder.keyword().onField("gmlId").matching(s).createQuery();
FullTextQuery query = textEntityManager.createFullTextQuery(luceneQ, WebBuilding.class);
query.setMaxResults(5);
@SuppressWarnings("unchecked")
List<WebBuilding> resultList = query.getResultList();
for (WebBuilding b : resultList) {
System.out.println(b.getGmlId());
}
return null;
} finally {
textEntityManager.getTransaction().commit();
}
}
public static WebBuilding getBuildingForGmlId(String gmlId, int modelId, EntityManager manager) {
manager.getTransaction().begin();
try {
TypedQuery<WebBuilding> query = manager.createQuery("FROM WebBuilding WHERE model.id = ?1 AND gmlId = ?2",
WebBuilding.class);
query.setParameter(1, modelId);
query.setParameter(2, gmlId);
return query.getSingleResult();
} finally {
manager.getTransaction().commit();
}
}
public static long getBuildingCountForModel(int modelId, EntityManager manager) {
manager.getTransaction().begin();
try {
javax.persistence.Query query = manager
.createQuery("SELECT COUNT (b.id) FROM WebBuilding b WHERE b.model.id = ?1");
query.setParameter(1, modelId);
return (Long) query.getSingleResult();
} finally {
manager.getTransaction().commit();
}
}
public static List<BuildingReference> getBuildingsWithErrorIndicator(int from, int modelId,
Integer validationId, EntityManager manager) {
Session session = manager.unwrap(Session.class);
try {
session.getTransaction().begin();
@SuppressWarnings("unchecked")
NativeQuery<Object[]> nQuery = session.createSQLQuery(
"SELECT b.id, b.gml_id, b.model_width, CASE WHEN e.id IS NULL THEN FALSE ELSE TRUE END "
+ "FROM building_reference b "
+ "LEFT JOIN (SELECT br.id FROM building_reference br WHERE EXISTS "
+ "(SELECT 1 FROM weberror ee WHERE ee.building_id = br.id AND ee.validation_id = ?2)) AS e ON (e.id = b.id) "
+ "WHERE b.model_id = ?1");
nQuery.setParameter(1, modelId);
nQuery.setParameter(2, validationId);
nQuery.setFirstResult(from);
nQuery.setMaxResults(20);
List<Object[]> list = nQuery.list();
List<BuildingReference> result = new ArrayList<>();
for (Object[] objects : list) {
result.add(new BuildingReferenceWithErrorIndicator((Integer) objects[0], (String) objects[1], (Double) objects[2], (Boolean) objects[3]));
}
return result;
} finally {
session.getTransaction().commit();
}
}
public static long getErrorBuildingCountForModel(int modelId, Integer validationId, EntityManager manager) {
Session session = manager.unwrap(Session.class);
session.getTransaction().begin();
try {
@SuppressWarnings("unchecked")
NativeQuery<Object> nQuery = session.createSQLQuery(
"SELECT COUNT(b.id) "
+ "FROM building_reference b "
+ "JOIN (SELECT br.id FROM building_reference br WHERE EXISTS "
+ "(SELECT 1 FROM weberror ee WHERE ee.building_id = br.id AND ee.validation_id = ?2)) AS e ON (e.id = b.id) "
+ "WHERE b.model_id = ?1");
nQuery.setParameter(1, modelId);
nQuery.setParameter(2, validationId);
return ((BigInteger) nQuery.getSingleResult()).longValueExact();
} finally {
session.getTransaction().commit();
}
}
public static List<BuildingReference> getErrorBuildingsWithErrorIndicator(int from, int modelId,
Integer validationId, EntityManager manager) {
Session session = manager.unwrap(Session.class);
try {
session.getTransaction().begin();
@SuppressWarnings("unchecked")
NativeQuery<Object[]> nQuery = session.createSQLQuery(
"SELECT b.id, b.gml_id, b.model_width, TRUE "
+ "FROM building_reference b "
+ "JOIN (SELECT br.id FROM building_reference br WHERE EXISTS "
+ "(SELECT 1 FROM weberror ee WHERE ee.building_id = br.id AND ee.validation_id = ?2)) AS e ON (e.id = b.id) "
+ "WHERE b.model_id = ?1");
nQuery.setParameter(1, modelId);
nQuery.setParameter(2, validationId);
nQuery.setFirstResult(from);
nQuery.setMaxResults(20);
List<Object[]> list = nQuery.list();
List<BuildingReference> result = new ArrayList<>();
for (Object[] objects : list) {
result.add(new BuildingReferenceWithErrorIndicator((Integer) objects[0], (String) objects[1], (Double) objects[2], (Boolean) objects[3]));
}
return result;
} finally {
session.getTransaction().commit();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Validation;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebError;
public class ErrorQueries {
public static void addErrorToBuilding(WebBuilding building, Validation validation, WebError webError, EntityManager manager) {
manager.getTransaction().begin();
try {
building.getErrors().add(webError);
validation.getErrors().add(webError);
manager.persist(webError);
} finally {
manager.getTransaction().commit();
}
}
public static List<WebError> getErrorsForBuilding(int buildingId, int validationId, EntityManager manager) {
manager.getTransaction().begin();
try {
TypedQuery<WebError> query = manager.createQuery("FROM WebError WHERE building.id = ?1 AND validation.id =?2", WebError.class);
query.setParameter(1, buildingId);
query.setParameter(2, validationId);
return query.getResultList();
} finally {
manager.getTransaction().commit();
}
}
public static void deleteErrorsForBuilding(int buildingId, EntityManager manager) {
manager.getTransaction().begin();
try {
Query query = manager.createQuery("DELETE FROM WebError WHERE building.id = ?1");
query.setParameter(1, buildingId);
query.executeUpdate();
} finally {
manager.getTransaction().commit();
}
}
public static void deleteErrorsForValidation(int validationId, EntityManager manager) {
manager.getTransaction().begin();
try {
Query query = manager.createQuery("DELETE FROM WebError WHERE validation.id = ?1");
query.setParameter(1, validationId);
query.executeUpdate();
} finally {
manager.getTransaction().commit();
}
}
public static void deleteErrorsForModel(int modelId, EntityManager manager) {
manager.getTransaction().begin();
try {
Query query = manager.createQuery("DELETE er FROM WebError er JOIN FETCH er.building b WHERE b.model.id = ?1");
query.setParameter(1, modelId);
query.executeUpdate();
} finally {
manager.getTransaction().commit();
}
}
public static List<WebError> getErrorsForModel(int modelId, EntityManager manager) {
manager.getTransaction().begin();
try {
TypedQuery<WebError> query = manager.createQuery("FROM WebError WHERE building.model.id = ?1", WebError.class);
query.setParameter(1, modelId);
return query.getResultList();
} finally {
manager.getTransaction().commit();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import javax.persistence.EntityManager;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebGeometry;
public class GeometryQueries {
private GeometryQueries() {
// only static use
}
public static void persistGeometryAndApplyToBuilding(WebGeometry geom, WebBuilding ref, EntityManager manager) {
manager.getTransaction().begin();
try {
manager.persist(geom);
} finally {
manager.getTransaction().commit();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import de.hft.stuttgart.citydoctor2.webservice.model.ParseStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.GmlFile;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebCityDoctorModel;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
public class ModelQueries {
private ModelQueries() {
// only static usage
}
public static void storeModel(WebCityDoctorModel webModel, EntityManager manager) {
try {
manager.getTransaction().begin();
manager.persist(webModel);
} finally {
manager.getTransaction().commit();
}
}
public static void updateStatus(WebCityDoctorModel webModel, ParseStatus status, EntityManager manager) {
try {
manager.getTransaction().begin();
webModel.setStatus(status);
} finally {
manager.getTransaction().commit();
}
}
public static void updateModelWithBlob(WebCityDoctorModel webModel, GmlFile blob, EntityManager manager) {
try {
manager.getTransaction().begin();
manager.persist(blob);
webModel.setZipFile(blob);
} finally {
manager.getTransaction().commit();
}
}
public static void cleanup() {
EntityManager manager = HibernateUtils.createManager();
try {
manager.getTransaction().begin();
Query query = manager.createQuery("DELETE FROM WebCityDoctorModel WHERE status = " + ParseStatus.PARSING.ordinal());
query.executeUpdate();
manager.getTransaction().commit();
} finally {
manager.close();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import java.time.LocalDateTime;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Token;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
public class TokenQueries {
private TokenQueries() {
// not used
}
public static Token getTokenForTokenString(String inputToken, String address, EntityManager manager) {
manager.getTransaction().begin();
Token token = null;
try {
TypedQuery<Token> q = manager.createQuery("FROM Token t WHERE t.tokenString = ?1 AND address = ?2", Token.class);
q.setParameter(1, inputToken);
q.setParameter(2, address);
token = q.getSingleResult();
} catch (NoResultException e) {
// ignore
} finally {
manager.getTransaction().commit();
}
return token;
}
public static void persistToken(Token token, EntityManager manager) {
manager.getTransaction().begin();
try {
manager.persist(token);
} finally {
manager.getTransaction().commit();
}
}
public static void updateExpirationDate(LocalDateTime expirationDate, Token token, EntityManager manager) {
manager.getTransaction().begin();
try {
token.setExpires(expirationDate);
} finally {
manager.getTransaction().commit();
}
}
public static Token getTokenForUser(User user, String addr, EntityManager manager) {
manager.getTransaction().begin();
Token token = null;
try {
TypedQuery<Token> q = manager.createQuery("FROM Token t WHERE t.user.id = ?1 AND address = ?2", Token.class);
q.setParameter(1, user.getId());
q.setParameter(2, addr);
token = q.getSingleResult();
} catch (NoResultException e) {
// ignore
} finally {
manager.getTransaction().commit();
}
return token;
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
public class UserQueries {
private UserQueries() {
// only static use
}
public static User getUserForUsername(String username, EntityManager manager) {
manager.getTransaction().begin();
TypedQuery<User> q = manager.createQuery("FROM User WHERE mail = ?1", User.class);
q.setParameter(1, username);
User user = null;
try {
user = q.getSingleResult();
} catch (NoResultException e) {
// ignore
} finally {
manager.getTransaction().commit();
}
return user;
}
public static void createUser(User user, EntityManager manager) {
manager.getTransaction().begin();
try {
manager.persist(user);
} finally {
manager.getTransaction().commit();
}
}
public static void deleteUser(User user, EntityManager manager) {
manager.getTransaction().begin();
try {
manager.remove(user);
} finally {
manager.getTransaction().commit();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.database;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import de.hft.stuttgart.citydoctor2.webservice.model.ValidationStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.FeatureValidationStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Validation;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebCityDoctorModel;
public class ValidationQueries {
private ValidationQueries() {
// only static use
}
public static void addFeatureValidationStatus(WebBuilding b, Validation v, FeatureValidationStatus s, EntityManager manager) {
try {
manager.getTransaction().begin();
b.getErrorStatus().add(s);
v.getErrorStatus().add(s);
manager.persist(s);
} finally {
manager.getTransaction().commit();
}
}
public static void persistValidation(EntityManager manager, WebCityDoctorModel model, Validation validation) {
try {
manager.getTransaction().begin();
manager.persist(validation);
model.getValidations().add(validation);
} finally {
manager.getTransaction().commit();
}
}
public static void updateStatus(Validation valid, ValidationStatus status, EntityManager manager) {
try {
manager.getTransaction().begin();
valid.setStatus(status);
} finally {
manager.getTransaction().commit();
}
}
public static void updateValidationWithReports(Validation validation, byte[] pdfArray,
byte[] xmlArray, EntityManager manager) {
try {
manager.getTransaction().begin();
validation.setPdfReport(pdfArray);
validation.setXmlReport(xmlArray);
} finally {
manager.getTransaction().commit();
}
}
public static Validation getValidation(int validationId, EntityManager manager) {
return manager.find(Validation.class, validationId);
}
public static boolean hasFeatureErrors(WebBuilding b, Validation validation, EntityManager manager) {
try {
manager.getTransaction().begin();
Query query = manager.createQuery("SELECT 1 FROM WebError WHERE EXISTS (SELECT 1 FROM WebError WHERE building = ?1 AND validation = ?2)");
query.setParameter(1, b);
query.setParameter(2, validation);
return !query.getResultList().isEmpty();
} finally {
manager.getTransaction().commit();
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.webservice.AuthenticationException;
import de.hft.stuttgart.citydoctor2.webservice.database.ErrorQueries;
import de.hft.stuttgart.citydoctor2.webservice.model.ErrorReference;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebCityDoctorModel;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebError;
import de.hft.stuttgart.citydoctor2.webservice.utils.AuthenticationUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("")
public class BuildingEndpoint {
private static final Logger logger = LogManager.getLogger(BuildingEndpoint.class);
@GET
@Path("buildings/{buildingId}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getGeometry(@PathParam("buildingId") int buildingId, @Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
WebBuilding building = manager.find(WebBuilding.class, buildingId);
Response response = checkAccessRightsForBuilding(buildingId, user, building);
if (response != null) {
return response;
}
byte[] array = building.getViewData();
return Response.ok(array).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while retrieving building with id {}", buildingId);
logger.catching(e);
return Response.serverError().build();
} finally {
if (manager != null) {
manager.close();
}
}
}
@GET
@Path("buildings/{buildingId}/validation/{validationId}/errors")
@Produces(MediaType.APPLICATION_JSON)
public Response getErrors(@PathParam("buildingId") int buildingId, @PathParam("validationId") int validationId,
@Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
WebBuilding building = manager.find(WebBuilding.class, buildingId);
Response response = checkAccessRightsForBuilding(buildingId, user, building);
if (response != null) {
return response;
}
List<ErrorReference> refs = new ArrayList<>();
List<WebError> errors = ErrorQueries.getErrorsForBuilding(buildingId, validationId, manager);
for (WebError err : errors) {
refs.add(ErrorReference.of(err));
}
return Response.ok(refs).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while retrieving errors for building with id {}", buildingId);
logger.catching(e);
return Response.serverError().build();
} finally {
if (manager != null) {
manager.close();
}
}
}
private Response checkAccessRightsForBuilding(int buildingId, User user, WebBuilding building) {
if (building == null) {
logger.warn("User {} tried to access non existing building with id {}", user.getId(), buildingId);
return Response.status(Status.FORBIDDEN).build();
}
WebCityDoctorModel model = building.getModel();
if (model.getOwner().getId() != user.getId()) {
logger.warn("User {} tried to access not owned model with id {}", user.getId(), model.getId());
return Response.status(Status.FORBIDDEN).build();
}
return null;
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.webservice.model.AvailableChecksReturnType;
import de.hft.stuttgart.citydoctor2.webservice.model.CheckReturnType;
@Path("checks")
public class ChecksEndpoint {
private AvailableChecksReturnType returnValue;
public ChecksEndpoint() {
returnValue = new AvailableChecksReturnType();
List<CheckReturnType> geometricChecks = new ArrayList<>();
List<CheckReturnType> semanticChecks = new ArrayList<>();
returnValue.setGeometricChecks(geometricChecks);
returnValue.setSemanticChecks(semanticChecks);
List<CheckPrototype> prototypes = Checks.getCheckPrototypes();
for (CheckPrototype prototype : prototypes) {
CheckReturnType returnVal = new CheckReturnType();
returnVal.setName(prototype.getCheckId().toString());
List<DefaultParameter> defaultParameters = new ArrayList<>();
for (Requirement req : prototype.checksRequirements()) {
defaultParameters.addAll(req.getDefaultParameter());
}
returnVal.setParameters(defaultParameters);
if (prototype.getType() == RequirementType.GEOMETRY) {
geometricChecks.add(returnVal);
} else if (prototype.getType() == RequirementType.SEMANTIC) {
semanticChecks.add(returnVal);
} else {
throw new IllegalStateException("Cannot handle check type: " + prototype.getType());
}
}
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getChecks() {
return Response.ok(returnValue).build();
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.webservice.AuthenticationException;
import de.hft.stuttgart.citydoctor2.webservice.database.TokenQueries;
import de.hft.stuttgart.citydoctor2.webservice.database.UserQueries;
import de.hft.stuttgart.citydoctor2.webservice.model.LoginSuccessfulReturnType;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Token;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
import de.hft.stuttgart.citydoctor2.webservice.utils.AuthenticationUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HashUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HexUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("/login")
public class LoginEndpoint {
private static Logger logger = LogManager.getLogger(LoginEndpoint.class);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response authenticateUser(@FormParam("username") String username, @FormParam("password") String password,
@Context HttpServletRequest request) {
logger.trace("Login attempt from {}, password hidden", username);
if (username == null || password == null) {
return Response.status(Status.BAD_REQUEST).build();
}
EntityManager manager = HibernateUtils.createManager();
try {
User user = UserQueries.getUserForUsername(username, manager);
if (user == null) {
throw new AuthenticationException("Unknown user");
}
authenticate(user, password);
String addr = request.getLocalAddr();
Token token = TokenQueries.getTokenForUser(user, addr, manager);
if (token == null) {
token = createToken(user, addr);
TokenQueries.persistToken(token, manager);
} else {
LocalDateTime expires = token.getExpires();
if (expires.isBefore(LocalDateTime.now())) {
manager.getTransaction().begin();
manager.remove(token);
manager.getTransaction().commit();
// token expired, issue new one
token = createToken(user, addr);
TokenQueries.persistToken(token, manager);
}
}
logger.trace("Login successful by user {}", user.getId());
LoginSuccessfulReturnType returnType = new LoginSuccessfulReturnType(token.getTokenString(),
token.getExpires(), user.getId());
return Response.status(Status.OK).entity(returnType).build();
} catch (AuthenticationException e) {
logger.trace("Authentication denied for user {}, reason: {}", username, e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.catching(Level.FATAL, e);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
} finally {
manager.close();
}
}
@GET
public Response logout(@Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
AuthenticationUtils.removeTokenFromUser(request, manager);
return Response.ok().build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} finally {
if (manager != null) {
manager.close();
}
}
}
private Token createToken(User user, String addr) {
byte[] bytes = new byte[16];
SecureRandom r = new SecureRandom();
r.nextBytes(bytes);
String tokenString = HexUtils.encode(bytes);
Token token = new Token();
token.setAddress(addr);
token.setUser(user);
token.setExpires(LocalDateTime.now().plusHours(3));
token.setTokenString(tokenString);
return token;
}
private void authenticate(User user, String password) throws AuthenticationException, NoSuchAlgorithmException {
String hash = HashUtils.createPasswordHash(password, user.getSalt());
String storedPassword = user.getPasswordHash();
if (!storedPassword.equals(hash)) {
throw new AuthenticationException("Wrong password");
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.webservice.AuthenticationException;
import de.hft.stuttgart.citydoctor2.webservice.utils.AuthenticationUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("logout")
public class LogoutEndpoint {
private static final Logger logger = LogManager.getLogger(LogoutEndpoint.class);
@POST
public Response logout(@Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
AuthenticationUtils.removeTokenFromUser(request, manager);
return Response.ok().build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while logging out unknown user");
logger.catching(e);
return Response.serverError().build();
} finally {
if (manager != null) {
manager.close();
}
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.persistence.EntityManager;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.webservice.AuthenticationException;
import de.hft.stuttgart.citydoctor2.webservice.database.BuildingQueries;
import de.hft.stuttgart.citydoctor2.webservice.database.ModelQueries;
import de.hft.stuttgart.citydoctor2.webservice.model.BuildingReference;
import de.hft.stuttgart.citydoctor2.webservice.model.BuildingsReturnType;
import de.hft.stuttgart.citydoctor2.webservice.model.ModelReference;
import de.hft.stuttgart.citydoctor2.webservice.model.ParseStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.ValidationReference;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.GmlFile;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Validation;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebCityDoctorModel;
import de.hft.stuttgart.citydoctor2.webservice.utils.AuthenticationUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("models")
public class ModelsEndpoint {
private static final String ERROR_WHILE_RETRIEVING_MODELS = "Error while retrieving models";
private static final String ACCESS_VIOLATION = "User {} tried to access not owned model with id {}";
private static final Logger logger = LogManager.getLogger(ModelsEndpoint.class);
private static final AtomicLong FILE_COUNTER = new AtomicLong(0);
private static final String DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final int NAME_LENGTH = 40;
private static final Random RANDOM = new Random();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getModels(@DefaultValue("0") @QueryParam("from") int from, @Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
List<ModelReference> models = new ArrayList<>();
for (WebCityDoctorModel webModel : user.getOwnedModels()) {
ModelReference ref = new ModelReference(webModel.getId(), webModel.getFileName(), webModel.getStatus());
models.add(ref);
for (Validation valid : webModel.getValidations()) {
ref.getValidations().add(ValidationReference.of(valid));
}
}
return Response.ok(models).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal(ERROR_WHILE_RETRIEVING_MODELS, e);
return Response.serverError().build();
} finally {
HibernateUtils.closeManager(manager);
}
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response addModel(@FormDataParam("file") InputStream fileStream,
@FormDataParam("file") FormDataContentDisposition fileDetails, @Context HttpServletRequest request,
@Context ServletContext context) {
if (fileStream == null || fileDetails == null) {
return Response.status(Status.BAD_REQUEST).entity("No file provided").build();
} else if (fileDetails.getFileName().length() > 255) {
return Response.status(Status.BAD_REQUEST).entity("File name is too long (> 255 characters").build();
}
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
final File tempDir = (File) context.getAttribute("javax.servlet.context.tempdir");
final String tempFileName = String.valueOf(FILE_COUNTER.getAndIncrement());
File tempFile = new File(tempDir.getAbsolutePath() + File.separator + tempFileName);
Files.copy(fileStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
String fileName = fileDetails.getFileName();
WebCityDoctorModel model = new WebCityDoctorModel();
model.setFileName(fileName);
model.setOwner(user);
model.setStatus(ParseStatus.PARSING);
ModelQueries.storeModel(model, manager);
handleNewModel(model, tempFile, tempDir, context);
ModelReference ref = new ModelReference(model.getId(), model.getFileName(), model.getStatus());
return Response.ok(ref).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while handling uploaded file.", e);
return Response.serverError().build();
} finally {
HibernateUtils.closeManager(manager);
}
}
@GET
@Path("{modelId}/error_buildings")
@Produces(MediaType.APPLICATION_JSON)
public Response getErrorBuildings(@PathParam("modelId") int modelId,
@QueryParam("from") @DefaultValue("0") int from, @QueryParam("valid") Integer validationId,
@Context HttpServletRequest request) {
if (validationId == null) {
return Response.status(Status.BAD_REQUEST).build();
}
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
WebCityDoctorModel model = manager.find(WebCityDoctorModel.class, modelId);
if (model.getOwner().getId() != user.getId()) {
logger.warn(ACCESS_VIOLATION, user.getId(), model.getId());
return Response.status(Status.FORBIDDEN).build();
}
List<BuildingReference> buildings;
long maxCount = BuildingQueries.getErrorBuildingCountForModel(modelId, validationId, manager);
buildings = BuildingQueries.getErrorBuildingsWithErrorIndicator(from, modelId, validationId, manager);
BuildingsReturnType returnValue = new BuildingsReturnType();
returnValue.setFrom(from);
returnValue.setTo(Math.min(from + 25l, maxCount));
returnValue.setBuildings(buildings);
return Response.ok(returnValue).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal(ERROR_WHILE_RETRIEVING_MODELS, e);
return Response.serverError().build();
} finally {
HibernateUtils.closeManager(manager);
}
}
@GET
@Path("{modelId}/buildings")
@Produces(MediaType.APPLICATION_JSON)
public Response getBuildings(@PathParam("modelId") int modelId, @QueryParam("from") @DefaultValue("0") int from,
@QueryParam("valid") Integer validationId, @Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
WebCityDoctorModel model = manager.find(WebCityDoctorModel.class, modelId);
if (model.getOwner().getId() != user.getId()) {
logger.warn(ACCESS_VIOLATION, user.getId(), model.getId());
return Response.status(Status.FORBIDDEN).build();
}
List<BuildingReference> buildings;
long maxCount = BuildingQueries.getBuildingCountForModel(modelId, manager);
if (validationId == null) {
buildings = BuildingQueries.getBuildingsForModel(from, modelId, manager);
} else {
buildings = BuildingQueries.getBuildingsWithErrorIndicator(from, modelId, validationId, manager);
}
BuildingsReturnType returnValue = new BuildingsReturnType();
returnValue.setFrom(from);
returnValue.setTo(Math.min(from + 25l, maxCount));
returnValue.setBuildings(buildings);
return Response.ok(returnValue).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal(ERROR_WHILE_RETRIEVING_MODELS, e);
return Response.serverError().build();
} finally {
HibernateUtils.closeManager(manager);
}
}
@DELETE
@Path("{modelId}")
public Response deleteModel(@PathParam("modelId") int modelId, @Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
WebCityDoctorModel model = manager.find(WebCityDoctorModel.class, modelId);
if (model.getOwner().getId() != user.getId()) {
logger.warn(ACCESS_VIOLATION, user.getId(), model.getId());
return Response.status(Status.FORBIDDEN).build();
}
if (model.getZipFile() != null && model.getZipFile().getFilePath() != null) {
File zip = new File(model.getZipFile().getFilePath());
Files.delete(zip.toPath());
}
manager.getTransaction().begin();
manager.remove(model);
manager.getTransaction().commit();
return Response.ok().build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while deleting model {}", modelId, e);
return Response.serverError().build();
} finally {
HibernateUtils.closeManager(manager);
}
}
private void handleNewModel(WebCityDoctorModel oldModel, File gmlFile, File tempDir, ServletContext context) {
Thread t = new Thread(() -> {
EntityManager manager = HibernateUtils.createManager();
WebCityDoctorModel model = manager.merge(oldModel);
File parseFile = storeModelAsZipFile(gmlFile, tempDir, context, manager, model);
try {
parseDataModel(parseFile, model, manager);
ModelQueries.updateStatus(model, ParseStatus.OK, manager);
} catch (UncheckedIOException | CityGmlParseException e) {
logger.catching(e);
ModelQueries.updateStatus(model, ParseStatus.ERROR, manager);
} finally {
manager.close();
if (parseFile != null) {
try {
Files.delete(parseFile.toPath());
} catch (IOException e1) {
logger.catching(e1);
}
}
}
});
t.setUncaughtExceptionHandler((thread, e) -> {
logger.catching(e);
EntityManager manager = HibernateUtils.createManager();
WebCityDoctorModel model = manager.merge(oldModel);
ModelQueries.updateStatus(model, ParseStatus.ERROR, manager);
manager.close();
});
t.start();
}
/**
* Stores the gml file as a zip into the configured folder. Returns the unpacked
* file in a temporary directory.
*
* @param gmlFile the incoming file
* @param tempDir the temporary folder for the unzipped files
* @param context servlet context for retrieving where to store the zip files
* @param manager the database access manager
* @param model the associated data model for the file
* @return the unzipped file in a temporary directory
*/
private File storeModelAsZipFile(File gmlFile, File tempDir, ServletContext context, EntityManager manager,
WebCityDoctorModel model) {
boolean isZipFile = isZipFile(model.getFileName());
File parseFile = gmlFile;
if (!parseFile.canWrite()) {
logger.warn("Cannot write the file, deletion will fail, before zip");
}
File zipFile = gmlFile;
String storagePath = context.getInitParameter("fileStorage");
File fileStorageDir = new File(storagePath);
try {
if (!isZipFile) {
zipFile = createZipFile(gmlFile, fileStorageDir);
if (!parseFile.canWrite()) {
logger.warn("Cannot write the file, deletion will fail, after zip");
}
} else {
File copy = getStorageFile(fileStorageDir);
Files.move(zipFile.toPath(), copy.toPath());
zipFile = copy;
parseFile = unzipFile(zipFile, tempDir);
}
} catch (IOException e) {
logger.catching(e);
ModelQueries.updateStatus(model, ParseStatus.ERROR, manager);
}
GmlFile fileModel = new GmlFile();
fileModel.setFilePath(zipFile.getAbsolutePath());
ModelQueries.updateModelWithBlob(model, fileModel, manager);
return parseFile;
}
private File unzipFile(File zipFile, File tempDir) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)))) {
ZipEntry entry = zis.getNextEntry();
if (entry == null) {
throw new IllegalStateException("Zip contains no files");
}
final String tempFileName = String.valueOf(FILE_COUNTER.getAndIncrement());
File tempFile = new File(tempDir.getAbsolutePath() + File.separator + tempFileName);
Files.copy(zis, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
if (zis.getNextEntry() != null) {
throw new IllegalStateException("Zip contains more than one file");
}
return tempFile;
}
}
private void parseDataModel(File file, WebCityDoctorModel model, EntityManager manager)
throws CityGmlParseException {
ParserConfiguration config = new ParserConfiguration(8, false);
CityGmlConsumer coConsumer = new CityGmlConsumer() {
@Override
public void accept(CityObject co) {
if (co instanceof Building) {
try {
mapBuilding(model, co, manager);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} else {
throw new UnsupportedOperationException();
}
logger.debug(co.getGmlId().getGmlString());
}
};
CityGmlParser.streamCityGml(file.getAbsolutePath(), config, coConsumer, null);
}
private void mapBuilding(WebCityDoctorModel model, CityObject co, EntityManager manager) throws IOException {
Building b = (Building) co;
Lod highestLod = findHighestLod(b);
WebBuilding buildingRef = new WebBuilding();
buildingRef.setModel(model);
buildingRef.setGmlId(b.getGmlId().getGmlString());
if (highestLod == null) {
buildingRef.setViewData(new byte[] {});
} else {
List<Polygon> polys = collectPolygonsForLod(b, highestLod);
if (polys.isEmpty()) {
throw new IllegalStateException("Found empty geometries for Lod: " + highestLod);
}
byte[] geometryData;
BoundingBox bbox = BoundingBox.of(polys);
geometryData = createGeometryData(polys, bbox.getCenter());
double width = Math.max(bbox.getWidth(), bbox.getDepth());
buildingRef.setModelWidth(width);
buildingRef.setViewData(geometryData);
}
BuildingQueries.persistBuilding(buildingRef, manager);
}
private byte[] createGeometryData(List<Polygon> polys, Vector3d center) throws IOException {
byte[] geometryData;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos)) {
for (Polygon p : polys) {
Vector3d normal = p.calculateNormalNormalized();
float red = 1.0f;
float green = 1.0f;
float blue = 1.0f;
BoundarySurface surface = p.getPartOfSurface();
if (surface != null && surface.getType() == BoundarySurfaceType.ROOF) {
green = 0.0f;
blue = 0.0f;
}
TesselatedPolygon tesselatedPolygon = p.tesselate();
for (Triangle3d t : tesselatedPolygon.getTriangles()) {
writeTriangle(dos, normal, red, green, blue, t, center);
}
}
dos.flush();
geometryData = baos.toByteArray();
}
return geometryData;
}
private void writeTriangle(DataOutputStream dos, Vector3d normal, float red, float green, float blue, Triangle3d t,
Vector3d center) throws IOException {
float normalX = (float) normal.getX();
float normalY = (float) normal.getY();
float normalZ = (float) normal.getZ();
dos.writeFloat((float) (t.getP1().getX() - center.getX()));
dos.writeFloat((float) (t.getP1().getY() - center.getY()));
dos.writeFloat((float) (t.getP1().getZ() - center.getZ()));
dos.writeFloat(normalX);
dos.writeFloat(normalY);
dos.writeFloat(normalZ);
dos.writeFloat(red);
dos.writeFloat(green);
dos.writeFloat(blue);
dos.writeFloat((float) (t.getP2().getX() - center.getX()));
dos.writeFloat((float) (t.getP2().getY() - center.getY()));
dos.writeFloat((float) (t.getP2().getZ() - center.getZ()));
dos.writeFloat(normalX);
dos.writeFloat(normalY);
dos.writeFloat(normalZ);
dos.writeFloat(red);
dos.writeFloat(green);
dos.writeFloat(blue);
dos.writeFloat((float) (t.getP3().getX() - center.getX()));
dos.writeFloat((float) (t.getP3().getY() - center.getY()));
dos.writeFloat((float) (t.getP3().getZ() - center.getZ()));
dos.writeFloat(normalX);
dos.writeFloat(normalY);
dos.writeFloat(normalZ);
dos.writeFloat(red);
dos.writeFloat(green);
dos.writeFloat(blue);
}
private List<Polygon> collectPolygonsForLod(Building b, Lod highestLod) {
List<Polygon> polygons = new ArrayList<>();
collectAbstractBuildingPolygons(b, polygons, highestLod);
for (BuildingPart bp : b.getBuildingParts()) {
collectAbstractBuildingPolygons(bp, polygons, highestLod);
}
return polygons;
}
private void collectAbstractBuildingPolygons(AbstractBuilding ab, List<Polygon> polygons, Lod highestLod) {
collectCityObjectPolygons(ab, polygons, highestLod);
for (Installation bi : ab.getBuildingInstallations()) {
collectCityObjectPolygons(bi, polygons, highestLod);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
collectCityObjectPolygons(bs, polygons, highestLod);
}
}
for (BoundarySurface bs : ab.getBoundarySurfaces()) {
collectCityObjectPolygons(bs, polygons, highestLod);
}
}
private void collectCityObjectPolygons(CityObject co, List<Polygon> polygons, Lod highestLod) {
for (Geometry geom : co.getGeometries()) {
if (geom.getLod() == highestLod) {
for (Polygon p : geom.getPolygons()) {
if (!p.isLink()) {
polygons.add(p);
}
}
}
}
}
private Lod findHighestLod(Building b) {
Lod lod = findHighestAbstractBuildingLod(b);
for (BuildingPart bp : b.getBuildingParts()) {
Lod bpLod = findHighestAbstractBuildingLod(bp);
lod = getHigherLod(lod, bpLod);
}
return lod;
}
private Lod findHighestAbstractBuildingLod(AbstractBuilding ab) {
Lod lod = findHighestCityObjectLod(ab);
for (Installation bi : ab.getBuildingInstallations()) {
Lod biLod = findHighestCityObjectLod(bi);
lod = getHigherLod(lod, biLod);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
Lod bsLod = findHighestCityObjectLod(bs);
lod = getHigherLod(lod, bsLod);
}
}
for (BoundarySurface bs : ab.getBoundarySurfaces()) {
Lod bsLod = findHighestCityObjectLod(bs);
lod = getHigherLod(lod, bsLod);
}
return lod;
}
private Lod getHigherLod(Lod lod, Lod bsLod) {
if (lod == null) {
lod = bsLod;
} else {
if (!lod.isHigher(bsLod)) {
lod = bsLod;
}
}
return lod;
}
private Lod findHighestCityObjectLod(CityObject co) {
Lod highestLod = null;
for (Geometry geom : co.getGeometries()) {
if (highestLod == null) {
highestLod = geom.getLod();
} else {
if (geom.getLod().isHigher(highestLod)) {
highestLod = geom.getLod();
}
}
}
return highestLod;
}
private File createZipFile(File gmlFile, File storageDir) throws IOException {
if (!gmlFile.exists() || gmlFile.isDirectory()) {
throw new IllegalStateException("File does not exist or is a directory");
}
File zipFile = getStorageFile(storageDir);
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
ZipEntry entry = new ZipEntry(gmlFile.getName());
zipOut.putNextEntry(entry);
java.nio.file.Path path = gmlFile.toPath();
Files.copy(path, zipOut);
}
return zipFile;
}
private boolean isZipFile(String fileName) {
int lastIndex = fileName.lastIndexOf('.');
if (lastIndex != -1) {
return fileName.substring(lastIndex).equalsIgnoreCase("zip");
}
return false;
}
private File getStorageFile(File dir) {
String name = generateRandomName();
File f = new File(dir.getAbsolutePath() + File.separator + name);
while (f.exists()) {
name = generateRandomName();
f = new File(dir.getAbsolutePath() + File.separator + name);
}
return f;
}
private String generateRandomName() {
StringBuilder sb = new StringBuilder(NAME_LENGTH);
for (int i = 0; i < NAME_LENGTH; i++) {
sb.append(DIGITS.charAt(RANDOM.nextInt(DIGITS.length())));
}
return sb.toString();
}
@GET
@Path("{modelId}/status")
@Produces(MediaType.APPLICATION_JSON)
public Response getStatus(@PathParam("modelId") int modelId, @Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
WebCityDoctorModel model = manager.find(WebCityDoctorModel.class, modelId);
if (model.getOwner().getId() != user.getId()) {
return Response.status(Status.FORBIDDEN).build();
}
ModelReference ref = new ModelReference(model.getId(), model.getFileName(), model.getStatus());
return Response.ok(ref).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} finally {
HibernateUtils.closeManager(manager);
}
}
@SuppressWarnings("unused")
private String determineModelName(WebCityDoctorModel webModel) {
String modelName = webModel.getFileName();
int fileEndingIndex = modelName.lastIndexOf('.');
if (fileEndingIndex != -1) {
modelName = modelName.substring(0, fileEndingIndex);
}
return modelName;
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.persistence.EntityManager;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.webservice.database.UserQueries;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
import de.hft.stuttgart.citydoctor2.webservice.utils.HashUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HexUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("register")
public class RegisterEndpoint {
private static Logger logger = LogManager.getLogger(RegisterEndpoint.class);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response register(@FormParam("username") String username, @FormParam("password") String password) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = UserQueries.getUserForUsername(username, manager);
if (user != null) {
return Response.status(Status.CONFLICT).entity("Username already taken").build();
}
String salt = createSalt();
logger.debug("Salt for new User: {}", salt);
String passwordHash = HashUtils.createPasswordHash(password, salt);
user = new User();
user.setMail(username);
user.setPasswordHash(passwordHash);
user.setSalt(salt);
UserQueries.createUser(user, manager);
return Response.ok().build();
} catch (NoSuchAlgorithmException e) {
logger.fatal(e);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
} finally {
if (manager != null) {
manager.close();
}
}
}
private String createSalt() {
SecureRandom sr = new SecureRandom();
byte[] bytes = new byte[8];
sr.nextBytes(bytes);
return HexUtils.encode(bytes);
}
}
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipInputStream;
import javax.persistence.EntityManager;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.webservice.AuthenticationException;
import de.hft.stuttgart.citydoctor2.webservice.database.BuildingQueries;
import de.hft.stuttgart.citydoctor2.webservice.database.ErrorQueries;
import de.hft.stuttgart.citydoctor2.webservice.database.ValidationQueries;
import de.hft.stuttgart.citydoctor2.webservice.model.ValidationReference;
import de.hft.stuttgart.citydoctor2.webservice.model.ValidationStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.FeatureValidationStatus;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.User;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.Validation;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebCityDoctorModel;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebError;
import de.hft.stuttgart.citydoctor2.webservice.utils.AuthenticationUtils;
import de.hft.stuttgart.citydoctor2.webservice.utils.HibernateUtils;
@Path("models")
public class ValidationEndpoint {
private static final Logger logger = LogManager.getLogger(ValidationEndpoint.class);
private static final AtomicInteger FILE_COUNTER = new AtomicInteger(0);
@Path("{modelId}/validations")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response addValidation(@FormDataParam("file") InputStream fileStream,
@FormDataParam("file") FormDataContentDisposition fileDetails, @Context HttpServletRequest request,
@PathParam("modelId") int modelId, @Context ServletContext context) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
WebCityDoctorModel model = manager.find(WebCityDoctorModel.class, modelId);
if (model.getOwner().getId() != user.getId()) {
return Response.status(Status.FORBIDDEN).build();
}
ValidationConfiguration config = ValidationConfiguration.loadValidationConfig(fileStream);
Validation validation = new Validation(model, ValidationStatus.VALIDATING, fileDetails.getFileName());
ValidationQueries.persistValidation(manager, model, validation);
startValidationProcess(context, model, config, validation);
ValidationReference validRef = new ValidationReference(validation.getId(), fileDetails.getFileName(),
validation.getStatus());
return Response.ok(validRef).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} finally {
if (manager != null) {
manager.close();
}
}
}
@Path("validations/{validationId}/status")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getValidationStatus(@PathParam("validationId") int validationId,
@Context HttpServletRequest request) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
manager.getTransaction().begin();
Validation validation = manager.find(Validation.class, validationId);
manager.getTransaction().commit();
if (validation == null) {
return Response.status(Status.BAD_REQUEST).build();
}
if (user.getId() != validation.getModel().getOwner().getId()) {
return Response.status(Status.FORBIDDEN).build();
}
ValidationReference validRef = new ValidationReference(validation.getId(), validation.getName(),
validation.getStatus());
return Response.ok(validRef).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} finally {
if (manager != null) {
manager.close();
}
}
}
@Path("validations/{validationId}/xml")
@GET
@Produces(MediaType.APPLICATION_XML)
public Response getXmlReport(@Context HttpServletRequest request, @PathParam("validationId") int validationId) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
Validation valid = ValidationQueries.getValidation(validationId, manager);
WebCityDoctorModel model = valid.getModel();
if (model.getOwner().getId() != user.getId()) {
return Response.status(Status.FORBIDDEN).build();
}
if (valid.getStatus() != ValidationStatus.OK) {
Response.status(Status.BAD_REQUEST).build();
}
StreamingOutput out = new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException {
output.write(valid.getXmlReport());
}
};
int lastIndexOf = model.getFileName().lastIndexOf('.');
String fileName = model.getFileName();
if (lastIndexOf > 0) {
fileName = model.getFileName().substring(0, lastIndexOf);
}
fileName = "report_" + fileName + ".xml";
return Response.ok(out).header("Content-Disposition", "attachment; filename=" + fileName).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} finally {
if (manager != null) {
manager.close();
}
}
}
@Path("validations/{validationId}/pdf")
@GET
@Produces("application/pdf")
public Response getPdfReport(@Context HttpServletRequest request, @PathParam("validationId") int validationId) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
Validation valid = ValidationQueries.getValidation(validationId, manager);
WebCityDoctorModel model = valid.getModel();
if (model.getOwner().getId() != user.getId()) {
return Response.status(Status.FORBIDDEN).build();
}
if (valid.getStatus() != ValidationStatus.OK) {
Response.status(Status.BAD_REQUEST).build();
}
StreamingOutput out = new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException {
output.write(valid.getPdfReport());
}
};
int lastIndexOf = model.getFileName().lastIndexOf('.');
String fileName = model.getFileName();
if (lastIndexOf > 0) {
fileName = model.getFileName().substring(0, lastIndexOf);
}
fileName = "report_" + fileName + ".pdf";
return Response.ok(out).header("Content-Disposition", "attachment; filename=" + fileName).build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while fetching pdf report for validation id " + validationId, e);
return Response.serverError().build();
} finally {
if (manager != null) {
manager.close();
}
}
}
@Path("validations/{validationId}")
@DELETE
public Response deleteValidation(@Context HttpServletRequest request, @PathParam("validationId") int validationId) {
EntityManager manager = null;
try {
manager = HibernateUtils.createManager();
User user = AuthenticationUtils.authenticateUser(request, manager);
if (user == null) {
return Response.status(Status.FORBIDDEN).build();
}
Validation valid = ValidationQueries.getValidation(validationId, manager);
WebCityDoctorModel model = valid.getModel();
if (model.getOwner().getId() != user.getId()) {
return Response.status(Status.FORBIDDEN).build();
}
manager.getTransaction().begin();
manager.remove(valid);
manager.getTransaction().commit();
return Response.ok().build();
} catch (AuthenticationException e) {
logger.trace(AuthenticationUtils.AUTHENTICATION_DENIED, request.getRemoteAddr(), e);
return Response.status(Status.FORBIDDEN).build();
} catch (Exception e) {
logger.fatal("Error while deleting validation id " + validationId, e);
return Response.serverError().build();
} finally {
if (manager != null) {
manager.close();
}
}
}
private void startValidationProcess(ServletContext context, WebCityDoctorModel oldModel,
ValidationConfiguration config, Validation oldValidation) {
Thread t = new Thread(() -> {
final File tempDir = (File) context.getAttribute("javax.servlet.context.tempdir");
String pdfFileName = FILE_COUNTER.getAndIncrement() + ".pdf";
String tempPdfPath = tempDir.getAbsolutePath() + File.separator + pdfFileName;
String xmlFileName = FILE_COUNTER.getAndIncrement() + ".xml";
String tempXmlPath = tempDir.getAbsolutePath() + File.separator + xmlFileName;
EntityManager manager = HibernateUtils.createManager();
WebCityDoctorModel model = manager.merge(oldModel);
Validation validation = manager.merge(oldValidation);
File gmlFile = null;
try {
String gmlFileName = FILE_COUNTER.getAndIncrement() + ".gml";
String gmlFileString = tempDir.getAbsolutePath() + File.separator + gmlFileName;
gmlFile = new File(gmlFileString);
unpackGmlFile(model, gmlFile);
FeatureCheckedListener l = co -> {
Set<CheckError> errors = new HashSet<>();
List<CheckError> errorList = new ArrayList<>();
co.collectContainedErrors(errorList);
errors.addAll(errorList);
WebBuilding building = BuildingQueries.getBuildingForGmlId(co.getGmlId().getGmlString(),
model.getId(), manager);
FeatureValidationStatus status = new FeatureValidationStatus();
status.setWasValidated(co.hasCheckResults());
status.setHasError(!errors.isEmpty());
ValidationQueries.addFeatureValidationStatus(building, validation, status, manager);
if (!errors.isEmpty()) {
for (CheckError err : errors) {
WebError webError = new WebError();
webError.setBuilding(building);
webError.setName(err.getErrorId().toString());
webError.setValidation(validation);
ErrorQueries.addErrorToBuilding(building, validation, webError, manager);
}
}
};
Checker.streamCheck(gmlFile, tempXmlPath, tempPdfPath, config, l, null);
ValidationQueries.updateValidationWithReports(validation, readToByteArray(tempPdfPath),
readToByteArray(tempXmlPath), manager);
ValidationQueries.updateStatus(validation, ValidationStatus.OK, manager);
} catch (IOException | CityGmlParseException e1) {
logger.fatal("Error while validating {}", model.getFileName());
logger.catching(e1);
ValidationQueries.updateStatus(validation, ValidationStatus.ERROR, manager);
} finally {
manager.close();
try {
if (gmlFile != null && gmlFile.exists()) {
Files.delete(gmlFile.toPath());
}
File pdfFile = new File(tempPdfPath);
if (pdfFile.exists()) {
Files.delete(pdfFile.toPath());
}
File xmlFile = new File(tempXmlPath);
if (xmlFile.exists()) {
Files.delete(xmlFile.toPath());
}
} catch (IOException e1) {
logger.catching(e1);
}
}
});
t.setUncaughtExceptionHandler((thread, e) -> {
logger.catching(e);
setValidationStatusToError(oldValidation);
});
t.start();
}
private byte[] readToByteArray(String tempPdfPath) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
File pdfFile = new File(tempPdfPath);
Files.copy(pdfFile.toPath(), baos);
return baos.toByteArray();
}
private void setValidationStatusToError(Validation validation) {
EntityManager manager = HibernateUtils.createManager();
Validation valid = manager.merge(validation);
ValidationQueries.updateStatus(valid, ValidationStatus.ERROR, manager);
manager.close();
}
private void unpackGmlFile(WebCityDoctorModel model, File gmlFile) throws IOException {
File zipFile = new File(model.getZipFile().getFilePath());
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
zis.getNextEntry();
Files.copy(zis, gmlFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
import java.util.List;
public class AvailableChecksReturnType {
private List<CheckReturnType> geometricChecks;
private List<CheckReturnType> semanticChecks;
public List<CheckReturnType> getGeometricChecks() {
return geometricChecks;
}
public void setGeometricChecks(List<CheckReturnType> geometricChecks) {
this.geometricChecks = geometricChecks;
}
public List<CheckReturnType> getSemanticChecks() {
return semanticChecks;
}
public void setSemanticChecks(List<CheckReturnType> semanticChecks) {
this.semanticChecks = semanticChecks;
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebBuilding;
public class BuildingReference {
private int id;
private String gmlId;
private double width;
private List<ErrorReference> errors = new ArrayList<>();
public static BuildingReference of(WebBuilding ref) {
return new BuildingReference(ref.getId(), ref.getGmlId(), ref.getModelWidth());
}
public BuildingReference(int id, String gmlId, double width) {
super();
this.id = id;
this.gmlId = gmlId;
this.width = width;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getGmlId() {
return gmlId;
}
public void setGmlId(String gmlId) {
this.gmlId = gmlId;
}
public List<ErrorReference> getErrors() {
return errors;
}
public void setErrors(List<ErrorReference> errors) {
this.errors = errors;
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
public class BuildingReferenceWithErrorIndicator extends BuildingReference {
private boolean hasErrors;
public BuildingReferenceWithErrorIndicator(int id, String gmlId, double width, boolean hasErrors) {
super(id, gmlId, width);
this.hasErrors = hasErrors;
}
public boolean isHasErrors() {
return hasErrors;
}
public void setHasErrors(boolean hasErrors) {
this.hasErrors = hasErrors;
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
import java.util.ArrayList;
import java.util.List;
public class BuildingsReturnType {
private long from;
private long to;
private List<BuildingReference> buildings = new ArrayList<>();
public long getFrom() {
return from;
}
public void setFrom(long from) {
this.from = from;
}
public long getTo() {
return to;
}
public void setTo(long to) {
this.to = to;
}
public List<BuildingReference> getBuildings() {
return buildings;
}
public void setBuildings(List<BuildingReference> buildings) {
this.buildings = buildings;
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
public class CheckReturnType {
private String name;
private List<DefaultParameter> parameters = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<DefaultParameter> getParameters() {
return parameters;
}
public void setParameters(List<DefaultParameter> parameters) {
this.parameters = parameters;
}
}
package de.hft.stuttgart.citydoctor2.webservice.model;
import de.hft.stuttgart.citydoctor2.webservice.model.entities.WebError;
public class ErrorReference {
private int id;
private String name;
public static ErrorReference of(WebError err) {
return new ErrorReference(err.getId(), err.getName());
}
private ErrorReference(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment