Read Scheduler(Fixed-delay) from Database in Spring boot - spring-boot

I'm developing a spring boot project which uses spring batch scheduler to read data after 2 sec's and send it to the message broker (Activemq) which works fine with hardcoded fixed delay.
However, i'm now trying to read the #Scheduled(fixedDelay) from database rather hard coded but looks like nothing is working out. I can see the expression contains 10 secs but scheduler doesn't start
#Service
public class QuoteService implements ApplicationListener<BrokerAvailabilityEvent> {
private static Log logger = LogFactory.getLog(QuoteService.class);
private final MessageSendingOperations<String> messagingTemplate;
private final StockQuoteGenerator quoteGenerator = new StockQuoteGenerator();
private AtomicBoolean brokerAvailable = new AtomicBoolean();
private ReadCronExpressionDataService readCronExpressionDataService;
private int expression;
#Autowired
public QuoteService(MessageSendingOperations<String> messagingTemplate,ReadCronExpressionDataService readCronExpressionDataService) {
this.messagingTemplate = messagingTemplate;
this.readCronExpressionDataService=readCronExpressionDataService;
expression = readCronExpressionDataService.readData();
}
#Scheduled(fixedDelay=expression) //#Scheduled(fixedDelay=2000)
public void sendQuotes() {
for (Quote quote : this.quoteGenerator.generateQuotes()) {
if (logger.isTraceEnabled()) {
logger.trace("Sending quote " + quote);
}
if (this.brokerAvailable.get()) {
this.messagingTemplate.convertAndSend("/topic/price.stock." + quote.getTicker(), quote);
}
}
}
private static class StockQuoteGenerator {
private static final MathContext mathContext = new MathContext(2);
private final Random random = new Random();
private final Map<String, String> prices = new ConcurrentHashMap<>();
public StockQuoteGenerator() {
this.prices.put("CTXS", "24.30");
this.prices.put("DELL", "13.03");
this.prices.put("EMC", "24.13");
this.prices.put("GOOG", "893.49");
this.prices.put("MSFT", "34.21");
this.prices.put("ORCL", "31.22");
this.prices.put("RHT", "48.30");
this.prices.put("VMW", "66.98");
}
public Set<Quote> generateQuotes() {
Set<Quote> quotes = new HashSet<>();
for (String ticker : this.prices.keySet()) {
BigDecimal price = getPrice(ticker);
quotes.add(new Quote(ticker, price));
}
return quotes;
}
private BigDecimal getPrice(String ticker) {
BigDecimal seedPrice = new BigDecimal(this.prices.get(ticker), mathContext);
double range = seedPrice.multiply(new BigDecimal(0.02)).doubleValue();
BigDecimal priceChange = new BigDecimal(String.valueOf(this.random.nextDouble() * range), mathContext);
return seedPrice.add(priceChange);
}
}
}
Any idea?

Related

How can we mock Objects/REST Call when using FeignClient in Spring Boot (Microservices)?

