Jersey Rest media streaming not working - java

I encounter this exception. How can I resolve it?
m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public javax.ws.rs.core.Response com.digit.spread.controller.VideoController.downloadVideo(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]: java.io.FileNotFoundException: videoFile (Le fichier sp▒cifi▒ est introuvable)
Code:
#RequestMapping(value = "download.do", method = RequestMethod.GET)
public Response downloadVideo(
#RequestParam(value = "videoId", required = true) String videoId,
HttpServletRequest request, HttpServletResponse response) throws IOException {
String mail = SecurityContextHolder.getContext()
.getAuthentication().getName();
System.out.println(mail+": Download video file starts . . . videoId:"+videoId);
Video video = videoBean.getVideoObject(videoId);
InputStream videoFile = videoBean.getVideoFile(video.getFileId());
long videoFileSize =videoBean.getVideoFileSize(video.getFileId());
String range = request.getHeader("Range") ;
final int chunk_size = 1024 * 1024; // 1MB chunks
if (range == null) {
StreamingOutput streamer = new StreamingOutput() {
#Override
public void write(final OutputStream output) throws IOException, WebApplicationException {
final FileChannel inputChannel = new FileInputStream("videoFile").getChannel();
final WritableByteChannel outputChannel = Channels.newChannel(output);
try {
inputChannel.transferTo(0, inputChannel.size(), outputChannel);
} finally {
// closing the channels
inputChannel.close();
outputChannel.close();
}
}
};
return Response.ok(streamer).header(HttpHeaders.CONTENT_LENGTH, videoFileSize).build();
}
String[] ranges = range.split("=")[1].split("-");
final int from = Integer.parseInt(ranges[0]);
/**
* Chunk media if the range upper bound is unspecified. Chrome sends "bytes=0-"
*/
int to = chunk_size + from;
if (to >= videoFileSize) {
to = (int) (videoFileSize- 1);
}
if (ranges.length == 2) {
to = Integer.parseInt(ranges[1]);
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, videoFileSize);
final RandomAccessFile raf = new RandomAccessFile("videoFile", "r");
raf.seek(from);
final int len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
Response.ResponseBuilder res = Response.ok(streamer).status(206)
.header("Accept-Ranges", "bytes")
.header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth());
return Response.ok(streamer).header(HttpHeaders.CONTENT_LENGTH, videoFileSize).build();
}

Related

SpringBoot Application cannot find wav file in linux server

I have a problem with springboot application that should work as a server for android application. I have audio file (.wav) that android application should receive from a server.
On local host it works very well, but when I make it on linux server there NullPointerException is appearing.
Here is my code of AudioController:
#RestController
#RequestMapping("/audiovideo")
public class AudioController {
public static final String AUDIO_PATH = "/root/audios/";
public static final int BYTE_RANGE = 128;
#GetMapping("/audios/{fileName}")
public Mono<ResponseEntity<byte[]>> streamAudio(#RequestHeader(value = "Range", required = false) String httpRangeList,
#PathVariable("fileName") String fileName) {
return Mono.just(getContent(AUDIO_PATH, fileName, httpRangeList, "audio"));
}
private ResponseEntity<byte[]> getContent(String location, String fileName, String range, String contentTypePrefix) {
long rangeStart = 0;
long rangeEnd;
byte[] data;
Long fileSize;
String fileType = fileName.substring(fileName.lastIndexOf(".")+1);
try {
fileSize = Optional.ofNullable(fileName)
.map(file -> Paths.get(getFilePath(location), file))
.map(this::sizeFromFile)
.orElse(0L);
if (range == null) {
return ResponseEntity.status(HttpStatus.OK)
.header("Content-Type", contentTypePrefix+"/" + fileType)
.header("Content-Length", String.valueOf(fileSize))
.body(readByteRange(location, fileName, rangeStart, fileSize - 1));
}
String[] ranges = range.split("-");
rangeStart = Long.parseLong(ranges[0].substring(6));
if (ranges.length > 1) {
rangeEnd = Long.parseLong(ranges[1]);
} else {
rangeEnd = fileSize - 1;
}
if (fileSize < rangeEnd) {
rangeEnd = fileSize - 1;
}
data = readByteRange(location, fileName, rangeStart, rangeEnd);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
String contentLength = String.valueOf((rangeEnd - rangeStart) + 1);
return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
.header("Content-Type", contentTypePrefix + "/" + fileType)
.header("Accept-Ranges", "bytes")
.header("Content-Length", contentLength)
.header("Content-Range", "bytes" + " " + rangeStart + "-" + rangeEnd + "/" + fileSize)
.body(data);
}
public byte[] readByteRange(String location, String filename, long start, long end) throws IOException {
Path path = Paths.get(getFilePath(location), filename);
try (InputStream inputStream = (Files.newInputStream(path));
ByteArrayOutputStream bufferedOutputStream = new ByteArrayOutputStream()) {
byte[] data = new byte[BYTE_RANGE];
int nRead;
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
bufferedOutputStream.write(data, 0, nRead);
}
bufferedOutputStream.flush();
byte[] result = new byte[(int) (end - start) + 1];
System.arraycopy(bufferedOutputStream.toByteArray(), (int) start, result, 0, result.length);
return result;
}
}
private String getFilePath(String location) {
URL url = this.getClass().getResource(location);
return new File(url.getFile()).getAbsolutePath();
}
private Long sizeFromFile(Path path) {
try {
return Files.size(path);
} catch (IOException ex) {
e.printStackTrace();
}
return 0L;
}
}
File is located in right path (/root/audios/[FileName])
Is there any solution of this problem?
P.S. There is another controller for music info but it works perfectly and I don't know why is the audio controller isn't working correctly
Here it is:
#RequestMapping("/musicinfo/jsons")
#RestController
public class APIController {
#GetMapping(value = "/{filename}")
public ResponseEntity<StreamingResponseBody> streamInfo(#PathVariable String filename) throws FileNotFoundException{
File file = ResourceUtils.getFile("/root/musicinfo/" + filename);
StreamingResponseBody responseBody = outputStream -> {
Files.copy(file.toPath(), outputStream);
};
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(responseBody);
}
}
Thanks forehead for help!!!

Does TUSClient support proxy

