495 changed files with 50928 additions and 0 deletions
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.config; |
|||
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|||
|
|||
@Configuration |
|||
@ConfigurationProperties(prefix = "security.jwt") |
|||
public class JwtSettings { |
|||
/** |
|||
* {@link JwtToken} will expire after this time. |
|||
*/ |
|||
private Integer tokenExpirationTime; |
|||
|
|||
/** |
|||
* Token issuer. |
|||
*/ |
|||
private String tokenIssuer; |
|||
|
|||
/** |
|||
* Key is used to sign {@link JwtToken}. |
|||
*/ |
|||
private String tokenSigningKey; |
|||
|
|||
/** |
|||
* {@link JwtToken} can be refreshed during this timeframe. |
|||
*/ |
|||
private Integer refreshTokenExpTime; |
|||
|
|||
public Integer getRefreshTokenExpTime() { |
|||
return refreshTokenExpTime; |
|||
} |
|||
|
|||
public void setRefreshTokenExpTime(Integer refreshTokenExpTime) { |
|||
this.refreshTokenExpTime = refreshTokenExpTime; |
|||
} |
|||
|
|||
public Integer getTokenExpirationTime() { |
|||
return tokenExpirationTime; |
|||
} |
|||
|
|||
public void setTokenExpirationTime(Integer tokenExpirationTime) { |
|||
this.tokenExpirationTime = tokenExpirationTime; |
|||
} |
|||
|
|||
public String getTokenIssuer() { |
|||
return tokenIssuer; |
|||
} |
|||
public void setTokenIssuer(String tokenIssuer) { |
|||
this.tokenIssuer = tokenIssuer; |
|||
} |
|||
|
|||
public String getTokenSigningKey() { |
|||
return tokenSigningKey; |
|||
} |
|||
|
|||
public void setTokenSigningKey(String tokenSigningKey) { |
|||
this.tokenSigningKey = tokenSigningKey; |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.config; |
|||
|
|||
import org.springframework.context.MessageSource; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.context.support.ResourceBundleMessageSource; |
|||
|
|||
@Configuration |
|||
public class ThingsboardMessageConfiguration { |
|||
|
|||
@Bean |
|||
public MessageSource messageSource() { |
|||
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); |
|||
messageSource.setBasename("i18n/messages"); |
|||
messageSource.setDefaultEncoding("UTF-8"); |
|||
return messageSource; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,161 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.config; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.boot.autoconfigure.security.SecurityProperties; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.core.annotation.Order; |
|||
import org.springframework.security.authentication.AuthenticationManager; |
|||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
|||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
|||
import org.springframework.security.config.http.SessionCreationPolicy; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
|||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
|||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
|||
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
|||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider; |
|||
import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter; |
|||
import org.thingsboard.server.service.security.auth.jwt.*; |
|||
import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
@Configuration |
|||
@EnableWebSecurity |
|||
@EnableGlobalMethodSecurity(prePostEnabled=true) |
|||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) |
|||
public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter { |
|||
|
|||
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; |
|||
public static final String JWT_TOKEN_QUERY_PARAM = "token"; |
|||
|
|||
public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**"; |
|||
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; |
|||
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; |
|||
public static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**"}; |
|||
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; |
|||
public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; |
|||
|
|||
@Autowired private ThingsboardErrorResponseHandler restAccessDeniedHandler; |
|||
@Autowired private AuthenticationSuccessHandler successHandler; |
|||
@Autowired private AuthenticationFailureHandler failureHandler; |
|||
@Autowired private RestAuthenticationProvider restAuthenticationProvider; |
|||
@Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; |
|||
@Autowired private RefreshTokenAuthenticationProvider refreshTokenAuthenticationProvider; |
|||
|
|||
@Autowired |
|||
@Qualifier("jwtHeaderTokenExtractor") |
|||
private TokenExtractor jwtHeaderTokenExtractor; |
|||
|
|||
@Autowired |
|||
@Qualifier("jwtQueryTokenExtractor") |
|||
private TokenExtractor jwtQueryTokenExtractor; |
|||
|
|||
@Autowired private AuthenticationManager authenticationManager; |
|||
|
|||
@Autowired private ObjectMapper objectMapper; |
|||
|
|||
@Bean |
|||
protected RestLoginProcessingFilter buildRestLoginProcessingFilter() throws Exception { |
|||
RestLoginProcessingFilter filter = new RestLoginProcessingFilter(FORM_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper); |
|||
filter.setAuthenticationManager(this.authenticationManager); |
|||
return filter; |
|||
} |
|||
|
|||
@Bean |
|||
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { |
|||
List<String> pathsToSkip = new ArrayList(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); |
|||
pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT)); |
|||
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); |
|||
JwtTokenAuthenticationProcessingFilter filter |
|||
= new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtHeaderTokenExtractor, matcher); |
|||
filter.setAuthenticationManager(this.authenticationManager); |
|||
return filter; |
|||
} |
|||
|
|||
@Bean |
|||
protected RefreshTokenProcessingFilter buildRefreshTokenProcessingFilter() throws Exception { |
|||
RefreshTokenProcessingFilter filter = new RefreshTokenProcessingFilter(TOKEN_REFRESH_ENTRY_POINT, successHandler, failureHandler, objectMapper); |
|||
filter.setAuthenticationManager(this.authenticationManager); |
|||
return filter; |
|||
} |
|||
|
|||
@Bean |
|||
protected JwtTokenAuthenticationProcessingFilter buildWsJwtTokenAuthenticationProcessingFilter() throws Exception { |
|||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(WS_TOKEN_BASED_AUTH_ENTRY_POINT); |
|||
JwtTokenAuthenticationProcessingFilter filter |
|||
= new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtQueryTokenExtractor, matcher); |
|||
filter.setAuthenticationManager(this.authenticationManager); |
|||
return filter; |
|||
} |
|||
|
|||
@Bean |
|||
@Override |
|||
public AuthenticationManager authenticationManagerBean() throws Exception { |
|||
return super.authenticationManagerBean(); |
|||
} |
|||
|
|||
@Override |
|||
protected void configure(AuthenticationManagerBuilder auth) { |
|||
auth.authenticationProvider(restAuthenticationProvider); |
|||
auth.authenticationProvider(jwtAuthenticationProvider); |
|||
auth.authenticationProvider(refreshTokenAuthenticationProvider); |
|||
} |
|||
|
|||
@Bean |
|||
protected BCryptPasswordEncoder passwordEncoder() { |
|||
return new BCryptPasswordEncoder(); |
|||
} |
|||
|
|||
@Override |
|||
protected void configure(HttpSecurity http) throws Exception { |
|||
http.headers().frameOptions().disable() |
|||
.and() |
|||
.csrf().disable() |
|||
.exceptionHandling() |
|||
.and() |
|||
.sessionManagement() |
|||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) |
|||
.and() |
|||
.authorizeRequests() |
|||
.antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API
|
|||
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
|
|||
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
|
|||
.antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points
|
|||
.and() |
|||
.authorizeRequests() |
|||
.antMatchers(WS_TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected WebSocket API End-points
|
|||
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
|
|||
.and() |
|||
.exceptionHandling().accessDeniedHandler(restAccessDeniedHandler) |
|||
.and() |
|||
.addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
|||
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
|||
.addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
|||
.addFilterBefore(buildWsJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.config; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
|
|||
@Controller |
|||
public class WebConfig { |
|||
|
|||
@RequestMapping(value = "/{path:^(?!api$)(?!static$)[^\\.]*}/**") |
|||
public String redirect() { |
|||
return "forward:/index.html"; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.config; |
|||
|
|||
import java.util.Map; |
|||
|
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.controller.plugin.PluginWebSocketHandler; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.server.ServerHttpRequest; |
|||
import org.springframework.http.server.ServerHttpResponse; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.web.socket.WebSocketHandler; |
|||
import org.springframework.web.socket.config.annotation.EnableWebSocket; |
|||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer; |
|||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; |
|||
import org.springframework.web.socket.server.HandshakeInterceptor; |
|||
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; |
|||
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; |
|||
|
|||
@Configuration |
|||
@EnableWebSocket |
|||
public class WebSocketConfiguration implements WebSocketConfigurer { |
|||
|
|||
public static final String WS_PLUGIN_PREFIX = "/api/ws/plugins/"; |
|||
public static final String WS_SECURITY_USER_ATTRIBUTE = "SECURITY_USER"; |
|||
private static final String WS_PLUGIN_MAPPING = WS_PLUGIN_PREFIX + "**"; |
|||
|
|||
@Bean |
|||
public ServletServerContainerFactoryBean createWebSocketContainer() { |
|||
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); |
|||
container.setMaxTextMessageBufferSize(8192); |
|||
container.setMaxBinaryMessageBufferSize(8192); |
|||
return container; |
|||
} |
|||
|
|||
@Override |
|||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { |
|||
registry.addHandler(pluginWsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") |
|||
.addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() { |
|||
|
|||
@Override |
|||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, |
|||
Map<String, Object> attributes) throws Exception { |
|||
SecurityUser user = null; |
|||
try { |
|||
user = getCurrentUser(); |
|||
} catch (ThingsboardException ex) {} |
|||
if (user == null) { |
|||
response.setStatusCode(HttpStatus.UNAUTHORIZED); |
|||
return false; |
|||
} else { |
|||
attributes.put(WS_SECURITY_USER_ATTRIBUTE, user); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, |
|||
Exception exception) { |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Bean |
|||
public WebSocketHandler pluginWsHandler() { |
|||
return new PluginWebSocketHandler(); |
|||
} |
|||
|
|||
protected SecurityUser getCurrentUser() throws ThingsboardException { |
|||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
|||
if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { |
|||
return (SecurityUser) authentication.getPrincipal(); |
|||
} else { |
|||
throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.dao.settings.AdminSettingsService; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.mail.MailService; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api/admin") |
|||
public class AdminController extends BaseController { |
|||
|
|||
@Autowired |
|||
private MailService mailService; |
|||
|
|||
@Autowired |
|||
private AdminSettingsService adminSettingsService; |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/settings/{key}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public AdminSettings getAdminSettings(@PathVariable("key") String key) throws ThingsboardException { |
|||
try { |
|||
return checkNotNull(adminSettingsService.findAdminSettingsByKey(key)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/settings", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public AdminSettings saveAdminSettings(@RequestBody AdminSettings adminSettings) throws ThingsboardException { |
|||
try { |
|||
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(adminSettings)); |
|||
if (adminSettings.getKey().equals("mail")) { |
|||
mailService.updateMailConfiguration(); |
|||
} |
|||
return adminSettings; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/settings/testMail", method = RequestMethod.POST) |
|||
public void sendTestMail(@RequestBody AdminSettings adminSettings) throws ThingsboardException { |
|||
try { |
|||
adminSettings = checkNotNull(adminSettings); |
|||
if (adminSettings.getKey().equals("mail")) { |
|||
String email = getCurrentUser().getEmail(); |
|||
mailService.sendTestMail(adminSettings.getJsonValue(), email); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,236 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.security.UserCredentials; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.mail.MailService; |
|||
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.net.URI; |
|||
import java.net.URISyntaxException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
@Slf4j |
|||
public class AuthController extends BaseController { |
|||
|
|||
|
|||
|
|||
@Autowired |
|||
private BCryptPasswordEncoder passwordEncoder; |
|||
|
|||
@Autowired |
|||
private JwtTokenFactory tokenFactory; |
|||
|
|||
@Autowired |
|||
private RefreshTokenRepository refreshTokenRepository; |
|||
|
|||
@Autowired |
|||
private UserService userService; |
|||
|
|||
@Autowired |
|||
private MailService mailService; |
|||
|
|||
@PreAuthorize("isAuthenticated()") |
|||
@RequestMapping(value = "/auth/user", method = RequestMethod.GET) |
|||
public @ResponseBody User getUser() throws ThingsboardException { |
|||
try { |
|||
SecurityUser securityUser = getCurrentUser(); |
|||
return userService.findUserById(securityUser.getId()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("isAuthenticated()") |
|||
@RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void changePassword ( |
|||
@RequestParam(value = "currentPassword") String currentPassword, |
|||
@RequestParam(value = "newPassword") String newPassword) throws ThingsboardException { |
|||
try { |
|||
SecurityUser securityUser = getCurrentUser(); |
|||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(securityUser.getId()); |
|||
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) { |
|||
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
userCredentials.setPassword(passwordEncoder.encode(newPassword)); |
|||
userService.saveUserCredentials(userCredentials); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@RequestMapping(value = "/noauth/activate", params = { "activateToken" }, method = RequestMethod.GET) |
|||
public ResponseEntity<String> checkActivateToken( |
|||
@RequestParam(value = "activateToken") String activateToken) { |
|||
HttpHeaders headers = new HttpHeaders(); |
|||
HttpStatus responseStatus; |
|||
UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(activateToken); |
|||
if (userCredentials != null) { |
|||
String createPasswordURI = "/login/createPassword"; |
|||
try { |
|||
URI location = new URI(createPasswordURI + "?activateToken=" + activateToken); |
|||
headers.setLocation(location); |
|||
responseStatus = HttpStatus.PERMANENT_REDIRECT; |
|||
} catch (URISyntaxException e) { |
|||
log.error("Unable to create URI with address [{}]", createPasswordURI); |
|||
responseStatus = HttpStatus.BAD_REQUEST; |
|||
} |
|||
} else { |
|||
responseStatus = HttpStatus.CONFLICT; |
|||
} |
|||
return new ResponseEntity<>(headers, responseStatus); |
|||
} |
|||
|
|||
@RequestMapping(value = "/noauth/resetPasswordByEmail", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void requestResetPasswordByEmail ( |
|||
@RequestParam(value = "email") String email, |
|||
HttpServletRequest request) throws ThingsboardException { |
|||
try { |
|||
UserCredentials userCredentials = userService.requestPasswordReset(email); |
|||
|
|||
String baseUrl = String.format("%s://%s:%d", |
|||
request.getScheme(), |
|||
request.getServerName(), |
|||
request.getServerPort()); |
|||
String resetPasswordUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, |
|||
userCredentials.getResetToken()); |
|||
|
|||
mailService.sendResetPasswordEmail(resetPasswordUrl, email); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@RequestMapping(value = "/noauth/resetPassword", params = { "resetToken" }, method = RequestMethod.GET) |
|||
public ResponseEntity<String> checkResetToken( |
|||
@RequestParam(value = "resetToken") String resetToken) { |
|||
HttpHeaders headers = new HttpHeaders(); |
|||
HttpStatus responseStatus; |
|||
String resetPasswordURI = "/login/resetPassword"; |
|||
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); |
|||
if (userCredentials != null) { |
|||
try { |
|||
URI location = new URI(resetPasswordURI + "?resetToken=" + resetToken); |
|||
headers.setLocation(location); |
|||
responseStatus = HttpStatus.PERMANENT_REDIRECT; |
|||
} catch (URISyntaxException e) { |
|||
log.error("Unable to create URI with address [{}]", resetPasswordURI); |
|||
responseStatus = HttpStatus.BAD_REQUEST; |
|||
} |
|||
} else { |
|||
responseStatus = HttpStatus.CONFLICT; |
|||
} |
|||
return new ResponseEntity<>(headers, responseStatus); |
|||
} |
|||
|
|||
@RequestMapping(value = "/noauth/activate", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
@ResponseBody |
|||
public JsonNode activateUser( |
|||
@RequestParam(value = "activateToken") String activateToken, |
|||
@RequestParam(value = "password") String password, |
|||
HttpServletRequest request) throws ThingsboardException { |
|||
try { |
|||
String encodedPassword = passwordEncoder.encode(password); |
|||
UserCredentials credentials = userService.activateUserCredentials(activateToken, encodedPassword); |
|||
User user = userService.findUserById(credentials.getUserId()); |
|||
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled()); |
|||
String baseUrl = String.format("%s://%s:%d", |
|||
request.getScheme(), |
|||
request.getServerName(), |
|||
request.getServerPort()); |
|||
String loginUrl = String.format("%s/login", baseUrl); |
|||
String email = user.getEmail(); |
|||
mailService.sendAccountActivatedEmail(loginUrl, email); |
|||
|
|||
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
|||
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
|||
|
|||
ObjectMapper objectMapper = new ObjectMapper(); |
|||
ObjectNode tokenObject = objectMapper.createObjectNode(); |
|||
tokenObject.put("token", accessToken.getToken()); |
|||
tokenObject.put("refreshToken", refreshToken.getToken()); |
|||
return tokenObject; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@RequestMapping(value = "/noauth/resetPassword", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
@ResponseBody |
|||
public JsonNode resetPassword( |
|||
@RequestParam(value = "resetToken") String resetToken, |
|||
@RequestParam(value = "password") String password, |
|||
HttpServletRequest request) throws ThingsboardException { |
|||
try { |
|||
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); |
|||
if (userCredentials != null) { |
|||
String encodedPassword = passwordEncoder.encode(password); |
|||
userCredentials.setPassword(encodedPassword); |
|||
userCredentials.setResetToken(null); |
|||
userCredentials = userService.saveUserCredentials(userCredentials); |
|||
User user = userService.findUserById(userCredentials.getUserId()); |
|||
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); |
|||
String baseUrl = String.format("%s://%s:%d", |
|||
request.getScheme(), |
|||
request.getServerName(), |
|||
request.getServerPort()); |
|||
String loginUrl = String.format("%s/login", baseUrl); |
|||
String email = user.getEmail(); |
|||
mailService.sendPasswordWasResetEmail(loginUrl, email); |
|||
|
|||
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
|||
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
|||
|
|||
ObjectMapper objectMapper = new ObjectMapper(); |
|||
ObjectNode tokenObject = objectMapper.createObjectNode(); |
|||
tokenObject.put("token", accessToken.getToken()); |
|||
tokenObject.put("refreshToken", refreshToken.getToken()); |
|||
return tokenObject; |
|||
} else { |
|||
throw new ThingsboardException("Invalid reset token!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,377 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.web.bind.annotation.ExceptionHandler; |
|||
import org.thingsboard.server.actors.service.ActorService; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.id.*; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.data.plugin.PluginMetaData; |
|||
import org.thingsboard.server.common.data.rule.RuleMetaData; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.widget.WidgetType; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.customer.CustomerService; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.plugin.PluginService; |
|||
import org.thingsboard.server.dao.rule.RuleService; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.dao.widget.WidgetTypeService; |
|||
import org.thingsboard.server.dao.widget.WidgetsBundleService; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.component.ComponentDiscoveryService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import javax.mail.MessagingException; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.dao.service.Validator.validateId; |
|||
|
|||
@Slf4j |
|||
public abstract class BaseController { |
|||
|
|||
@Autowired |
|||
private ThingsboardErrorResponseHandler errorResponseHandler; |
|||
|
|||
@Autowired |
|||
protected CustomerService customerService; |
|||
|
|||
@Autowired |
|||
protected UserService userService; |
|||
|
|||
@Autowired |
|||
protected DeviceService deviceService; |
|||
|
|||
@Autowired |
|||
protected DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Autowired |
|||
protected WidgetsBundleService widgetsBundleService; |
|||
|
|||
@Autowired |
|||
protected WidgetTypeService widgetTypeService; |
|||
|
|||
@Autowired |
|||
protected DashboardService dashboardService; |
|||
|
|||
@Autowired |
|||
protected ComponentDiscoveryService componentDescriptorService; |
|||
|
|||
@Autowired |
|||
protected RuleService ruleService; |
|||
|
|||
@Autowired |
|||
protected PluginService pluginService; |
|||
|
|||
@Autowired |
|||
protected ActorService actorService; |
|||
|
|||
|
|||
@ExceptionHandler(ThingsboardException.class) |
|||
public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { |
|||
errorResponseHandler.handle(ex, response); |
|||
} |
|||
|
|||
ThingsboardException handleException(Exception exception) { |
|||
return handleException(exception, true); |
|||
} |
|||
|
|||
private ThingsboardException handleException(Exception exception, boolean logException) { |
|||
if (logException) { |
|||
log.error("Error [{}]", exception.getMessage()); |
|||
} |
|||
|
|||
String cause = ""; |
|||
if (exception.getCause() != null) { |
|||
cause = exception.getCause().getClass().getCanonicalName(); |
|||
} |
|||
|
|||
if (exception instanceof ThingsboardException) { |
|||
return (ThingsboardException) exception; |
|||
} else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException |
|||
|| exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { |
|||
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} else if (exception instanceof MessagingException) { |
|||
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); |
|||
} else { |
|||
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); |
|||
} |
|||
} |
|||
|
|||
<T> T checkNotNull(T reference) throws ThingsboardException { |
|||
if (reference == null) { |
|||
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
return reference; |
|||
} |
|||
|
|||
<T> T checkNotNull(Optional<T> reference) throws ThingsboardException { |
|||
if (reference.isPresent()) { |
|||
return reference.get(); |
|||
} else { |
|||
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
} |
|||
|
|||
void checkParameter(String name, String param) throws ThingsboardException { |
|||
if (StringUtils.isEmpty(param)) { |
|||
throw new ThingsboardException("Parameter '" + name + "' can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
} |
|||
|
|||
UUID toUUID(String id) { |
|||
return UUID.fromString(id); |
|||
} |
|||
|
|||
TimePageLink createPageLink(int limit, Long startTime, Long endTime, boolean ascOrder, String idOffset) { |
|||
UUID idOffsetUuid = null; |
|||
if (StringUtils.isNotEmpty(idOffset)) { |
|||
idOffsetUuid = toUUID(idOffset); |
|||
} |
|||
return new TimePageLink(limit, startTime, endTime, ascOrder, idOffsetUuid); |
|||
} |
|||
|
|||
|
|||
TextPageLink createPageLink(int limit, String textSearch, String idOffset, String textOffset) { |
|||
UUID idOffsetUuid = null; |
|||
if (StringUtils.isNotEmpty(idOffset)) { |
|||
idOffsetUuid = toUUID(idOffset); |
|||
} |
|||
return new TextPageLink(limit, textSearch, idOffsetUuid, textOffset); |
|||
} |
|||
|
|||
protected SecurityUser getCurrentUser() throws ThingsboardException { |
|||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
|||
if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { |
|||
return (SecurityUser) authentication.getPrincipal(); |
|||
} else { |
|||
throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION); |
|||
} |
|||
} |
|||
|
|||
void checkTenantId(TenantId tenantId) throws ThingsboardException { |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
SecurityUser authUser = getCurrentUser(); |
|||
if (authUser.getAuthority() != Authority.SYS_ADMIN && |
|||
(authUser.getTenantId() == null || !authUser.getTenantId().equals(tenantId))) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
} |
|||
|
|||
protected TenantId getTenantId() throws ThingsboardException { |
|||
return getCurrentUser().getTenantId(); |
|||
} |
|||
|
|||
Customer checkCustomerId(CustomerId customerId) throws ThingsboardException { |
|||
try { |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
SecurityUser authUser = getCurrentUser(); |
|||
if (authUser.getAuthority() == Authority.SYS_ADMIN || |
|||
(authUser.getAuthority() != Authority.TENANT_ADMIN && |
|||
(authUser.getCustomerId() == null || !authUser.getCustomerId().equals(customerId)))) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
Customer customer = customerService.findCustomerById(customerId); |
|||
checkCustomer(customer); |
|||
return customer; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
private void checkCustomer(Customer customer) throws ThingsboardException { |
|||
checkNotNull(customer); |
|||
checkTenantId(customer.getTenantId()); |
|||
} |
|||
|
|||
User checkUserId(UserId userId) throws ThingsboardException { |
|||
try { |
|||
validateId(userId, "Incorrect userId " + userId); |
|||
User user = userService.findUserById(userId); |
|||
checkUser(user); |
|||
return user; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
private void checkUser(User user) throws ThingsboardException { |
|||
checkNotNull(user); |
|||
checkTenantId(user.getTenantId()); |
|||
if (user.getAuthority() == Authority.CUSTOMER_USER) { |
|||
checkCustomerId(user.getCustomerId()); |
|||
} |
|||
} |
|||
|
|||
Device checkDeviceId(DeviceId deviceId) throws ThingsboardException { |
|||
try { |
|||
validateId(deviceId, "Incorrect deviceId " + deviceId); |
|||
Device device = deviceService.findDeviceById(deviceId); |
|||
checkDevice(device); |
|||
return device; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
private void checkDevice(Device device) throws ThingsboardException { |
|||
checkNotNull(device); |
|||
checkTenantId(device.getTenantId()); |
|||
if (device.getCustomerId() != null && !device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
checkCustomerId(device.getCustomerId()); |
|||
} |
|||
} |
|||
|
|||
WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException { |
|||
try { |
|||
validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); |
|||
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(widgetsBundleId); |
|||
checkWidgetsBundle(widgetsBundle, modify); |
|||
return widgetsBundle; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
private void checkWidgetsBundle(WidgetsBundle widgetsBundle, boolean modify) throws ThingsboardException { |
|||
checkNotNull(widgetsBundle); |
|||
if (widgetsBundle.getTenantId() != null && !widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
checkTenantId(widgetsBundle.getTenantId()); |
|||
} else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
} |
|||
|
|||
WidgetType checkWidgetTypeId(WidgetTypeId widgetTypeId, boolean modify) throws ThingsboardException { |
|||
try { |
|||
validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); |
|||
WidgetType widgetType = widgetTypeService.findWidgetTypeById(widgetTypeId); |
|||
checkWidgetType(widgetType, modify); |
|||
return widgetType; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
void checkWidgetType(WidgetType widgetType, boolean modify) throws ThingsboardException { |
|||
checkNotNull(widgetType); |
|||
if (widgetType.getTenantId() != null && !widgetType.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
checkTenantId(widgetType.getTenantId()); |
|||
} else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
} |
|||
|
|||
Dashboard checkDashboardId(DashboardId dashboardId) throws ThingsboardException { |
|||
try { |
|||
validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
|||
Dashboard dashboard = dashboardService.findDashboardById(dashboardId); |
|||
checkDashboard(dashboard); |
|||
return dashboard; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
private void checkDashboard(Dashboard dashboard) throws ThingsboardException { |
|||
checkNotNull(dashboard); |
|||
checkTenantId(dashboard.getTenantId()); |
|||
if (dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
checkCustomerId(dashboard.getCustomerId()); |
|||
} |
|||
} |
|||
|
|||
ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { |
|||
try { |
|||
log.debug("[{}] Lookup component descriptor", clazz); |
|||
ComponentDescriptor componentDescriptor = checkNotNull(componentDescriptorService.getComponent(clazz)); |
|||
return componentDescriptor; |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
List<ComponentDescriptor> checkComponentDescriptorsByType(ComponentType type) throws ThingsboardException { |
|||
try { |
|||
log.debug("[{}] Lookup component descriptors", type); |
|||
return componentDescriptorService.getComponents(type); |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
List<ComponentDescriptor> checkPluginActionsByPluginClazz(String pluginClazz) throws ThingsboardException { |
|||
try { |
|||
checkComponentDescriptorByClazz(pluginClazz); |
|||
log.debug("[{}] Lookup plugin actions", pluginClazz); |
|||
return componentDescriptorService.getPluginActions(pluginClazz); |
|||
} catch (Exception e) { |
|||
throw handleException(e, false); |
|||
} |
|||
} |
|||
|
|||
protected PluginMetaData checkPlugin(PluginMetaData plugin) throws ThingsboardException { |
|||
checkNotNull(plugin); |
|||
SecurityUser authUser = getCurrentUser(); |
|||
TenantId tenantId = plugin.getTenantId(); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
if (authUser.getAuthority() != Authority.SYS_ADMIN) { |
|||
if (authUser.getTenantId() == null || |
|||
!tenantId.getId().equals(ModelConstants.NULL_UUID) && !authUser.getTenantId().equals(tenantId)) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
|
|||
} else if (tenantId.getId().equals(ModelConstants.NULL_UUID)) { |
|||
plugin.setConfiguration(null); |
|||
} |
|||
} |
|||
return plugin; |
|||
} |
|||
|
|||
protected RuleMetaData checkRule(RuleMetaData rule) throws ThingsboardException { |
|||
checkNotNull(rule); |
|||
checkTenantId(rule.getTenantId()); |
|||
return rule; |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class ComponentDescriptorController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
|||
@RequestMapping(value = "/component/{componentDescriptorClazz:.+}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public ComponentDescriptor getComponentDescriptorByClazz(@PathVariable("componentDescriptorClazz") String strComponentDescriptorClazz) throws ThingsboardException { |
|||
checkParameter("strComponentDescriptorClazz", strComponentDescriptorClazz); |
|||
try { |
|||
return checkComponentDescriptorByClazz(strComponentDescriptorClazz); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
|||
@RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<ComponentDescriptor> getComponentDescriptorsByType(@PathVariable("componentType") String strComponentType) throws ThingsboardException { |
|||
checkParameter("componentType", strComponentType); |
|||
try { |
|||
return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
|||
@RequestMapping(value = "/components/actions/{pluginClazz:.+}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<ComponentDescriptor> getPluginActionsByPluginClazz(@PathVariable("pluginClazz") String pluginClazz) throws ThingsboardException { |
|||
checkParameter("pluginClazz", pluginClazz); |
|||
try { |
|||
return checkPluginActionsByPluginClazz(pluginClazz); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class CustomerController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/customer/{customerId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Customer getCustomerById(@PathVariable("customerId") String strCustomerId) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
return checkCustomerId(customerId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Customer saveCustomer(@RequestBody Customer customer) throws ThingsboardException { |
|||
try { |
|||
customer.setTenantId(getCurrentUser().getTenantId()); |
|||
return checkNotNull(customerService.saveCustomer(customer)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/{customerId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteCustomer(@PathVariable("customerId") String strCustomerId) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
customerService.deleteCustomer(customerId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customers", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Customer> getCustomers(@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(customerService.findCustomersByTenantId(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,148 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class DashboardController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Dashboard getDashboardById(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { |
|||
checkParameter("dashboardId", strDashboardId); |
|||
try { |
|||
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
|||
return checkDashboardId(dashboardId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/dashboard", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Dashboard saveDashboard(@RequestBody Dashboard dashboard) throws ThingsboardException { |
|||
try { |
|||
dashboard.setTenantId(getCurrentUser().getTenantId()); |
|||
return checkNotNull(dashboardService.saveDashboard(dashboard)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteDashboard(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { |
|||
checkParameter("dashboardId", strDashboardId); |
|||
try { |
|||
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
|||
checkDashboardId(dashboardId); |
|||
dashboardService.deleteDashboard(dashboardId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Dashboard assignDashboardToCustomer(@PathVariable("customerId") String strCustomerId, |
|||
@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
checkParameter("dashboardId", strDashboardId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
|
|||
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
|||
checkDashboardId(dashboardId); |
|||
|
|||
return checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/dashboard/{dashboardId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public Dashboard unassignDashboardFromCustomer(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { |
|||
checkParameter("dashboardId", strDashboardId); |
|||
try { |
|||
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
|||
Dashboard dashboard = checkDashboardId(dashboardId); |
|||
if (dashboard.getCustomerId() == null || dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
throw new IncorrectParameterException("Dashboard isn't assigned to any customer!"); |
|||
} |
|||
return checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Dashboard> getTenantDashboards( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/customer/{customerId}/dashboards", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Dashboard> getCustomerDashboards( |
|||
@PathVariable("customerId") String strCustomerId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,176 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class DeviceController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Device getDeviceById(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { |
|||
checkParameter("deviceId", strDeviceId); |
|||
try { |
|||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
|||
return checkDeviceId(deviceId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/device", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Device saveDevice(@RequestBody Device device) throws ThingsboardException { |
|||
try { |
|||
device.setTenantId(getCurrentUser().getTenantId()); |
|||
return checkNotNull(deviceService.saveDevice(device)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteDevice(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { |
|||
checkParameter("deviceId", strDeviceId); |
|||
try { |
|||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
|||
checkDeviceId(deviceId); |
|||
deviceService.deleteDevice(deviceId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/{customerId}/device/{deviceId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Device assignDeviceToCustomer(@PathVariable("customerId") String strCustomerId, |
|||
@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
checkParameter("deviceId", strDeviceId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
|
|||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
|||
checkDeviceId(deviceId); |
|||
|
|||
return checkNotNull(deviceService.assignDeviceToCustomer(deviceId, customerId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/device/{deviceId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public Device unassignDeviceFromCustomer(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { |
|||
checkParameter("deviceId", strDeviceId); |
|||
try { |
|||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
|||
Device device = checkDeviceId(deviceId); |
|||
if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
throw new IncorrectParameterException("Device isn't assigned to any customer!"); |
|||
} |
|||
return checkNotNull(deviceService.unassignDeviceFromCustomer(deviceId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/device/{deviceId}/credentials", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public DeviceCredentials getDeviceCredentialsByDeviceId(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { |
|||
checkParameter("deviceId", strDeviceId); |
|||
try { |
|||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
|||
checkDeviceId(deviceId); |
|||
return checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/device/credentials", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public DeviceCredentials saveDeviceCredentials(@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException { |
|||
checkNotNull(deviceCredentials); |
|||
try { |
|||
checkDeviceId(deviceCredentials.getDeviceId()); |
|||
return checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/tenant/devices", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Device> getTenantDevices( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/customer/{customerId}/devices", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Device> getCustomerDevices( |
|||
@PathVariable("customerId") String strCustomerId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.Event; |
|||
import org.thingsboard.server.common.data.id.*; |
|||
import org.thingsboard.server.common.data.page.TimePageData; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.event.EventService; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class EventController extends BaseController { |
|||
|
|||
@Autowired |
|||
private EventService eventService; |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TimePageData<Event> getEvents( |
|||
@PathVariable("entityType") String strEntityType, |
|||
@PathVariable("entityId") String strEntityId, |
|||
@PathVariable("eventType") String eventType, |
|||
@RequestParam("tenantId") String strTenantId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) Long startTime, |
|||
@RequestParam(required = false) Long endTime, |
|||
@RequestParam(required = false, defaultValue = "false") boolean ascOrder, |
|||
@RequestParam(required = false) String offset |
|||
) throws ThingsboardException { |
|||
checkParameter("EntityId", strEntityId); |
|||
checkParameter("EntityType", strEntityType); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
if (!tenantId.getId().equals(ModelConstants.NULL_UUID) && |
|||
!tenantId.equals(getCurrentUser().getTenantId())) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); |
|||
return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), eventType, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TimePageData<Event> getEvents( |
|||
@PathVariable("entityType") String strEntityType, |
|||
@PathVariable("entityId") String strEntityId, |
|||
@RequestParam("tenantId") String strTenantId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) Long startTime, |
|||
@RequestParam(required = false) Long endTime, |
|||
@RequestParam(required = false, defaultValue = "false") boolean ascOrder, |
|||
@RequestParam(required = false) String offset |
|||
) throws ThingsboardException { |
|||
checkParameter("EntityId", strEntityId); |
|||
checkParameter("EntityType", strEntityType); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
if (!tenantId.getId().equals(ModelConstants.NULL_UUID) && |
|||
!tenantId.equals(getCurrentUser().getTenantId())) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); |
|||
return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
|
|||
private EntityId getEntityId(String strEntityType, String strEntityId) throws ThingsboardException { |
|||
EntityId entityId; |
|||
EntityType entityType = EntityType.valueOf(strEntityType); |
|||
switch (entityType) { |
|||
case RULE: |
|||
entityId = new RuleId(toUUID(strEntityId)); |
|||
break; |
|||
case PLUGIN: |
|||
entityId = new PluginId(toUUID(strEntityId)); |
|||
break; |
|||
case DEVICE: |
|||
entityId = new DeviceId(toUUID(strEntityId)); |
|||
break; |
|||
default: |
|||
throw new ThingsboardException("EntityType ['" + entityType + "'] is incorrect!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
return entityId; |
|||
} |
|||
} |
|||
@ -0,0 +1,197 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.id.PluginId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.common.data.plugin.PluginMetaData; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class PluginController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin/{pluginId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PluginMetaData getPluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { |
|||
checkParameter("pluginId", strPluginId); |
|||
try { |
|||
PluginId pluginId = new PluginId(toUUID(strPluginId)); |
|||
return checkPlugin(pluginService.findPluginById(pluginId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin/token/{pluginToken}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PluginMetaData getPluginByToken(@PathVariable("pluginToken") String pluginToken) throws ThingsboardException { |
|||
checkParameter("pluginToken", pluginToken); |
|||
try { |
|||
return checkPlugin(pluginService.findPluginByApiToken(pluginToken)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public PluginMetaData savePlugin(@RequestBody PluginMetaData source) throws ThingsboardException { |
|||
try { |
|||
boolean created = source.getId() == null; |
|||
source.setTenantId(getCurrentUser().getTenantId()); |
|||
PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source)); |
|||
actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), |
|||
created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
|||
return plugin; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin/{pluginId}/activate", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void activatePluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { |
|||
checkParameter("pluginId", strPluginId); |
|||
try { |
|||
PluginId pluginId = new PluginId(toUUID(strPluginId)); |
|||
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
|||
pluginService.activatePluginById(pluginId); |
|||
actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin/{pluginId}/suspend", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void suspendPluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { |
|||
checkParameter("pluginId", strPluginId); |
|||
try { |
|||
PluginId pluginId = new PluginId(toUUID(strPluginId)); |
|||
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
|||
pluginService.suspendPluginById(pluginId); |
|||
actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/plugin/system", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<PluginMetaData> getSystemPlugins( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(pluginService.findSystemPlugins(pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/plugin/tenant/{tenantId}", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<PluginMetaData> getTenantPlugins( |
|||
@PathVariable("tenantId") String strTenantId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("tenantId", strTenantId); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(pluginService.findTenantPlugins(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugins", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<PluginMetaData> getPlugins() throws ThingsboardException { |
|||
try { |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
return checkNotNull(pluginService.findSystemPlugins()); |
|||
} else { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
List<PluginMetaData> plugins = checkNotNull(pluginService.findAllTenantPluginsByTenantId(tenantId)); |
|||
plugins.stream() |
|||
.filter(plugin -> plugin.getTenantId().getId().equals(ModelConstants.NULL_UUID)) |
|||
.forEach(plugin -> plugin.setConfiguration(null)); |
|||
return plugins; |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<PluginMetaData> getTenantPlugins( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(pluginService.findTenantPlugins(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/plugin/{pluginId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deletePlugin(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { |
|||
checkParameter("pluginId", strPluginId); |
|||
try { |
|||
PluginId pluginId = new PluginId(toUUID(strPluginId)); |
|||
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
|||
pluginService.deletePluginById(pluginId); |
|||
actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,193 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.id.RuleId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.common.data.plugin.PluginMetaData; |
|||
import org.thingsboard.server.common.data.rule.RuleMetaData; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class RuleController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule/{ruleId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public RuleMetaData getRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { |
|||
checkParameter("ruleId", strRuleId); |
|||
try { |
|||
RuleId ruleId = new RuleId(toUUID(strRuleId)); |
|||
return checkRule(ruleService.findRuleById(ruleId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule/token/{pluginToken}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<RuleMetaData> getRulesByPluginToken(@PathVariable("pluginToken") String pluginToken) throws ThingsboardException { |
|||
checkParameter("pluginToken", pluginToken); |
|||
try { |
|||
PluginMetaData plugin = checkPlugin(pluginService.findPluginByApiToken(pluginToken)); |
|||
return ruleService.findPluginRules(plugin.getApiToken()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public RuleMetaData saveRule(@RequestBody RuleMetaData source) throws ThingsboardException { |
|||
try { |
|||
boolean created = source.getId() == null; |
|||
source.setTenantId(getCurrentUser().getTenantId()); |
|||
RuleMetaData rule = checkNotNull(ruleService.saveRule(source)); |
|||
actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), |
|||
created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
|||
return rule; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule/{ruleId}/activate", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void activateRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { |
|||
checkParameter("ruleId", strRuleId); |
|||
try { |
|||
RuleId ruleId = new RuleId(toUUID(strRuleId)); |
|||
RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
|||
ruleService.activateRuleById(ruleId); |
|||
actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.ACTIVATED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule/{ruleId}/suspend", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void suspendRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { |
|||
checkParameter("ruleId", strRuleId); |
|||
try { |
|||
RuleId ruleId = new RuleId(toUUID(strRuleId)); |
|||
RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
|||
ruleService.suspendRuleById(ruleId); |
|||
actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.SUSPENDED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/rule/system", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<RuleMetaData> getSystemRules( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(ruleService.findSystemRules(pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/rule/tenant/{tenantId}", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<RuleMetaData> getTenantRules( |
|||
@PathVariable("tenantId") String strTenantId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("tenantId", strTenantId); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(ruleService.findTenantRules(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rules", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<RuleMetaData> getRules() throws ThingsboardException { |
|||
try { |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
return checkNotNull(ruleService.findSystemRules()); |
|||
} else { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(ruleService.findAllTenantRulesByTenantId(tenantId)); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<RuleMetaData> getTenantRules( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(ruleService.findTenantRules(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/rule/{ruleId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteRule(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { |
|||
checkParameter("ruleId", strRuleId); |
|||
try { |
|||
RuleId ruleId = new RuleId(toUUID(strRuleId)); |
|||
RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
|||
ruleService.deleteRuleById(ruleId); |
|||
actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.DELETED); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.tenant.TenantService; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class TenantController extends BaseController { |
|||
|
|||
@Autowired |
|||
private TenantService tenantService; |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Tenant getTenantById(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { |
|||
checkParameter("tenantId", strTenantId); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
checkTenantId(tenantId); |
|||
return checkNotNull(tenantService.findTenantById(tenantId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/tenant", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException { |
|||
try { |
|||
return checkNotNull(tenantService.saveTenant(tenant)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteTenant(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { |
|||
checkParameter("tenantId", strTenantId); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
tenantService.deleteTenant(tenantId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/tenants", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Tenant> getTenants(@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(tenantService.findTenants(pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,179 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UserId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.security.UserCredentials; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.mail.MailService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class UserController extends BaseController { |
|||
|
|||
@Autowired |
|||
private MailService mailService; |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public User getUserById(@PathVariable("userId") String strUserId) throws ThingsboardException { |
|||
checkParameter("userId", strUserId); |
|||
try { |
|||
UserId userId = new UserId(toUUID(strUserId)); |
|||
SecurityUser authUser = getCurrentUser(); |
|||
if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(userId)) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
return checkUserId(userId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/user", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public User saveUser(@RequestBody User user, |
|||
HttpServletRequest request) throws ThingsboardException { |
|||
try { |
|||
SecurityUser authUser = getCurrentUser(); |
|||
if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(user.getId())) { |
|||
throw new ThingsboardException("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED); |
|||
} |
|||
boolean sendEmail = user.getId() == null; |
|||
if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) { |
|||
user.setTenantId(getCurrentUser().getTenantId()); |
|||
} |
|||
User savedUser = checkNotNull(userService.saveUser(user)); |
|||
if (sendEmail) { |
|||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(savedUser.getId()); |
|||
String baseUrl = String.format("%s://%s:%d", |
|||
request.getScheme(), |
|||
request.getServerName(), |
|||
request.getServerPort()); |
|||
String activateUrl = String.format("%s/api/noauth/activate?activateToken=%s", baseUrl, |
|||
userCredentials.getActivateToken()); |
|||
String email = savedUser.getEmail(); |
|||
try { |
|||
mailService.sendActivationEmail(activateUrl, email); |
|||
} catch (ThingsboardException e) { |
|||
userService.deleteUser(savedUser.getId()); |
|||
throw e; |
|||
} |
|||
} |
|||
return savedUser; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void sendActivationEmail( |
|||
@RequestParam(value = "email") String email, |
|||
HttpServletRequest request) throws ThingsboardException { |
|||
try { |
|||
User user = checkNotNull(userService.findUserByEmail(email)); |
|||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); |
|||
if (!userCredentials.isEnabled()) { |
|||
String baseUrl = String.format("%s://%s:%d", |
|||
request.getScheme(), |
|||
request.getServerName(), |
|||
request.getServerPort()); |
|||
String activateUrl = String.format("%s/api/noauth/activate?activateToken=%s", baseUrl, |
|||
userCredentials.getActivateToken()); |
|||
mailService.sendActivationEmail(activateUrl, email); |
|||
} else { |
|||
throw new ThingsboardException("User is already active!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteUser(@PathVariable("userId") String strUserId) throws ThingsboardException { |
|||
checkParameter("userId", strUserId); |
|||
try { |
|||
UserId userId = new UserId(toUUID(strUserId)); |
|||
checkUserId(userId); |
|||
userService.deleteUser(userId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('SYS_ADMIN')") |
|||
@RequestMapping(value = "/tenant/{tenantId}/users", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<User> getTenantAdmins( |
|||
@PathVariable("tenantId") String strTenantId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("tenantId", strTenantId); |
|||
try { |
|||
TenantId tenantId = new TenantId(toUUID(strTenantId)); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(userService.findTenantAdmins(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/{customerId}/users", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<User> getCustomerUsers( |
|||
@PathVariable("customerId") String strCustomerId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,118 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.WidgetTypeId; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.widget.WidgetType; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class WidgetTypeController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public WidgetType getWidgetTypeById(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { |
|||
checkParameter("widgetTypeId", strWidgetTypeId); |
|||
try { |
|||
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); |
|||
return checkWidgetTypeId(widgetTypeId, false); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetType", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public WidgetType saveWidgetType(@RequestBody WidgetType widgetType) throws ThingsboardException { |
|||
try { |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
widgetType.setTenantId(new TenantId(ModelConstants.NULL_UUID)); |
|||
} else { |
|||
widgetType.setTenantId(getCurrentUser().getTenantId()); |
|||
} |
|||
return checkNotNull(widgetTypeService.saveWidgetType(widgetType)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteWidgetType(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { |
|||
checkParameter("widgetTypeId", strWidgetTypeId); |
|||
try { |
|||
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); |
|||
checkWidgetTypeId(widgetTypeId, true); |
|||
widgetTypeService.deleteWidgetType(widgetTypeId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetTypes", params = { "isSystem", "bundleAlias"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<WidgetType> getBundleWidgetTypes( |
|||
@RequestParam boolean isSystem, |
|||
@RequestParam String bundleAlias) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId; |
|||
if (isSystem) { |
|||
tenantId = new TenantId(ModelConstants.NULL_UUID); |
|||
} else { |
|||
tenantId = getCurrentUser().getTenantId(); |
|||
} |
|||
return checkNotNull(widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(tenantId, bundleAlias)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/widgetType", params = { "isSystem", "bundleAlias", "alias" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public WidgetType getWidgetType( |
|||
@RequestParam boolean isSystem, |
|||
@RequestParam String bundleAlias, |
|||
@RequestParam String alias) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId; |
|||
if (isSystem) { |
|||
tenantId = new TenantId(ModelConstants.NULL_UUID); |
|||
} else { |
|||
tenantId = getCurrentUser().getTenantId(); |
|||
} |
|||
WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdBundleAliasAndAlias(tenantId, bundleAlias, alias); |
|||
checkWidgetType(widgetType, false); |
|||
return widgetType; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.WidgetsBundleId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class WidgetsBundleController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public WidgetsBundle getWidgetsBundleById(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { |
|||
checkParameter("widgetsBundleId", strWidgetsBundleId); |
|||
try { |
|||
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); |
|||
return checkWidgetsBundleId(widgetsBundleId, false); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public WidgetsBundle saveWidgetsBundle(@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { |
|||
try { |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); |
|||
} else { |
|||
widgetsBundle.setTenantId(getCurrentUser().getTenantId()); |
|||
} |
|||
return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteWidgetsBundle(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { |
|||
checkParameter("widgetsBundleId", strWidgetsBundleId); |
|||
try { |
|||
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); |
|||
checkWidgetsBundleId(widgetsBundleId, true); |
|||
widgetsBundleService.deleteWidgetsBundle(widgetsBundleId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetsBundles", params = { "limit" }, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<WidgetsBundle> getWidgetsBundles( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(pageLink)); |
|||
} else { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink)); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/widgetsBundles", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<WidgetsBundle> getWidgetsBundles() throws ThingsboardException { |
|||
try { |
|||
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
|||
return checkNotNull(widgetsBundleService.findSystemWidgetsBundles()); |
|||
} else { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId)); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller.plugin; |
|||
|
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.RequestEntity; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.ResponseStatus; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
import org.thingsboard.server.actors.service.ActorService; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.PluginMetaData; |
|||
import org.thingsboard.server.controller.BaseController; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.plugin.PluginService; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginConstants; |
|||
import org.thingsboard.server.extensions.api.plugins.rest.BasicPluginRestMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.rest.RestRequest; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
|
|||
@RestController |
|||
@RequestMapping(PluginConstants.PLUGIN_URL_PREFIX) |
|||
@Slf4j |
|||
public class PluginApiController extends BaseController { |
|||
|
|||
@Autowired |
|||
private ActorService actorService; |
|||
|
|||
@Autowired |
|||
private PluginService pluginService; |
|||
|
|||
@SuppressWarnings("rawtypes") |
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/{pluginToken}/**") |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public DeferredResult<ResponseEntity> processRequest( |
|||
@PathVariable("pluginToken") String pluginToken, |
|||
RequestEntity<byte[]> requestEntity, |
|||
HttpServletRequest request) |
|||
throws ThingsboardException { |
|||
log.debug("[{}] Going to process requst uri: {}", pluginToken, requestEntity.getUrl()); |
|||
DeferredResult<ResponseEntity> result = new DeferredResult<ResponseEntity>(); |
|||
PluginMetaData pluginMd = pluginService.findPluginByApiToken(pluginToken); |
|||
if (pluginMd == null) { |
|||
result.setErrorResult(new PluginNotFoundException("Plugin with token: " + pluginToken + " not found!")); |
|||
} else { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
CustomerId customerId = getCurrentUser().getCustomerId(); |
|||
if (validatePluginAccess(pluginMd, tenantId, customerId)) { |
|||
if(ModelConstants.NULL_UUID.equals(tenantId.getId())){ |
|||
tenantId = null; |
|||
} |
|||
PluginApiCallSecurityContext securityCtx = new PluginApiCallSecurityContext(pluginMd.getTenantId(), pluginMd.getId(), tenantId, customerId); |
|||
actorService.process(new BasicPluginRestMsg(securityCtx, new RestRequest(requestEntity, request), result)); |
|||
} else { |
|||
result.setResult(new ResponseEntity<>(HttpStatus.FORBIDDEN)); |
|||
} |
|||
|
|||
} |
|||
return result; |
|||
} |
|||
|
|||
public static boolean validatePluginAccess(PluginMetaData pluginMd, TenantId tenantId, CustomerId customerId) { |
|||
boolean systemAdministrator = tenantId == null || ModelConstants.NULL_UUID.equals(tenantId.getId()); |
|||
boolean tenantAdministrator = !systemAdministrator && (customerId == null || ModelConstants.NULL_UUID.equals(customerId.getId())); |
|||
boolean systemPlugin = ModelConstants.NULL_UUID.equals(pluginMd.getTenantId().getId()); |
|||
|
|||
boolean validUser = false; |
|||
if (systemPlugin) { |
|||
if (pluginMd.isPublicAccess() || systemAdministrator) { |
|||
// All users can access public system plugins. Only system
|
|||
// users can access private system plugins
|
|||
validUser = true; |
|||
} |
|||
} else { |
|||
if ((pluginMd.isPublicAccess() || tenantAdministrator) && tenantId.equals(pluginMd.getTenantId())) { |
|||
// All tenant users can access public tenant plugins. Only tenant
|
|||
// administrator can access private tenant plugins
|
|||
validUser = true; |
|||
} |
|||
} |
|||
return validUser; |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller.plugin; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.web.bind.annotation.ResponseStatus; |
|||
|
|||
@ResponseStatus(HttpStatus.NOT_FOUND) |
|||
public class PluginNotFoundException extends RuntimeException { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
public PluginNotFoundException(String message){ |
|||
super(message); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,203 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller.plugin; |
|||
|
|||
import java.io.IOException; |
|||
import java.net.URI; |
|||
import java.security.InvalidParameterException; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.context.annotation.Lazy; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.thingsboard.server.actors.service.ActorService; |
|||
import org.thingsboard.server.config.WebSocketConfiguration; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginConstants; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.PluginMetaData; |
|||
import org.thingsboard.server.dao.plugin.PluginService; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.BasicPluginWebsocketSessionRef; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRef; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.SessionEvent; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.msg.SessionEventPluginWebSocketMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.msg.TextPluginWebSocketMsg; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.socket.CloseStatus; |
|||
import org.springframework.web.socket.TextMessage; |
|||
import org.springframework.web.socket.WebSocketSession; |
|||
import org.springframework.web.socket.handler.TextWebSocketHandler; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class PluginWebSocketHandler extends TextWebSocketHandler implements PluginWebSocketMsgEndpoint { |
|||
|
|||
private static final ConcurrentMap<String, SessionMetaData> internalSessionMap = new ConcurrentHashMap<>(); |
|||
private static final ConcurrentMap<String, String> externalSessionMap = new ConcurrentHashMap<>(); |
|||
|
|||
@Autowired @Lazy |
|||
private ActorService actorService; |
|||
|
|||
@Autowired @Lazy |
|||
private PluginService pluginService; |
|||
|
|||
@Override |
|||
public void handleTextMessage(WebSocketSession session, TextMessage message) { |
|||
try { |
|||
log.info("[{}] Processing {}", session.getId(), message); |
|||
SessionMetaData sessionMd = internalSessionMap.get(session.getId()); |
|||
if (sessionMd != null) { |
|||
actorService.process(new TextPluginWebSocketMsg(sessionMd.sessionRef, message.getPayload())); |
|||
} else { |
|||
log.warn("[{}] Failed to find session", session.getId()); |
|||
session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!")); |
|||
} |
|||
session.sendMessage(message); |
|||
} catch (IOException e) { |
|||
log.warn("IO error", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void afterConnectionEstablished(WebSocketSession session) throws Exception { |
|||
super.afterConnectionEstablished(session); |
|||
try { |
|||
String internalSessionId = session.getId(); |
|||
PluginWebsocketSessionRef sessionRef = toRef(session); |
|||
String externalSessionId = sessionRef.getSessionId(); |
|||
internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef)); |
|||
externalSessionMap.put(externalSessionId, internalSessionId); |
|||
actorService.process(new SessionEventPluginWebSocketMsg(sessionRef, SessionEvent.onEstablished())); |
|||
log.info("[{}][{}] Session is started", externalSessionId, session.getId()); |
|||
} catch (InvalidParameterException e) { |
|||
log.warn("[[{}] Failed to start session", session.getId(), e); |
|||
session.close(CloseStatus.BAD_DATA.withReason(e.getMessage())); |
|||
} catch (Exception e) { |
|||
log.warn("[{}] Failed to start session", session.getId(), e); |
|||
session.close(CloseStatus.SERVER_ERROR.withReason(e.getMessage())); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void handleTransportError(WebSocketSession session, Throwable tError) throws Exception { |
|||
super.handleTransportError(session, tError); |
|||
SessionMetaData sessionMd = internalSessionMap.get(session.getId()); |
|||
if (sessionMd != null) { |
|||
actorService.process(new SessionEventPluginWebSocketMsg(sessionMd.sessionRef, SessionEvent.onError(tError))); |
|||
} else { |
|||
log.warn("[{}] Failed to find session", session.getId()); |
|||
} |
|||
log.trace("[{}] Session transport error", session.getId(), tError); |
|||
} |
|||
|
|||
@Override |
|||
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { |
|||
super.afterConnectionClosed(session, closeStatus); |
|||
SessionMetaData sessionMd = internalSessionMap.remove(session.getId()); |
|||
if (sessionMd != null) { |
|||
externalSessionMap.remove(sessionMd.sessionRef.getSessionId()); |
|||
actorService.process(new SessionEventPluginWebSocketMsg(sessionMd.sessionRef, SessionEvent.onClosed())); |
|||
} |
|||
log.info("[{}] Session is closed", session.getId()); |
|||
} |
|||
|
|||
private PluginWebsocketSessionRef toRef(WebSocketSession session) throws IOException { |
|||
URI sessionUri = session.getUri(); |
|||
String path = sessionUri.getPath(); |
|||
path = path.substring(WebSocketConfiguration.WS_PLUGIN_PREFIX.length()); |
|||
if (path.length() == 0) { |
|||
throw new IllegalArgumentException("URL should contain plugin token!"); |
|||
} |
|||
String[] pathElements = path.split("/"); |
|||
String pluginToken = pathElements[0]; |
|||
// TODO: cache
|
|||
PluginMetaData pluginMd = pluginService.findPluginByApiToken(pluginToken); |
|||
if (pluginMd == null) { |
|||
throw new InvalidParameterException("Can't find plugin with specified token!"); |
|||
} else { |
|||
SecurityUser currentUser = (SecurityUser) session.getAttributes().get(WebSocketConfiguration.WS_SECURITY_USER_ATTRIBUTE); |
|||
TenantId tenantId = currentUser.getTenantId(); |
|||
CustomerId customerId = currentUser.getCustomerId(); |
|||
if (PluginApiController.validatePluginAccess(pluginMd, tenantId, customerId)) { |
|||
PluginApiCallSecurityContext securityCtx = new PluginApiCallSecurityContext(pluginMd.getTenantId(), pluginMd.getId(), tenantId, |
|||
currentUser.getCustomerId()); |
|||
return new BasicPluginWebsocketSessionRef(UUID.randomUUID().toString(), securityCtx, session.getUri(), session.getAttributes(), |
|||
session.getLocalAddress(), session.getRemoteAddress()); |
|||
} else { |
|||
throw new SecurityException("Current user is not allowed to use this plugin!"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static class SessionMetaData { |
|||
private final WebSocketSession session; |
|||
private final PluginWebsocketSessionRef sessionRef; |
|||
|
|||
public SessionMetaData(WebSocketSession session, PluginWebsocketSessionRef sessionRef) { |
|||
super(); |
|||
this.session = session; |
|||
this.sessionRef = sessionRef; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void send(PluginWebsocketMsg<?> wsMsg) throws IOException { |
|||
PluginWebsocketSessionRef sessionRef = wsMsg.getSessionRef(); |
|||
String externalId = sessionRef.getSessionId(); |
|||
log.debug("[{}] Processing {}", externalId, wsMsg); |
|||
String internalId = externalSessionMap.get(externalId); |
|||
if (internalId != null) { |
|||
SessionMetaData sessionMd = internalSessionMap.get(internalId); |
|||
if (sessionMd != null) { |
|||
if (wsMsg instanceof TextPluginWebSocketMsg) { |
|||
String payload = ((TextPluginWebSocketMsg) wsMsg).getPayload(); |
|||
sessionMd.session.sendMessage(new TextMessage(payload)); |
|||
} |
|||
} else { |
|||
log.warn("[{}][{}] Failed to find session by internal id", externalId, internalId); |
|||
} |
|||
} else { |
|||
log.warn("[{}] Failed to find session by external id", externalId); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void close(PluginWebsocketSessionRef sessionRef) throws IOException { |
|||
String externalId = sessionRef.getSessionId(); |
|||
log.debug("[{}] Processing close request", externalId); |
|||
String internalId = externalSessionMap.get(externalId); |
|||
if (internalId != null) { |
|||
SessionMetaData sessionMd = internalSessionMap.get(internalId); |
|||
if (sessionMd != null) { |
|||
sessionMd.session.close(CloseStatus.NORMAL); |
|||
} else { |
|||
log.warn("[{}][{}] Failed to find session by internal id", externalId, internalId); |
|||
} |
|||
} else { |
|||
log.warn("[{}] Failed to find session by external id", externalId); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.controller.plugin; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRef; |
|||
import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; |
|||
|
|||
public interface PluginWebSocketMsgEndpoint { |
|||
|
|||
void send(PluginWebsocketMsg<?> wsMsg) throws IOException; |
|||
|
|||
void close(PluginWebsocketSessionRef sessionRef) throws IOException; |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.exception; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonValue; |
|||
|
|||
public enum ThingsboardErrorCode { |
|||
|
|||
GENERAL(2), |
|||
AUTHENTICATION(10), |
|||
JWT_TOKEN_EXPIRED(11), |
|||
PERMISSION_DENIED(20), |
|||
INVALID_ARGUMENTS(30), |
|||
BAD_REQUEST_PARAMS(31), |
|||
ITEM_NOT_FOUND(32); |
|||
|
|||
private int errorCode; |
|||
|
|||
ThingsboardErrorCode(int errorCode) { |
|||
this.errorCode = errorCode; |
|||
} |
|||
|
|||
@JsonValue |
|||
public int getErrorCode() { |
|||
return errorCode; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.exception; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
|
|||
import java.util.Date; |
|||
|
|||
public class ThingsboardErrorResponse { |
|||
// HTTP Response Status Code
|
|||
private final HttpStatus status; |
|||
|
|||
// General Error message
|
|||
private final String message; |
|||
|
|||
// Error code
|
|||
private final ThingsboardErrorCode errorCode; |
|||
|
|||
private final Date timestamp; |
|||
|
|||
protected ThingsboardErrorResponse(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { |
|||
this.message = message; |
|||
this.errorCode = errorCode; |
|||
this.status = status; |
|||
this.timestamp = new java.util.Date(); |
|||
} |
|||
|
|||
public static ThingsboardErrorResponse of(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { |
|||
return new ThingsboardErrorResponse(message, errorCode, status); |
|||
} |
|||
|
|||
public Integer getStatus() { |
|||
return status.value(); |
|||
} |
|||
|
|||
public String getMessage() { |
|||
return message; |
|||
} |
|||
|
|||
public ThingsboardErrorCode getErrorCode() { |
|||
return errorCode; |
|||
} |
|||
|
|||
public Date getTimestamp() { |
|||
return timestamp; |
|||
} |
|||
} |
|||
@ -0,0 +1,133 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.exception; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.security.access.AccessDeniedException; |
|||
import org.springframework.security.authentication.BadCredentialsException; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.web.access.AccessDeniedHandler; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; |
|||
import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
@Component |
|||
@Slf4j |
|||
public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { |
|||
|
|||
@Autowired |
|||
private ObjectMapper mapper; |
|||
|
|||
@Override |
|||
public void handle(HttpServletRequest request, HttpServletResponse response, |
|||
AccessDeniedException accessDeniedException) throws IOException, |
|||
ServletException { |
|||
if (!response.isCommitted()) { |
|||
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
|||
response.setStatus(HttpStatus.FORBIDDEN.value()); |
|||
mapper.writeValue(response.getWriter(), |
|||
ThingsboardErrorResponse.of("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)); |
|||
} |
|||
} |
|||
|
|||
public void handle(Exception exception, HttpServletResponse response) { |
|||
log.debug("Processing exception {}", exception.getMessage(), exception); |
|||
if (!response.isCommitted()) { |
|||
try { |
|||
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
|||
|
|||
if (exception instanceof ThingsboardException) { |
|||
handleThingsboardException((ThingsboardException) exception, response); |
|||
} else if (exception instanceof AccessDeniedException) { |
|||
handleAccessDeniedException(response); |
|||
} else if (exception instanceof AuthenticationException) { |
|||
handleAuthenticationException((AuthenticationException) exception, response); |
|||
} else { |
|||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(exception.getMessage(), |
|||
ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR)); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("Can't handle exception", e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { |
|||
|
|||
ThingsboardErrorCode errorCode = thingsboardException.getErrorCode(); |
|||
HttpStatus status; |
|||
|
|||
switch (errorCode) { |
|||
case AUTHENTICATION: |
|||
status = HttpStatus.UNAUTHORIZED; |
|||
break; |
|||
case PERMISSION_DENIED: |
|||
status = HttpStatus.FORBIDDEN; |
|||
break; |
|||
case INVALID_ARGUMENTS: |
|||
status = HttpStatus.BAD_REQUEST; |
|||
break; |
|||
case ITEM_NOT_FOUND: |
|||
status = HttpStatus.NOT_FOUND; |
|||
break; |
|||
case BAD_REQUEST_PARAMS: |
|||
status = HttpStatus.BAD_REQUEST; |
|||
break; |
|||
case GENERAL: |
|||
status = HttpStatus.INTERNAL_SERVER_ERROR; |
|||
break; |
|||
default: |
|||
status = HttpStatus.INTERNAL_SERVER_ERROR; |
|||
break; |
|||
} |
|||
|
|||
response.setStatus(status.value()); |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(thingsboardException.getMessage(), errorCode, status)); |
|||
} |
|||
|
|||
private void handleAccessDeniedException(HttpServletResponse response) throws IOException { |
|||
response.setStatus(HttpStatus.FORBIDDEN.value()); |
|||
mapper.writeValue(response.getWriter(), |
|||
ThingsboardErrorResponse.of("You don't have permission to perform this operation!", |
|||
ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)); |
|||
|
|||
} |
|||
|
|||
private void handleAuthenticationException(AuthenticationException authenticationException, HttpServletResponse response) throws IOException { |
|||
response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
|||
if (authenticationException instanceof BadCredentialsException) { |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); |
|||
} else if (authenticationException instanceof JwtExpiredTokenException) { |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)); |
|||
} else if (authenticationException instanceof AuthMethodNotSupportedException) { |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(authenticationException.getMessage(), ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); |
|||
} |
|||
mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.exception; |
|||
|
|||
public class ThingsboardException extends Exception { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private ThingsboardErrorCode errorCode; |
|||
|
|||
public ThingsboardException() { |
|||
super(); |
|||
} |
|||
|
|||
public ThingsboardException(ThingsboardErrorCode errorCode) { |
|||
this.errorCode = errorCode; |
|||
} |
|||
|
|||
public ThingsboardException(String message, ThingsboardErrorCode errorCode) { |
|||
super(message); |
|||
this.errorCode = errorCode; |
|||
} |
|||
|
|||
public ThingsboardException(String message, Throwable cause, ThingsboardErrorCode errorCode) { |
|||
super(message, cause); |
|||
this.errorCode = errorCode; |
|||
} |
|||
|
|||
public ThingsboardException(Throwable cause, ThingsboardErrorCode errorCode) { |
|||
super(cause); |
|||
this.errorCode = errorCode; |
|||
} |
|||
|
|||
public ThingsboardErrorCode getErrorCode() { |
|||
return errorCode; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.environment; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.zookeeper.Environment; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
|
|||
/** |
|||
* Created by igor on 11/24/16. |
|||
*/ |
|||
|
|||
@Service("environmentLogService") |
|||
@ConditionalOnProperty(prefix = "zk", value = "enabled", havingValue = "false", matchIfMissing = true) |
|||
@Slf4j |
|||
public class EnvironmentLogService { |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
Environment.logEnv("Thingsboard server environment: ", log); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,208 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.mail; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Locale; |
|||
import java.util.Map; |
|||
import java.util.Properties; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.mail.internet.MimeMessage; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.apache.velocity.app.VelocityEngine; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.dao.settings.AdminSettingsService; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.MessageSource; |
|||
import org.springframework.core.NestedRuntimeException; |
|||
import org.springframework.mail.javamail.JavaMailSenderImpl; |
|||
import org.springframework.mail.javamail.MimeMessageHelper; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.ui.velocity.VelocityEngineUtils; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
@Service |
|||
@Slf4j |
|||
public class DefaultMailService implements MailService { |
|||
|
|||
@Autowired |
|||
private MessageSource messages; |
|||
|
|||
@Autowired |
|||
private VelocityEngine engine; |
|||
|
|||
private JavaMailSenderImpl mailSender; |
|||
|
|||
private String mailFrom; |
|||
|
|||
@Autowired |
|||
private AdminSettingsService adminSettingsService; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
updateMailConfiguration(); |
|||
} |
|||
|
|||
@Override |
|||
public void updateMailConfiguration() { |
|||
AdminSettings settings = adminSettingsService.findAdminSettingsByKey("mail"); |
|||
JsonNode jsonConfig = settings.getJsonValue(); |
|||
mailSender = createMailSender(jsonConfig); |
|||
mailFrom = jsonConfig.get("mailFrom").asText(); |
|||
} |
|||
|
|||
private JavaMailSenderImpl createMailSender(JsonNode jsonConfig) { |
|||
JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); |
|||
mailSender.setHost(jsonConfig.get("smtpHost").asText()); |
|||
mailSender.setPort(parsePort(jsonConfig.get("smtpPort").asText())); |
|||
mailSender.setUsername(jsonConfig.get("username").asText()); |
|||
mailSender.setPassword(jsonConfig.get("password").asText()); |
|||
mailSender.setJavaMailProperties(createJavaMailProperties(jsonConfig)); |
|||
return mailSender; |
|||
} |
|||
|
|||
private Properties createJavaMailProperties(JsonNode jsonConfig) { |
|||
Properties javaMailProperties = new Properties(); |
|||
String protocol = jsonConfig.get("smtpProtocol").asText(); |
|||
javaMailProperties.put("mail.transport.protocol", protocol); |
|||
javaMailProperties.put("mail." + protocol + ".host", jsonConfig.get("smtpHost").asText()); |
|||
javaMailProperties.put("mail." + protocol + ".port", jsonConfig.get("smtpPort").asText()); |
|||
javaMailProperties.put("mail." + protocol + ".timeout", jsonConfig.get("timeout").asText()); |
|||
javaMailProperties.put("mail." + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(jsonConfig.get("username").asText()))); |
|||
javaMailProperties.put("mail." + protocol + ".starttls.enable", jsonConfig.get("enableTls")); |
|||
return javaMailProperties; |
|||
} |
|||
|
|||
private int parsePort(String strPort) { |
|||
try { |
|||
return Integer.valueOf(strPort); |
|||
} catch (NumberFormatException e) { |
|||
throw new IncorrectParameterException(String.format("Invalid smtp port value: %s", strPort)); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void sendTestMail(JsonNode jsonConfig, String email) throws ThingsboardException { |
|||
JavaMailSenderImpl testMailSender = createMailSender(jsonConfig); |
|||
String mailFrom = jsonConfig.get("mailFrom").asText(); |
|||
String subject = messages.getMessage("test.message.subject", null, Locale.US); |
|||
|
|||
Map<String, Object> model = new HashMap<String, Object>(); |
|||
model.put("targetEmail", email); |
|||
|
|||
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, |
|||
"test.vm", "UTF-8", model); |
|||
|
|||
sendMail(testMailSender, mailFrom, email, subject, message); |
|||
} |
|||
|
|||
@Override |
|||
public void sendActivationEmail(String activationLink, String email) throws ThingsboardException { |
|||
|
|||
String subject = messages.getMessage("activation.subject", null, Locale.US); |
|||
|
|||
Map<String, Object> model = new HashMap<String, Object>(); |
|||
model.put("activationLink", activationLink); |
|||
model.put("targetEmail", email); |
|||
|
|||
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, |
|||
"activation.vm", "UTF-8", model); |
|||
|
|||
sendMail(mailSender, mailFrom, email, subject, message); |
|||
} |
|||
|
|||
@Override |
|||
public void sendAccountActivatedEmail(String loginLink, String email) throws ThingsboardException { |
|||
|
|||
String subject = messages.getMessage("account.activated.subject", null, Locale.US); |
|||
|
|||
Map<String, Object> model = new HashMap<String, Object>(); |
|||
model.put("loginLink", loginLink); |
|||
model.put("targetEmail", email); |
|||
|
|||
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, |
|||
"account.activated.vm", "UTF-8", model); |
|||
|
|||
sendMail(mailSender, mailFrom, email, subject, message); |
|||
} |
|||
|
|||
@Override |
|||
public void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException { |
|||
|
|||
String subject = messages.getMessage("reset.password.subject", null, Locale.US); |
|||
|
|||
Map<String, Object> model = new HashMap<String, Object>(); |
|||
model.put("passwordResetLink", passwordResetLink); |
|||
model.put("targetEmail", email); |
|||
|
|||
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, |
|||
"reset.password.vm", "UTF-8", model); |
|||
|
|||
sendMail(mailSender, mailFrom, email, subject, message); |
|||
} |
|||
|
|||
@Override |
|||
public void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException { |
|||
|
|||
String subject = messages.getMessage("password.was.reset.subject", null, Locale.US); |
|||
|
|||
Map<String, Object> model = new HashMap<String, Object>(); |
|||
model.put("loginLink", loginLink); |
|||
model.put("targetEmail", email); |
|||
|
|||
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, |
|||
"password.was.reset.vm", "UTF-8", model); |
|||
|
|||
sendMail(mailSender, mailFrom, email, subject, message); |
|||
} |
|||
|
|||
|
|||
private void sendMail(JavaMailSenderImpl mailSender, |
|||
String mailFrom, String email, |
|||
String subject, String message) throws ThingsboardException { |
|||
try { |
|||
MimeMessage mimeMsg = mailSender.createMimeMessage(); |
|||
MimeMessageHelper helper = new MimeMessageHelper(mimeMsg, "UTF-8"); |
|||
helper.setFrom(mailFrom); |
|||
helper.setTo(email); |
|||
helper.setSubject(subject); |
|||
helper.setText(message, true); |
|||
mailSender.send(helper.getMimeMessage()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
protected ThingsboardException handleException(Exception exception) { |
|||
String message; |
|||
if (exception instanceof NestedRuntimeException) { |
|||
message = ((NestedRuntimeException)exception).getMostSpecificCause().getMessage(); |
|||
} else { |
|||
message = exception.getMessage(); |
|||
} |
|||
return new ThingsboardException(String.format("Unable to send mail: %s", message), |
|||
ThingsboardErrorCode.GENERAL); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.mail; |
|||
|
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
|
|||
public interface MailService { |
|||
|
|||
void updateMailConfiguration(); |
|||
|
|||
void sendTestMail(JsonNode config, String email) throws ThingsboardException; |
|||
|
|||
void sendActivationEmail(String activationLink, String email) throws ThingsboardException; |
|||
|
|||
void sendAccountActivatedEmail(String loginLink, String email) throws ThingsboardException; |
|||
|
|||
void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException; |
|||
|
|||
void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException; |
|||
|
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth; |
|||
|
|||
import org.springframework.security.authentication.AbstractAuthenticationToken; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
public abstract class AbstractJwtAuthenticationToken extends AbstractAuthenticationToken { |
|||
|
|||
private static final long serialVersionUID = -6212297506742428406L; |
|||
|
|||
private RawAccessJwtToken rawAccessToken; |
|||
private SecurityUser securityUser; |
|||
|
|||
public AbstractJwtAuthenticationToken(RawAccessJwtToken unsafeToken) { |
|||
super(null); |
|||
this.rawAccessToken = unsafeToken; |
|||
this.setAuthenticated(false); |
|||
} |
|||
|
|||
public AbstractJwtAuthenticationToken(SecurityUser securityUser) { |
|||
super(securityUser.getAuthorities()); |
|||
this.eraseCredentials(); |
|||
this.securityUser = securityUser; |
|||
super.setAuthenticated(true); |
|||
} |
|||
|
|||
@Override |
|||
public void setAuthenticated(boolean authenticated) { |
|||
if (authenticated) { |
|||
throw new IllegalArgumentException( |
|||
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); |
|||
} |
|||
super.setAuthenticated(false); |
|||
} |
|||
|
|||
@Override |
|||
public Object getCredentials() { |
|||
return rawAccessToken; |
|||
} |
|||
|
|||
@Override |
|||
public Object getPrincipal() { |
|||
return this.securityUser; |
|||
} |
|||
|
|||
@Override |
|||
public void eraseCredentials() { |
|||
super.eraseCredentials(); |
|||
this.rawAccessToken = null; |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth; |
|||
|
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
public class JwtAuthenticationToken extends AbstractJwtAuthenticationToken { |
|||
|
|||
private static final long serialVersionUID = -8487219769037942225L; |
|||
|
|||
public JwtAuthenticationToken(RawAccessJwtToken unsafeToken) { |
|||
super(unsafeToken); |
|||
} |
|||
|
|||
public JwtAuthenticationToken(SecurityUser securityUser) { |
|||
super(securityUser); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth; |
|||
|
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
public class RefreshAuthenticationToken extends AbstractJwtAuthenticationToken { |
|||
|
|||
private static final long serialVersionUID = -1311042791508924523L; |
|||
|
|||
public RefreshAuthenticationToken(RawAccessJwtToken unsafeToken) { |
|||
super(unsafeToken); |
|||
} |
|||
|
|||
public RefreshAuthenticationToken(SecurityUser securityUser) { |
|||
super(securityUser); |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import io.jsonwebtoken.Claims; |
|||
import io.jsonwebtoken.Jws; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.authentication.AuthenticationProvider; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.config.JwtSettings; |
|||
import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Component |
|||
@SuppressWarnings("unchecked") |
|||
public class JwtAuthenticationProvider implements AuthenticationProvider { |
|||
|
|||
private final JwtTokenFactory tokenFactory; |
|||
|
|||
@Autowired |
|||
public JwtAuthenticationProvider(JwtTokenFactory tokenFactory) { |
|||
this.tokenFactory = tokenFactory; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
|||
RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials(); |
|||
SecurityUser securityUser = tokenFactory.parseAccessJwtToken(rawAccessToken); |
|||
return new JwtAuthenticationToken(securityUser); |
|||
} |
|||
|
|||
@Override |
|||
public boolean supports(Class<?> authentication) { |
|||
return (JwtAuthenticationToken.class.isAssignableFrom(authentication)); |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.context.SecurityContext; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.security.web.util.matcher.RequestMatcher; |
|||
import org.thingsboard.server.config.ThingsboardSecurityConfiguration; |
|||
import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; |
|||
import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
import javax.servlet.FilterChain; |
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { |
|||
private final AuthenticationFailureHandler failureHandler; |
|||
private final TokenExtractor tokenExtractor; |
|||
|
|||
@Autowired |
|||
public JwtTokenAuthenticationProcessingFilter(AuthenticationFailureHandler failureHandler, |
|||
TokenExtractor tokenExtractor, RequestMatcher matcher) { |
|||
super(matcher); |
|||
this.failureHandler = failureHandler; |
|||
this.tokenExtractor = tokenExtractor; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) |
|||
throws AuthenticationException, IOException, ServletException { |
|||
RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(request)); |
|||
return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token)); |
|||
} |
|||
|
|||
@Override |
|||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, |
|||
Authentication authResult) throws IOException, ServletException { |
|||
SecurityContext context = SecurityContextHolder.createEmptyContext(); |
|||
context.setAuthentication(authResult); |
|||
SecurityContextHolder.setContext(context); |
|||
chain.doFilter(request, response); |
|||
} |
|||
|
|||
@Override |
|||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, |
|||
AuthenticationException failed) throws IOException, ServletException { |
|||
SecurityContextHolder.clearContext(); |
|||
failureHandler.onAuthenticationFailure(request, response, failed); |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.authentication.AuthenticationProvider; |
|||
import org.springframework.security.authentication.DisabledException; |
|||
import org.springframework.security.authentication.InsufficientAuthenticationException; |
|||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.Assert; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.security.UserCredentials; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.service.security.auth.RefreshAuthenticationToken; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
@Component |
|||
public class RefreshTokenAuthenticationProvider implements AuthenticationProvider { |
|||
|
|||
private final JwtTokenFactory tokenFactory; |
|||
private final UserService userService; |
|||
|
|||
@Autowired |
|||
public RefreshTokenAuthenticationProvider(final UserService userService, final JwtTokenFactory tokenFactory) { |
|||
this.userService = userService; |
|||
this.tokenFactory = tokenFactory; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
|||
Assert.notNull(authentication, "No authentication data provided"); |
|||
RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials(); |
|||
SecurityUser unsafeUser = tokenFactory.parseRefreshToken(rawAccessToken); |
|||
|
|||
User user = userService.findUserById(unsafeUser.getId()); |
|||
if (user == null) { |
|||
throw new UsernameNotFoundException("User not found by refresh token"); |
|||
} |
|||
|
|||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); |
|||
if (userCredentials == null) { |
|||
throw new UsernameNotFoundException("User credentials not found"); |
|||
} |
|||
|
|||
if (!userCredentials.isEnabled()) { |
|||
throw new DisabledException("User is not active"); |
|||
} |
|||
|
|||
if (user.getAuthority() == null) throw new InsufficientAuthenticationException("User has no authority assigned"); |
|||
|
|||
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); |
|||
|
|||
return new RefreshAuthenticationToken(securityUser); |
|||
} |
|||
|
|||
@Override |
|||
public boolean supports(Class<?> authentication) { |
|||
return (RefreshAuthenticationToken.class.isAssignableFrom(authentication)); |
|||
} |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.http.HttpMethod; |
|||
import org.springframework.security.authentication.AuthenticationServiceException; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
|||
import org.thingsboard.server.service.security.auth.RefreshAuthenticationToken; |
|||
import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; |
|||
import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; |
|||
|
|||
import javax.servlet.FilterChain; |
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
public class RefreshTokenProcessingFilter extends AbstractAuthenticationProcessingFilter { |
|||
private static Logger logger = LoggerFactory.getLogger(RefreshTokenProcessingFilter.class); |
|||
|
|||
private final AuthenticationSuccessHandler successHandler; |
|||
private final AuthenticationFailureHandler failureHandler; |
|||
|
|||
private final ObjectMapper objectMapper; |
|||
|
|||
public RefreshTokenProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler, |
|||
AuthenticationFailureHandler failureHandler, ObjectMapper mapper) { |
|||
super(defaultProcessUrl); |
|||
this.successHandler = successHandler; |
|||
this.failureHandler = failureHandler; |
|||
this.objectMapper = mapper; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) |
|||
throws AuthenticationException, IOException, ServletException { |
|||
if (!HttpMethod.POST.name().equals(request.getMethod())) { |
|||
if(logger.isDebugEnabled()) { |
|||
logger.debug("Authentication method not supported. Request method: " + request.getMethod()); |
|||
} |
|||
throw new AuthMethodNotSupportedException("Authentication method not supported"); |
|||
} |
|||
|
|||
RefreshTokenRequest refreshTokenRequest; |
|||
try { |
|||
refreshTokenRequest = objectMapper.readValue(request.getReader(), RefreshTokenRequest.class); |
|||
} catch (Exception e) { |
|||
throw new AuthenticationServiceException("Invalid refresh token request payload"); |
|||
} |
|||
|
|||
if (StringUtils.isBlank(refreshTokenRequest.getRefreshToken())) { |
|||
throw new AuthenticationServiceException("Refresh token is not provided"); |
|||
} |
|||
|
|||
RawAccessJwtToken token = new RawAccessJwtToken(refreshTokenRequest.getRefreshToken()); |
|||
|
|||
return this.getAuthenticationManager().authenticate(new RefreshAuthenticationToken(token)); |
|||
} |
|||
|
|||
@Override |
|||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, |
|||
Authentication authResult) throws IOException, ServletException { |
|||
successHandler.onAuthenticationSuccess(request, response, authResult); |
|||
} |
|||
|
|||
@Override |
|||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, |
|||
AuthenticationException failed) throws IOException, ServletException { |
|||
SecurityContextHolder.clearContext(); |
|||
failureHandler.onAuthenticationFailure(request, response, failed); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|||
|
|||
@Component |
|||
public class RefreshTokenRepository { |
|||
|
|||
private final JwtTokenFactory tokenFactory; |
|||
|
|||
@Autowired |
|||
public RefreshTokenRepository(final JwtTokenFactory tokenFactory) { |
|||
this.tokenFactory = tokenFactory; |
|||
} |
|||
|
|||
public JwtToken requestRefreshToken(SecurityUser user) { |
|||
return tokenFactory.createRefreshToken(user); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
|
|||
public class RefreshTokenRequest { |
|||
private String refreshToken; |
|||
|
|||
@JsonCreator |
|||
public RefreshTokenRequest(@JsonProperty("refreshToken") String refreshToken) { |
|||
this.refreshToken = refreshToken; |
|||
} |
|||
|
|||
public String getRefreshToken() { |
|||
return refreshToken; |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt; |
|||
|
|||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
|||
import org.springframework.security.web.util.matcher.OrRequestMatcher; |
|||
import org.springframework.security.web.util.matcher.RequestMatcher; |
|||
import org.springframework.util.Assert; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public class SkipPathRequestMatcher implements RequestMatcher { |
|||
private OrRequestMatcher matchers; |
|||
private RequestMatcher processingMatcher; |
|||
|
|||
public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) { |
|||
Assert.notNull(pathsToSkip); |
|||
List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList()); |
|||
matchers = new OrRequestMatcher(m); |
|||
processingMatcher = new AntPathRequestMatcher(processingPath); |
|||
} |
|||
|
|||
@Override |
|||
public boolean matches(HttpServletRequest request) { |
|||
if (matchers.matches(request)) { |
|||
return false; |
|||
} |
|||
return processingMatcher.matches(request) ? true : false; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt.extractor; |
|||
|
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.security.authentication.AuthenticationServiceException; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.config.ThingsboardSecurityConfiguration; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
|
|||
@Component(value="jwtHeaderTokenExtractor") |
|||
public class JwtHeaderTokenExtractor implements TokenExtractor { |
|||
public static String HEADER_PREFIX = "Bearer "; |
|||
|
|||
@Override |
|||
public String extract(HttpServletRequest request) { |
|||
String header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM); |
|||
if (StringUtils.isBlank(header)) { |
|||
throw new AuthenticationServiceException("Authorization header cannot be blank!"); |
|||
} |
|||
|
|||
if (header.length() < HEADER_PREFIX.length()) { |
|||
throw new AuthenticationServiceException("Invalid authorization header size."); |
|||
} |
|||
|
|||
return header.substring(HEADER_PREFIX.length(), header.length()); |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt.extractor; |
|||
|
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.security.authentication.AuthenticationServiceException; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.config.ThingsboardSecurityConfiguration; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
|
|||
@Component(value="jwtQueryTokenExtractor") |
|||
public class JwtQueryTokenExtractor implements TokenExtractor { |
|||
|
|||
@Override |
|||
public String extract(HttpServletRequest request) { |
|||
String token = null; |
|||
if (request.getParameterMap() != null && !request.getParameterMap().isEmpty()) { |
|||
String[] tokenParamValue = request.getParameterMap().get(ThingsboardSecurityConfiguration.JWT_TOKEN_QUERY_PARAM); |
|||
if (tokenParamValue != null && tokenParamValue.length == 1) { |
|||
token = tokenParamValue[0]; |
|||
} |
|||
} |
|||
if (StringUtils.isBlank(token)) { |
|||
throw new AuthenticationServiceException("Authorization query parameter cannot be blank!"); |
|||
} |
|||
|
|||
return token; |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.jwt.extractor; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
|
|||
public interface TokenExtractor { |
|||
public String extract(HttpServletRequest request); |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.rest; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
|
|||
public class LoginRequest { |
|||
private String username; |
|||
private String password; |
|||
|
|||
@JsonCreator |
|||
public LoginRequest(@JsonProperty("username") String username, @JsonProperty("password") String password) { |
|||
this.username = username; |
|||
this.password = password; |
|||
} |
|||
|
|||
public String getUsername() { |
|||
return username; |
|||
} |
|||
|
|||
public String getPassword() { |
|||
return password; |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.rest; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.authentication.*; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.Assert; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.security.UserCredentials; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
@Component |
|||
public class RestAuthenticationProvider implements AuthenticationProvider { |
|||
|
|||
private final BCryptPasswordEncoder encoder; |
|||
private final UserService userService; |
|||
|
|||
@Autowired |
|||
public RestAuthenticationProvider(final UserService userService, final BCryptPasswordEncoder encoder) { |
|||
this.userService = userService; |
|||
this.encoder = encoder; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
|||
Assert.notNull(authentication, "No authentication data provided"); |
|||
|
|||
String username = (String) authentication.getPrincipal(); |
|||
String password = (String) authentication.getCredentials(); |
|||
|
|||
User user = userService.findUserByEmail(username); |
|||
if (user == null) { |
|||
throw new UsernameNotFoundException("User not found: " + username); |
|||
} |
|||
|
|||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); |
|||
if (userCredentials == null) { |
|||
throw new UsernameNotFoundException("User credentials not found"); |
|||
} |
|||
|
|||
if (!userCredentials.isEnabled()) { |
|||
throw new DisabledException("User is not active"); |
|||
} |
|||
|
|||
if (!encoder.matches(password, userCredentials.getPassword())) { |
|||
throw new BadCredentialsException("Authentication Failed. Username or Password not valid."); |
|||
} |
|||
|
|||
if (user.getAuthority() == null) throw new InsufficientAuthenticationException("User has no authority assigned"); |
|||
|
|||
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); |
|||
|
|||
return new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()); |
|||
} |
|||
|
|||
@Override |
|||
public boolean supports(Class<?> authentication) { |
|||
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.rest; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
@Component |
|||
public class RestAwareAuthenticationFailureHandler implements AuthenticationFailureHandler { |
|||
|
|||
private final ThingsboardErrorResponseHandler errorResponseHandler; |
|||
|
|||
@Autowired |
|||
public RestAwareAuthenticationFailureHandler(ThingsboardErrorResponseHandler errorResponseHandler) { |
|||
this.errorResponseHandler = errorResponseHandler; |
|||
} |
|||
|
|||
@Override |
|||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, |
|||
AuthenticationException e) throws IOException, ServletException { |
|||
errorResponseHandler.handle(e, response); |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.rest; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.web.WebAttributes; |
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import javax.servlet.http.HttpSession; |
|||
import java.io.IOException; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
@Component |
|||
public class RestAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler { |
|||
private final ObjectMapper mapper; |
|||
private final JwtTokenFactory tokenFactory; |
|||
private final RefreshTokenRepository refreshTokenRepository; |
|||
|
|||
@Autowired |
|||
public RestAwareAuthenticationSuccessHandler(final ObjectMapper mapper, final JwtTokenFactory tokenFactory, final RefreshTokenRepository refreshTokenRepository) { |
|||
this.mapper = mapper; |
|||
this.tokenFactory = tokenFactory; |
|||
this.refreshTokenRepository = refreshTokenRepository; |
|||
} |
|||
|
|||
@Override |
|||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, |
|||
Authentication authentication) throws IOException, ServletException { |
|||
SecurityUser securityUser = (SecurityUser) authentication.getPrincipal(); |
|||
|
|||
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
|||
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
|||
|
|||
Map<String, String> tokenMap = new HashMap<String, String>(); |
|||
tokenMap.put("token", accessToken.getToken()); |
|||
tokenMap.put("refreshToken", refreshToken.getToken()); |
|||
|
|||
response.setStatus(HttpStatus.OK.value()); |
|||
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
|||
mapper.writeValue(response.getWriter(), tokenMap); |
|||
|
|||
clearAuthenticationAttributes(request); |
|||
} |
|||
|
|||
/** |
|||
* Removes temporary authentication-related data which may have been stored |
|||
* in the session during the authentication process.. |
|||
* |
|||
*/ |
|||
protected final void clearAuthenticationAttributes(HttpServletRequest request) { |
|||
HttpSession session = request.getSession(false); |
|||
|
|||
if (session == null) { |
|||
return; |
|||
} |
|||
|
|||
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); |
|||
} |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.auth.rest; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.http.HttpMethod; |
|||
import org.springframework.security.authentication.AuthenticationServiceException; |
|||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
|||
import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; |
|||
|
|||
import javax.servlet.FilterChain; |
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
public class RestLoginProcessingFilter extends AbstractAuthenticationProcessingFilter { |
|||
private static Logger logger = LoggerFactory.getLogger(RestLoginProcessingFilter.class); |
|||
|
|||
private final AuthenticationSuccessHandler successHandler; |
|||
private final AuthenticationFailureHandler failureHandler; |
|||
|
|||
private final ObjectMapper objectMapper; |
|||
|
|||
public RestLoginProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler, |
|||
AuthenticationFailureHandler failureHandler, ObjectMapper mapper) { |
|||
super(defaultProcessUrl); |
|||
this.successHandler = successHandler; |
|||
this.failureHandler = failureHandler; |
|||
this.objectMapper = mapper; |
|||
} |
|||
|
|||
@Override |
|||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) |
|||
throws AuthenticationException, IOException, ServletException { |
|||
if (!HttpMethod.POST.name().equals(request.getMethod())) { |
|||
if(logger.isDebugEnabled()) { |
|||
logger.debug("Authentication method not supported. Request method: " + request.getMethod()); |
|||
} |
|||
throw new AuthMethodNotSupportedException("Authentication method not supported"); |
|||
} |
|||
|
|||
LoginRequest loginRequest; |
|||
try { |
|||
loginRequest = objectMapper.readValue(request.getReader(), LoginRequest.class); |
|||
} catch (Exception e) { |
|||
throw new AuthenticationServiceException("Invalid login request payload"); |
|||
} |
|||
|
|||
if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) { |
|||
throw new AuthenticationServiceException("Username or Password not provided"); |
|||
} |
|||
|
|||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()); |
|||
|
|||
return this.getAuthenticationManager().authenticate(token); |
|||
} |
|||
|
|||
@Override |
|||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, |
|||
Authentication authResult) throws IOException, ServletException { |
|||
successHandler.onAuthenticationSuccess(request, response, authResult); |
|||
} |
|||
|
|||
@Override |
|||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, |
|||
AuthenticationException failed) throws IOException, ServletException { |
|||
SecurityContextHolder.clearContext(); |
|||
failureHandler.onAuthenticationFailure(request, response, failed); |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.device; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; |
|||
import org.thingsboard.server.common.transport.auth.DeviceAuthResult; |
|||
import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class DefaultDeviceAuthService implements DeviceAuthService { |
|||
|
|||
@Autowired |
|||
DeviceService deviceService; |
|||
|
|||
@Autowired |
|||
DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Override |
|||
public DeviceAuthResult process(DeviceCredentialsFilter credentialsFilter) { |
|||
log.trace("Lookup device credentials using filter {}", credentialsFilter); |
|||
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credentialsFilter.getCredentialsId()); |
|||
if (credentials != null) { |
|||
log.trace("Credentials found {}", credentials); |
|||
if (credentials.getCredentialsType() == credentialsFilter.getCredentialsType()) { |
|||
switch (credentials.getCredentialsType()) { |
|||
case ACCESS_TOKEN: |
|||
// Credentials ID matches Credentials value in this
|
|||
// primitive case;
|
|||
return DeviceAuthResult.of(credentials.getDeviceId()); |
|||
default: |
|||
return DeviceAuthResult.of("Credentials Type is not supported yet!"); |
|||
} |
|||
} else { |
|||
return DeviceAuthResult.of("Credentials Type mismatch!"); |
|||
} |
|||
} else { |
|||
log.trace("Credentials not found!"); |
|||
return DeviceAuthResult.of("Credentials Not Found!"); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Optional<Device> findDeviceById(DeviceId deviceId) { |
|||
return Optional.ofNullable(deviceService.findDeviceById(deviceId)); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.exception; |
|||
|
|||
import org.springframework.security.authentication.AuthenticationServiceException; |
|||
|
|||
public class AuthMethodNotSupportedException extends AuthenticationServiceException { |
|||
private static final long serialVersionUID = 3705043083010304496L; |
|||
|
|||
public AuthMethodNotSupportedException(String msg) { |
|||
super(msg); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.exception; |
|||
|
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|||
|
|||
public class JwtExpiredTokenException extends AuthenticationException { |
|||
private static final long serialVersionUID = -5959543783324224864L; |
|||
|
|||
private JwtToken token; |
|||
|
|||
public JwtExpiredTokenException(String msg) { |
|||
super(msg); |
|||
} |
|||
|
|||
public JwtExpiredTokenException(JwtToken token, String msg, Throwable t) { |
|||
super(msg, t); |
|||
this.token = token; |
|||
} |
|||
|
|||
public String token() { |
|||
return this.token.getToken(); |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.model; |
|||
|
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.id.UserId; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.Collection; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public class SecurityUser extends User { |
|||
|
|||
private static final long serialVersionUID = -797397440703066079L; |
|||
|
|||
private Collection<GrantedAuthority> authorities; |
|||
private boolean enabled; |
|||
|
|||
public SecurityUser() { |
|||
super(); |
|||
} |
|||
|
|||
public SecurityUser(UserId id) { |
|||
super(id); |
|||
} |
|||
|
|||
public SecurityUser(User user, boolean enabled) { |
|||
super(user); |
|||
this.enabled = enabled; |
|||
} |
|||
|
|||
public Collection<? extends GrantedAuthority> getAuthorities() { |
|||
if (authorities == null) { |
|||
authorities = Arrays.asList(SecurityUser.this.getAuthority()).stream() |
|||
.map(authority -> new SimpleGrantedAuthority(authority.name())) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
return authorities; |
|||
} |
|||
|
|||
public boolean isEnabled() { |
|||
return enabled; |
|||
} |
|||
|
|||
public void setEnabled(boolean enabled) { |
|||
this.enabled = enabled; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.model.token; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import io.jsonwebtoken.Claims; |
|||
|
|||
public final class AccessJwtToken implements JwtToken { |
|||
private final String rawToken; |
|||
@JsonIgnore |
|||
private Claims claims; |
|||
|
|||
protected AccessJwtToken(final String token, Claims claims) { |
|||
this.rawToken = token; |
|||
this.claims = claims; |
|||
} |
|||
|
|||
public String getToken() { |
|||
return this.rawToken; |
|||
} |
|||
|
|||
public Claims getClaims() { |
|||
return claims; |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.model.token; |
|||
|
|||
public interface JwtToken { |
|||
String getToken(); |
|||
} |
|||
@ -0,0 +1,158 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.model.token; |
|||
|
|||
import io.jsonwebtoken.Claims; |
|||
import io.jsonwebtoken.Jws; |
|||
import io.jsonwebtoken.Jwts; |
|||
import io.jsonwebtoken.SignatureAlgorithm; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.joda.time.DateTime; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UserId; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.config.JwtSettings; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Component |
|||
public class JwtTokenFactory { |
|||
|
|||
private static final String SCOPES = "scopes"; |
|||
private static final String USER_ID = "userId"; |
|||
private static final String FIRST_NAME = "firstName"; |
|||
private static final String LAST_NAME = "lastName"; |
|||
private static final String ENABLED = "enabled"; |
|||
private static final String TENANT_ID = "tenantId"; |
|||
private static final String CUSTOMER_ID = "customerId"; |
|||
|
|||
private final JwtSettings settings; |
|||
|
|||
@Autowired |
|||
public JwtTokenFactory(JwtSettings settings) { |
|||
this.settings = settings; |
|||
} |
|||
|
|||
/** |
|||
* Factory method for issuing new JWT Tokens. |
|||
*/ |
|||
public AccessJwtToken createAccessJwtToken(SecurityUser securityUser) { |
|||
if (StringUtils.isBlank(securityUser.getEmail())) |
|||
throw new IllegalArgumentException("Cannot create JWT Token without username/email"); |
|||
|
|||
if (securityUser.getAuthority() == null) |
|||
throw new IllegalArgumentException("User doesn't have any privileges"); |
|||
|
|||
Claims claims = Jwts.claims().setSubject(securityUser.getEmail()); |
|||
claims.put(SCOPES, securityUser.getAuthorities().stream().map(s -> s.getAuthority()).collect(Collectors.toList())); |
|||
claims.put(USER_ID, securityUser.getId().getId().toString()); |
|||
claims.put(FIRST_NAME, securityUser.getFirstName()); |
|||
claims.put(LAST_NAME, securityUser.getLastName()); |
|||
claims.put(ENABLED, securityUser.isEnabled()); |
|||
if (securityUser.getTenantId() != null) { |
|||
claims.put(TENANT_ID, securityUser.getTenantId().getId().toString()); |
|||
} |
|||
if (securityUser.getCustomerId() != null) { |
|||
claims.put(CUSTOMER_ID, securityUser.getCustomerId().getId().toString()); |
|||
} |
|||
|
|||
DateTime currentTime = new DateTime(); |
|||
|
|||
String token = Jwts.builder() |
|||
.setClaims(claims) |
|||
.setIssuer(settings.getTokenIssuer()) |
|||
.setIssuedAt(currentTime.toDate()) |
|||
.setExpiration(currentTime.plusSeconds(settings.getTokenExpirationTime()).toDate()) |
|||
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
|||
.compact(); |
|||
|
|||
return new AccessJwtToken(token, claims); |
|||
} |
|||
|
|||
public SecurityUser parseAccessJwtToken(RawAccessJwtToken rawAccessToken) { |
|||
Jws<Claims> jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); |
|||
Claims claims = jwsClaims.getBody(); |
|||
String subject = claims.getSubject(); |
|||
List<String> scopes = claims.get(SCOPES, List.class); |
|||
if (scopes == null || scopes.isEmpty()) { |
|||
throw new IllegalArgumentException("JWT Token doesn't have any scopes"); |
|||
} |
|||
|
|||
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class)))); |
|||
securityUser.setEmail(subject); |
|||
securityUser.setAuthority(Authority.parse(scopes.get(0))); |
|||
securityUser.setFirstName(claims.get(FIRST_NAME, String.class)); |
|||
securityUser.setLastName(claims.get(LAST_NAME, String.class)); |
|||
securityUser.setEnabled(claims.get(ENABLED, Boolean.class)); |
|||
String tenantId = claims.get(TENANT_ID, String.class); |
|||
if (tenantId != null) { |
|||
securityUser.setTenantId(new TenantId(UUID.fromString(tenantId))); |
|||
} |
|||
String customerId = claims.get(CUSTOMER_ID, String.class); |
|||
if (customerId != null) { |
|||
securityUser.setCustomerId(new CustomerId(UUID.fromString(customerId))); |
|||
} |
|||
|
|||
return securityUser; |
|||
} |
|||
|
|||
public JwtToken createRefreshToken(SecurityUser securityUser) { |
|||
if (StringUtils.isBlank(securityUser.getEmail())) { |
|||
throw new IllegalArgumentException("Cannot create JWT Token without username/email"); |
|||
} |
|||
|
|||
DateTime currentTime = new DateTime(); |
|||
|
|||
Claims claims = Jwts.claims().setSubject(securityUser.getEmail()); |
|||
claims.put(SCOPES, Arrays.asList(Authority.REFRESH_TOKEN.name())); |
|||
claims.put(USER_ID, securityUser.getId().getId().toString()); |
|||
|
|||
String token = Jwts.builder() |
|||
.setClaims(claims) |
|||
.setIssuer(settings.getTokenIssuer()) |
|||
.setId(UUID.randomUUID().toString()) |
|||
.setIssuedAt(currentTime.toDate()) |
|||
.setExpiration(currentTime.plusSeconds(settings.getRefreshTokenExpTime()).toDate()) |
|||
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
|||
.compact(); |
|||
|
|||
return new AccessJwtToken(token, claims); |
|||
} |
|||
|
|||
public SecurityUser parseRefreshToken(RawAccessJwtToken rawAccessToken) { |
|||
Jws<Claims> jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); |
|||
Claims claims = jwsClaims.getBody(); |
|||
String subject = claims.getSubject(); |
|||
List<String> scopes = claims.get(SCOPES, List.class); |
|||
if (scopes == null || scopes.isEmpty()) { |
|||
throw new IllegalArgumentException("Refresh Token doesn't have any scopes"); |
|||
} |
|||
if (!scopes.get(0).equals(Authority.REFRESH_TOKEN.name())) { |
|||
throw new IllegalArgumentException("Invalid Refresh Token scope"); |
|||
} |
|||
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class)))); |
|||
securityUser.setEmail(subject); |
|||
return securityUser; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.service.security.model.token; |
|||
|
|||
import io.jsonwebtoken.*; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.security.authentication.BadCredentialsException; |
|||
import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; |
|||
|
|||
public class RawAccessJwtToken implements JwtToken { |
|||
private static Logger logger = LoggerFactory.getLogger(RawAccessJwtToken.class); |
|||
|
|||
private String token; |
|||
|
|||
public RawAccessJwtToken(String token) { |
|||
this.token = token; |
|||
} |
|||
|
|||
/** |
|||
* Parses and validates JWT Token signature. |
|||
* |
|||
* @throws BadCredentialsException |
|||
* @throws JwtExpiredTokenException |
|||
* |
|||
*/ |
|||
public Jws<Claims> parseClaims(String signingKey) { |
|||
try { |
|||
return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token); |
|||
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException | SignatureException ex) { |
|||
logger.error("Invalid JWT Token", ex); |
|||
throw new BadCredentialsException("Invalid JWT token: ", ex); |
|||
} catch (ExpiredJwtException expiredEx) { |
|||
logger.info("JWT Token is expired", expiredEx); |
|||
throw new JwtExpiredTokenException(this, "JWT Token expired", expiredEx); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public String getToken() { |
|||
return token; |
|||
} |
|||
} |
|||
@ -0,0 +1,176 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
Licensed 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. |
|||
|
|||
--> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard</groupId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<artifactId>server</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>dao</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>Thingsboard Server DAO Layer</name> |
|||
<url>http://thingsboard.org</url> |
|||
|
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<main.dir>${basedir}/..</main.dir> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server.common</groupId> |
|||
<artifactId>data</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.slf4j</groupId> |
|||
<artifactId>slf4j-api</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.slf4j</groupId> |
|||
<artifactId>log4j-over-slf4j</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-core</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-classic</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-test</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>junit</groupId> |
|||
<artifactId>junit</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.mockito</groupId> |
|||
<artifactId>mockito-all</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-lang3</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>commons-validator</groupId> |
|||
<artifactId>commons-validator</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.fasterxml.jackson.core</groupId> |
|||
<artifactId>jackson-databind</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.github.fge</groupId> |
|||
<artifactId>json-schema-validator</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-context</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-tx</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.datastax.cassandra</groupId> |
|||
<artifactId>cassandra-driver-core</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.datastax.cassandra</groupId> |
|||
<artifactId>cassandra-driver-mapping</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.datastax.cassandra</groupId> |
|||
<artifactId>cassandra-driver-extras</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>io.takari.junit</groupId> |
|||
<artifactId>takari-cpsuite</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.google.guava</groupId> |
|||
<artifactId>guava</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.cassandraunit</groupId> |
|||
<artifactId>cassandra-unit</artifactId> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.slf4j</groupId> |
|||
<artifactId>slf4j-log4j12</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.curator</groupId> |
|||
<artifactId>curator-x-discovery</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.hazelcast</groupId> |
|||
<artifactId>hazelcast-zookeeper</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.hazelcast</groupId> |
|||
<artifactId>hazelcast</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.hazelcast</groupId> |
|||
<artifactId>hazelcast-spring</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-autoconfigure</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-surefire-plugin</artifactId> |
|||
<version>${surfire.version}</version> |
|||
<configuration> |
|||
<includes> |
|||
<include>**/*TestSuite.java</include> |
|||
</includes> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-jar-plugin</artifactId> |
|||
<version>${jar-plugin.version}</version> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>test-jar</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
</project> |
|||
@ -0,0 +1,93 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import com.datastax.driver.core.*; |
|||
import com.datastax.driver.core.exceptions.CodecNotFoundException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.dao.cassandra.CassandraCluster; |
|||
import org.thingsboard.server.dao.model.type.*; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractDao { |
|||
|
|||
@Autowired |
|||
protected CassandraCluster cluster; |
|||
|
|||
private Session session; |
|||
|
|||
private ConsistencyLevel defaultReadLevel; |
|||
private ConsistencyLevel defaultWriteLevel; |
|||
|
|||
protected Session getSession() { |
|||
if (session == null) { |
|||
session = cluster.getSession(); |
|||
defaultReadLevel = cluster.getDefaultReadConsistencyLevel(); |
|||
defaultWriteLevel = cluster.getDefaultWriteConsistencyLevel(); |
|||
CodecRegistry registry = session.getCluster().getConfiguration().getCodecRegistry(); |
|||
registerCodecIfNotFound(registry, new JsonCodec()); |
|||
registerCodecIfNotFound(registry, new DeviceCredentialsTypeCodec()); |
|||
registerCodecIfNotFound(registry, new AuthorityCodec()); |
|||
registerCodecIfNotFound(registry, new ComponentLifecycleStateCodec()); |
|||
registerCodecIfNotFound(registry, new ComponentTypeCodec()); |
|||
registerCodecIfNotFound(registry, new ComponentScopeCodec()); |
|||
registerCodecIfNotFound(registry, new EntityTypeCodec()); |
|||
} |
|||
return session; |
|||
} |
|||
|
|||
private void registerCodecIfNotFound(CodecRegistry registry, TypeCodec<?> codec) { |
|||
try { |
|||
registry.codecFor(codec.getCqlType(), codec.getJavaType()); |
|||
} catch (CodecNotFoundException e) { |
|||
registry.register(codec); |
|||
} |
|||
} |
|||
|
|||
protected ResultSet executeRead(Statement statement) { |
|||
return execute(statement, defaultReadLevel); |
|||
} |
|||
|
|||
protected ResultSet executeWrite(Statement statement) { |
|||
return execute(statement, defaultWriteLevel); |
|||
} |
|||
|
|||
|
|||
protected ResultSetFuture executeAsyncRead(Statement statement) { |
|||
return executeAsync(statement, defaultReadLevel); |
|||
} |
|||
|
|||
protected ResultSetFuture executeAsyncWrite(Statement statement) { |
|||
return executeAsync(statement, defaultWriteLevel); |
|||
} |
|||
|
|||
private ResultSet execute(Statement statement, ConsistencyLevel level) { |
|||
log.debug("Execute cassandra statement {}", statement); |
|||
if (statement.getConsistencyLevel() == null) { |
|||
statement.setConsistencyLevel(level); |
|||
} |
|||
return getSession().execute(statement); |
|||
} |
|||
|
|||
private ResultSetFuture executeAsync(Statement statement, ConsistencyLevel level) { |
|||
log.debug("Execute cassandra async statement {}", statement); |
|||
if (statement.getConsistencyLevel() == null) { |
|||
statement.setConsistencyLevel(level); |
|||
} |
|||
return getSession().executeAsync(statement); |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import com.datastax.driver.core.ResultSet; |
|||
import com.datastax.driver.core.Statement; |
|||
import com.datastax.driver.core.querybuilder.QueryBuilder; |
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.Mapper; |
|||
import com.datastax.driver.mapping.Result; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.dao.model.BaseEntity; |
|||
import org.thingsboard.server.dao.model.wrapper.EntityResultSet; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.lt; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractModelDao<T extends BaseEntity<?>> extends AbstractDao implements Dao<T> { |
|||
|
|||
protected abstract Class<T> getColumnFamilyClass(); |
|||
|
|||
protected abstract String getColumnFamilyName(); |
|||
|
|||
protected Mapper<T> getMapper() { |
|||
return cluster.getMapper(getColumnFamilyClass()); |
|||
} |
|||
|
|||
protected List<T> findListByStatement(Statement statement) { |
|||
List<T> list = Collections.emptyList(); |
|||
if (statement != null) { |
|||
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()); |
|||
ResultSet resultSet = getSession().execute(statement); |
|||
Result<T> result = getMapper().map(resultSet); |
|||
if (result != null) { |
|||
list = result.all(); |
|||
} |
|||
} |
|||
return list; |
|||
} |
|||
|
|||
protected T findOneByStatement(Statement statement) { |
|||
T object = null; |
|||
if (statement != null) { |
|||
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()); |
|||
ResultSet resultSet = getSession().execute(statement); |
|||
Result<T> result = getMapper().map(resultSet); |
|||
if (result != null) { |
|||
object = result.one(); |
|||
} |
|||
} |
|||
return object; |
|||
} |
|||
|
|||
protected Statement getSaveQuery(T dto) { |
|||
return getMapper().saveQuery(dto); |
|||
} |
|||
|
|||
protected EntityResultSet<T> saveWithResult(T entity) { |
|||
log.debug("Save entity {}", entity); |
|||
if (entity.getId() == null) { |
|||
entity.setId(UUIDs.timeBased()); |
|||
} else { |
|||
removeById(entity.getId()); |
|||
} |
|||
Statement saveStatement = getSaveQuery(entity); |
|||
saveStatement.setConsistencyLevel(cluster.getDefaultWriteConsistencyLevel()); |
|||
ResultSet resultSet = executeWrite(saveStatement); |
|||
return new EntityResultSet<>(resultSet, entity); |
|||
} |
|||
|
|||
public T save(T entity) { |
|||
return saveWithResult(entity).getEntity(); |
|||
} |
|||
|
|||
public T findById(UUID key) { |
|||
log.debug("Get entity by key {}", key); |
|||
Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, key)); |
|||
log.trace("Execute query {}", query); |
|||
return findOneByStatement(query); |
|||
} |
|||
|
|||
public ResultSet removeById(UUID key) { |
|||
Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, key)); |
|||
log.debug("Remove request: {}", delete.toString()); |
|||
return getSession().execute(delete); |
|||
} |
|||
|
|||
|
|||
public List<T> find() { |
|||
log.debug("Get all entities from column family {}", getColumnFamilyName()); |
|||
return findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel())); |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import com.datastax.driver.core.querybuilder.Clause; |
|||
import com.datastax.driver.core.querybuilder.QueryBuilder; |
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.datastax.driver.core.querybuilder.Select.Where; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.model.SearchTextEntity; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import java.util.List; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.gt; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.gte; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.lt; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
|
|||
public abstract class AbstractSearchTextDao<T extends SearchTextEntity<?>> extends AbstractModelDao<T> { |
|||
|
|||
public T save(T entity) { |
|||
entity.setSearchText(entity.getSearchTextSource().toLowerCase()); |
|||
return super.save(entity); |
|||
} |
|||
|
|||
protected List<T> findPageWithTextSearch(String searchView, List<Clause> clauses, TextPageLink pageLink) { |
|||
Select select = select().from(searchView); |
|||
Where query = select.where(); |
|||
for (Clause clause : clauses) { |
|||
query.and(clause); |
|||
} |
|||
query.limit(pageLink.getLimit()); |
|||
if (!StringUtils.isEmpty(pageLink.getTextOffset())) { |
|||
query.and(eq(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextOffset())); |
|||
query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset())); |
|||
List<T> result = findListByStatement(query); |
|||
if (result.size() < pageLink.getLimit()) { |
|||
select = select().from(searchView); |
|||
query = select.where(); |
|||
for (Clause clause : clauses) { |
|||
query.and(clause); |
|||
} |
|||
query.and(QueryBuilder.gt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextOffset())); |
|||
if (!StringUtils.isEmpty(pageLink.getTextSearch())) { |
|||
query.and(QueryBuilder.lt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearchBound())); |
|||
} |
|||
int limit = pageLink.getLimit() - result.size(); |
|||
query.limit(limit); |
|||
result.addAll(findListByStatement(query)); |
|||
} |
|||
return result; |
|||
} else if (!StringUtils.isEmpty(pageLink.getTextSearch())) { |
|||
query.and(QueryBuilder.gte(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearch())); |
|||
query.and(QueryBuilder.lt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearchBound())); |
|||
return findListByStatement(query); |
|||
} else { |
|||
return findListByStatement(query); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import com.datastax.driver.core.querybuilder.Clause; |
|||
import com.datastax.driver.core.querybuilder.Ordering; |
|||
import com.datastax.driver.core.querybuilder.QueryBuilder; |
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.datastax.driver.core.querybuilder.Select.Where; |
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.model.BaseEntity; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.model.SearchTextEntity; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
|
|||
public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends AbstractModelDao<T> { |
|||
|
|||
|
|||
protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, TimePageLink pageLink) { |
|||
return findPageWithTimeSearch(searchView, clauses, Collections.emptyList(), pageLink); |
|||
} |
|||
|
|||
protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, Ordering ordering, TimePageLink pageLink) { |
|||
return findPageWithTimeSearch(searchView, clauses, Collections.singletonList(ordering), pageLink); |
|||
} |
|||
|
|||
|
|||
protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink) { |
|||
Select select = select().from(searchView); |
|||
Where query = select.where(); |
|||
for (Clause clause : clauses) { |
|||
query.and(clause); |
|||
} |
|||
query.limit(pageLink.getLimit()); |
|||
if (pageLink.isAscOrder()) { |
|||
if (pageLink.getIdOffset() != null) { |
|||
query.and(QueryBuilder.gt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset())); |
|||
} else if (pageLink.getStartTime() != null) { |
|||
final UUID startOf = UUIDs.startOf(pageLink.getStartTime()); |
|||
query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf)); |
|||
} |
|||
if (pageLink.getEndTime() != null) { |
|||
final UUID endOf = UUIDs.endOf(pageLink.getEndTime()); |
|||
query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf)); |
|||
} |
|||
} else { |
|||
if (pageLink.getIdOffset() != null) { |
|||
query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset())); |
|||
} else if (pageLink.getEndTime() != null) { |
|||
final UUID endOf = UUIDs.endOf(pageLink.getEndTime()); |
|||
query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf)); |
|||
} |
|||
if (pageLink.getStartTime() != null) { |
|||
final UUID startOf = UUIDs.startOf(pageLink.getStartTime()); |
|||
query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf)); |
|||
} |
|||
} |
|||
List<Ordering> orderings = new ArrayList<>(topLevelOrderings); |
|||
if (pageLink.isAscOrder()) { |
|||
orderings.add(QueryBuilder.asc(ModelConstants.ID_PROPERTY)); |
|||
} else { |
|||
orderings.add(QueryBuilder.desc(ModelConstants.ID_PROPERTY)); |
|||
} |
|||
query.orderBy(orderings.toArray(new Ordering[orderings.size()])); |
|||
return findListByStatement(query); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import com.datastax.driver.core.ResultSet; |
|||
|
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
public interface Dao<T> { |
|||
|
|||
List<T> find(); |
|||
|
|||
T findById(UUID id); |
|||
|
|||
T save(T t); |
|||
|
|||
ResultSet removeById(UUID id); |
|||
|
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collection; |
|||
import java.util.Collections; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.id.UUIDBased; |
|||
import org.thingsboard.server.dao.model.ToData; |
|||
|
|||
public abstract class DaoUtil { |
|||
|
|||
private DaoUtil() { |
|||
} |
|||
|
|||
public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { |
|||
List<T> list = Collections.emptyList(); |
|||
if (toDataList != null && !toDataList.isEmpty()) { |
|||
list = new ArrayList<>(); |
|||
for (ToData<T> object : toDataList) { |
|||
list.add(object.toData()); |
|||
} |
|||
} |
|||
return list; |
|||
} |
|||
|
|||
public static <T> T getData(ToData<T> data) { |
|||
T object = null; |
|||
if (data != null) { |
|||
object = data.toData(); |
|||
} |
|||
return object; |
|||
} |
|||
|
|||
public static UUID getId(UUIDBased idBased) { |
|||
UUID id = null; |
|||
if (idBased != null) { |
|||
id = idBased.getId(); |
|||
} |
|||
return id; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,159 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.cassandra; |
|||
|
|||
|
|||
import com.datastax.driver.core.Cluster; |
|||
import com.datastax.driver.core.ConsistencyLevel; |
|||
import com.datastax.driver.core.ProtocolOptions.Compression; |
|||
import com.datastax.driver.core.Session; |
|||
import com.datastax.driver.core.exceptions.NoHostAvailableException; |
|||
import com.datastax.driver.mapping.Mapper; |
|||
import com.datastax.driver.mapping.MappingManager; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.dao.exception.DatabaseException; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.annotation.PreDestroy; |
|||
import java.io.Closeable; |
|||
import java.net.InetSocketAddress; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.StringTokenizer; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
@Data |
|||
public class CassandraCluster { |
|||
|
|||
private static final String COMMA = ","; |
|||
private static final String COLON = ":"; |
|||
|
|||
@Value("${cassandra.cluster_name}") |
|||
private String clusterName; |
|||
@Value("${cassandra.keyspace_name}") |
|||
private String keyspaceName; |
|||
@Value("${cassandra.url}") |
|||
private String url; |
|||
@Value("${cassandra.compression}") |
|||
private String compression; |
|||
@Value("${cassandra.ssl}") |
|||
private Boolean ssl; |
|||
@Value("${cassandra.jmx}") |
|||
private Boolean jmx; |
|||
@Value("${cassandra.metrics}") |
|||
private Boolean metrics; |
|||
@Value("${cassandra.credentials}") |
|||
private Boolean credentials; |
|||
@Value("${cassandra.username}") |
|||
private String username; |
|||
@Value("${cassandra.password}") |
|||
private String password; |
|||
@Value("${cassandra.init_timeout_ms}") |
|||
private long initTimeout; |
|||
@Value("${cassandra.init_retry_interval_ms}") |
|||
private long initRetryInterval; |
|||
|
|||
@Autowired |
|||
private CassandraSocketOptions socketOpts; |
|||
|
|||
@Autowired |
|||
private CassandraQueryOptions queryOpts; |
|||
|
|||
private Cluster cluster; |
|||
private Session session; |
|||
private MappingManager mappingManager; |
|||
|
|||
public <T> Mapper<T> getMapper(Class<T> clazz) { |
|||
return mappingManager.mapper(clazz); |
|||
} |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
long endTime = System.currentTimeMillis() + initTimeout; |
|||
while (System.currentTimeMillis() < endTime) { |
|||
try { |
|||
Cluster.Builder builder = Cluster.builder() |
|||
.addContactPointsWithPorts(getContactPoints(url)) |
|||
.withClusterName(clusterName) |
|||
.withSocketOptions(socketOpts.getOpts()); |
|||
builder.withQueryOptions(queryOpts.getOpts()); |
|||
builder.withCompression(StringUtils.isEmpty(compression) ? Compression.NONE : Compression.valueOf(compression.toUpperCase())); |
|||
if (ssl) { |
|||
builder.withSSL(); |
|||
} |
|||
if (!jmx) { |
|||
builder.withoutJMXReporting(); |
|||
} |
|||
if (!metrics) { |
|||
builder.withoutMetrics(); |
|||
} |
|||
if (credentials) { |
|||
builder.withCredentials(username, password); |
|||
} |
|||
cluster = builder.build(); |
|||
cluster.init(); |
|||
session = cluster.connect(keyspaceName); |
|||
mappingManager = new MappingManager(session); |
|||
break; |
|||
} catch (Exception e) { |
|||
log.warn("Failed to initialize cassandra cluster due to {}. Will retry in {} ms", e.getMessage(), initRetryInterval); |
|||
try { |
|||
Thread.sleep(initRetryInterval); |
|||
} catch (InterruptedException ie) { |
|||
log.warn("Failed to wait until retry", ie); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@PreDestroy |
|||
public void close() { |
|||
if (cluster != null) { |
|||
cluster.close(); |
|||
} |
|||
} |
|||
|
|||
private List<InetSocketAddress> getContactPoints(String url) { |
|||
List<InetSocketAddress> result; |
|||
if (StringUtils.isBlank(url)) { |
|||
result = Collections.emptyList(); |
|||
} else { |
|||
result = new ArrayList<>(); |
|||
for (String hostPort : url.split(COMMA)) { |
|||
String host = hostPort.split(COLON)[0]; |
|||
Integer port = Integer.valueOf(hostPort.split(COLON)[1]); |
|||
result.add(new InetSocketAddress(host, port)); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
public ConsistencyLevel getDefaultReadConsistencyLevel() { |
|||
return queryOpts.getDefaultReadConsistencyLevel(); |
|||
} |
|||
|
|||
public ConsistencyLevel getDefaultWriteConsistencyLevel() { |
|||
return queryOpts.getDefaultWriteConsistencyLevel(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.cassandra; |
|||
|
|||
import com.datastax.driver.core.ConsistencyLevel; |
|||
import com.datastax.driver.core.QueryOptions; |
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank; |
|||
|
|||
@Component |
|||
@Configuration |
|||
@Data |
|||
public class CassandraQueryOptions { |
|||
|
|||
@Value("${cassandra.query.default_fetch_size}") |
|||
private Integer defaultFetchSize; |
|||
@Value("${cassandra.query.read_consistency_level}") |
|||
private String readConsistencyLevel; |
|||
@Value("${cassandra.query.write_consistency_level}") |
|||
private String writeConsistencyLevel; |
|||
|
|||
private QueryOptions opts; |
|||
|
|||
private ConsistencyLevel defaultReadConsistencyLevel; |
|||
private ConsistencyLevel defaultWriteConsistencyLevel; |
|||
|
|||
@PostConstruct |
|||
public void initOpts(){ |
|||
opts = new QueryOptions(); |
|||
opts.setFetchSize(defaultFetchSize); |
|||
} |
|||
|
|||
protected ConsistencyLevel getDefaultReadConsistencyLevel() { |
|||
if (defaultReadConsistencyLevel == null) { |
|||
if (readConsistencyLevel != null) { |
|||
defaultReadConsistencyLevel = ConsistencyLevel.valueOf(readConsistencyLevel.toUpperCase()); |
|||
} else { |
|||
defaultReadConsistencyLevel = ConsistencyLevel.ONE; |
|||
} |
|||
} |
|||
return defaultReadConsistencyLevel; |
|||
} |
|||
|
|||
protected ConsistencyLevel getDefaultWriteConsistencyLevel() { |
|||
if (defaultWriteConsistencyLevel == null) { |
|||
if (writeConsistencyLevel != null) { |
|||
defaultWriteConsistencyLevel = ConsistencyLevel.valueOf(writeConsistencyLevel.toUpperCase()); |
|||
} else { |
|||
defaultWriteConsistencyLevel = ConsistencyLevel.ONE; |
|||
} |
|||
} |
|||
return defaultWriteConsistencyLevel; |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.cassandra; |
|||
|
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.datastax.driver.core.SocketOptions; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
|
|||
@Component |
|||
@Configuration |
|||
@Data |
|||
public class CassandraSocketOptions { |
|||
|
|||
@Value("${cassandra.socket.connect_timeout}") |
|||
private int connectTimeoutMillis; |
|||
@Value("${cassandra.socket.read_timeout}") |
|||
private int readTimeoutMillis; |
|||
@Value("${cassandra.socket.keep_alive}") |
|||
private Boolean keepAlive; |
|||
@Value("${cassandra.socket.reuse_address}") |
|||
private Boolean reuseAddress; |
|||
@Value("${cassandra.socket.so_linger}") |
|||
private Integer soLinger; |
|||
@Value("${cassandra.socket.tcp_no_delay}") |
|||
private Boolean tcpNoDelay; |
|||
@Value("${cassandra.socket.receive_buffer_size}") |
|||
private Integer receiveBufferSize; |
|||
@Value("${cassandra.socket.send_buffer_size}") |
|||
private Integer sendBufferSize; |
|||
|
|||
private SocketOptions opts; |
|||
|
|||
@PostConstruct |
|||
public void initOpts() { |
|||
opts = new SocketOptions(); |
|||
opts.setConnectTimeoutMillis(connectTimeoutMillis); |
|||
opts.setReadTimeoutMillis(readTimeoutMillis); |
|||
if (keepAlive != null) { |
|||
opts.setKeepAlive(keepAlive); |
|||
} |
|||
if (reuseAddress != null) { |
|||
opts.setReuseAddress(reuseAddress); |
|||
} |
|||
if (soLinger != null) { |
|||
opts.setSoLinger(soLinger); |
|||
} |
|||
if (tcpNoDelay != null) { |
|||
opts.setTcpNoDelay(tcpNoDelay); |
|||
} |
|||
if (receiveBufferSize != null) { |
|||
opts.setReceiveBufferSize(receiveBufferSize); |
|||
} |
|||
if (sendBufferSize != null) { |
|||
opts.setSendBufferSize(sendBufferSize); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,169 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.component; |
|||
|
|||
import com.datastax.driver.core.ResultSet; |
|||
import com.datastax.driver.core.Statement; |
|||
import com.datastax.driver.core.querybuilder.QueryBuilder; |
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentScope; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.dao.AbstractSearchTextDao; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.model.ComponentDescriptorEntity; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Component |
|||
@Slf4j |
|||
public class BaseComponentDescriptorDao extends AbstractSearchTextDao<ComponentDescriptorEntity> implements ComponentDescriptorDao { |
|||
|
|||
@Override |
|||
protected Class<ComponentDescriptorEntity> getColumnFamilyClass() { |
|||
return ComponentDescriptorEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return ModelConstants.COMPONENT_DESCRIPTOR_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public Optional<ComponentDescriptorEntity> save(ComponentDescriptor component) { |
|||
ComponentDescriptorEntity entity = new ComponentDescriptorEntity(component); |
|||
log.debug("Save component entity [{}]", entity); |
|||
Optional<ComponentDescriptorEntity> result = saveIfNotExist(entity); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Saved result: [{}] for component entity [{}]", result.isPresent(), result.orElse(null)); |
|||
} else { |
|||
log.debug("Saved result: [{}]", result.isPresent()); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public ComponentDescriptorEntity findById(ComponentDescriptorId componentId) { |
|||
log.debug("Search component entity by id [{}]", componentId); |
|||
ComponentDescriptorEntity entity = super.findById(componentId.getId()); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Search result: [{}] for component entity [{}]", entity != null, entity); |
|||
} else { |
|||
log.debug("Search result: [{}]", entity != null); |
|||
} |
|||
return entity; |
|||
} |
|||
|
|||
@Override |
|||
public ComponentDescriptorEntity findByClazz(String clazz) { |
|||
log.debug("Search component entity by clazz [{}]", clazz); |
|||
Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, clazz)); |
|||
log.trace("Execute query [{}]", query); |
|||
ComponentDescriptorEntity entity = findOneByStatement(query); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Search result: [{}] for component entity [{}]", entity != null, entity); |
|||
} else { |
|||
log.debug("Search result: [{}]", entity != null); |
|||
} |
|||
return entity; |
|||
} |
|||
|
|||
@Override |
|||
public List<ComponentDescriptorEntity> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink) { |
|||
log.debug("Try to find component by type [{}] and pageLink [{}]", type, pageLink); |
|||
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(ModelConstants.COMPONENT_DESCRIPTOR_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY, type.name())), pageLink); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Search result: [{}]", Arrays.toString(entities.toArray())); |
|||
} else { |
|||
log.debug("Search result: [{}]", entities.size()); |
|||
} |
|||
return entities; |
|||
} |
|||
|
|||
@Override |
|||
public List<ComponentDescriptorEntity> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink) { |
|||
log.debug("Try to find component by scope [{}] and type [{}] and pageLink [{}]", scope, type, pageLink); |
|||
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(ModelConstants.COMPONENT_DESCRIPTOR_BY_SCOPE_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY, type.name()), |
|||
eq(ModelConstants.COMPONENT_DESCRIPTOR_SCOPE_PROPERTY, scope.name())), pageLink); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Search result: [{}]", Arrays.toString(entities.toArray())); |
|||
} else { |
|||
log.debug("Search result: [{}]", entities.size()); |
|||
} |
|||
return entities; |
|||
} |
|||
|
|||
public ResultSet removeById(UUID key) { |
|||
Statement delete = QueryBuilder.delete().all().from(ModelConstants.COMPONENT_DESCRIPTOR_BY_ID).where(eq(ModelConstants.ID_PROPERTY, key)); |
|||
log.debug("Remove request: {}", delete.toString()); |
|||
return getSession().execute(delete); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteById(ComponentDescriptorId id) { |
|||
log.debug("Delete plugin meta-data entity by id [{}]", id); |
|||
ResultSet resultSet = removeById(id.getId()); |
|||
log.debug("Delete result: [{}]", resultSet.wasApplied()); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteByClazz(String clazz) { |
|||
log.debug("Delete plugin meta-data entity by id [{}]", clazz); |
|||
Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, clazz)); |
|||
log.debug("Remove request: {}", delete.toString()); |
|||
ResultSet resultSet = getSession().execute(delete); |
|||
log.debug("Delete result: [{}]", resultSet.wasApplied()); |
|||
} |
|||
|
|||
private Optional<ComponentDescriptorEntity> saveIfNotExist(ComponentDescriptorEntity entity) { |
|||
if (entity.getId() == null) { |
|||
entity.setId(UUIDs.timeBased()); |
|||
} |
|||
|
|||
ResultSet rs = executeRead(QueryBuilder.insertInto(getColumnFamilyName()) |
|||
.value(ModelConstants.ID_PROPERTY, entity.getId()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_NAME_PROPERTY, entity.getName()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, entity.getClazz()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY, entity.getType()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_SCOPE_PROPERTY, entity.getScope()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_CONFIGURATION_DESCRIPTOR_PROPERTY, entity.getConfigurationDescriptor()) |
|||
.value(ModelConstants.COMPONENT_DESCRIPTOR_ACTIONS_PROPERTY, entity.getActions()) |
|||
.value(ModelConstants.SEARCH_TEXT_PROPERTY, entity.getSearchText()) |
|||
.ifNotExists() |
|||
); |
|||
if (rs.wasApplied()) { |
|||
return Optional.of(entity); |
|||
} else { |
|||
return Optional.empty(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,133 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.component; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.github.fge.jsonschema.core.exceptions.ProcessingException; |
|||
import com.github.fge.jsonschema.core.report.ProcessingReport; |
|||
import com.github.fge.jsonschema.main.JsonSchemaFactory; |
|||
import com.github.fge.jsonschema.main.JsonValidator; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentScope; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ComponentDescriptorEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.service.Validator; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class BaseComponentDescriptorService implements ComponentDescriptorService { |
|||
|
|||
@Autowired |
|||
private ComponentDescriptorDao componentDescriptorDao; |
|||
|
|||
@Override |
|||
public ComponentDescriptor saveComponent(ComponentDescriptor component) { |
|||
componentValidator.validate(component); |
|||
Optional<ComponentDescriptorEntity> result = componentDescriptorDao.save(component); |
|||
if (result.isPresent()) { |
|||
return getData(result.get()); |
|||
} else { |
|||
return getData(componentDescriptorDao.findByClazz(component.getClazz())); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ComponentDescriptor findById(ComponentDescriptorId componentId) { |
|||
Validator.validateId(componentId, "Incorrect component id for search request."); |
|||
return getData(componentDescriptorDao.findById(componentId)); |
|||
} |
|||
|
|||
@Override |
|||
public ComponentDescriptor findByClazz(String clazz) { |
|||
Validator.validateString(clazz, "Incorrect clazz for search request."); |
|||
return getData(componentDescriptorDao.findByClazz(clazz)); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink) { |
|||
Validator.validatePageLink(pageLink, "Incorrect PageLink object for search plugin components request."); |
|||
List<ComponentDescriptorEntity> pluginEntities = componentDescriptorDao.findByTypeAndPageLink(type, pageLink); |
|||
List<ComponentDescriptor> components = convertDataList(pluginEntities); |
|||
return new TextPageData<>(components, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink) { |
|||
Validator.validatePageLink(pageLink, "Incorrect PageLink object for search plugin components request."); |
|||
List<ComponentDescriptorEntity> pluginEntities = componentDescriptorDao.findByScopeAndTypeAndPageLink(scope, type, pageLink); |
|||
List<ComponentDescriptor> components = convertDataList(pluginEntities); |
|||
return new TextPageData<>(components, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteByClazz(String clazz) { |
|||
Validator.validateString(clazz, "Incorrect clazz for delete request."); |
|||
componentDescriptorDao.deleteByClazz(clazz); |
|||
} |
|||
|
|||
@Override |
|||
public boolean validate(ComponentDescriptor component, JsonNode configuration) { |
|||
JsonValidator validator = JsonSchemaFactory.byDefault().getValidator(); |
|||
try { |
|||
if (!component.getConfigurationDescriptor().has("schema")) { |
|||
throw new DataValidationException("Configuration descriptor doesn't contain schema property!"); |
|||
} |
|||
JsonNode configurationSchema = component.getConfigurationDescriptor().get("schema"); |
|||
ProcessingReport report = validator.validate(configurationSchema, configuration); |
|||
return report.isSuccess(); |
|||
} catch (ProcessingException e) { |
|||
throw new IncorrectParameterException(e.getMessage(), e); |
|||
} |
|||
} |
|||
|
|||
private DataValidator<ComponentDescriptor> componentValidator = |
|||
new DataValidator<ComponentDescriptor>() { |
|||
@Override |
|||
protected void validateDataImpl(ComponentDescriptor plugin) { |
|||
if (plugin.getType() == null) { |
|||
throw new DataValidationException("Component type should be specified!."); |
|||
} |
|||
if (plugin.getScope() == null) { |
|||
throw new DataValidationException("Component scope should be specified!."); |
|||
} |
|||
if (StringUtils.isEmpty(plugin.getName())) { |
|||
throw new DataValidationException("Component name should be specified!."); |
|||
} |
|||
if (StringUtils.isEmpty(plugin.getClazz())) { |
|||
throw new DataValidationException("Component clazz should be specified!."); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.component; |
|||
|
|||
import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentScope; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.ComponentDescriptorEntity; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
public interface ComponentDescriptorDao extends Dao<ComponentDescriptorEntity> { |
|||
|
|||
Optional<ComponentDescriptorEntity> save(ComponentDescriptor component); |
|||
|
|||
ComponentDescriptorEntity findById(ComponentDescriptorId componentId); |
|||
|
|||
ComponentDescriptorEntity findByClazz(String clazz); |
|||
|
|||
List<ComponentDescriptorEntity> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink); |
|||
|
|||
List<ComponentDescriptorEntity> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink); |
|||
|
|||
void deleteById(ComponentDescriptorId componentId); |
|||
|
|||
void deleteByClazz(String clazz); |
|||
|
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.component; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentScope; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
public interface ComponentDescriptorService { |
|||
|
|||
ComponentDescriptor saveComponent(ComponentDescriptor component); |
|||
|
|||
ComponentDescriptor findById(ComponentDescriptorId componentId); |
|||
|
|||
ComponentDescriptor findByClazz(String clazz); |
|||
|
|||
TextPageData<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink); |
|||
|
|||
TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink); |
|||
|
|||
boolean validate(ComponentDescriptor component, JsonNode configuration); |
|||
|
|||
void deleteByClazz(String clazz); |
|||
|
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.customer; |
|||
|
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
|
|||
/** |
|||
* The Interface CustomerDao. |
|||
*/ |
|||
public interface CustomerDao extends Dao<CustomerEntity> { |
|||
|
|||
/** |
|||
* Save or update customer object |
|||
* |
|||
* @param customer the customer object |
|||
* @return saved customer object |
|||
*/ |
|||
CustomerEntity save(Customer customer); |
|||
|
|||
/** |
|||
* Find customers by tenant id and page link. |
|||
* |
|||
* @param tenantId the tenant id |
|||
* @param pageLink the page link |
|||
* @return the list of customer objects |
|||
*/ |
|||
List<CustomerEntity> findCustomersByTenantId(UUID tenantId, TextPageLink pageLink); |
|||
|
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.customer; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.AbstractSearchTextDao; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
@Component |
|||
@Slf4j |
|||
public class CustomerDaoImpl extends AbstractSearchTextDao<CustomerEntity> implements CustomerDao { |
|||
|
|||
@Override |
|||
protected Class<CustomerEntity> getColumnFamilyClass() { |
|||
return CustomerEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return ModelConstants.CUSTOMER_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public CustomerEntity save(Customer customer) { |
|||
log.debug("Save customer [{}] ", customer); |
|||
return save(new CustomerEntity(customer)); |
|||
} |
|||
|
|||
@Override |
|||
public List<CustomerEntity> findCustomersByTenantId(UUID tenantId, TextPageLink pageLink) { |
|||
log.debug("Try to find customers by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
|||
List<CustomerEntity> customerEntities = findPageWithTextSearch(ModelConstants.CUSTOMER_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(ModelConstants.CUSTOMER_TENANT_ID_PROPERTY, tenantId)), |
|||
pageLink); |
|||
log.trace("Found customers [{}] by tenantId [{}] and pageLink [{}]", customerEntities, tenantId, pageLink); |
|||
return customerEntities; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.customer; |
|||
|
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
|
|||
public interface CustomerService { |
|||
|
|||
public Customer findCustomerById(CustomerId customerId); |
|||
|
|||
public Customer saveCustomer(Customer customer); |
|||
|
|||
public void deleteCustomer(CustomerId customerId); |
|||
|
|||
public TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); |
|||
|
|||
public void deleteCustomersByTenantId(TenantId tenantId); |
|||
|
|||
} |
|||
@ -0,0 +1,145 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.customer; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
|
|||
import java.util.List; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
import org.thingsboard.server.dao.model.TenantEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.service.PaginatedRemover; |
|||
import org.thingsboard.server.dao.tenant.TenantDao; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.dao.service.Validator; |
|||
@Service |
|||
@Slf4j |
|||
public class CustomerServiceImpl implements CustomerService { |
|||
|
|||
@Autowired |
|||
private CustomerDao customerDao; |
|||
|
|||
@Autowired |
|||
private UserService userService; |
|||
|
|||
@Autowired |
|||
private TenantDao tenantDao; |
|||
|
|||
@Autowired |
|||
private DeviceService deviceService; |
|||
|
|||
@Autowired |
|||
private DashboardService dashboardService; |
|||
|
|||
@Override |
|||
public Customer findCustomerById(CustomerId customerId) { |
|||
log.trace("Executing findCustomerById [{}]", customerId); |
|||
Validator.validateId(customerId, "Incorrect customerId " + customerId); |
|||
CustomerEntity customerEntity = customerDao.findById(customerId.getId()); |
|||
return getData(customerEntity); |
|||
} |
|||
|
|||
@Override |
|||
public Customer saveCustomer(Customer customer) { |
|||
log.trace("Executing saveCustomer [{}]", customer); |
|||
customerValidator.validate(customer); |
|||
CustomerEntity customerEntity = customerDao.save(customer); |
|||
return getData(customerEntity); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteCustomer(CustomerId customerId) { |
|||
log.trace("Executing deleteCustomer [{}]", customerId); |
|||
Validator.validateId(customerId, "Incorrect tenantId " + customerId); |
|||
Customer customer = findCustomerById(customerId); |
|||
if (customer == null) { |
|||
throw new IncorrectParameterException("Unable to delete non-existent customer."); |
|||
} |
|||
dashboardService.unassignCustomerDashboards(customer.getTenantId(), customerId); |
|||
deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); |
|||
userService.deleteCustomerUsers(customer.getTenantId(), customerId); |
|||
customerDao.removeById(customerId.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink) { |
|||
log.trace("Executing findCustomersByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<CustomerEntity> customerEntities = customerDao.findCustomersByTenantId(tenantId.getId(), pageLink); |
|||
List<Customer> customers = convertDataList(customerEntities); |
|||
return new TextPageData<Customer>(customers, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteCustomersByTenantId(TenantId tenantId) { |
|||
log.trace("Executing deleteCustomersByTenantId, tenantId [{}]", tenantId); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
customersByTenantRemover.removeEntitites(tenantId); |
|||
} |
|||
|
|||
private DataValidator<Customer> customerValidator = |
|||
new DataValidator<Customer>() { |
|||
@Override |
|||
protected void validateDataImpl(Customer customer) { |
|||
if (StringUtils.isEmpty(customer.getTitle())) { |
|||
throw new DataValidationException("Customer title should be specified!"); |
|||
} |
|||
if (!StringUtils.isEmpty(customer.getEmail())) { |
|||
validateEmail(customer.getEmail()); |
|||
} |
|||
if (customer.getTenantId() == null) { |
|||
throw new DataValidationException("Customer should be assigned to tenant!"); |
|||
} else { |
|||
TenantEntity tenant = tenantDao.findById(customer.getTenantId().getId()); |
|||
if (tenant == null) { |
|||
throw new DataValidationException("Customer is referencing to non-existent tenant!"); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
private PaginatedRemover<TenantId, CustomerEntity> customersByTenantRemover = |
|||
new PaginatedRemover<TenantId, CustomerEntity>() { |
|||
|
|||
@Override |
|||
protected List<CustomerEntity> findEntities(TenantId id, TextPageLink pageLink) { |
|||
return customerDao.findCustomersByTenantId(id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(CustomerEntity entity) { |
|||
deleteCustomer(new CustomerId(entity.getId())); |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.dashboard; |
|||
|
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.DashboardEntity; |
|||
|
|||
/** |
|||
* The Interface DashboardDao. |
|||
* |
|||
* @param <T> the generic type |
|||
*/ |
|||
public interface DashboardDao extends Dao<DashboardEntity> { |
|||
|
|||
/** |
|||
* Save or update dashboard object |
|||
* |
|||
* @param dashboard the dashboard object |
|||
* @return saved dashboard object |
|||
*/ |
|||
DashboardEntity save(Dashboard dashboard); |
|||
|
|||
/** |
|||
* Find dashboards by tenantId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param pageLink the page link |
|||
* @return the list of dashboard objects |
|||
*/ |
|||
List<DashboardEntity> findDashboardsByTenantId(UUID tenantId, TextPageLink pageLink); |
|||
|
|||
/** |
|||
* Find dashboards by tenantId, customerId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param customerId the customerId |
|||
* @param pageLink the page link |
|||
* @return the list of dashboard objects |
|||
*/ |
|||
List<DashboardEntity> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); |
|||
|
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.dashboard; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_COLUMN_FAMILY_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_CUSTOMER_ID_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_TENANT_ID_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.AbstractSearchTextDao; |
|||
import org.thingsboard.server.dao.model.DashboardEntity; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
public class DashboardDaoImpl extends AbstractSearchTextDao<DashboardEntity> implements DashboardDao { |
|||
|
|||
@Override |
|||
protected Class<DashboardEntity> getColumnFamilyClass() { |
|||
return DashboardEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return DASHBOARD_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public DashboardEntity save(Dashboard dashboard) { |
|||
log.debug("Save dashboard [{}] ", dashboard); |
|||
return save(new DashboardEntity(dashboard)); |
|||
} |
|||
|
|||
@Override |
|||
public List<DashboardEntity> findDashboardsByTenantId(UUID tenantId, TextPageLink pageLink) { |
|||
log.debug("Try to find dashboards by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
|||
List<DashboardEntity> dashboardEntities = findPageWithTextSearch(DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(DASHBOARD_TENANT_ID_PROPERTY, tenantId), |
|||
eq(DASHBOARD_CUSTOMER_ID_PROPERTY, NULL_UUID)), |
|||
pageLink); |
|||
|
|||
log.trace("Found dashboards [{}] by tenantId [{}] and pageLink [{}]", dashboardEntities, tenantId, pageLink); |
|||
return dashboardEntities; |
|||
} |
|||
|
|||
@Override |
|||
public List<DashboardEntity> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { |
|||
log.debug("Try to find dashboards by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); |
|||
List<DashboardEntity> dashboardEntities = findPageWithTextSearch(DASHBOARD_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(DASHBOARD_CUSTOMER_ID_PROPERTY, customerId), |
|||
eq(DASHBOARD_TENANT_ID_PROPERTY, tenantId)), |
|||
pageLink); |
|||
|
|||
log.trace("Found dashboards [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", dashboardEntities, tenantId, customerId, pageLink); |
|||
return dashboardEntities; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.dashboard; |
|||
|
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
|
|||
public interface DashboardService { |
|||
|
|||
public Dashboard findDashboardById(DashboardId dashboardId); |
|||
|
|||
public Dashboard saveDashboard(Dashboard dashboard); |
|||
|
|||
public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); |
|||
|
|||
public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId); |
|||
|
|||
public void deleteDashboard(DashboardId dashboardId); |
|||
|
|||
public TextPageData<Dashboard> findDashboardsByTenantId(TenantId tenantId, TextPageLink pageLink); |
|||
|
|||
public void deleteDashboardsByTenantId(TenantId tenantId); |
|||
|
|||
public TextPageData<Dashboard> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); |
|||
|
|||
public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); |
|||
|
|||
} |
|||
@ -0,0 +1,195 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.dashboard; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
|
|||
import java.util.List; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.customer.CustomerDao; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
import org.thingsboard.server.dao.model.DashboardEntity; |
|||
import org.thingsboard.server.dao.model.TenantEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.service.PaginatedRemover; |
|||
import org.thingsboard.server.dao.tenant.TenantDao; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.service.Validator; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class DashboardServiceImpl implements DashboardService { |
|||
|
|||
@Autowired |
|||
private DashboardDao dashboardDao; |
|||
|
|||
@Autowired |
|||
private TenantDao tenantDao; |
|||
|
|||
@Autowired |
|||
private CustomerDao customerDao; |
|||
|
|||
@Override |
|||
public Dashboard findDashboardById(DashboardId dashboardId) { |
|||
log.trace("Executing findDashboardById [{}]", dashboardId); |
|||
Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
|||
DashboardEntity dashboardEntity = dashboardDao.findById(dashboardId.getId()); |
|||
return getData(dashboardEntity); |
|||
} |
|||
|
|||
@Override |
|||
public Dashboard saveDashboard(Dashboard dashboard) { |
|||
log.trace("Executing saveDashboard [{}]", dashboard); |
|||
dashboardValidator.validate(dashboard); |
|||
DashboardEntity dashboardEntity = dashboardDao.save(dashboard); |
|||
return getData(dashboardEntity); |
|||
} |
|||
|
|||
@Override |
|||
public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId) { |
|||
Dashboard dashboard = findDashboardById(dashboardId); |
|||
dashboard.setCustomerId(customerId); |
|||
return saveDashboard(dashboard); |
|||
} |
|||
|
|||
@Override |
|||
public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId) { |
|||
Dashboard dashboard = findDashboardById(dashboardId); |
|||
dashboard.setCustomerId(null); |
|||
return saveDashboard(dashboard); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteDashboard(DashboardId dashboardId) { |
|||
log.trace("Executing deleteDashboard [{}]", dashboardId); |
|||
Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
|||
dashboardDao.removeById(dashboardId.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Dashboard> findDashboardsByTenantId(TenantId tenantId, TextPageLink pageLink) { |
|||
log.trace("Executing findDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<DashboardEntity> dashboardEntities = dashboardDao.findDashboardsByTenantId(tenantId.getId(), pageLink); |
|||
List<Dashboard> dashboards = convertDataList(dashboardEntities); |
|||
return new TextPageData<Dashboard>(dashboards, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteDashboardsByTenantId(TenantId tenantId) { |
|||
log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
tenantDashboardsRemover.removeEntitites(tenantId); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Dashboard> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { |
|||
log.trace("Executing findDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
Validator.validateId(customerId, "Incorrect customerId " + customerId); |
|||
Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<DashboardEntity> dashboardEntities = dashboardDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); |
|||
List<Dashboard> dashboards = convertDataList(dashboardEntities); |
|||
return new TextPageData<Dashboard>(dashboards, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { |
|||
log.trace("Executing unassignCustomerDashboards, tenantId [{}], customerId [{}]", tenantId, customerId); |
|||
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
Validator.validateId(customerId, "Incorrect customerId " + customerId); |
|||
new CustomerDashboardsUnassigner(tenantId).removeEntitites(customerId); |
|||
} |
|||
|
|||
private DataValidator<Dashboard> dashboardValidator = |
|||
new DataValidator<Dashboard>() { |
|||
@Override |
|||
protected void validateDataImpl(Dashboard dashboard) { |
|||
if (StringUtils.isEmpty(dashboard.getTitle())) { |
|||
throw new DataValidationException("Dashboard title should be specified!"); |
|||
} |
|||
if (dashboard.getTenantId() == null) { |
|||
throw new DataValidationException("Dashboard should be assigned to tenant!"); |
|||
} else { |
|||
TenantEntity tenant = tenantDao.findById(dashboard.getTenantId().getId()); |
|||
if (tenant == null) { |
|||
throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); |
|||
} |
|||
} |
|||
if (dashboard.getCustomerId() == null) { |
|||
dashboard.setCustomerId(new CustomerId(ModelConstants.NULL_UUID)); |
|||
} else if (!dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
CustomerEntity customer = customerDao.findById(dashboard.getCustomerId().getId()); |
|||
if (customer == null) { |
|||
throw new DataValidationException("Can't assign dashboard to non-existent customer!"); |
|||
} |
|||
if (!customer.getTenantId().equals(dashboard.getTenantId().getId())) { |
|||
throw new DataValidationException("Can't assign dashboard to customer from different tenant!"); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
private PaginatedRemover<TenantId, DashboardEntity> tenantDashboardsRemover = |
|||
new PaginatedRemover<TenantId, DashboardEntity>() { |
|||
|
|||
@Override |
|||
protected List<DashboardEntity> findEntities(TenantId id, TextPageLink pageLink) { |
|||
return dashboardDao.findDashboardsByTenantId(id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(DashboardEntity entity) { |
|||
deleteDashboard(new DashboardId(entity.getId())); |
|||
} |
|||
}; |
|||
|
|||
class CustomerDashboardsUnassigner extends PaginatedRemover<CustomerId, DashboardEntity> { |
|||
|
|||
private TenantId tenantId; |
|||
|
|||
CustomerDashboardsUnassigner(TenantId tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
@Override |
|||
protected List<DashboardEntity> findEntities(CustomerId id, TextPageLink pageLink) { |
|||
return dashboardDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(DashboardEntity entity) { |
|||
unassignDashboardFromCustomer(new DashboardId(entity.getId())); |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.DeviceCredentialsEntity; |
|||
|
|||
/** |
|||
* The Interface DeviceCredentialsDao. |
|||
* |
|||
* @param <T> the generic type |
|||
*/ |
|||
public interface DeviceCredentialsDao extends Dao<DeviceCredentialsEntity> { |
|||
|
|||
/** |
|||
* Save or update device credentials object |
|||
* |
|||
* @param deviceCredentials the device credentials object |
|||
* @return saved device credentials object |
|||
*/ |
|||
DeviceCredentialsEntity save(DeviceCredentials deviceCredentials); |
|||
|
|||
/** |
|||
* Find device credentials by device id. |
|||
* |
|||
* @param deviceId the device id |
|||
* @return the device credentials object |
|||
*/ |
|||
DeviceCredentialsEntity findByDeviceId(UUID deviceId); |
|||
|
|||
/** |
|||
* Find device credentials by credentials id. |
|||
* |
|||
* @param credentialsId the credentials id |
|||
* @return the device credentials object |
|||
*/ |
|||
DeviceCredentialsEntity findByCredentialsId(String credentialsId); |
|||
|
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.AbstractModelDao; |
|||
import org.thingsboard.server.dao.model.DeviceCredentialsEntity; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Repository; |
|||
|
|||
import com.datastax.driver.core.querybuilder.Select.Where; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
public class DeviceCredentialsDaoImpl extends AbstractModelDao<DeviceCredentialsEntity> implements DeviceCredentialsDao { |
|||
|
|||
@Override |
|||
protected Class<DeviceCredentialsEntity> getColumnFamilyClass() { |
|||
return DeviceCredentialsEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return ModelConstants.DEVICE_CREDENTIALS_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentialsEntity findByDeviceId(UUID deviceId) { |
|||
log.debug("Try to find device credentials by deviceId [{}] ", deviceId); |
|||
Where query = select().from(ModelConstants.DEVICE_CREDENTIALS_BY_DEVICE_COLUMN_FAMILY_NAME) |
|||
.where(eq(ModelConstants.DEVICE_CREDENTIALS_DEVICE_ID_PROPERTY, deviceId)); |
|||
log.trace("Execute query {}", query); |
|||
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(query); |
|||
log.trace("Found device credentials [{}] by deviceId [{}]", deviceCredentialsEntity, deviceId); |
|||
return deviceCredentialsEntity; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentialsEntity findByCredentialsId(String credentialsId) { |
|||
log.debug("Try to find device credentials by credentialsId [{}] ", credentialsId); |
|||
Where query = select().from(ModelConstants.DEVICE_CREDENTIALS_BY_CREDENTIALS_ID_COLUMN_FAMILY_NAME) |
|||
.where(eq(ModelConstants.DEVICE_CREDENTIALS_CREDENTIALS_ID_PROPERTY, credentialsId)); |
|||
log.trace("Execute query {}", query); |
|||
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(query); |
|||
log.trace("Found device credentials [{}] by credentialsId [{}]", deviceCredentialsEntity, credentialsId); |
|||
return deviceCredentialsEntity; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentialsEntity save(DeviceCredentials deviceCredentials) { |
|||
log.debug("Save device credentials [{}] ", deviceCredentials); |
|||
return save(new DeviceCredentialsEntity(deviceCredentials)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import org.springframework.cache.annotation.CacheEvict; |
|||
import org.springframework.cache.annotation.Cacheable; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
|
|||
import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; |
|||
|
|||
public interface DeviceCredentialsService { |
|||
|
|||
DeviceCredentials findDeviceCredentialsByDeviceId(DeviceId deviceId); |
|||
|
|||
@Cacheable(cacheNames = DEVICE_CREDENTIALS_CACHE, unless="#result == null") |
|||
DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId); |
|||
|
|||
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, keyGenerator="previousDeviceCredentialsId", beforeInvocation = true) |
|||
DeviceCredentials updateDeviceCredentials(DeviceCredentials deviceCredentials); |
|||
|
|||
DeviceCredentials createDeviceCredentials(DeviceCredentials deviceCredentials); |
|||
|
|||
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, key="#deviceCredentials.credentialsId") |
|||
void deleteDeviceCredentials(DeviceCredentials deviceCredentials); |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.model.DeviceCredentialsEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
import static org.thingsboard.server.dao.service.Validator.validateId; |
|||
import static org.thingsboard.server.dao.service.Validator.validateString; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class DeviceCredentialsServiceImpl implements DeviceCredentialsService { |
|||
|
|||
@Autowired |
|||
private DeviceCredentialsDao deviceCredentialsDao; |
|||
|
|||
@Autowired |
|||
private DeviceService deviceService; |
|||
|
|||
@Override |
|||
public DeviceCredentials findDeviceCredentialsByDeviceId(DeviceId deviceId) { |
|||
log.trace("Executing findDeviceCredentialsByDeviceId [{}]", deviceId); |
|||
validateId(deviceId, "Incorrect deviceId " + deviceId); |
|||
DeviceCredentialsEntity deviceCredentialsEntity = deviceCredentialsDao.findByDeviceId(deviceId.getId()); |
|||
return getData(deviceCredentialsEntity); |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId) { |
|||
log.trace("Executing findDeviceCredentialsByCredentialsId [{}]", credentialsId); |
|||
validateString(credentialsId, "Incorrect credentialsId " + credentialsId); |
|||
DeviceCredentialsEntity deviceCredentialsEntity = deviceCredentialsDao.findByCredentialsId(credentialsId); |
|||
return getData(deviceCredentialsEntity); |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials updateDeviceCredentials(DeviceCredentials deviceCredentials) { |
|||
return saveOrUpdare(deviceCredentials); |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials createDeviceCredentials(DeviceCredentials deviceCredentials) { |
|||
return saveOrUpdare(deviceCredentials); |
|||
} |
|||
|
|||
private DeviceCredentials saveOrUpdare(DeviceCredentials deviceCredentials) { |
|||
log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); |
|||
credentialsValidator.validate(deviceCredentials); |
|||
return getData(deviceCredentialsDao.save(deviceCredentials)); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteDeviceCredentials(DeviceCredentials deviceCredentials) { |
|||
log.trace("Executing deleteDeviceCredentials [{}]", deviceCredentials); |
|||
deviceCredentialsDao.removeById(deviceCredentials.getUuidId()); |
|||
} |
|||
|
|||
private DataValidator<DeviceCredentials> credentialsValidator = |
|||
new DataValidator<DeviceCredentials>() { |
|||
|
|||
@Override |
|||
protected void validateCreate(DeviceCredentials deviceCredentials) { |
|||
DeviceCredentialsEntity existingCredentialsEntity = deviceCredentialsDao.findByCredentialsId(deviceCredentials.getCredentialsId()); |
|||
if (existingCredentialsEntity != null) { |
|||
throw new DataValidationException("Create of existent device credentials!"); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void validateUpdate(DeviceCredentials deviceCredentials) { |
|||
DeviceCredentialsEntity existingCredentialsEntity = deviceCredentialsDao.findById(deviceCredentials.getUuidId()); |
|||
if (existingCredentialsEntity == null) { |
|||
throw new DataValidationException("Unable to update non-existent device credentials!"); |
|||
} |
|||
DeviceCredentialsEntity sameCredentialsIdEntity = deviceCredentialsDao.findByCredentialsId(deviceCredentials.getCredentialsId()); |
|||
if (sameCredentialsIdEntity != null && !sameCredentialsIdEntity.getId().equals(deviceCredentials.getUuidId())) { |
|||
throw new DataValidationException("Specified credentials are already registered!"); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void validateDataImpl(DeviceCredentials deviceCredentials) { |
|||
if (deviceCredentials.getDeviceId() == null) { |
|||
throw new DataValidationException("Device credentials should be assigned to device!"); |
|||
} |
|||
if (deviceCredentials.getCredentialsType() == null) { |
|||
throw new DataValidationException("Device credentials type should be specified!"); |
|||
} |
|||
if (StringUtils.isEmpty(deviceCredentials.getCredentialsId())) { |
|||
throw new DataValidationException("Device credentials id should be specified!"); |
|||
} |
|||
switch (deviceCredentials.getCredentialsType()) { |
|||
case ACCESS_TOKEN: |
|||
if (deviceCredentials.getCredentialsId().length() < 1 || deviceCredentials.getCredentialsId().length() > 20) { |
|||
throw new DataValidationException("Incorrect access token length [" + deviceCredentials.getCredentialsId().length() + "]!"); |
|||
} |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
Device device = deviceService.findDeviceById(deviceCredentials.getDeviceId()); |
|||
if (device == null) { |
|||
throw new DataValidationException("Can't assign device credentials to non-existent device!"); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.DeviceEntity; |
|||
|
|||
/** |
|||
* The Interface DeviceDao. |
|||
* |
|||
*/ |
|||
public interface DeviceDao extends Dao<DeviceEntity> { |
|||
|
|||
/** |
|||
* Save or update device object |
|||
* |
|||
* @param device the device object |
|||
* @return saved device object |
|||
*/ |
|||
DeviceEntity save(Device device); |
|||
|
|||
/** |
|||
* Find devices by tenantId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param pageLink the page link |
|||
* @return the list of device objects |
|||
*/ |
|||
List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink); |
|||
|
|||
/** |
|||
* Find devices by tenantId, customerId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param customerId the customerId |
|||
* @param pageLink the page link |
|||
* @return the list of device objects |
|||
*/ |
|||
List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); |
|||
|
|||
/** |
|||
* Find devices by tenantId and device name. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param name the device name |
|||
* @return the optional device object |
|||
*/ |
|||
Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String name); |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.*; |
|||
|
|||
import java.util.*; |
|||
|
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.AbstractSearchTextDao; |
|||
import org.thingsboard.server.dao.model.DeviceEntity; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implements DeviceDao { |
|||
|
|||
@Override |
|||
protected Class<DeviceEntity> getColumnFamilyClass() { |
|||
return DeviceEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return DEVICE_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public DeviceEntity save(Device device) { |
|||
log.debug("Save device [{}] ", device); |
|||
return save(new DeviceEntity(device)); |
|||
} |
|||
|
|||
@Override |
|||
public List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink) { |
|||
log.debug("Try to find devices by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
|||
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Collections.singletonList(eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), pageLink); |
|||
|
|||
log.trace("Found devices [{}] by tenantId [{}] and pageLink [{}]", deviceEntities, tenantId, pageLink); |
|||
return deviceEntities; |
|||
} |
|||
|
|||
@Override |
|||
public List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { |
|||
log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); |
|||
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), |
|||
eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), |
|||
pageLink); |
|||
|
|||
log.trace("Found devices [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, pageLink); |
|||
return deviceEntities; |
|||
} |
|||
|
|||
@Override |
|||
public Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String deviceName) { |
|||
Select select = select().from(DEVICE_BY_TENANT_AND_NAME_VIEW_NAME); |
|||
Select.Where query = select.where(); |
|||
query.and(eq(DEVICE_TENANT_ID_PROPERTY, tenantId)); |
|||
query.and(eq(DEVICE_NAME_PROPERTY, deviceName)); |
|||
return Optional.ofNullable(findOneByStatement(query)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
|
|||
public interface DeviceService { |
|||
|
|||
Device findDeviceById(DeviceId deviceId); |
|||
|
|||
Device saveDevice(Device device); |
|||
|
|||
Device assignDeviceToCustomer(DeviceId deviceId, CustomerId customerId); |
|||
|
|||
Device unassignDeviceFromCustomer(DeviceId deviceId); |
|||
|
|||
void deleteDevice(DeviceId deviceId); |
|||
|
|||
TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink); |
|||
|
|||
void deleteDevicesByTenantId(TenantId tenantId); |
|||
|
|||
TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); |
|||
|
|||
void unassignCustomerDevices(TenantId tenantId, CustomerId customerId); |
|||
} |
|||
@ -0,0 +1,231 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.device; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.RandomStringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
import org.thingsboard.server.dao.customer.CustomerDao; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
import org.thingsboard.server.dao.model.DeviceEntity; |
|||
import org.thingsboard.server.dao.model.TenantEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.service.PaginatedRemover; |
|||
import org.thingsboard.server.dao.tenant.TenantDao; |
|||
|
|||
import java.util.List; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
|||
import static org.thingsboard.server.dao.service.Validator.validateId; |
|||
import static org.thingsboard.server.dao.service.Validator.validatePageLink; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class DeviceServiceImpl implements DeviceService { |
|||
|
|||
@Autowired |
|||
private DeviceDao deviceDao; |
|||
|
|||
@Autowired |
|||
private TenantDao tenantDao; |
|||
|
|||
@Autowired |
|||
private CustomerDao customerDao; |
|||
|
|||
@Autowired |
|||
private DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Override |
|||
public Device findDeviceById(DeviceId deviceId) { |
|||
log.trace("Executing findDeviceById [{}]", deviceId); |
|||
validateId(deviceId, "Incorrect deviceId " + deviceId); |
|||
DeviceEntity deviceEntity = deviceDao.findById(deviceId.getId()); |
|||
return getData(deviceEntity); |
|||
} |
|||
|
|||
@Override |
|||
public Device saveDevice(Device device) { |
|||
log.trace("Executing saveDevice [{}]", device); |
|||
deviceValidator.validate(device); |
|||
DeviceEntity deviceEntity = deviceDao.save(device); |
|||
if (device.getId() == null) { |
|||
DeviceCredentials deviceCredentials = new DeviceCredentials(); |
|||
deviceCredentials.setDeviceId(new DeviceId(deviceEntity.getId())); |
|||
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); |
|||
deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20)); |
|||
deviceCredentialsService.createDeviceCredentials(deviceCredentials); |
|||
} |
|||
return getData(deviceEntity); |
|||
} |
|||
|
|||
@Override |
|||
public Device assignDeviceToCustomer(DeviceId deviceId, CustomerId customerId) { |
|||
Device device = findDeviceById(deviceId); |
|||
device.setCustomerId(customerId); |
|||
return saveDevice(device); |
|||
} |
|||
|
|||
@Override |
|||
public Device unassignDeviceFromCustomer(DeviceId deviceId) { |
|||
Device device = findDeviceById(deviceId); |
|||
device.setCustomerId(null); |
|||
return saveDevice(device); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteDevice(DeviceId deviceId) { |
|||
log.trace("Executing deleteDevice [{}]", deviceId); |
|||
validateId(deviceId, "Incorrect deviceId " + deviceId); |
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId); |
|||
if (deviceCredentials != null) { |
|||
deviceCredentialsService.deleteDeviceCredentials(deviceCredentials); |
|||
} |
|||
deviceDao.removeById(deviceId.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink) { |
|||
log.trace("Executing findDevicesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink); |
|||
List<Device> devices = convertDataList(deviceEntities); |
|||
return new TextPageData<Device>(devices, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteDevicesByTenantId(TenantId tenantId) { |
|||
log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
tenantDevicesRemover.removeEntitites(tenantId); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { |
|||
log.trace("Executing findDevicesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); |
|||
List<Device> devices = convertDataList(deviceEntities); |
|||
return new TextPageData<Device>(devices, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public void unassignCustomerDevices(TenantId tenantId, CustomerId customerId) { |
|||
log.trace("Executing unassignCustomerDevices, tenantId [{}], customerId [{}]", tenantId, customerId); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
new CustomerDevicesUnassigner(tenantId).removeEntitites(customerId); |
|||
} |
|||
|
|||
private DataValidator<Device> deviceValidator = |
|||
new DataValidator<Device>() { |
|||
|
|||
@Override |
|||
protected void validateCreate(Device device) { |
|||
deviceDao.findDevicesByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent( |
|||
d -> { |
|||
throw new DataValidationException("Device with such name already exists!"); |
|||
} |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
protected void validateUpdate(Device device) { |
|||
deviceDao.findDevicesByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent( |
|||
d -> { |
|||
if (!d.getId().equals(device.getUuidId())) { |
|||
throw new DataValidationException("Device with such name already exists!"); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
protected void validateDataImpl(Device device) { |
|||
if (StringUtils.isEmpty(device.getName())) { |
|||
throw new DataValidationException("Device name should be specified!"); |
|||
} |
|||
if (device.getTenantId() == null) { |
|||
throw new DataValidationException("Device should be assigned to tenant!"); |
|||
} else { |
|||
TenantEntity tenant = tenantDao.findById(device.getTenantId().getId()); |
|||
if (tenant == null) { |
|||
throw new DataValidationException("Device is referencing to non-existent tenant!"); |
|||
} |
|||
} |
|||
if (device.getCustomerId() == null) { |
|||
device.setCustomerId(new CustomerId(NULL_UUID)); |
|||
} else if (!device.getCustomerId().getId().equals(NULL_UUID)) { |
|||
CustomerEntity customer = customerDao.findById(device.getCustomerId().getId()); |
|||
if (customer == null) { |
|||
throw new DataValidationException("Can't assign device to non-existent customer!"); |
|||
} |
|||
if (!customer.getTenantId().equals(device.getTenantId().getId())) { |
|||
throw new DataValidationException("Can't assign device to customer from different tenant!"); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
private PaginatedRemover<TenantId, DeviceEntity> tenantDevicesRemover = |
|||
new PaginatedRemover<TenantId, DeviceEntity>() { |
|||
|
|||
@Override |
|||
protected List<DeviceEntity> findEntities(TenantId id, TextPageLink pageLink) { |
|||
return deviceDao.findDevicesByTenantId(id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(DeviceEntity entity) { |
|||
deleteDevice(new DeviceId(entity.getId())); |
|||
} |
|||
}; |
|||
|
|||
class CustomerDevicesUnassigner extends PaginatedRemover<CustomerId, DeviceEntity> { |
|||
|
|||
private TenantId tenantId; |
|||
|
|||
CustomerDevicesUnassigner(TenantId tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
@Override |
|||
protected List<DeviceEntity> findEntities(CustomerId id, TextPageLink pageLink) { |
|||
return deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(DeviceEntity entity) { |
|||
unassignDeviceFromCustomer(new DeviceId(entity.getId())); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,136 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.event; |
|||
|
|||
import com.datastax.driver.core.ResultSet; |
|||
import com.datastax.driver.core.querybuilder.Insert; |
|||
import com.datastax.driver.core.querybuilder.QueryBuilder; |
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.Event; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.AbstractSearchTimeDao; |
|||
import org.thingsboard.server.dao.model.EventEntity; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; |
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.select; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_BY_ID_VIEW_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_BY_TYPE_AND_ID_VIEW_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_COLUMN_FAMILY_NAME; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
public class BaseEventDao extends AbstractSearchTimeDao<EventEntity> implements EventDao { |
|||
|
|||
@Override |
|||
protected Class<EventEntity> getColumnFamilyClass() { |
|||
return EventEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return EVENT_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public EventEntity save(Event event) { |
|||
log.debug("Save event [{}] ", event); |
|||
return save(new EventEntity(event), false).orElse(null); |
|||
} |
|||
|
|||
@Override |
|||
public Optional<EventEntity> saveIfNotExists(Event event) { |
|||
return save(new EventEntity(event), true); |
|||
} |
|||
|
|||
@Override |
|||
public EventEntity findEvent(UUID tenantId, EntityId entityId, String eventType, String eventUid) { |
|||
log.debug("Search event entity by [{}][{}][{}][{}]", tenantId, entityId, eventType, eventUid); |
|||
Select.Where query = select().from(getColumnFamilyName()).where( |
|||
eq(ModelConstants.EVENT_TENANT_ID_PROPERTY, tenantId)) |
|||
.and(eq(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entityId.getEntityType())) |
|||
.and(eq(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entityId.getId())) |
|||
.and(eq(ModelConstants.EVENT_TYPE_PROPERTY, eventType)) |
|||
.and(eq(ModelConstants.EVENT_UID_PROPERTY, eventUid)); |
|||
log.trace("Execute query [{}]", query); |
|||
EventEntity entity = findOneByStatement(query); |
|||
if (log.isTraceEnabled()) { |
|||
log.trace("Search result: [{}] for event entity [{}]", entity != null, entity); |
|||
} else { |
|||
log.debug("Search result: [{}]", entity != null); |
|||
} |
|||
return entity; |
|||
} |
|||
|
|||
@Override |
|||
public List<EventEntity> findEvents(UUID tenantId, EntityId entityId, TimePageLink pageLink) { |
|||
log.trace("Try to find events by tenant [{}], entity [{}]and pageLink [{}]", tenantId, entityId, pageLink); |
|||
List<EventEntity> entities = findPageWithTimeSearch(EVENT_BY_ID_VIEW_NAME, |
|||
Arrays.asList(eq(ModelConstants.EVENT_TENANT_ID_PROPERTY, tenantId), |
|||
eq(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entityId.getEntityType()), |
|||
eq(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entityId.getId())), |
|||
pageLink); |
|||
log.trace("Found events by tenant [{}], entity [{}] and pageLink [{}]", tenantId, entityId, pageLink); |
|||
return entities; |
|||
} |
|||
|
|||
@Override |
|||
public List<EventEntity> findEvents(UUID tenantId, EntityId entityId, String eventType, TimePageLink pageLink) { |
|||
log.trace("Try to find events by tenant [{}], entity [{}], type [{}] and pageLink [{}]", tenantId, entityId, eventType, pageLink); |
|||
List<EventEntity> entities = findPageWithTimeSearch(EVENT_BY_TYPE_AND_ID_VIEW_NAME, |
|||
Arrays.asList(eq(ModelConstants.EVENT_TENANT_ID_PROPERTY, tenantId), |
|||
eq(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entityId.getEntityType()), |
|||
eq(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entityId.getId()), |
|||
eq(ModelConstants.EVENT_TYPE_PROPERTY, eventType)), |
|||
pageLink.isAscOrder() ? QueryBuilder.asc(ModelConstants.EVENT_TYPE_PROPERTY) : |
|||
QueryBuilder.desc(ModelConstants.EVENT_TYPE_PROPERTY), |
|||
pageLink); |
|||
log.trace("Found events by tenant [{}], entity [{}], type [{}] and pageLink [{}]", tenantId, entityId, eventType, pageLink); |
|||
return entities; |
|||
} |
|||
|
|||
private Optional<EventEntity> save(EventEntity entity, boolean ifNotExists) { |
|||
if (entity.getId() == null) { |
|||
entity.setId(UUIDs.timeBased()); |
|||
} |
|||
Insert insert = QueryBuilder.insertInto(getColumnFamilyName()) |
|||
.value(ModelConstants.ID_PROPERTY, entity.getId()) |
|||
.value(ModelConstants.EVENT_TENANT_ID_PROPERTY, entity.getTenantId()) |
|||
.value(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entity.getEntityType()) |
|||
.value(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entity.getEntityId()) |
|||
.value(ModelConstants.EVENT_TYPE_PROPERTY, entity.getEventType()) |
|||
.value(ModelConstants.EVENT_UID_PROPERTY, entity.getEventUId()) |
|||
.value(ModelConstants.EVENT_BODY_PROPERTY, entity.getBody()); |
|||
if (ifNotExists) { |
|||
insert = insert.ifNotExists(); |
|||
} |
|||
ResultSet rs = executeWrite(insert); |
|||
if (rs.wasApplied()) { |
|||
return Optional.of(entity); |
|||
} else { |
|||
return Optional.empty(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.event; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Event; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EventId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TimePageData; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.model.EventEntity; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
|||
import static org.thingsboard.server.dao.DaoUtil.getData; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class BaseEventService implements EventService { |
|||
|
|||
private final TenantId systemTenantId = new TenantId(NULL_UUID); |
|||
|
|||
@Autowired |
|||
public EventDao eventDao; |
|||
|
|||
@Override |
|||
public Event save(Event event) { |
|||
eventValidator.validate(event); |
|||
if (event.getTenantId() == null) { |
|||
log.trace("Save system event with predefined id {}", systemTenantId); |
|||
event.setTenantId(systemTenantId); |
|||
} |
|||
if (event.getId() == null) { |
|||
event.setId(new EventId(UUIDs.timeBased())); |
|||
} |
|||
if (StringUtils.isEmpty(event.getUid())) { |
|||
event.setUid(event.getId().toString()); |
|||
} |
|||
return getData(eventDao.save(event)); |
|||
} |
|||
|
|||
@Override |
|||
public Optional<Event> saveIfNotExists(Event event) { |
|||
eventValidator.validate(event); |
|||
if (StringUtils.isEmpty(event.getUid())) { |
|||
throw new DataValidationException("Event uid should be specified!."); |
|||
} |
|||
if (event.getTenantId() == null) { |
|||
log.trace("Save system event with predefined id {}", systemTenantId); |
|||
event.setTenantId(systemTenantId); |
|||
} |
|||
if (event.getId() == null) { |
|||
event.setId(new EventId(UUIDs.timeBased())); |
|||
} |
|||
Optional<EventEntity> result = eventDao.saveIfNotExists(event); |
|||
return result.isPresent() ? Optional.of(getData(result.get())) : Optional.empty(); |
|||
} |
|||
|
|||
@Override |
|||
public Optional<Event> findEvent(TenantId tenantId, EntityId entityId, String eventType, String eventUid) { |
|||
if (tenantId == null) { |
|||
throw new DataValidationException("Tenant id should be specified!."); |
|||
} |
|||
if (entityId == null) { |
|||
throw new DataValidationException("Entity id should be specified!."); |
|||
} |
|||
if (StringUtils.isEmpty(eventType)) { |
|||
throw new DataValidationException("Event type should be specified!."); |
|||
} |
|||
if (StringUtils.isEmpty(eventUid)) { |
|||
throw new DataValidationException("Event uid should be specified!."); |
|||
} |
|||
EventEntity entity = eventDao.findEvent(tenantId.getId(), entityId, eventType, eventUid); |
|||
return entity != null ? Optional.of(getData(entity)) : Optional.empty(); |
|||
} |
|||
|
|||
@Override |
|||
public TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, TimePageLink pageLink) { |
|||
List<EventEntity> entities = eventDao.findEvents(tenantId.getId(), entityId, pageLink); |
|||
List<Event> events = convertDataList(entities); |
|||
return new TimePageData<Event>(events, pageLink); |
|||
} |
|||
|
|||
|
|||
@Override |
|||
public TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, String eventType, TimePageLink pageLink) { |
|||
List<EventEntity> entities = eventDao.findEvents(tenantId.getId(), entityId, eventType, pageLink); |
|||
List<Event> events = convertDataList(entities); |
|||
return new TimePageData<Event>(events, pageLink); |
|||
} |
|||
|
|||
private DataValidator<Event> eventValidator = |
|||
new DataValidator<Event>() { |
|||
@Override |
|||
protected void validateDataImpl(Event event) { |
|||
if (event.getEntityId() == null) { |
|||
throw new DataValidationException("Entity id should be specified!."); |
|||
} |
|||
if (StringUtils.isEmpty(event.getType())) { |
|||
throw new DataValidationException("Event type should be specified!."); |
|||
} |
|||
if (event.getBody() == null) { |
|||
throw new DataValidationException("Event body should be specified!."); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.event; |
|||
|
|||
import org.thingsboard.server.common.data.Event; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.EventEntity; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* The Interface DeviceDao. |
|||
* |
|||
* @param <T> the generic type |
|||
*/ |
|||
public interface EventDao extends Dao<EventEntity> { |
|||
|
|||
/** |
|||
* Save or update event object |
|||
* |
|||
* @param event the event object |
|||
* @return saved event object |
|||
*/ |
|||
EventEntity save(Event event); |
|||
|
|||
/** |
|||
* Save event object if it is not yet saved |
|||
* |
|||
* @param event the event object |
|||
* @return saved event object |
|||
*/ |
|||
Optional<EventEntity> saveIfNotExists(Event event); |
|||
|
|||
/** |
|||
* Find event by tenantId, entityId and eventUid. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param entityId the entityId |
|||
* @param eventType the eventType |
|||
* @param eventUid the eventUid |
|||
* @return the event |
|||
*/ |
|||
EventEntity findEvent(UUID tenantId, EntityId entityId, String eventType, String eventUid); |
|||
|
|||
/** |
|||
* Find events by tenantId, entityId and pageLink. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param entityId the entityId |
|||
* @param pageLink the pageLink |
|||
* @return the event list |
|||
*/ |
|||
List<EventEntity> findEvents(UUID tenantId, EntityId entityId, TimePageLink pageLink); |
|||
|
|||
/** |
|||
* Find events by tenantId, entityId, eventType and pageLink. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param entityId the entityId |
|||
* @param eventType the eventType |
|||
* @param pageLink the pageLink |
|||
* @return the event list |
|||
*/ |
|||
List<EventEntity> findEvents(UUID tenantId, EntityId entityId, String eventType, TimePageLink pageLink); |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.event; |
|||
|
|||
import org.thingsboard.server.common.data.Event; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TimePageData; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
|
|||
public interface EventService { |
|||
|
|||
Event save(Event event); |
|||
|
|||
Optional<Event> saveIfNotExists(Event event); |
|||
|
|||
Optional<Event> findEvent(TenantId tenantId, EntityId entityId, String eventType, String eventUid); |
|||
|
|||
TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, TimePageLink pageLink); |
|||
|
|||
TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, String eventType, TimePageLink pageLink); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.exception; |
|||
|
|||
public class DataValidationException extends RuntimeException { |
|||
|
|||
private static final long serialVersionUID = 7659985660312721830L; |
|||
|
|||
public DataValidationException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public DataValidationException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.exception; |
|||
|
|||
public class DatabaseException extends RuntimeException { |
|||
|
|||
private static final long serialVersionUID = 3463762014441887103L; |
|||
|
|||
public DatabaseException() { |
|||
super(); |
|||
} |
|||
|
|||
public DatabaseException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
|
|||
public DatabaseException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public DatabaseException(Throwable cause) { |
|||
super(cause); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.exception; |
|||
|
|||
|
|||
public class IncorrectParameterException extends RuntimeException { |
|||
|
|||
private static final long serialVersionUID = 601995650578985289L; |
|||
|
|||
public IncorrectParameterException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public IncorrectParameterException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
} |
|||
@ -0,0 +1,147 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_COLUMN_FAMILY_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_JSON_VALUE_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_KEY_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.common.data.id.AdminSettingsId; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
|
|||
@Table(name = ADMIN_SETTINGS_COLUMN_FAMILY_NAME) |
|||
public final class AdminSettingsEntity implements BaseEntity<AdminSettings> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = 899117723388310403L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@Column(name = ADMIN_SETTINGS_KEY_PROPERTY) |
|||
private String key; |
|||
|
|||
@Column(name = ADMIN_SETTINGS_JSON_VALUE_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode jsonValue; |
|||
|
|||
public AdminSettingsEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public AdminSettingsEntity(AdminSettings adminSettings) { |
|||
if (adminSettings.getId() != null) { |
|||
this.id = adminSettings.getId().getId(); |
|||
} |
|||
this.key = adminSettings.getKey(); |
|||
this.jsonValue = adminSettings.getJsonValue(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public String getKey() { |
|||
return key; |
|||
} |
|||
|
|||
public void setKey(String key) { |
|||
this.key = key; |
|||
} |
|||
|
|||
public JsonNode getJsonValue() { |
|||
return jsonValue; |
|||
} |
|||
|
|||
public void setJsonValue(JsonNode jsonValue) { |
|||
this.jsonValue = jsonValue; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((id == null) ? 0 : id.hashCode()); |
|||
result = prime * result + ((jsonValue == null) ? 0 : jsonValue.hashCode()); |
|||
result = prime * result + ((key == null) ? 0 : key.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; |
|||
AdminSettingsEntity other = (AdminSettingsEntity) obj; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
if (jsonValue == null) { |
|||
if (other.jsonValue != null) |
|||
return false; |
|||
} else if (!jsonValue.equals(other.jsonValue)) |
|||
return false; |
|||
if (key == null) { |
|||
if (other.key != null) |
|||
return false; |
|||
} else if (!key.equals(other.key)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("AdminSettingsEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", key="); |
|||
builder.append(key); |
|||
builder.append(", jsonValue="); |
|||
builder.append(jsonValue); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public AdminSettings toData() { |
|||
AdminSettings adminSettings = new AdminSettings(new AdminSettingsId(id)); |
|||
adminSettings.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
adminSettings.setKey(key); |
|||
adminSettings.setJsonValue(jsonValue); |
|||
return adminSettings; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.UUID; |
|||
|
|||
public interface BaseEntity<D> extends ToData<D>, Serializable { |
|||
|
|||
UUID getId(); |
|||
|
|||
void setId(UUID id); |
|||
|
|||
} |
|||
@ -0,0 +1,162 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
|||
import org.thingsboard.server.common.data.plugin.ComponentScope; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Table(name = ModelConstants.COMPONENT_DESCRIPTOR_COLUMN_FAMILY_NAME) |
|||
public class ComponentDescriptorEntity implements SearchTextEntity<ComponentDescriptor> { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@PartitionKey |
|||
@Column(name = ModelConstants.ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY) |
|||
private ComponentType type; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_SCOPE_PROPERTY) |
|||
private ComponentScope scope; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_NAME_PROPERTY) |
|||
private String name; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY) |
|||
private String clazz; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_CONFIGURATION_DESCRIPTOR_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode configurationDescriptor; |
|||
|
|||
@Column(name = ModelConstants.COMPONENT_DESCRIPTOR_ACTIONS_PROPERTY) |
|||
private String actions; |
|||
|
|||
@Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) |
|||
private String searchText; |
|||
|
|||
public ComponentDescriptorEntity() { |
|||
} |
|||
|
|||
public ComponentDescriptorEntity(ComponentDescriptor component) { |
|||
if (component.getId() != null) { |
|||
this.id = component.getId().getId(); |
|||
} |
|||
this.actions = component.getActions(); |
|||
this.type = component.getType(); |
|||
this.scope = component.getScope(); |
|||
this.name = component.getName(); |
|||
this.clazz = component.getClazz(); |
|||
this.configurationDescriptor = component.getConfigurationDescriptor(); |
|||
this.searchText = component.getName(); |
|||
} |
|||
|
|||
@Override |
|||
public ComponentDescriptor toData() { |
|||
ComponentDescriptor data = new ComponentDescriptor(new ComponentDescriptorId(id)); |
|||
data.setType(type); |
|||
data.setScope(scope); |
|||
data.setName(this.getName()); |
|||
data.setClazz(this.getClazz()); |
|||
data.setActions(this.getActions()); |
|||
data.setConfigurationDescriptor(this.getConfigurationDescriptor()); |
|||
return data; |
|||
} |
|||
|
|||
@Override |
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
@Override |
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public String getActions() { |
|||
return actions; |
|||
} |
|||
|
|||
public void setActions(String actions) { |
|||
this.actions = actions; |
|||
} |
|||
|
|||
public ComponentType getType() { |
|||
return type; |
|||
} |
|||
|
|||
public void setType(ComponentType type) { |
|||
this.type = type; |
|||
} |
|||
|
|||
public ComponentScope getScope() { |
|||
return scope; |
|||
} |
|||
|
|||
public void setScope(ComponentScope scope) { |
|||
this.scope = scope; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public String getClazz() { |
|||
return clazz; |
|||
} |
|||
|
|||
public void setClazz(String clazz) { |
|||
this.clazz = clazz; |
|||
} |
|||
|
|||
public JsonNode getConfigurationDescriptor() { |
|||
return configurationDescriptor; |
|||
} |
|||
|
|||
public void setConfigurationDescriptor(JsonNode configurationDescriptor) { |
|||
this.configurationDescriptor = configurationDescriptor; |
|||
} |
|||
|
|||
public String getSearchText() { |
|||
return searchText; |
|||
} |
|||
|
|||
@Override |
|||
public void setSearchText(String searchText) { |
|||
this.searchText = searchText; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchTextSource() { |
|||
return searchText; |
|||
} |
|||
} |
|||
@ -0,0 +1,365 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import static org.thingsboard.server.dao.model.ModelConstants.ADDRESS2_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ADDRESS_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.CITY_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.COUNTRY_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ADDITIONAL_INFO_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_COLUMN_FAMILY_NAME; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_TENANT_ID_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_TITLE_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.EMAIL_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.PHONE_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.STATE_PROPERTY; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.ZIP_PROPERTY; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
|
|||
@Table(name = CUSTOMER_COLUMN_FAMILY_NAME) |
|||
public final class CustomerEntity implements SearchTextEntity<Customer> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = -7732527103760948490L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@PartitionKey(value = 1) |
|||
@Column(name = CUSTOMER_TENANT_ID_PROPERTY) |
|||
private UUID tenantId; |
|||
|
|||
@Column(name = CUSTOMER_TITLE_PROPERTY) |
|||
private String title; |
|||
|
|||
@Column(name = SEARCH_TEXT_PROPERTY) |
|||
private String searchText; |
|||
|
|||
@Column(name = COUNTRY_PROPERTY) |
|||
private String country; |
|||
|
|||
@Column(name = STATE_PROPERTY) |
|||
private String state; |
|||
|
|||
@Column(name = CITY_PROPERTY) |
|||
private String city; |
|||
|
|||
@Column(name = ADDRESS_PROPERTY) |
|||
private String address; |
|||
|
|||
@Column(name = ADDRESS2_PROPERTY) |
|||
private String address2; |
|||
|
|||
@Column(name = ZIP_PROPERTY) |
|||
private String zip; |
|||
|
|||
@Column(name = PHONE_PROPERTY) |
|||
private String phone; |
|||
|
|||
@Column(name = EMAIL_PROPERTY) |
|||
private String email; |
|||
|
|||
@Column(name = CUSTOMER_ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode additionalInfo; |
|||
|
|||
public CustomerEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public CustomerEntity(Customer customer) { |
|||
if (customer.getId() != null) { |
|||
this.id = customer.getId().getId(); |
|||
} |
|||
this.tenantId = customer.getTenantId().getId(); |
|||
this.title = customer.getTitle(); |
|||
this.country = customer.getCountry(); |
|||
this.state = customer.getState(); |
|||
this.city = customer.getCity(); |
|||
this.address = customer.getAddress(); |
|||
this.address2 = customer.getAddress2(); |
|||
this.zip = customer.getZip(); |
|||
this.phone = customer.getPhone(); |
|||
this.email = customer.getEmail(); |
|||
this.additionalInfo = customer.getAdditionalInfo(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public UUID getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
public void setTenantId(UUID tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
public String getTitle() { |
|||
return title; |
|||
} |
|||
|
|||
public void setTitle(String title) { |
|||
this.title = title; |
|||
} |
|||
|
|||
public String getCountry() { |
|||
return country; |
|||
} |
|||
|
|||
public void setCountry(String country) { |
|||
this.country = country; |
|||
} |
|||
|
|||
public String getState() { |
|||
return state; |
|||
} |
|||
|
|||
public void setState(String state) { |
|||
this.state = state; |
|||
} |
|||
|
|||
public String getCity() { |
|||
return city; |
|||
} |
|||
|
|||
public void setCity(String city) { |
|||
this.city = city; |
|||
} |
|||
|
|||
public String getAddress() { |
|||
return address; |
|||
} |
|||
|
|||
public void setAddress(String address) { |
|||
this.address = address; |
|||
} |
|||
|
|||
public String getAddress2() { |
|||
return address2; |
|||
} |
|||
|
|||
public void setAddress2(String address2) { |
|||
this.address2 = address2; |
|||
} |
|||
|
|||
public String getZip() { |
|||
return zip; |
|||
} |
|||
|
|||
public void setZip(String zip) { |
|||
this.zip = zip; |
|||
} |
|||
|
|||
public String getPhone() { |
|||
return phone; |
|||
} |
|||
|
|||
public void setPhone(String phone) { |
|||
this.phone = phone; |
|||
} |
|||
|
|||
public String getEmail() { |
|||
return email; |
|||
} |
|||
|
|||
public void setEmail(String email) { |
|||
this.email = email; |
|||
} |
|||
|
|||
public JsonNode getAdditionalInfo() { |
|||
return additionalInfo; |
|||
} |
|||
|
|||
public void setAdditionalInfo(JsonNode additionalInfo) { |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchTextSource() { |
|||
return title; |
|||
} |
|||
|
|||
@Override |
|||
public void setSearchText(String searchText) { |
|||
this.searchText = searchText; |
|||
} |
|||
|
|||
public String getSearchText() { |
|||
return searchText; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); |
|||
result = prime * result + ((address == null) ? 0 : address.hashCode()); |
|||
result = prime * result + ((address2 == null) ? 0 : address2.hashCode()); |
|||
result = prime * result + ((city == null) ? 0 : city.hashCode()); |
|||
result = prime * result + ((country == null) ? 0 : country.hashCode()); |
|||
result = prime * result + ((email == null) ? 0 : email.hashCode()); |
|||
result = prime * result + ((id == null) ? 0 : id.hashCode()); |
|||
result = prime * result + ((phone == null) ? 0 : phone.hashCode()); |
|||
result = prime * result + ((state == null) ? 0 : state.hashCode()); |
|||
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
|||
result = prime * result + ((title == null) ? 0 : title.hashCode()); |
|||
result = prime * result + ((zip == null) ? 0 : zip.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; |
|||
CustomerEntity other = (CustomerEntity) obj; |
|||
if (additionalInfo == null) { |
|||
if (other.additionalInfo != null) |
|||
return false; |
|||
} else if (!additionalInfo.equals(other.additionalInfo)) |
|||
return false; |
|||
if (address == null) { |
|||
if (other.address != null) |
|||
return false; |
|||
} else if (!address.equals(other.address)) |
|||
return false; |
|||
if (address2 == null) { |
|||
if (other.address2 != null) |
|||
return false; |
|||
} else if (!address2.equals(other.address2)) |
|||
return false; |
|||
if (city == null) { |
|||
if (other.city != null) |
|||
return false; |
|||
} else if (!city.equals(other.city)) |
|||
return false; |
|||
if (country == null) { |
|||
if (other.country != null) |
|||
return false; |
|||
} else if (!country.equals(other.country)) |
|||
return false; |
|||
if (email == null) { |
|||
if (other.email != null) |
|||
return false; |
|||
} else if (!email.equals(other.email)) |
|||
return false; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
if (phone == null) { |
|||
if (other.phone != null) |
|||
return false; |
|||
} else if (!phone.equals(other.phone)) |
|||
return false; |
|||
if (state == null) { |
|||
if (other.state != null) |
|||
return false; |
|||
} else if (!state.equals(other.state)) |
|||
return false; |
|||
if (tenantId == null) { |
|||
if (other.tenantId != null) |
|||
return false; |
|||
} else if (!tenantId.equals(other.tenantId)) |
|||
return false; |
|||
if (title == null) { |
|||
if (other.title != null) |
|||
return false; |
|||
} else if (!title.equals(other.title)) |
|||
return false; |
|||
if (zip == null) { |
|||
if (other.zip != null) |
|||
return false; |
|||
} else if (!zip.equals(other.zip)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("CustomerEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", tenantId="); |
|||
builder.append(tenantId); |
|||
builder.append(", title="); |
|||
builder.append(title); |
|||
builder.append(", country="); |
|||
builder.append(country); |
|||
builder.append(", state="); |
|||
builder.append(state); |
|||
builder.append(", city="); |
|||
builder.append(city); |
|||
builder.append(", address="); |
|||
builder.append(address); |
|||
builder.append(", address2="); |
|||
builder.append(address2); |
|||
builder.append(", zip="); |
|||
builder.append(zip); |
|||
builder.append(", phone="); |
|||
builder.append(phone); |
|||
builder.append(", email="); |
|||
builder.append(email); |
|||
builder.append(", additionalInfo="); |
|||
builder.append(additionalInfo); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public Customer toData() { |
|||
Customer customer = new Customer(new CustomerId(id)); |
|||
customer.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
customer.setTenantId(new TenantId(tenantId)); |
|||
customer.setTitle(title); |
|||
customer.setCountry(country); |
|||
customer.setState(state); |
|||
customer.setCity(city); |
|||
customer.setAddress(address); |
|||
customer.setAddress2(address2); |
|||
customer.setZip(zip); |
|||
customer.setPhone(phone); |
|||
customer.setEmail(email); |
|||
customer.setAdditionalInfo(additionalInfo); |
|||
return customer; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,221 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
|
|||
@Table(name = ModelConstants.DASHBOARD_COLUMN_FAMILY_NAME) |
|||
public final class DashboardEntity implements SearchTextEntity<Dashboard> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = 2998395951247446191L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ModelConstants.ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@PartitionKey(value = 1) |
|||
@Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) |
|||
private UUID tenantId; |
|||
|
|||
@PartitionKey(value = 2) |
|||
@Column(name = ModelConstants.DASHBOARD_CUSTOMER_ID_PROPERTY) |
|||
private UUID customerId; |
|||
|
|||
@Column(name = ModelConstants.DASHBOARD_TITLE_PROPERTY) |
|||
private String title; |
|||
|
|||
@Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) |
|||
private String searchText; |
|||
|
|||
@Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode configuration; |
|||
|
|||
public DashboardEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public DashboardEntity(Dashboard dashboard) { |
|||
if (dashboard.getId() != null) { |
|||
this.id = dashboard.getId().getId(); |
|||
} |
|||
if (dashboard.getTenantId() != null) { |
|||
this.tenantId = dashboard.getTenantId().getId(); |
|||
} |
|||
if (dashboard.getCustomerId() != null) { |
|||
this.customerId = dashboard.getCustomerId().getId(); |
|||
} |
|||
this.title = dashboard.getTitle(); |
|||
this.configuration = dashboard.getConfiguration(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public UUID getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
public void setTenantId(UUID tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
public UUID getCustomerId() { |
|||
return customerId; |
|||
} |
|||
|
|||
public void setCustomerId(UUID customerId) { |
|||
this.customerId = customerId; |
|||
} |
|||
|
|||
public String getTitle() { |
|||
return title; |
|||
} |
|||
|
|||
public void setTitle(String title) { |
|||
this.title = title; |
|||
} |
|||
|
|||
public JsonNode getConfiguration() { |
|||
return configuration; |
|||
} |
|||
|
|||
public void setConfiguration(JsonNode configuration) { |
|||
this.configuration = configuration; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchTextSource() { |
|||
return title; |
|||
} |
|||
|
|||
@Override |
|||
public void setSearchText(String searchText) { |
|||
this.searchText = searchText; |
|||
} |
|||
|
|||
public String getSearchText() { |
|||
return searchText; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((configuration == null) ? 0 : configuration.hashCode()); |
|||
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
|||
result = prime * result + ((id == null) ? 0 : id.hashCode()); |
|||
result = prime * result + ((searchText == null) ? 0 : searchText.hashCode()); |
|||
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
|||
result = prime * result + ((title == null) ? 0 : title.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; |
|||
DashboardEntity other = (DashboardEntity) obj; |
|||
if (configuration == null) { |
|||
if (other.configuration != null) |
|||
return false; |
|||
} else if (!configuration.equals(other.configuration)) |
|||
return false; |
|||
if (customerId == null) { |
|||
if (other.customerId != null) |
|||
return false; |
|||
} else if (!customerId.equals(other.customerId)) |
|||
return false; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
if (searchText == null) { |
|||
if (other.searchText != null) |
|||
return false; |
|||
} else if (!searchText.equals(other.searchText)) |
|||
return false; |
|||
if (tenantId == null) { |
|||
if (other.tenantId != null) |
|||
return false; |
|||
} else if (!tenantId.equals(other.tenantId)) |
|||
return false; |
|||
if (title == null) { |
|||
if (other.title != null) |
|||
return false; |
|||
} else if (!title.equals(other.title)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("DashboardEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", tenantId="); |
|||
builder.append(tenantId); |
|||
builder.append(", customerId="); |
|||
builder.append(customerId); |
|||
builder.append(", title="); |
|||
builder.append(title); |
|||
builder.append(", searchText="); |
|||
builder.append(searchText); |
|||
builder.append(", configuration="); |
|||
builder.append(configuration); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public Dashboard toData() { |
|||
Dashboard dashboard = new Dashboard(new DashboardId(id)); |
|||
dashboard.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
if (tenantId != null) { |
|||
dashboard.setTenantId(new TenantId(tenantId)); |
|||
} |
|||
if (customerId != null) { |
|||
dashboard.setCustomerId(new CustomerId(customerId)); |
|||
} |
|||
dashboard.setTitle(title); |
|||
dashboard.setConfiguration(configuration); |
|||
return dashboard; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,186 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import org.thingsboard.server.common.data.id.DeviceCredentialsId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
import org.thingsboard.server.dao.model.type.DeviceCredentialsTypeCodec; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
|
|||
@Table(name = ModelConstants.DEVICE_CREDENTIALS_COLUMN_FAMILY_NAME) |
|||
public final class DeviceCredentialsEntity implements BaseEntity<DeviceCredentials> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = -2667310560260623272L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ModelConstants.ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@Column(name = ModelConstants.DEVICE_CREDENTIALS_DEVICE_ID_PROPERTY) |
|||
private UUID deviceId; |
|||
|
|||
@Column(name = ModelConstants.DEVICE_CREDENTIALS_CREDENTIALS_TYPE_PROPERTY, codec = DeviceCredentialsTypeCodec.class) |
|||
private DeviceCredentialsType credentialsType; |
|||
|
|||
@Column(name = ModelConstants.DEVICE_CREDENTIALS_CREDENTIALS_ID_PROPERTY) |
|||
private String credentialsId; |
|||
|
|||
@Column(name = ModelConstants.DEVICE_CREDENTIALS_CREDENTIALS_VALUE_PROPERTY) |
|||
private String credentialsValue; |
|||
|
|||
public DeviceCredentialsEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public DeviceCredentialsEntity(DeviceCredentials deviceCredentials) { |
|||
if (deviceCredentials.getId() != null) { |
|||
this.id = deviceCredentials.getId().getId(); |
|||
} |
|||
if (deviceCredentials.getDeviceId() != null) { |
|||
this.deviceId = deviceCredentials.getDeviceId().getId(); |
|||
} |
|||
this.credentialsType = deviceCredentials.getCredentialsType(); |
|||
this.credentialsId = deviceCredentials.getCredentialsId(); |
|||
this.credentialsValue = deviceCredentials.getCredentialsValue(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public UUID getDeviceId() { |
|||
return deviceId; |
|||
} |
|||
|
|||
public void setDeviceId(UUID deviceId) { |
|||
this.deviceId = deviceId; |
|||
} |
|||
|
|||
public DeviceCredentialsType getCredentialsType() { |
|||
return credentialsType; |
|||
} |
|||
|
|||
public void setCredentialsType(DeviceCredentialsType credentialsType) { |
|||
this.credentialsType = credentialsType; |
|||
} |
|||
|
|||
public String getCredentialsId() { |
|||
return credentialsId; |
|||
} |
|||
|
|||
public void setCredentialsId(String credentialsId) { |
|||
this.credentialsId = credentialsId; |
|||
} |
|||
|
|||
public String getCredentialsValue() { |
|||
return credentialsValue; |
|||
} |
|||
|
|||
public void setCredentialsValue(String credentialsValue) { |
|||
this.credentialsValue = credentialsValue; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((credentialsId == null) ? 0 : credentialsId.hashCode()); |
|||
result = prime * result + ((credentialsType == null) ? 0 : credentialsType.hashCode()); |
|||
result = prime * result + ((credentialsValue == null) ? 0 : credentialsValue.hashCode()); |
|||
result = prime * result + ((deviceId == null) ? 0 : deviceId.hashCode()); |
|||
result = prime * result + ((id == null) ? 0 : id.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; |
|||
DeviceCredentialsEntity other = (DeviceCredentialsEntity) obj; |
|||
if (credentialsId == null) { |
|||
if (other.credentialsId != null) |
|||
return false; |
|||
} else if (!credentialsId.equals(other.credentialsId)) |
|||
return false; |
|||
if (credentialsType != other.credentialsType) |
|||
return false; |
|||
if (credentialsValue == null) { |
|||
if (other.credentialsValue != null) |
|||
return false; |
|||
} else if (!credentialsValue.equals(other.credentialsValue)) |
|||
return false; |
|||
if (deviceId == null) { |
|||
if (other.deviceId != null) |
|||
return false; |
|||
} else if (!deviceId.equals(other.deviceId)) |
|||
return false; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("DeviceCredentialsEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", deviceId="); |
|||
builder.append(deviceId); |
|||
builder.append(", credentialsType="); |
|||
builder.append(credentialsType); |
|||
builder.append(", credentialsId="); |
|||
builder.append(credentialsId); |
|||
builder.append(", credentialsValue="); |
|||
builder.append(credentialsValue); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials toData() { |
|||
DeviceCredentials deviceCredentials = new DeviceCredentials(new DeviceCredentialsId(id)); |
|||
deviceCredentials.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
if (deviceId != null) { |
|||
deviceCredentials.setDeviceId(new DeviceId(deviceId)); |
|||
} |
|||
deviceCredentials.setCredentialsType(credentialsType); |
|||
deviceCredentials.setCredentialsId(credentialsId); |
|||
deviceCredentials.setCredentialsValue(credentialsValue); |
|||
return deviceCredentials; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,214 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* Licensed 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.thingsboard.server.dao.model; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.dao.model.ModelConstants.*; |
|||
|
|||
@Table(name = DEVICE_COLUMN_FAMILY_NAME) |
|||
public final class DeviceEntity implements SearchTextEntity<Device> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = -1265181166886910152L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@PartitionKey(value = 1) |
|||
@Column(name = DEVICE_TENANT_ID_PROPERTY) |
|||
private UUID tenantId; |
|||
|
|||
@PartitionKey(value = 2) |
|||
@Column(name = DEVICE_CUSTOMER_ID_PROPERTY) |
|||
private UUID customerId; |
|||
|
|||
@Column(name = DEVICE_NAME_PROPERTY) |
|||
private String name; |
|||
|
|||
@Column(name = SEARCH_TEXT_PROPERTY) |
|||
private String searchText; |
|||
|
|||
@Column(name = DEVICE_ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode additionalInfo; |
|||
|
|||
public DeviceEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public DeviceEntity(Device device) { |
|||
if (device.getId() != null) { |
|||
this.id = device.getId().getId(); |
|||
} |
|||
if (device.getTenantId() != null) { |
|||
this.tenantId = device.getTenantId().getId(); |
|||
} |
|||
if (device.getCustomerId() != null) { |
|||
this.customerId = device.getCustomerId().getId(); |
|||
} |
|||
this.name = device.getName(); |
|||
this.additionalInfo = device.getAdditionalInfo(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public UUID getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
public void setTenantId(UUID tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
public UUID getCustomerId() { |
|||
return customerId; |
|||
} |
|||
|
|||
public void setCustomerId(UUID customerId) { |
|||
this.customerId = customerId; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public JsonNode getAdditionalInfo() { |
|||
return additionalInfo; |
|||
} |
|||
|
|||
public void setAdditionalInfo(JsonNode additionalInfo) { |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchTextSource() { |
|||
return name; |
|||
} |
|||
|
|||
@Override |
|||
public void setSearchText(String searchText) { |
|||
this.searchText = searchText; |
|||
} |
|||
|
|||
public String getSearchText() { |
|||
return searchText; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); |
|||
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
|||
result = prime * result + ((id == null) ? 0 : id.hashCode()); |
|||
result = prime * result + ((name == null) ? 0 : name.hashCode()); |
|||
result = prime * result + ((tenantId == null) ? 0 : tenantId.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; |
|||
DeviceEntity other = (DeviceEntity) obj; |
|||
if (additionalInfo == null) { |
|||
if (other.additionalInfo != null) |
|||
return false; |
|||
} else if (!additionalInfo.equals(other.additionalInfo)) |
|||
return false; |
|||
if (customerId == null) { |
|||
if (other.customerId != null) |
|||
return false; |
|||
} else if (!customerId.equals(other.customerId)) |
|||
return false; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
if (name == null) { |
|||
if (other.name != null) |
|||
return false; |
|||
} else if (!name.equals(other.name)) |
|||
return false; |
|||
if (tenantId == null) { |
|||
if (other.tenantId != null) |
|||
return false; |
|||
} else if (!tenantId.equals(other.tenantId)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("DeviceEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", tenantId="); |
|||
builder.append(tenantId); |
|||
builder.append(", customerId="); |
|||
builder.append(customerId); |
|||
builder.append(", name="); |
|||
builder.append(name); |
|||
builder.append(", additionalInfo="); |
|||
builder.append(additionalInfo); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public Device toData() { |
|||
Device device = new Device(new DeviceId(id)); |
|||
device.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
if (tenantId != null) { |
|||
device.setTenantId(new TenantId(tenantId)); |
|||
} |
|||
if (customerId != null) { |
|||
device.setCustomerId(new CustomerId(customerId)); |
|||
} |
|||
device.setName(name); |
|||
device.setAdditionalInfo(additionalInfo); |
|||
return device; |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue