You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2018/10/02 11:55:13 UTC

empire-db git commit: EMPIREDB-271 Vue project: error handling added

Repository: empire-db
Updated Branches:
  refs/heads/master 795b587bd -> f9a7d1091


EMPIREDB-271
Vue project: error handling added


Project: http://git-wip-us.apache.org/repos/asf/empire-db/repo
Commit: http://git-wip-us.apache.org/repos/asf/empire-db/commit/f9a7d109
Tree: http://git-wip-us.apache.org/repos/asf/empire-db/tree/f9a7d109
Diff: http://git-wip-us.apache.org/repos/asf/empire-db/diff/f9a7d109

Branch: refs/heads/master
Commit: f9a7d109168f8e796e33a8c5a552c7371ec576bd
Parents: 795b587
Author: Rainer Döbele <do...@apache.org>
Authored: Tue Oct 2 13:55:09 2018 +0200
Committer: Rainer Döbele <do...@apache.org>
Committed: Tue Oct 2 13:55:09 2018 +0200

----------------------------------------------------------------------
 .../empire/rest/app/RecordInitException.java    | 54 +++++++++++++++++++
 .../apache/empire/rest/json/JsoErrorInfo.java   | 48 +++++++++++++++++
 .../rest/service/AuthenticationService.java     | 26 +++------
 .../empire/rest/service/EmployeeService.java    | 56 +++++++++++++-------
 .../org/apache/empire/rest/service/Service.java | 45 ++++++++++++++++
 .../empire/vue/sample/db/RecordContext.java     |  8 +++
 .../vue/sample/db/records/SampleRecord.java     | 19 ++++++-
 .../src/main/vue/src/App.vue                    | 49 ++++++++++++++++-
 .../src/main/vue/src/api/emp-api.js             |  2 +-
 .../src/main/vue/src/assets/css/layout.css      |  6 +--
 .../src/main/vue/src/pages/employeeDetail.vue   | 15 +++---
 .../src/main/vue/src/pages/employeeList.vue     |  4 +-
 .../src/main/vue/src/pages/login.vue            |  8 +--
 13 files changed, 277 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/app/RecordInitException.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/app/RecordInitException.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/app/RecordInitException.java