Please consider the below code. We are using TUSClient to upload large files in chunks.
public void uploadFile(UploadFileResponse uploadFileResponse, File file) {
try {
if (System.getProperty("sun.net.http.allowRestrictedHeaders") == null) {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
byte[] bytes = Files.readAllBytes(file.toPath());
Map headers = new HashMap();
headers.put("token", getToken());
headers.put("Content-Length", Integer.toString(bytes.length));
final TusUpload upload = new TusUpload(file);
TusClient client = new TusClient();
client.setUploadCreationURL(new URL(uploadFileResponse.getUploadUrl()));
client.setHeaders(headers);
client.enableResuming(new TusURLMemoryStore());
Integer chunkSize = 1024 * 1024 * 1;
Map metadata = new HashMap();
metadata.put("name", file.getName());
metadata.put("chunkSize", String.format("%d", chunkSize));
metadata.put("contentType", "text/xml");
upload.setMetadata(metadata);
TusExecutor executor = new TusExecutor() {
#Override
protected void makeAttempt() throws IOException, ProtocolException {
TusUploader uploader = client.resumeOrCreateUpload(upload);
uploader.setChunkSize(chunkSize);
int result = 0;
do {
result = uploader.uploadChunk();
} while (result > -1);
uploader.finish();
}
};
executor.makeAttempts();
}catch (Exception e){
throw new customException(e);
}
}
Now the above code worked in an environment where there was no proxy. Now if a proxy support is required, how to add proxy support in TUSClient.

Read rcon command response

I want to send rcon command to server using java, to do this I'm using the following library https://github.com/Kronos666/rkon-core
When i run command like this
Rcon rcon = new Rcon("127.0.0.1", 27015, "mypassword".getBytes());
// Example: On a minecraft server this will list the connected players
String result = rcon.command("list");
// Display the result in the console
System.out.println(result);
My server show response in console Gc connection established from... and so on
but in java app i have the empty result, it's not null, it's just empty
String result = rcon.command("list");
How can i take response from server using rcon protocol?
Try this:
try {
Rcon rcon = new Rcon("127.0.0.1", 27015, "mypassword".getBytes());
String result = rcon.command("list");
System.out.println(result);
} catch (AuthenticationException e) {
String result = "Authentication failed";
}
Finally I write my own implementation:
public final class RconClient implements AutoCloseable {
private static final int MAX_SIZE = 4096;
private final Socket socket;
private final RconData data;
private static final Logger LOG = LoggerFactory.getLogger(RconClient.class);
#SuppressWarnings("ConstructorShouldNotThrowExceptions")
public RconClient(final String host,
final int port,
final byte[] password) throws IOException {
this.socket = new Socket(host, port);
final RconData requst = request(new RconData(RconData.AUTH, password));
if (requst.getId() == -1) {
LOG.error("Wrong password or ip to connect to rcon");
throw new LoginException(host, port);
}
this.data = read();
}
public String command(String command) throws IOException {
command = "get5_status";
final RconData response = request(new RconData(command.getBytes()));
return new String(response.getPayload(), Charset.forName("UTF-8"));
}
public RconData request(RconData packet) throws IOException {
try {
write(packet);
return read();
} catch (final SocketException exception) {
socket.close();
throw exception;
}
}
private void write(RconData packet) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(packet.getPayload().length + 14);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt(packet.getPayload().length + 10);
buffer.putInt(packet.getId());
buffer.putInt(packet.getType());
buffer.put(packet.getPayload());
buffer.put((byte)0);
buffer.put((byte)0);
socket.getOutputStream().write(buffer.array());
socket.getOutputStream().flush();
}
private RconData read() throws IOException {
byte[] packet = new byte[MAX_SIZE];
int packetSize = this.socket.getInputStream().read(packet);
ByteBuffer buffer = ByteBuffer.wrap(packet, 0, packetSize);
buffer.order(ByteOrder.LITTLE_ENDIAN);
if (buffer.remaining() < 4) {
throw new WrongPacketException();
}
int size = buffer.getInt();
if (buffer.remaining() < size) {
throw new WrongPacketException();
}
int id = buffer.getInt();
int type = buffer.getInt();
byte[] payload = new byte[size - 10];
buffer.get(payload);
buffer.get(new byte[2]);
return new RconData(id, type, payload);
}
#Override
public void close() throws IOException {
this.socket.close();
}
}
Where RconData it's simple POJO with byte[] password property,

how to upload file into googlecloud through java

