Merge "Portal Spring Boot Development"
diff --git a/portal-BE/pom.xml b/portal-BE/pom.xml
index 6a42e87..a7e8588 100644
--- a/portal-BE/pom.xml
+++ b/portal-BE/pom.xml
@@ -50,6 +50,11 @@
 			<optional>true</optional>
 		</dependency>
 		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-aop</artifactId>
+			<version>2.1.6.RELEASE</version>
+		</dependency>
+		<dependency>
 			<groupId>com.h2database</groupId>
 			<artifactId>h2</artifactId>
 			<scope>runtime</scope>
@@ -59,6 +64,24 @@
 			<artifactId>mysql-connector-java</artifactId>
 			<scope>runtime</scope>
 		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.glassfish/javax.el -->
+		<dependency>
+			<groupId>org.glassfish</groupId>
+			<artifactId>javax.el</artifactId>
+			<version>3.0.1-b11</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/javax.el/el-api -->
+		<dependency>
+			<groupId>javax.el</groupId>
+			<artifactId>el-api</artifactId>
+			<version>2.2.1-b04</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
+		<dependency>
+			<groupId>org.jsoup</groupId>
+			<artifactId>jsoup</artifactId>
+			<version>1.12.1</version>
+		</dependency>
 		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
diff --git a/portal-BE/src/main/java/org/onap/portal/aop/service/FnLanguageServiceAOP.java b/portal-BE/src/main/java/org/onap/portal/aop/service/FnLanguageServiceAOP.java
new file mode 100644
index 0000000..250a6e2
--- /dev/null
+++ b/portal-BE/src/main/java/org/onap/portal/aop/service/FnLanguageServiceAOP.java
@@ -0,0 +1,77 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.aop.service;
+
+import java.security.Principal;
+import java.util.stream.Collectors;
+import javax.validation.ConstraintViolation;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.onap.portal.domain.db.fn.FnLanguage;
+import org.onap.portal.validation.DataValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+public class FnLanguageServiceAOP {
+       private static final Logger LOGGER = LoggerFactory.getLogger(FnLanguageServiceAOP.class);
+
+       @Autowired
+       private DataValidator dataValidator;
+
+       @Before("execution(* org.onap.portal.service.fn.FnLanguageService.save(..)) && args(principal, fnLanguage)")
+       public void save(final Principal principal, final FnLanguage fnLanguage) {
+              if (fnLanguage == null) {
+                     LOGGER.error("User " + principal.getName() + " try to save NULL fnLanguage");
+                     throw new NullPointerException("FnLanguage cannot be null or empty");
+              }
+              if (!dataValidator.isValid(fnLanguage)) {
+                     String violations = dataValidator.getConstraintViolations(fnLanguage).stream()
+                             .map(ConstraintViolation::getMessage)
+                             .collect(Collectors.joining(", "));
+                     LOGGER.error("User " + principal.getName() + " try to save not valid fnLanguage: " + violations);
+                     throw new IllegalArgumentException("FnLanguage is not valid, " + violations);
+              }
+       }
+}
diff --git a/portal-BE/src/main/java/org/onap/portal/controller/LanguageController.java b/portal-BE/src/main/java/org/onap/portal/controller/LanguageController.java
index 2c88694..2ea4ff2 100644
--- a/portal-BE/src/main/java/org/onap/portal/controller/LanguageController.java
+++ b/portal-BE/src/main/java/org/onap/portal/controller/LanguageController.java
@@ -40,15 +40,23 @@
 
 package org.onap.portal.controller;
 
+import java.security.Principal;
 import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.onap.portal.aop.service.FnLanguageServiceAOP;
 import org.onap.portal.domain.db.fn.FnLanguage;
 import org.onap.portal.domain.db.fn.FnUser;
+import org.onap.portal.domain.dto.PortalRestResponse;
+import org.onap.portal.domain.dto.PortalRestStatusEnum;
 import org.onap.portal.service.fn.FnLanguageService;
 import org.onap.portal.service.fn.FnUserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -57,6 +65,7 @@
 @RestController
 @RequestMapping("/auxapi")
 public class LanguageController {
+       private static final Logger LOGGER = LoggerFactory.getLogger(LanguageController.class);
 
        private final FnLanguageService languageService;
        private final FnUserService fnUserService;
@@ -68,12 +77,12 @@
               this.fnUserService = fnUserService;
        }
 