I am working on Micro-Services Project and a requirement came where the communication between 2 micro-services need to happen. So, I used FeignClient Interface Approach to get it done.
Here is the FeignClientInterface.java Class:
#AuthorizedFeignClient(name = "fcfhpickorders")
public interface FCFHPickOrderService {
#PutMapping(value = "/api/prescriptions/prescriptionCode", consumes = {"application/json", "application/merge-patch+json"})
public ResponseEntity<PrescriptionDTO> updatePrescriptionForBucketKey(
#NotNull #RequestBody PrescriptionDTO prescriptionDTO
);
}
Below is the function where I used the above declared function:
public Bucket setLinkedPrescriptionCode(Bucket bucket) {
if (bucket.getLinkedPrescriptionCode() != null) {
PrescriptionDTO prescription = new PrescriptionDTO();
prescription.setBucketKey(bucket.getBucketKey());
prescription.setPrescriptionCode(bucket.getLinkedPrescriptionCode());
ResponseEntity<PrescriptionDTO> prescriptionDTOResponseEntity = fcfhPickOrderService.updatePrescriptionForBucketKey(prescription);
if(prescriptionDTOResponseEntity.getStatusCode().isError()) {
bucket.setLinkedPrescriptionCode(null);
bucketRepository.save(bucket);
throw new ResourceNotFoundException("Prescription with " + bucket.getLinkedPrescriptionCode() + "Not Found");
}
}
return bucket;
}
I used the setLinkedPrescriptionCode(Bucket bucket) function while saving and updating an existing bucket. It worked fine.
I have some previously written test cases for creation and updation of bucket that are failing now because of the addition of the REST call.
#IntegrationTest
#ExtendWith(MockitoExtension.class)
#AutoConfigureMockMvc
#WithMockUser
class BucketResourceIT {
private static final String DEFAULT_BUCKET_KEY = "AAAAAAAAAA";
private static final String UPDATED_BUCKET_KEY = "BBBBBBBBBB";
private static final String DEFAULT_QR_CODE = "AAAAAAAAAA";
private static final String UPDATED_QR_CODE = "BBBBBBBBBB";
private static final String DEFAULT_LINKED_PRESCRIPTION_CODE = "AAAAAAAAAA";
private static final String UPDATED_LINKED_PRESCRIPTION_CODE = "BBBBBBBBBB";
private static final String ENTITY_API_URL = "/api/buckets";
private static final String ENTITY_API_URL_ID = ENTITY_API_URL + "/{id}";
private static Random random = new Random();
private static AtomicLong count = new AtomicLong(random.nextInt() + (2 * Integer.MAX_VALUE));
#Autowired
private BucketRepository bucketRepository;
#Mock
private BucketRepository bucketRepositoryMock;
#Autowired
private BucketMapper bucketMapper;
#Mock
private BucketService bucketServiceMock;
#Autowired
private EntityManager em;
#Autowired
private MockMvc restBucketMockMvc;
private Bucket bucket;
#Mock
private FCFHPickOrderService fcfhPickOrderService;
public static Bucket createEntity(EntityManager em) {
Bucket bucket = new Bucket()
.bucketKey(DEFAULT_BUCKET_KEY)
.qrCode(DEFAULT_QR_CODE)
.linkedPrescriptionCode(DEFAULT_LINKED_PRESCRIPTION_CODE);
return bucket;
}
public static Bucket createUpdatedEntity(EntityManager em) {
Bucket bucket = new Bucket()
.bucketKey(UPDATED_BUCKET_KEY)
.qrCode(UPDATED_QR_CODE)
.linkedPrescriptionCode(UPDATED_LINKED_PRESCRIPTION_CODE);
return bucket;
}
#BeforeEach
public void initTest() {
bucket = createEntity(em);
}
#Test
#Transactional
void createBucket() throws Exception {
int databaseSizeBeforeCreate = bucketRepository.findAll().size();
// Create the Bucket
BucketDTO bucketDTO = bucketMapper.toDto(bucket);
restBucketMockMvc
.perform(
post(ENTITY_API_URL)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(bucketDTO))
)
*.andExpect(status().isCreated());*
// Validate the Bucket in the database
List<Bucket> bucketList = bucketRepository.findAll();
assertThat(bucketList).hasSize(databaseSizeBeforeCreate + 1);
Bucket testBucket = bucketList.get(bucketList.size() - 1);
assertThat(testBucket.getBucketKey()).isEqualTo(DEFAULT_BUCKET_KEY);
assertThat(testBucket.getQrCode()).isEqualTo(DEFAULT_QR_CODE);
assertThat(testBucket.getLinkedPrescriptionCode()).isEqualTo(DEFAULT_LINKED_PRESCRIPTION_CODE);
}
#Test
#Transactional
void putNewBucket() throws Exception {
bucketRepository.saveAndFlush(bucket);
int databaseSizeBeforeUpdate = bucketRepository.findAll().size();
// Update the bucket
Bucket updatedBucket = bucketRepository.findById(bucket.getId()).get();
// Disconnect from session so that the updates on updatedBucket are not directly saved in db
em.detach(updatedBucket);
updatedBucket.bucketKey(UPDATED_BUCKET_KEY).qrCode(UPDATED_QR_CODE).linkedPrescriptionCode(UPDATED_LINKED_PRESCRIPTION_CODE);
BucketDTO bucketDTO = bucketMapper.toDto(updatedBucket);
restBucketMockMvc
.perform(
put(ENTITY_API_URL_ID, bucketDTO.getId())
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(bucketDTO))
)
*.andExpect(status().isOk());*
// Validate the Bucket in the database
List<Bucket> bucketList = bucketRepository.findAll();
assertThat(bucketList).hasSize(databaseSizeBeforeUpdate);
Bucket testBucket = bucketList.get(bucketList.size() - 1);
assertThat(testBucket.getBucketKey()).isEqualTo(UPDATED_BUCKET_KEY);
assertThat(testBucket.getQrCode()).isEqualTo(UPDATED_QR_CODE);
assertThat(testBucket.getLinkedPrescriptionCode()).isEqualTo(UPDATED_LINKED_PRESCRIPTION_CODE);
}
How should I update the above tests in order to fix the Assertion Errors that I am receiving?
BucketResourceIT > createBucket() FAILED
java.lang.AssertionError at BucketResourceIT.java:133
BucketResourceIT > putNewBucket() FAILED
java.lang.AssertionError at BucketResourceIT.java:294