I want to upload a file into bucket in Google cloud storage Api. But when i run the servelet class then it successfully deployed and it shows the output in browser like " Now see here your file content, that you have uploaded on storage..
File uploading done" .
But the problem is the servelet class will not establish the connection to Google cloud storage.And the file will not uploaded into bucket.Once check
the code and give suggestion to how to connect to bucket with this source code.
public class TestCloudStorageServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
private StorageService storage = new StorageService();
private static final int BUFFER_SIZE = 1024 * 1024;
private static final Logger log = Logger.getLogger(TestCloudStorageServlet.class.getName());
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
log.info(this.getServletInfo()+" Servlets called....");
resp.setContentType("text/plain");
resp.getWriter().println("Now see here your file content, that you have uploaded on storage..");
ServletFileUpload upload = new ServletFileUpload();
System.out.println(upload);
FileItemIterator iter;
try {
iter = upload.getItemIterator(req);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String fileName = item.getName();
String mime = item.getContentType();
storage.init(fileName, mime);
InputStream is = item.openStream();
byte[] b = new byte[BUFFER_SIZE];
int readBytes = is.read(b, 0, BUFFER_SIZE);
while (readBytes != -1) {
storage.storeFile(b, readBytes);
readBytes = is.read(b, 0, readBytes);
}
is.close();
storage.destroy();
resp.getWriter().println("File uploading done");
//resp.getWriter().println("READ:" + storage.readTextFileOnly(fileName));
log.info(this.getServletName()+" ended....");
}
}
catch (FileUploadException e) {
System.out.println("FileUploadException::"+e.getMessage());
log.severe(this.getServletName()+":FileUploadException::"+e.getMessage());
e.printStackTrace();
} catch (Exception e) {
log.severe(this.getServletName()+":Exception::"+e.getMessage());
System.out.println("Exception::"+e.getMessage());
e.printStackTrace();
}
}
my StorageService class for uploading file.
public class StorageService {
public static final String BUCKET_NAME = "mybucketname";
private FileWriteChannel writeChannel = null;
FileService fileService = FileServiceFactory.getFileService();
private OutputStream os = null;
private static final Logger log = Logger.getLogger(StorageService.class.getName());
public void init(String fileName, String mime) throws Exception {
System.out.println("Storage service:init() method: file name:"+fileName+" and mime:"+mime);
log.info("Storage service:init() method: file name:"+fileName+" and mime:"+mime);
log.info("test..");
GSFileOptionsBuilder builder = new GSFileOptionsBuilder()
.setAcl("public_read")
.setBucket(BUCKET_NAME)
.setKey(fileName)
.setMimeType(mime);
log.info("test..");
AppEngineFile writableFile = fileService.createNewGSFile(builder.build());
boolean lock = true;
writeChannel = fileService.openWriteChannel(writableFile, lock);
os = Channels.newOutputStream(writeChannel);
}
public void storeFile(byte[] b, int readSize) throws Exception {
os.write(b, 0, readSize);
os.flush();
}
public void destroy() throws Exception {
log.info("Storage service: destroy() method");
os.close();
writeChannel.closeFinally();
}
}

How to get text/xml as UTF-8 from a multipart/form-data request with RESTeasy?