new file mode 100644
index 0000000..42e0a79
--- /dev/null
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/app/RecordInitException.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.empire.rest.app;
+
+import java.util.List;
+
+import org.apache.empire.commons.ErrorType;
+import org.apache.empire.db.exceptions.FieldValueException;
+import org.apache.empire.exceptions.EmpireException;
+
+public class RecordInitException extends EmpireException
+{
+    private static final long serialVersionUID = 1L;
+
+    public static final ErrorType recordInitErrorType = new ErrorType("error.db.recordInitErrorType",  "Record initialization failed: {0}");
+    
+    private static String[] extractFieldErrorMessage(List<FieldValueException> fieldExeptions)
+    {
+        String[] params = new String[fieldExeptions.size()];
+        for (int i=0; i<params.length; i++)
+            params[i] = fieldExeptions.get(i).getMessage();
+        return params;
+    }
+    
+    private final List<FieldValueException> fieldExeptions;
+
+    public RecordInitException(List<FieldValueException> fieldExeptions)
+    {
+        super(recordInitErrorType, extractFieldErrorMessage(fieldExeptions));
+        this.fieldExeptions = fieldExeptions;
+    }
+
+    public List<FieldValueException> getFieldExeptions()
+    {
+        return fieldExeptions;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/json/JsoErrorInfo.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/json/JsoErrorInfo.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/json/JsoErrorInfo.java
new file mode 100644
index 0000000..9945911
--- /dev/null
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/json/JsoErrorInfo.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.empire.rest.json;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.apache.empire.exceptions.EmpireException;
+import org.apache.empire.rest.app.TextResolver;
+
+public class JsoErrorInfo extends LinkedHashSet<String>
+{
+    private static final long serialVersionUID = 1L;
+
+    public JsoErrorInfo(String message)
+    {
+        this.add(message);
+    }
+    
+    public JsoErrorInfo(EmpireException e, TextResolver resolver)
+    {
+        this.add(resolver.getExceptionMessage(e));
+    }
+    
+    public JsoErrorInfo(List<? extends EmpireException> list, TextResolver resolver)
+    {
+        for (EmpireException e : list)
+        {
+            this.add(resolver.getExceptionMessage(e));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/AuthenticationService.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/AuthenticationService.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/AuthenticationService.java
index 5b8b330..c5f9b2e 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/AuthenticationService.java
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/AuthenticationService.java
@@ -20,9 +20,6 @@ package org.apache.empire.rest.service;
 
 import java.util.UUID;
 
-import javax.json.Json;
-import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.FormParam;
@@ -35,6 +32,7 @@ import javax.ws.rs.core.NewCookie;
 import javax.ws.rs.core.Response;
 
 import org.apache.empire.commons.StringUtils;
+import org.apache.empire.rest.json.JsoErrorInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,30 +47,22 @@ public class AuthenticationService
     @Produces(MediaType.APPLICATION_JSON)
     public Response login(@FormParam("username") String username, @FormParam("password") String password)
     {
-        JsonObjectBuilder jsonObjBuilder;
         // Check params
         if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
-        {  
-            jsonObjBuilder = Json.createObjectBuilder();
-            jsonObjBuilder.add("error", "Invalid username or password.");
-            JsonObject jsonObj = jsonObjBuilder.build();
-            return Response.status(Response.Status.BAD_REQUEST).entity(jsonObj.toString()).build();
+        {   // empty username or password
+            JsoErrorInfo errorInfo = new JsoErrorInfo("Invalid username or password.");
+            return Response.status(Response.Status.BAD_REQUEST).entity(errorInfo).build();
         }
-
+        // Validate
         if (username.equals("bad") || password.equals("password"))
-        {
-            jsonObjBuilder = Json.createObjectBuilder();
-            jsonObjBuilder.add("error", "Bad user or password");
-            JsonObject jsonObj = jsonObjBuilder.build();
-            return Response.status(Response.Status.UNAUTHORIZED).entity(jsonObj.toString()).build();
+        {   // simulate invalid username / password
+            JsoErrorInfo errorInfo = new JsoErrorInfo("Bad user or password");
+            return Response.status(Response.Status.UNAUTHORIZED).entity(errorInfo).build();
         }
-        
         log.info("Log in for user {}", username);
-
         // Set Cookie
         String cookieValue = UUID.randomUUID().toString().replaceAll("-", "");
         NewCookie cookie = new NewCookie(Service.Consts.LOGIN_COOKIE_NAME, cookieValue, "/", null, null, NewCookie.DEFAULT_MAX_AGE, false);
-        
         // OK
         return Response.ok().cookie(cookie).build();
     }

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/EmployeeService.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/EmployeeService.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/EmployeeService.java
index d22d5f5..aef35f5 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/EmployeeService.java
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/EmployeeService.java
@@ -37,11 +37,13 @@ import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBJoinType;
 import org.apache.empire.db.DBReader;
 import org.apache.empire.exceptions.EmpireException;
+import org.apache.empire.rest.app.RecordInitException;
 import org.apache.empire.rest.app.SampleServiceApp;
 import org.apache.empire.rest.app.TextResolver;
 import org.apache.empire.rest.json.JsoColumnMeta;
 import org.apache.empire.rest.json.JsoRecordData;
 import org.apache.empire.rest.json.JsoResultWithMeta;
+import org.apache.empire.vue.sample.db.RecordContext;
 import org.apache.empire.vue.sample.db.SampleDB;
 import org.apache.empire.vue.sample.db.SampleDB.TDepartments;
 import org.apache.empire.vue.sample.db.SampleDB.TEmployees;
@@ -59,7 +61,8 @@ public class EmployeeService extends Service {
     @Produces(MediaType.APPLICATION_JSON)
     public Response getEmployeeFilter() {
 
-        TextResolver txtres = SampleServiceApp.instance().getTextResolver(Locale.ENGLISH);
+        RecordContext ctx = this.getRecordContext(); 
+	    TextResolver textResolver = ctx.getTextResolver();
 
         // Query Department options
         SampleDB db = getDatabase();
@@ -68,16 +71,16 @@ public class EmployeeService extends Service {
         cmd.join  (db.T_DEPARTMENTS.DEPARTMENT_ID, db.T_EMPLOYEES.DEPARTMENT_ID);
         cmd.groupBy(cmd.getSelectExprList());
         cmd.orderBy(db.T_DEPARTMENTS.NAME);
-        Options departmentOptions = db.queryOptionList(cmd, getRecordContext().getConnection());
+        Options departmentOptions = db.queryOptionList(cmd, ctx.getConnection());
         
         // Create Metadata
         TEmployees TE = db.T_EMPLOYEES;
         JsoColumnMeta[] meta = new JsoColumnMeta[] { 
-          new JsoColumnMeta(TE.EMPLOYEE_ID, txtres),
-          new JsoColumnMeta(TE.FIRST_NAME, txtres),
-          new JsoColumnMeta(TE.LAST_NAME, txtres),
-          new JsoColumnMeta(TE.DEPARTMENT_ID, txtres, departmentOptions, false, false, false),
-          new JsoColumnMeta(TE.GENDER, txtres),
+          new JsoColumnMeta(TE.EMPLOYEE_ID, textResolver),
+          new JsoColumnMeta(TE.FIRST_NAME, textResolver),
+          new JsoColumnMeta(TE.LAST_NAME, textResolver),
+          new JsoColumnMeta(TE.DEPARTMENT_ID, textResolver, departmentOptions, false, false, false),
+          new JsoColumnMeta(TE.GENDER, textResolver),
         };
         
         JsoRecordData filter = new JsoRecordData(meta);
@@ -142,16 +145,17 @@ public class EmployeeService extends Service {
 	@Produces(MediaType.APPLICATION_JSON)
 	public Response getEmployee(@PathParam("employeeId") int employeeId) {
 
+        RecordContext ctx = this.getRecordContext(); 
 	    try {
 	        // return a record
-	        EmployeeRecord rec = new EmployeeRecord(getDatabase(), getRecordContext());
+	        EmployeeRecord rec = new EmployeeRecord(getDatabase(), ctx);
             rec.read(employeeId);
             JsoRecordData emp = new JsoRecordData(rec);
             return Response.ok(new JsoResultWithMeta(emp, rec.getMeta())).build();
 	        
 	    } catch(EmpireException e) {
 	        log.error("Unable to load employee with id {}", employeeId);
-	        return Response.serverError().build();
+            return getErrorResponse(e, ctx);
 	    }
 	}
 
@@ -160,29 +164,42 @@ public class EmployeeService extends Service {
     @Produces(MediaType.APPLICATION_JSON)
     public Response addEmployee() {
 
+        RecordContext ctx = this.getRecordContext(); 
         try {
             // return a record
-            EmployeeRecord rec = new EmployeeRecord(getDatabase(), getRecordContext());
+            EmployeeRecord rec = new EmployeeRecord(getDatabase(), ctx);
             rec.create();
             JsoRecordData emp = new JsoRecordData(rec);
             return Response.ok(new JsoResultWithMeta(emp, rec.getMeta())).build();
             
         } catch(EmpireException e) {
             log.error("Unable to create an employee record");
-            return Response.serverError().build();
+            return getErrorResponse(e, ctx);
         }
     }
 
     @POST
-    @Path("/set")
+    @Path("/update")
     @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
     public Response updateEmployee(JsoRecordData employeeData) {
 
-        EmployeeRecord rec = new EmployeeRecord(getDatabase(), getRecordContext());
-        rec.init(employeeData, employeeData.isNewRecord());
-        rec.update();
-        
-        return Response.ok().build();
+        RecordContext ctx = this.getRecordContext(); 
+        try {
+            // return a record
+            EmployeeRecord rec = new EmployeeRecord(getDatabase(), ctx);
+            rec.init(employeeData, employeeData.isNewRecord());
+            rec.update();
+            return Response.ok().build();
+            
+        } catch(RecordInitException e) {
+            log.error("Record initialization failed due to {}", e.getMessage());
+            return getErrorResponse(e.getFieldExeptions(), ctx);
+
+        } catch(EmpireException e) {
+            log.error("Unable to update employee with id {}", employeeData.get("employeeId"));
+            return getErrorResponse(e, ctx);
+        }
     }
 
     @GET
@@ -190,15 +207,16 @@ public class EmployeeService extends Service {
     @Produces(MediaType.APPLICATION_JSON)
     public Response deleteEmployee(@PathParam("employeeId") int employeeId) {
 
+        RecordContext ctx = this.getRecordContext(); 
         try {
             // return a record
             SampleDB db = getDatabase();
-            db.T_EMPLOYEES.deleteRecord(employeeId, getRecordContext().getConnection());
+            db.T_EMPLOYEES.deleteRecord(employeeId, ctx.getConnection());
             return Response.ok().build();
             
         } catch(EmpireException e) {
             log.error("Unable to delete employee with id {}", employeeId);
-            return Response.serverError().build();
+            return getErrorResponse(e, ctx);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/Service.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/Service.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/Service.java
index 2328c06..f087e82 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/Service.java
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/rest/service/Service.java
@@ -19,13 +19,20 @@
 package org.apache.empire.rest.service;
 
 import java.sql.Connection;
+import java.util.List;
+import java.util.Locale;
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
 
+import org.apache.empire.exceptions.EmpireException;
+import org.apache.empire.rest.app.SampleServiceApp;
+import org.apache.empire.rest.app.TextResolver;
+import org.apache.empire.rest.json.JsoErrorInfo;
 import org.apache.empire.vue.sample.db.RecordContext;
 import org.apache.empire.vue.sample.db.SampleDB;
 import org.glassfish.jersey.server.ContainerRequest;
@@ -58,10 +65,12 @@ public abstract class Service {
     public static class ServiceRecordContext implements RecordContext
     {
         private final Connection conn;
+        private final TextResolver textResolver;
         
         public ServiceRecordContext(Connection conn)
         {
             this.conn = conn;
+            this.textResolver = SampleServiceApp.instance().getTextResolver(Locale.ENGLISH);
         }
 
         @Override
@@ -69,6 +78,12 @@ public abstract class Service {
         {
             return conn;
         }
+
+        @Override
+        public TextResolver getTextResolver()
+        {
+            return textResolver;
+        }
     }
     
 	@Context
@@ -97,6 +112,36 @@ public abstract class Service {
 		return this.req;
 	}
 
+	/**
+	 * EmpireException
+	 * @param e the exception
+	 * @param ctx the record context
+     * @return the error response
+	 */
+    
+	public Response getErrorResponse(EmpireException e, RecordContext ctx) {
+        return Response.serverError().entity(new JsoErrorInfo(e, ctx.getTextResolver())).build();
+    }
+
+	/**
+	 * Multiple Exceptions
+	 * @param extns the list of exceptions
+     * @param ctx the record context
+	 * @return the error response
+	 */
+	public Response getErrorResponse(List<? extends EmpireException> extns, RecordContext ctx) {
+        return Response.serverError().entity(new JsoErrorInfo(extns, ctx.getTextResolver())).build();
+    }
+	
+	/**
+	 * General error
+	 * @param e
+     * @return the error response
+	 */
+    public Response getErrorResponse(Exception e) {
+        return Response.serverError().build();
+    }
+
 	public String getRemoteAddr() {
 		// TODO check X-Real-IP / X-Forwarded-For
 		return this.req.getRemoteAddr();

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/RecordContext.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/RecordContext.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/RecordContext.java
index f4c9c0e..32d9418 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/RecordContext.java
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/RecordContext.java
@@ -20,6 +20,8 @@ package org.apache.empire.vue.sample.db;
 
 import java.sql.Connection;
 
+import org.apache.empire.rest.app.TextResolver;
+
 /**
  * Provide access to info and resources for a record instance
  * Add more to 
@@ -33,6 +35,12 @@ public interface RecordContext
      * @return the JDBC connection
      */
     Connection getConnection();
+
+    /**
+     * provides access to the text resolver
+     * @return the TextResolver
+     */
+    TextResolver getTextResolver();
     
     /**
      * provide access to the current user

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/records/SampleRecord.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/records/SampleRecord.java b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/records/SampleRecord.java
index 7acd4b4..eba7767 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/records/SampleRecord.java
+++ b/empire-db-examples/empire-db-example-vue/src/main/java/org/apache/empire/vue/sample/db/records/SampleRecord.java
@@ -18,12 +18,15 @@
  */
 package org.apache.empire.vue.sample.db.records;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
 import org.apache.empire.commons.Options;
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.exceptions.FieldValueException;
+import org.apache.empire.rest.app.RecordInitException;
 import org.apache.empire.rest.app.SampleServiceApp;
 import org.apache.empire.rest.app.TextResolver;
 import org.apache.empire.rest.json.JsoColumnMeta;
@@ -97,6 +100,7 @@ public abstract class SampleRecord<T extends SampleTable> extends DBRecord {
             super.read(T, key, recordContext.getConnection());
         }
         // set all fields
+        List<FieldValueException> exptns = new ArrayList<FieldValueException>(0);
         for (DBColumn c : T.getColumns())
         {   // skip all key columns
             if (T.isKeyColumn(c))
@@ -110,8 +114,19 @@ public abstract class SampleRecord<T extends SampleTable> extends DBRecord {
                 continue; 
             }
             Object value = data.getValue(prop, c.getDataType());
-            // set Value 
-            this.setValue(c, value);
+            // set Value
+            try {
+                // set the value
+                this.setValue(c, value);
+            } catch(FieldValueException e) {
+                // add exception to list
+                exptns.add(e);
+            }
+        }
+        // Exceptions?
+        if (!exptns.isEmpty())
+        {   // Init failed with exceptions
+            throw new RecordInitException(exptns);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/App.vue
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/App.vue b/empire-db-examples/empire-db-example-vue/src/main/vue/src/App.vue
index 880dbcd..6827a69 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/App.vue
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/App.vue
@@ -21,6 +21,14 @@
       <button class="rdp-button" @click="doLogout" v-if="this.isLoggedIn()">Logout</button>
     </div>
 
+    <div id="messages" v-if="messages">
+      <ul>
+        <template v-for="item in messages">
+          <li>{{item}}</li>
+        </template>
+      </ul>
+    </div>
+
     <router-view></router-view>
 
   </div>
@@ -35,7 +43,9 @@
 
     data () {
       return {
-        employeeFilter: undefined
+        employeeFilter: undefined,
+        messages: undefined,
+        redirectWithError: false
       }
     },
 
@@ -43,6 +53,16 @@
       this.startup()
     },
 
+    watch: {
+      $route (to, from) {
+        if (this.redirectWithError) {
+          this.redirectWithError = false
+        } else {
+          this.clearMessages()
+        }
+      }
+    },
+
     methods: {
       startup: function () {
         EMPAPI.debug('Application startup! Vue version is ' + Vue.version)
@@ -50,6 +70,33 @@
       clearData: function () {
         this.employeeFilter = undefined
       },
+      clearMessages: function () {
+        this.messages = undefined
+      },
+      addMessages: function (msgs) {
+        if (this.messages) {
+          this.messages = this.messages.concat(msgs)
+        } else {
+          this.messages = msgs
+        }
+      },
+      redirect: function (target) {
+        this.clearMessages()
+        this.$router.push(target)
+      },
+      handleError: function (error, target) {
+        // redirect to target
+        if (target) {
+          this.redirectWithError = true
+          this.$router.push(target)
+        }
+        // set message
+        if (error.responseJSON) {
+          this.addMessages(error.responseJSON)
+        } else {
+          this.addMessages([ error.statusText ])
+        }
+      },
       isLoggedIn: function () {
         if (EMPAPI.loggedIn === undefined) {
           EMPAPI.debug('EMPAPI.loggedIn is undefined!')

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/api/emp-api.js
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/api/emp-api.js b/empire-db-examples/empire-db-example-vue/src/main/vue/src/api/emp-api.js
index 343655a..ae4d046 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/api/emp-api.js
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/api/emp-api.js
@@ -134,7 +134,7 @@ const EMPAPI = {
   },
 
   updateEmployee: function (employeeData) {
-    return AJAX.postJSON('/employee/set', employeeData)
+    return AJAX.postJSON('/employee/update', employeeData)
   },
 
   deleteEmployee: function (employeeId) {

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/assets/css/layout.css
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/assets/css/layout.css b/empire-db-examples/empire-db-example-vue/src/main/vue/src/assets/css/layout.css
index 2d1b0dd..e43c767 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/assets/css/layout.css
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/assets/css/layout.css
@@ -64,8 +64,8 @@ A:hover { text-decoration:underline;}
 
 
 #messages ul {
-    background-color: #FBF0F0;
-    border:2px solid #8F99EF;
+  background-color: #FBF0F0;
+  border:2px solid #922727;
 	list-style-type: square;
 	padding: 8px;
 	padding-left: 24px;
@@ -79,7 +79,7 @@ A:hover { text-decoration:underline;}
     padding-right:5px;
 */
 	color: #922727;
-    font-weight: bold;
+  font-weight: bold;
 }
 
 

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeDetail.vue
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeDetail.vue b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeDetail.vue
index edbe9b8..f550c5b 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeDetail.vue
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeDetail.vue
@@ -90,33 +90,30 @@
         EMPAPI.debug('create employee record')
         EMPAPI.createEmployeeRecord(this.employeeId)
           .done(response => (this.onLoadDone(response)))
-        /*
-          .fail(() => this.$router.push('/login'))
-        */
+          .fail(response => (this.$parent.handleError(response, '/employeeList')))
       },
       loadDetails: function () {
         EMPAPI.debug('load employee record')
         EMPAPI.readEmployeeRecord(this.employeeId)
           .done(response => (this.onLoadDone(response)))
-        /*
-          .fail(() => this.$router.push('/login'))
-        */
+          .fail(response => (this.$parent.handleError(response, '/employeeList')))
       },
       doSave: function (event) {
+        this.$parent.clearMessages()
         EMPAPI.debug('load employee record')
         EMPAPI.updateEmployee(this.employeeRecord.data)
           .done(response => (this.onUpdateDone(response)))
+          .fail(response => (this.$parent.handleError(response)))
       },
       doDelete: function (event) {
         if (!confirm('Do you really want to delete this employee?')) {
           return
         }
+        this.$parent.clearMessages()
         EMPAPI.debug('load employee record')
         EMPAPI.deleteEmployee(this.employeeId)
           .done(response => (this.onUpdateDone(response)))
-        /*
-          .fail(() => this.$router.push('/login'))
-        */
+          .fail(response => (this.$parent.handleError(response, '/employeeList')))
       },
       doReturnToList: function (event) {
         this.$router.push('/employeeList')

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeList.vue
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeList.vue b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeList.vue
index 4e08f8c..1b098d3 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeList.vue
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/employeeList.vue
@@ -101,7 +101,6 @@
   import eInput from '../components/e-input'
   import eLabel from '../components/e-label'
   import eValue from '../components/e-value'
-  import app from '../App'
   // import $ from 'jquery'
 
   export default {
@@ -112,8 +111,7 @@
       eControl,
       eInput,
       eLabel,
-      eValue,
-      app
+      eValue
     },
 
     data () {

http://git-wip-us.apache.org/repos/asf/empire-db/blob/f9a7d109/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/login.vue
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/login.vue b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/login.vue
index f0eb178..493043a 100644
--- a/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/login.vue
+++ b/empire-db-examples/empire-db-example-vue/src/main/vue/src/pages/login.vue
@@ -62,13 +62,7 @@
       login: function () {
         EMPAPI.login(this.username, this.password)
           .done(() => this.$parent.onLoginComplete())
-          .fail(function (response) {
-            var msg = 'Der Dienst ist zur Zeit nicht verfügbar.'
-            if (response.responseJSON) {
-              msg = response.responseJSON.error
-            }
-            alert(msg)
-          })
+          .fail(response => (this.$parent.handleError(response)))
       }
     }
   }