Cannot Write Data to ElasticSearch with AbstractReactiveElasticsearchConfiguration

I am trying out to write data to my local Elasticsearch Docker Container (7.4.2), for simplicity I used the AbstractReactiveElasticsearchConfiguration given from Spring also Overriding the entityMapper function. The I constructed my repository extending the ReactiveElasticsearchRepository
Then in the end I used my autowired repository to saveAll() my collection of elements containing the data. However Elasticsearch doesn't write any data. Also i have a REST controller which is starting my whole process returning nothing basicly, DeferredResult>
The REST method coming from my ApiDelegateImpl
#Override
public DeferredResult<ResponseEntity<Void>> openUsageExporterStartPost() {
final DeferredResult<ResponseEntity<Void>> deferredResult = new DeferredResult<>();
ForkJoinPool.commonPool().execute(() -> {
try {
openUsageExporterAdapter.startExport();
deferredResult.setResult(ResponseEntity.accepted().build());
} catch (Exception e) {
deferredResult.setErrorResult(e);
}
}
);
return deferredResult;
}
My Elasticsearch Configuration
#Configuration
public class ElasticSearchConfig extends AbstractReactiveElasticsearchConfiguration {
#Value("${spring.data.elasticsearch.client.reactive.endpoints}")
private String elasticSearchEndpoint;
#Bean
#Override
public EntityMapper entityMapper() {
final ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}
#Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(elasticSearchEndpoint)
.build();
return ReactiveRestClients.create(clientConfiguration);
}
}
My Repository
public interface OpenUsageRepository extends ReactiveElasticsearchRepository<OpenUsage, Long> {
}
My DTO
#Data
#Document(indexName = "open_usages", type = "open_usages")
#TypeAlias("OpenUsage")
public class OpenUsage {
#Field(name = "id")
#Id
private Long id;
......
}
My Adapter Implementation
#Autowired
private final OpenUsageRepository openUsageRepository;
...transform entity into OpenUsage...
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
And finally my IT test
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#Testcontainers
#TestPropertySource(locations = {"classpath:application-it.properties"})
#ContextConfiguration(initializers = OpenUsageExporterApplicationIT.Initializer.class)
class OpenUsageExporterApplicationIT {
#LocalServerPort
private int port;
private final static String STARTCALL = "http://localhost:%s/open-usage-exporter/start/";
#Container
private static ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:6.8.4").withExposedPorts(9200);
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(final ConfigurableApplicationContext configurableApplicationContext) {
final List<String> pairs = new ArrayList<>();
pairs.add("spring.data.elasticsearch.client.reactive.endpoints=" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
pairs.add("spring.elasticsearch.rest.uris=http://" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
TestPropertyValues.of(pairs).applyTo(configurableApplicationContext);
}
}
#Test
void testExportToES() throws IOException, InterruptedException {
final List<OpenUsageEntity> openUsageEntities = dbPreparator.insertTestData();
assertTrue(openUsageEntities.size() > 0);
final String result = executeRestCall(STARTCALL);
// Awaitility here tells me nothing is in ElasticSearch :(
}
private String executeRestCall(final String urlTemplate) throws IOException {
final String url = String.format(urlTemplate, port);
final HttpUriRequest request = new HttpPost(url);
final HttpResponse response = HttpClientBuilder.create().build().execute(request);
// Get the result.
return EntityUtils.toString(response.getEntity());
}
}
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
This lacks a semicolon at the end, so it should not compile.
But I assume this is just a typo, and there is a semicolon in reality.
Anyway, saveAll() returns a Flux. This Flux is just a recipe for saving your data, and it is not 'executed' until subscribe() is called by someone (or something like blockLast()). You just throw that Flux away, so the saving never gets executed.
How to fix this? One option is to add .blockLast() call:
openUsageRepository.saveAll(openUsages).blockLast();
But this will save the data in a blocking way effectively defeating the reactivity.
Another option is, if the code you are calling saveAll() from supports reactivity is just to return the Flux returned by saveAll(), but, as your doSomething() has void return type, this is doubtful.
It is not seen how your startExport() connects to doSomething() anyway. But it looks like your 'calling code' does not use any notion of reactivity, so a real solution would be to either rewrite the calling code to use reactivity (obtain a Publisher and subscribe() on it, then wait till the data arrives), or revert to using blocking API (ElasticsearchRepository instead of ReactiveElasticsearchRepository).

Couchbase 5 bucket password setting

I am trying to write a sample in order to learn couchbase. I am trying to use it with spring boot and it’s crud repositories .
So I have downloaded latest docker image but the point is: i could not find the password of the bucket. The couchbase console allows only user creation but in spring, there is no equivalent of this usage like a username/password. It allows only bucketName and password which does not seem compatible with couchbase 5.
Am I missing anything here or is spring not compatible with couchbase 5? If spring is not compatible, which version of couchbase is ok?
Thx
Spring Data Couchbase is compatible with Couchbase Server 5.0. You can achieve the same auth as 4.x by creating a user with the same name as the bucket, then just use that bucket name and password from Spring Data if it's prior to 3.0/Kay.
The docs should cover this and if there's anything confusing there, please click the "feedback" button and offer what could be improved!
https://developer.couchbase.com/documentation/server/5.0/security/security-authorization.html
https://developer.couchbase.com/documentation/server/5.0/security/concepts-rba-for-apps.html
https://developer.couchbase.com/documentation/server/5.0/security/security-resources-under-access-control.html
I faced the same issue. I started debugging by getting into AbstractCouchbaseConfiguration and there i found
public abstract class AbstractCouchbaseConfiguration
extends AbstractCouchbaseDataConfiguration implements CouchbaseConfigurer {
....//some other configuration
#Override
#Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info();
}
What i did is created a bucket with the same name as of my couchbase user.
couchbase username : userdetail
couchbase password : ******
bucket name : userdetail
Couchbase driver supports connection to Couchbase 5 buckets using username/password. Problem is that spring-data-couchbase is not developed fast enough to cover all the new features Couchbase introduces. So, we need to help Spring to use a new bucket connection, doing it by overriding Couchbase cluster instantiation method of spring-data-couchbase configuration base class - org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration. This is the method we are looking at :
#Override
#Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info();
}
as we can see, it's not using username, just bucket and password, so in our configuration we will override it as following :
#Override
#Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().authenticate(couchbaseUsername, couchbasePassword).clusterManager().info();
}
that's it. Here is the full code of my spring-data-couchbase configuration :
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.cluster.ClusterInfo;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.config.BeanNames;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import javax.inject.Inject;
import java.security.KeyStore;
import java.util.List;
/**
* #author by avoinovan
*/
#Configuration
#EnableCouchbaseRepositories
public class ModelConfig extends AbstractCouchbaseConfiguration {
private final static int DEFAULT_HTTP_PORT = 8091;
private final static int DEFAULT_HTTP_SSL_PORT = 18091;
private final static int DEFAULT_CARRIER_PORT = 11210;
private final static int DEFAULT_CARRIER_SSL_PORT = 11207;
private final static long DEFAULT_KEEP_ALIVE_INTERVAL = 30000;
private final static int DEFAULT_SOCKET_CONNECT_TIMEOUT_MS = 5000;
private final static long DEFAULT_CONNECT_TIMEOUT_MS = 5000;
private final static long DEFAULT_MANAGEMENT_TIMEOUT_MS = 75000;
private final static long DEFAULT_DISCONNECT_TIMEOUT_MS = 25000;
private final static String PROPERTY_KEEP_ALIVE_INTERVAL_MS = "couchbase.keep_alive_interval_ms";
private final static String PROPERTY_SOCKET_CONNECT_TIMEOUT_MS = "couchbase.socket_connect_timeout_ms";
private final static String PROPERTY_CONNECT_TIMEOUT_MS = "couchbase.connect_timeout_ms";
private final static String PROPERTY_MANAGEMENT_TIMEOUT_MS = "couchbase.management_timeout_ms";
private final static String PROPERTY_DISCONNECT_TIMEOUT_MS = "couchbase.disconnect_timeout_ms";
private final static String PROPERTY_SSL_ENABLED = "couchbase.ssl.enabled";
private final static String PROPERTY_SSL_KEYSTORE_FILE = "couchbase.ssl.keystore.file";
private final static String PROPERTY_SSL_KEYSTORE_PASSWORD = "couchbase.ssl.keystore.password";
private final static String PROPERTY_SSL_TRUSTSTORE_FILE = "couchbase.ssl.truststore.file";
private final static String PROPERTY_SSL_TRUSTSTORE_PASSWORD = "couchbase.ssl.truststore.password";
private final static String PROPERTY_BOOTSTRAP_HTTP_ENABLED = "couchbase.bootstrap.http.enabled";
private final static String PROPERTY_BOOTSTRAP_HTTP_PORT = "couchbase.bootstrap.http.port";
private final static String PROPERTY_BOOTSTRAP_HTTP_SSL_PORT = "couchbase.bootstrap.http.ssl.port";
private final static String PROPERTY_BOOTSTRAP_CARRIER_ENABLED = "couchbase.bootstrap.carrier.enabled";
private final static String PROPERTY_BOOTSTRAP_CARRIER_PORT = "couchbase.bootstrap.carrier.port";
private final static String PROPERTY_BOOTSTRAP_CARRIER_SSL_PORT = "couchbase.bootstrap.carrier.ssl.port";
#Value("#{'${spring.couchbase.bootstrap-hosts}'.split(',')}")
private List<String> couchbaseBootstrapHosts;
#Value("${spring.couchbase.bucket.name}")
private String bucketName;
#Value("${spring.couchbase.password}")
private String couchbasePassword;
#Value("${spring.couchbase.username}")
private String couchbaseUsername;
private final Environment environment;
private final ResourceLoader resourceLoader;
#Inject
public ModelConfig(final Environment environment,
final ResourceLoader resourceLoader) {
this.environment = environment;
this.resourceLoader = resourceLoader;
}
protected List<String> getBootstrapHosts() {
return couchbaseBootstrapHosts;
}
protected String getBucketName() {
return bucketName;
}
protected String getBucketPassword() {
return couchbasePassword;
}
protected CouchbaseEnvironment getEnvironment() {
return DefaultCouchbaseEnvironment.builder()
.keepAliveInterval(environment.getProperty(PROPERTY_KEEP_ALIVE_INTERVAL_MS,
Long.class,
DEFAULT_KEEP_ALIVE_INTERVAL))
// timeout settings
.socketConnectTimeout(environment.getProperty(PROPERTY_SOCKET_CONNECT_TIMEOUT_MS,
Integer.class,
DEFAULT_SOCKET_CONNECT_TIMEOUT_MS))
.connectTimeout(environment.getProperty(PROPERTY_CONNECT_TIMEOUT_MS,
Long.class,
DEFAULT_CONNECT_TIMEOUT_MS))
.managementTimeout(environment.getProperty(PROPERTY_MANAGEMENT_TIMEOUT_MS,
Long.class,
DEFAULT_MANAGEMENT_TIMEOUT_MS))
.disconnectTimeout(environment.getProperty(PROPERTY_DISCONNECT_TIMEOUT_MS,
Long.class,
DEFAULT_DISCONNECT_TIMEOUT_MS))
// port and ssl
.sslEnabled(environment.getProperty(PROPERTY_SSL_ENABLED, Boolean.class, false))
.bootstrapHttpEnabled(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_ENABLED,
Boolean.class,
Boolean.TRUE))
.bootstrapHttpDirectPort(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_PORT,
Integer.class,
DEFAULT_HTTP_PORT))
.bootstrapHttpSslPort(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_SSL_PORT,
Integer.class,
DEFAULT_HTTP_SSL_PORT))
.bootstrapCarrierEnabled(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_ENABLED,
Boolean.class,
Boolean.TRUE))
.bootstrapCarrierDirectPort(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_PORT,
Integer.class,
DEFAULT_CARRIER_PORT))
.bootstrapCarrierSslPort(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_SSL_PORT,
Integer.class,
DEFAULT_CARRIER_SSL_PORT))
// keystore and trust store
.sslKeystore(createKeyStore(environment, resourceLoader))
.sslTruststore(createTrustStore(environment, resourceLoader))
.build();
}
#Override
#Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().authenticate(couchbaseUsername, couchbasePassword).clusterManager().info();
}
/**
* Return the {#link Bucket} instance to connect to.
*
* #throws Exception on Bean construction failure.
*/
#Override
#Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET)
public Bucket couchbaseClient() throws Exception {
//#Bean method can use another #Bean method in the same #Configuration by directly invoking it
return couchbaseCluster().openBucket(getBucketName());
}
private KeyStore createKeyStore(final Environment environment, final ResourceLoader resourceLoader) {
return loadKeyStore(environment, resourceLoader, PROPERTY_SSL_KEYSTORE_FILE, PROPERTY_SSL_KEYSTORE_PASSWORD);
}
private KeyStore createTrustStore(final Environment environment, final ResourceLoader resourceLoader) {
return loadKeyStore(environment, resourceLoader, PROPERTY_SSL_TRUSTSTORE_FILE, PROPERTY_SSL_TRUSTSTORE_PASSWORD);
}
private KeyStore loadKeyStore(final Environment environment,
final ResourceLoader resourceLoader,
final String fileProperty,
final String passwordProperty) {
String file = environment.getProperty(fileProperty);
String password = environment.getProperty(passwordProperty);
if (file != null) {
Resource resource = resourceLoader.getResource(file);
if (resource != null) {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(resource.getInputStream(), password == null ? null : password.toCharArray());
return keyStore;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
return null;
}
}

GWT 2.5 + Spring 3 + Hibernate 3 clear example

I saw questions about GWT + SPRING + HIBERNATE integration but none is clear or up to date with the current versions!
Please if there is anyone who has a clear and simple example of the integration (form submit and saving in DB) I will be extremely thankful!
If you could put the simple project in a ZIP and upload it (with its jars it will be great)
Thank you!
I guess this one using gwt 2.5.0-rc1, Spring 3.1.2.RELEASE and Hibernate 4 will be helpful. This project is using maven, so install maven which will take care of required dependencies. git clone it, command-line build with $ mvn clean install and dive into.
The basic gwt server-shared-client architecture is
Entity
#Entity
#Table(name = "TBL_BOOK")
public class Book implements Serializable {
private static final long serialVersionUID = -687874117917352477L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "TITLE", nullable = false)
private String title;
#Column(name = "SUBTITLE")
private String subtitle;
#Column(name = "AUTOR", nullable = false)
private String autor;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "ISBN")
private String isbn;
#Column(name = "GENRE")
private String genre;
#Temporal(TemporalType.DATE)
#Column(name = "PUBLISHED_DATE")
private Date publishedDate;
#Column(name = "PUBLISHER")
private String publisher;
public Book() {
}
public Book(Long id, String title, String subtitle, String autor,
String description, String isbn, String genre, Date publishedDate,
String publisher) {
this.id = id;
this.title = title;
this.subtitle = subtitle;
this.autor = autor;
this.description = description;
this.isbn = isbn;
this.genre = genre;
this.publishedDate = publishedDate;
this.publisher = publisher;
}
public Book(Book bookDTO) {
this.id = bookDTO.getId();
this.title = bookDTO.getTitle();
this.subtitle = bookDTO.getSubtitle();
this.autor = bookDTO.getAutor();
this.description = bookDTO.getDescription();
this.isbn = bookDTO.getIsbn();
this.genre = bookDTO.getGenre();
this.publishedDate = bookDTO.getPublishedDate();
this.publisher = bookDTO.getPublisher();
}
//getters and setters
#Override
public String toString() {
return "Book [id=" + id + ", title=" + title + ", subtitle=" + subtitle
+ ", author=" + autor + ", description=" + description
+ ", isbn=" + isbn + ", genre=" + genre + ", publishedDate="
+ publishedDate + ", publisher=" + publisher + "]";
}
}
web configuration
<!-- SpringGwt remote service servlet -->
<servlet>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<url-pattern>/GwtSpringHibernate/springGwtServices/*</url-pattern>
</servlet-mapping>
Client side stub for RPC
/**
* The client side stub for the RPC service.
*/
#RemoteServiceRelativePath("springGwtServices/bookService")
public interface BookService extends RemoteService {
public void saveOrUpdate(Book book) throws Exception;
public void delete(Book book) throws Exception;
public Book find(long id);
public List<Book> findAllEntries();
}
Server
#Service("bookService")
public class BookServiceImpl extends RemoteServiceServlet implements BookService {
private static final long serialVersionUID = -6547737229424190373L;
private static final Log LOG = LogFactory.getLog(BookServiceImpl.class);
#Autowired
private BookDAO bookDAO;
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void saveOrUpdate(Book book) throws Exception {
//
}
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void delete(Book book) throws Exception {
//
}
public Book find(long id) {
return bookDAO.findById(id);
}
public List<Book> findAllEntries() {
//
}
}
Client View
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GwtSpringHibernate implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
/**
* Create a remote service proxy to talk to the server-side Book service.
*/
private final BookServiceAsync bookService = GWT.create(BookService.class);
/**
* This is the entry point method.
*/
public void onModuleLoad() {
DateBox.DefaultFormat defaultFormatter = new DateBox.DefaultFormat(DateTimeFormat.getFormat("dd.MM.yyyy"));
// Add new Book Area
final TextBox titleField = new TextBox();
titleField.setFocus(true);
final TextBox subtitleField = new TextBox();
final TextBox autorField = new TextBox();
final TextBox descriptionField = new TextBox();
final TextBox isbnField = new TextBox();
final TextBox genreField = new TextBox();
final DateBox publishedDateField = new DateBox();
publishedDateField.setFormat(defaultFormatter);
final TextBox publisherField = new TextBox();
final Button saveButton = new Button("Save");
saveButton.addStyleName("button");
final Button retrieveButton = new Button("Retrieve");
retrieveButton.addStyleName("button");
final Label errorLabel = new Label();
// Add fields to the Rootpanel
RootPanel.get("title").add(titleField);
RootPanel.get("subtitle").add(subtitleField);
RootPanel.get("autor").add(autorField);
RootPanel.get("description").add(descriptionField);
RootPanel.get("isbn").add(isbnField);
RootPanel.get("genre").add(genreField);
RootPanel.get("publishedDate").add(publishedDateField);
RootPanel.get("publisher").add(publisherField);
RootPanel.get("btnSave").add(saveButton);
RootPanel.get("btnRetrieveAllEntries").add(retrieveButton);
RootPanel.get("errorLabelContainer").add(errorLabel);
// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
final HTML serverResponseLabel = new HTML();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending request to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);
// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
saveButton.setEnabled(true);
saveButton.setFocus(true);
retrieveButton.setEnabled(true);
}
});
class SaveBookHandler implements ClickHandler, KeyUpHandler {
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
saveBook();
}
}
public void onClick(ClickEvent arg0) {
saveBook();
}
private void saveBook() {
errorLabel.setText("");
String _title = titleField.getText();
String _subtitle = subtitleField.getText();
String _autor = autorField.getText();
String _desc = descriptionField.getText();
String _isbn = isbnField.getText();
String _genre = genreField.getText();
Date _publishedDate = publishedDateField.getValue();
String _publisher = publisherField.getText();
// First, we validate the input.
if (Validator.isBlank(_title) || Validator.isBlank(_autor)) {
String errorMessage = "Please enter at least the Title and the Autor of the book";
errorLabel.setText(errorMessage);
return;
}
Book bookDTO = new Book(null, _title, _subtitle, _autor, _desc, _isbn, _genre, _publishedDate, _publisher);
saveButton.setEnabled(false);
serverResponseLabel.setText("");
textToServerLabel.setText(bookDTO.toString());
bookService.saveOrUpdate(bookDTO, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
dialogBox.setText("Remote Procedure Call - Failure");
serverResponseLabel.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
dialogBox.center();
closeButton.setFocus(true);
}
public void onSuccess(Void noAnswer) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel.removeStyleName("serverResponseLabelError");
serverResponseLabel.setHTML("OK");
dialogBox.center();
closeButton.setFocus(true);
}
});
}
}
// Add a handler to send the book info to the server
SaveBookHandler saveBookHandler = new SaveBookHandler();
saveButton.addClickHandler(saveBookHandler);
publisherField.addKeyUpHandler(saveBookHandler);
// Create a handler for the retrieveButton
class RetrieveAllEntriesHandler implements ClickHandler {
/**
* Fired when the user clicks on the retrieveButton.
*/
public void onClick(ClickEvent event) {
retrieveAllEntries();
}
private void retrieveAllEntries() {
// Nothing to validate here
// Then, we send the input to the server.
retrieveButton.setEnabled(false);
errorLabel.setText("");
textToServerLabel.setText("");
serverResponseLabel.setText("");
bookService.findAllEntries(
new AsyncCallback<List<Book>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox.setText("Remote Procedure Call - Failure");
serverResponseLabel.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
dialogBox.center();
closeButton.setFocus(true);
}
public void onSuccess(List<Book> data) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel.removeStyleName("serverResponseLabelError");
if(data != null && !data.isEmpty()){
StringBuffer buffer = new StringBuffer();
for (Book book : data) {
buffer.append(book.toString());
buffer.append("<br /><br />");
}
serverResponseLabel.setHTML(buffer.toString());
} else {
serverResponseLabel.setHTML("No book information store in the database.");
}
dialogBox.center();
closeButton.setFocus(true);
}
});
}
}
// Add a handler
RetrieveAllEntriesHandler retrieveAllEntriesHandler = new RetrieveAllEntriesHandler();
retrieveButton.addClickHandler(retrieveAllEntriesHandler);
}
}
For more widgets, go through official widget library, UiBinder.
1) Download the zip file cited above from https://github.com/chieukam/gwt-spring-hibernate-tutorial/archive/master.zip and extract it somewhere
2) In Eclipse, create a new Maven project. Since there is no .project file provided in the above zip, you will need to confiugre all this manually.
3) Import "File System" from the place where you unzipped this project into your new Maven project.
At this point, I have some errors:
BookServiceAsync appears to be nonexistent, resulting in 6 compile errors.
"Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-war-plugin:2.1.1:exploded (execution: default, phase: compile)" in pom.xml, lines 162 and 185
This example seems to be somewhat incomplete. Am I missing something??