-       @RequestMapping(value = "/language",method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
+       @GetMapping(value = "/language", produces = "application/json;charset=UTF-8")
        public List<FnLanguage> getLanguageList() {
               return languageService.getLanguages();
        }
 
-       @RequestMapping(value = "/languageSetting/user/{loginId}",method = RequestMethod.POST)
+       @PostMapping(value = "/languageSetting/user/{loginId}")
        public void setUpUserLanguage(@RequestBody FnLanguage fnLanguage,
                @PathVariable("loginId") Long loginId) {
               if (fnUserService.getUser(loginId).isPresent()){
@@ -83,7 +92,7 @@
               }
        }
 
-       @RequestMapping(value = "/languageSetting/user/{loginId}",method = RequestMethod.GET)
+       @GetMapping(value = "/languageSetting/user/{loginId}")
        public FnLanguage getUserLanguage(HttpServletRequest request, HttpServletResponse response,
                @PathVariable("loginId") Long loginId) {
               if (fnUserService.getUser(loginId).isPresent()){
@@ -93,4 +102,20 @@
               return new FnLanguage();
        }
 
+       @PostMapping(value = "/language")
+       public PortalRestResponse<String> saveLanguage(final Principal principal, final FnLanguage fnLanguage){
+              PortalRestResponse<String> response = new PortalRestResponse<>();
+              try {
+                     response.setMessage("SUCCESS");
+                     response.setResponse(languageService.save(principal, fnLanguage).toString());
+                     response.setStatus(PortalRestStatusEnum.OK);
+              } catch (Exception e){
+                     response.setMessage("FAILURE");
+                     response.setResponse(e.getMessage());
+                     response.setStatus(PortalRestStatusEnum.ERROR);
+                     return response;
+              }
+              return response;
+       }
+
 }
diff --git a/portal-BE/src/main/java/org/onap/portal/domain/db/fn/FnLanguage.java b/portal-BE/src/main/java/org/onap/portal/domain/db/fn/FnLanguage.java
index f8dfac2..09cb5a6 100644
--- a/portal-BE/src/main/java/org/onap/portal/domain/db/fn/FnLanguage.java
+++ b/portal-BE/src/main/java/org/onap/portal/domain/db/fn/FnLanguage.java
@@ -45,6 +45,7 @@
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
 import javax.persistence.Table;
 import javax.validation.constraints.Digits;
 import javax.validation.constraints.NotNull;
@@ -53,6 +54,7 @@
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
+import lombok.ToString;
 import org.hibernate.validator.constraints.SafeHtml;
 /*
 CREATE TABLE `fn_language` (
@@ -66,13 +68,15 @@
 @Table(name = "fn_language")
 @NoArgsConstructor
 @AllArgsConstructor
+@ToString
 @Getter
 @Setter
 @Entity
+@SequenceGenerator(name="seq", initialValue=3, allocationSize=100)
 public class FnLanguage {
 
        @Id
-       @GeneratedValue(strategy = GenerationType.AUTO)
+       @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
        @Column(name = "language_id", length = 11, nullable = false, columnDefinition = "int(11) AUTO_INCREMENT")
        @Digits(integer = 11, fraction = 0)
        private Long languageId;
diff --git a/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestResponse.java b/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestResponse.java
new file mode 100644
index 0000000..f1ca07f
--- /dev/null
+++ b/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestResponse.java
@@ -0,0 +1,122 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.domain.dto;
+
+public class PortalRestResponse<T> {
+	
+	private PortalRestStatusEnum status;
+	private String message;
+	
+	private T response;
+	
+	public PortalRestResponse(){};
+	
+	public PortalRestResponse(PortalRestStatusEnum status, String message, T response){
+		this.status = status;
+		this.message = message;
+		this.response = response;
+	}
+
+	public PortalRestStatusEnum getStatus() {
+		return status;
+	}
+
+	public void setStatus(PortalRestStatusEnum status) {
+		this.status = status;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	public T getResponse() {
+		return response;
+	}
+
+	public void setResponse(T response) {
+		this.response = response;
+	}
+
+	@Override
+	public String toString() {
+		return "PortalRestResponse [status=" + status + ", message=" + message + ", response=" + response + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((message == null) ? 0 : message.hashCode());
+		result = prime * result + ((response == null) ? 0 : response.hashCode());
+		result = prime * result + ((status == null) ? 0 : status.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		PortalRestResponse other = (PortalRestResponse) obj;
+		if (message == null) {
+			if (other.message != null)
+				return false;
+		} else if (!message.equals(other.message))
+			return false;
+		if (response == null) {
+			if (other.response != null)
+				return false;
+		} else if (!response.equals(other.response))
+			return false;
+		if (status != other.status)
+			return false;
+		return true;
+	};	
+	
+	
+}
diff --git a/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestStatusEnum.java b/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestStatusEnum.java
new file mode 100644
index 0000000..0a175f6
--- /dev/null
+++ b/portal-BE/src/main/java/org/onap/portal/domain/dto/PortalRestStatusEnum.java
@@ -0,0 +1,57 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.domain.dto;
+
+public enum PortalRestStatusEnum{
+	OK("ok"),
+	WARN("WARNING"),
+	ERROR("error");
+	
+	private String value;
+	private PortalRestStatusEnum(String value){
+		this.value = value;
+	}
+	
+	@Override
+    public String toString() {
+        return value;
+    }
+}
diff --git a/portal-BE/src/main/java/org/onap/portal/service/fn/FnLanguageService.java b/portal-BE/src/main/java/org/onap/portal/service/fn/FnLanguageService.java
index cdbba06..da9c048 100644
--- a/portal-BE/src/main/java/org/onap/portal/service/fn/FnLanguageService.java
+++ b/portal-BE/src/main/java/org/onap/portal/service/fn/FnLanguageService.java
@@ -40,6 +40,7 @@
 
 package org.onap.portal.service.fn;
 
+import java.security.Principal;
 import java.util.List;
 import java.util.Optional;
 import org.onap.portal.dao.fn.FnLanguageDao;
@@ -56,10 +57,13 @@
               this.fnLanguageDao = fnLanguageDao;
        }
 
-       public Optional<FnLanguage> findById(Long id){
+       public Optional<FnLanguage> findById(final Long id){
               return fnLanguageDao.findById(id);
        }
        public List<FnLanguage> getLanguages(){
               return fnLanguageDao.findAll();
        }
+       public FnLanguage save(final Principal principal, final FnLanguage fnLanguage){
+              return fnLanguageDao.save(fnLanguage);
+       }
 }
diff --git a/portal-BE/src/test/java/org/onap/portal/controller/LanguageControllerTest.java b/portal-BE/src/test/java/org/onap/portal/controller/LanguageControllerTest.java
new file mode 100644
index 0000000..0015c00
--- /dev/null
+++ b/portal-BE/src/test/java/org/onap/portal/controller/LanguageControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.controller;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.onap.portal.dao.fn.FnLanguageDao;
+import org.onap.portal.domain.db.fn.FnLanguage;
+import org.onap.portal.domain.dto.PortalRestResponse;
+import org.onap.portal.domain.dto.PortalRestStatusEnum;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@TestPropertySource(locations="classpath:test.properties")
+class LanguageControllerTest {
+       private UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken("demo", "XZa6pS1vC0qKXWtn9wcZWdLx61L0=");
+
+       @Autowired
+       private LanguageController languageController;
+       @Autowired
+       private FnLanguageDao fnLanguageDao;
+
+       @Test
+       void saveLanguage() {
+              //Given
+              FnLanguage fnLanguage = new FnLanguage();
+              fnLanguage.setLanguageName("Polish");
+              fnLanguage.setLanguageAlias("PL");
+              //When
+              PortalRestResponse<String> expected = new PortalRestResponse<>();
+              expected.setMessage("SUCCESS");
+              expected.setResponse("FnLanguage(languageId=3, languageName=Polish, languageAlias=PL)");
+              expected.setStatus(PortalRestStatusEnum.OK);
+              PortalRestResponse<String> actual =  languageController.saveLanguage(principal, fnLanguage);
+              //Then
+
+              assertEquals(expected, actual);
+              //Clean up
+              fnLanguageDao.delete(fnLanguage);
+       }
+
+       @Test
+       void saveLanguageXSS() {
+              //Given
+              FnLanguage fnLanguage = new FnLanguage();
+              fnLanguage.setLanguageName("<script>alert(“XSS”)</script> ");
+              fnLanguage.setLanguageAlias("PL");
+              //When
+              PortalRestResponse<String> expected = new PortalRestResponse<>();
+              expected.setMessage("FAILURE");
+              expected.setResponse("FnLanguage is not valid, may have unsafe html content");
+              expected.setStatus(PortalRestStatusEnum.ERROR);
+              PortalRestResponse<String> actual =  languageController.saveLanguage(principal, fnLanguage);
+              //Then
+
+              assertEquals(expected, actual);
+              //Clean up
+              fnLanguageDao.delete(fnLanguage);
+       }
+
+}
\ No newline at end of file