thanks for your answer, but using an InputStream instead of using getBody(...) does also not work. The code below returns the same result as the one from my original post.
final InputStream inStream = fileUploadInput.getFormDataPart(searchedInput, InputStream.class, null);
// get bytes
final byte[] inBytes = new byte[1024];
final ByteArrayOutputStream outBytes = new ByteArrayOutputStream(inBytes.length);
int length = 0;
while((length = inStream.read(inBytes)) >= 0) {
outBytes.write(inBytes, 0, length);
}
final byte[] rawInput = outBytes.toByteArray();
// get Encoding
final String asciiInput = new String(rawInput, ASCII);
final String utf8 = new String(rawInput, UTF8);
final String isoLatin1 = new String(rawInput, ISO8859_1);
log.info("ASCII: " + ascii);
log.info("UTF8: " + utf8);
log.info("ISOLATIN1: " + isoLatin1);
return utf8;
ORIGINAL POST:
I want to upload UTF-8 encoded XML files using the HTML form below and read it on the server using a RESTEasy MultipartFormDataInput, and the Java code shown below. On the server side I seem to be getting the content of the file(s) ASCII encoded, independent of the actual encoding of the uploaded files (which is UTF-8) (accessing it the way described below). All characters not part of the ASCII character set are are being replaced by ?. How can I get 'text/xml' as UTF-8 from a 'multipart/form-data' request with RESTeasy? (I know it is possible to write a PreProcessor - Interceptor and get the raw bytes there, but I can't use this approach in my application).
Upload Form:
<html>
<body>
<h1>JAX-RS Upload Form</h1>
<form action="http://.../upload" method="POST" enctype="multipart/form-data">
<p>Select a file : <input type="file" name="upload"/></p>
<input type="submit" value="Upload It" />
</form>
</body>
</html>
Resource class:
#Path("/upload")
#POST
#Consumes("multipart/form-data")
public Response createUploadTemplate(
#Context HttpServletRequest req,
MultipartFormDataInput formInput) {
try {
final String templateXml = getInput("upload", formInput);
//...
} catch (Exception e) {
//...
}
}
private static String getInput(final String searchedInput, final MultipartFormDataInput fileUploadInput) throws BadRequestException, IOException {
try {
final Map<String, List<InputPart>> inputToInputPart = fileUploadInput.getFormDataMap();
if(inputToInputPart.containsKey(searchedInput)) {
final StringBuilder builder = new StringBuilder();
final List<InputPart> inputParts = inputToInputPart.get(searchedInput);
for(InputPart inputPart : inputParts) {
builder.append(inputPart.getBody(String.class,null));
}
return builder.toString();
} else {
throw new BadRequestException("The form send with the request does not contain an input element " + searchedInput + ".");
}
} catch(Exception e) {
throw new BadRequestException("The file upload failed.", e);
}
}
MessageBodyReader:
#Provider
#Consumes ("text/xml")
public class XmlStringReader implements MessageBodyReader<String> {
private static Logger log = LoggerFactory.getLogger(UploadedXmlStringReader.class);
private static final String ASCII = "ASCII";
private static final String ISO8859_1 = "ISO8859_1";
private static final String UTF8 = "UTF8";
#Override
public boolean isReadable(final Class<?> type,
final Type genericType,
final Annotation[] annotations,
final MediaType mediaType) {
boolean result = type.equals(String.class) && MediaType.TEXT_XML_TYPE.equals(mediaType);
log.info(MessageFormat.format("{0} == String.class && MediaType.TEXT_XML_TYPE == {1}: {2}", type, mediaType, result));
return result;
}
#Override
public String readFrom(final Class<String> type,
final Type genericType,
final Annotation[] annotations,
final MediaType mediaType,
final MultivaluedMap<String, String> httpHeaders,
final InputStream entityStream) throws IOException, WebApplicationException {
final byte[] inBytes = new byte[1024];
final ByteArrayOutputStream outBytes = new ByteArrayOutputStream(inBytes.length);
int length = 0;
while((length = entityStream.read(inBytes)) >= 0) {
outBytes.write(inBytes, 0, length);
}
final byte[] rawInput = outBytes.toByteArray();
final String ascii = new String(rawInput, ASCII);
final String utf8 = new String(rawInput, UTF8);
final String isoLatin1 = new String(rawInput, ISO8859_1);
log.info("ASCII: " + ascii);
log.info("UTF8: " + utf8);
log.info("ISOLATIN1: " + isoLatin1);
return utf8;
}
}
When no charset is defined in the content-type header of your HTTP request, resteasy assumes 'charset=US-ASCII'.
See org.jboss.resteasy.plugins.providers.multipart.InputPart:
/**
* If there is a content-type header without a charset parameter, charset=US-ASCII
* is assumed.
* <p>
* This can be overwritten by setting a different String value in
* {#link org.jboss.resteasy.spi.HttpRequest#setAttribute(String, Object)}
* with this ("resteasy.provider.multipart.inputpart.defaultCharset")
* String`enter code here` as key. It should be done in a
* {#link org.jboss.resteasy.spi.interception.PreProcessInterceptor}.
* </p>
*/
So, as a work-around you can do the following:
#Provider
#ServerInterceptor
public class CharsetPreProcessInterceptor implements PreProcessInterceptor {
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException {
request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, "charset=UTF-8");
return null;
}
}
I generally would not rely on the getBody method on InputPart. You can actually get each part as a raw input stream and read the data in yourself. Rather than relying on the framework to convert the content to a String.

Categories