Not able to deserialize an object with with List using Gson api

Getting the following exception while deserializing an object:
com.google.gson.JsonParseException:
The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#1e2befa
failed to deserialized json object
{"com.gsicommerce.analytics.platform.model.webstore.AnalyticsProduct":
[
{"id":"3680231","longTitle":"Graco SnugRide Infant Car Seat - Pippin","available":"true"}
]
}
given the type com.google.gson.ParameterizedTypeImpl#b565dd
Here is the class that I am trying to deserialize:
public class TrusRegWishAddItemEvent implements Serializable {
static final long serialVersionUID = 1L;
private final List<AnalyticsProduct> items;
private TrusRegWishAddItemEvent() {
items = null;
}
public TrusRegWishAddItemEvent(List<AnalyticsProduct> items) {
this.items = items;
}
public List<AnalyticsProduct> getItems() {
return items;
}
}
public class AnalyticsProduct implements Serializable {
static final long serialVersionUID = 1L;
private final long id;
private final String longTitle;
private final boolean available;
public AnalyticsProduct() {
id = 0;
longTitle = null;
available = false;
}
public AnalyticsProduct(long id, String longTitle, boolean available) {
this.id = id;
this.longTitle = longTitle;
this.available = available;
}
public long getId() {
return id;
}
public String getLongTitle() {
return longTitle;
}
public boolean isAvailable() {
return available;
}
}
Please guide.
If the JSON is
{
"items":
[
{
"id":"3680231",
"longTitle":"Graco SnugRide Infant Car Seat - Pippin",
"available":"true"
}
]
}
then the following example uses Gson to easily deserialize/serialize to/from the same Java data structure in the original question.
public static void main(String[] args) throws Exception
{
Gson gson = new Gson();
TrusRegWishAddItemEvent thing = gson.fromJson(new FileReader("input.json"), TrusRegWishAddItemEvent.class);
System.out.println(gson.toJson(thing));
}
If instead the JSON must be
{"com.gsicommerce.analytics.platform.model.webstore.AnalyticsProduct":
[
{"id":"3680231","longTitle":"Graco SnugRide Infant Car Seat - Pippin","available":"true"}
]
}
then it's necessary to translate the JSON element name "com.gsicommerce.analytics.platform.model.webstore.AnalyticsProduct" to the Java member items. To do so, Gson provides a couple of mechanisms, the simplest of which is to just annotate the items attribute in TrusRegWishAddItemEvent as follows.
class TrusRegWishAddItemEvent implements Serializable
{
static final long serialVersionUID = 1L;
#SerializedName("com.gsicommerce.analytics.platform.model.webstore.AnalyticsProduct")
private final List<AnalyticsProduct> items;
...
}
But without this #SerializedName annotation Gson doesn't throw an exception when attempting to deserialize, instead it just constructs a TrusRegWishAddItemEvent instance with items as a null reference. So, it's not clear what was done to generate the error message in the original question.

Resources