package eu.ttbox.androgister.web.rest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.common.base.Function;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import eu.ttbox.androgister.model.Product;
import eu.ttbox.androgister.repository.ProductRepository;
@Controller
@RequestMapping("/product")
@Transactional(propagation = Propagation.REQUIRED, readOnly = true, timeout = 1000)
public class ProductService {
private static final Logger LOG = LoggerFactory.getLogger(ProductService.class);
@Autowired
public ProductRepository productRepository;
@RequestMapping(value = "/{productId}", method = RequestMethod.GET)
@ResponseBody
public Product getById(@PathVariable UUID productId) {
Product product = productRepository.findById(productId);
return product;
}
@RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=application/json")
@ResponseBody
public List<Product> findProduct(@RequestParam(value = "s", defaultValue = "0") int firstResult, @RequestParam(value = "p", defaultValue = "10") int maxResult) {
List<Product> entities = null;
try {
entities = productRepository.findAll(); // firstResult, maxResult
} catch (Exception e) {
LOG.error("Error find all product " + e.getMessage(), e);
}
return entities;
}
// @Transactional(propagation = Propagation.REQUIRED)
// @RequestMapping(value = "/sync", method = RequestMethod.POST, consumes =
// MediaType.APPLICATION_JSON_VALUE)
// @ResponseBody
// public List<Product> syncProducts(@RequestBody List<Product> products) {
//
// LOG.info("Sync {} products ", products.size());
// return products;
// }
@Transactional(propagation = Propagation.REQUIRED)
@RequestMapping(value = "/sync", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public void syncProducts(@RequestParam(value = "syncstate", defaultValue = "-1") long syncstate, HttpServletRequest request, HttpServletResponse response) throws IOException, ConnectionException {
long begin = System.currentTimeMillis();
LOG.info("Sync Begin products : Last Sync State {}", syncstate);
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
MappingJsonFactory jsonFactory = new MappingJsonFactory(mapper);
// Prepare Writer
response.setContentType("application/json;charset=UTF-8");
// wrapper.setHeader("Content-length", "" +
// jsonContent.getBytes().length);
OutputStream os = response.getOutputStream();
final JsonGenerator jgen = jsonFactory.createGenerator(os, JsonEncoding.UTF8);
jgen.writeStartArray();
// ServletServerHttpResponse responseHeader = new
// ServletServerHttpResponse(response);
// MappingJackson2HttpMessageConverter jsonConverter = new
// MappingJackson2HttpMessageConverter();
// MediaType jsonMimeType = MediaType.APPLICATION_JSON;
// jsonConverter.write(entity, jsonMimeType,responseHeader);
// Read The file
BufferedReader is = request.getReader();
JsonParser jp = jsonFactory.createJsonParser(is);
// advance stream to START_ARRAY first:
JsonToken firstToken = jp.nextToken();
if (firstToken != JsonToken.START_ARRAY) {
throw new RuntimeException("Invalid Format");
}
final HashMap<UUID, Long> updatedEntity = new HashMap<UUID, Long>();
while (jp.nextToken() == JsonToken.START_OBJECT) {
// Read Entity
Product entity = mapper.readValue(jp, Product.class);
// Save Entity
LOG.debug("Read Product entity : {}", entity);
productRepository.persist(entity, begin);
updatedEntity.put(entity.serverId, entity.versionDate);
// Write the status
mapper.writeValue(jgen, entity);
jgen.flush();
}
// Read Other modify
Function<Product, Boolean> callback = new Function<Product, Boolean>() {
@Override
public Boolean apply(Product entity) {
try {
Long clientVersion = updatedEntity.get(entity.serverId);
if (clientVersion==null || !clientVersion.equals(entity.versionDate)) {
// Send server version
mapper.writeValue(jgen, entity);
}
} catch (Exception e) {
LOG.error("Callback read error : " + e.getMessage(), e);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
};
String salespointId = "ttbox"; // TODO
productRepository.findEntityUpdatedFrom(salespointId,syncstate, callback);
jp.close();
is.close();
// Close Writer
jgen.writeEndArray();
jgen.close();
long end = System.currentTimeMillis();
LOG.info("Sync {} products in {} ms", "End", (end-begin));
}
@Transactional(propagation = Propagation.REQUIRED)
@RequestMapping(value = "/init", method = RequestMethod.GET)
@ResponseBody
public int initProductList() {
int count = 0;
for (int i = 1; i < 20; i++) {
Product product = createMockProduct(i);
productRepository.persist(product);
LOG.debug("persist Product : {} ", product);
count++;
}
return count;
}
private Product createMockProduct(int productId) {
Product product = new Product();
// product.id = Long.valueOf(productId);
product.name = "Product name " + productId;
product.description = "Product name " + productId;
product.salepointId = "ttbox";
product.priceHT = Long.valueOf(productId);
return product;
}
}