PlayFramework: value as is not a member of Array[Byte] - scala

I want to make file download from a database using Play framework.
But when I use this code I get this message:
value as is not a member of Array[Byte]
And if I change Ok(bytOfImage.as("image/jpg")) to Ok(bytOfImage) it works good but I get a file with a name: secondindex without .jpg
Here's my controller:
def secondindex(number: Int) = Action {
var bytOfImage = Array[Byte](1)
val conn = DB.getConnection()
try {
val stmt = conn.createStatement
val rs = stmt.executeQuery("SELECT image from images where id = " + number)
while(rs.next()) {
var blob = rs.getBlob("image")
bytOfImage = blob.getBytes(1, blob.length().toInt)
blob.free()
}
} finally {
conn.close() }
Ok(bytOfImage.as("image/jpg"))
}

You are calling the as method on the wrong object. It should look as follows:
Ok(bytOfImage).as("image/jpg")

If you need download images from browser, you can use method SimpleResult
and add in header"Content-Disposition" -> "attachment"
For example change row Ok(bytOfImage.as("image/jpg")) in you code on
val enumImg: Enumerator[Array[Byte]] = { Enumerator(bytOfImage) }
SimpleResult (
header = ResponseHeader(200, Map("Content-Disposition" -> "attachment")),
body = enumImg
)

Related

Dealing and Sharing State with a Monix Task in a Recursive Loop

I have the following code that iterates recursively and does something over the network. As it goes over the network, I would like to do some optimizations, where the very first optimization would be to avoid going over the network for certain elements that I have already tried.
For example., in the case below, I call a URL, extract the HREF's found in that URL and call those URL's and report the status. As it could be possible that certain URL's might be fetched again, for those URL's that failed, I would like to add them to a global state so that when I encounter this URL the next time, I will avoid those network calls.
Here is the code:
def callURLWithCache(url: String): Task[HttpResult] = {
Task {
Http(url).timeout(connTimeoutMs = 1000, readTimeoutMs = 3000).asString
}.attempt.map {
case Left(err) =>
println(s"ERR happened ----------------- $url ************************ ${err.getMessage}")
// Add to the cache
val httpResult = HttpResult(source = url, isSuccess = false, statusCode = 1000, errorMessage = Some(err.getMessage))
val returnnnn: Try[Any] = httpResultErrorCache.put(url)(httpResult)
httpResult
case Right(doc) =>
if (doc.isError) {
HttpResult(source = url, isSuccess = doc.isSuccess, statusCode = doc.code)
} else {
val hrefs = (browser.parseString(doc.body) >> elementList("a[href]") >?> attr("href"))
.distinct.flatten.filter(_.startsWith("http"))
HttpResult(source = url, isSuccess = doc.isSuccess, statusCode = doc.code, elems = hrefs)
}
}
}
You can see in the case Left(....) block that I add the failed case class to the cache which I define globally on the enclosing class of this function as:
val underlyingCaffeineCache: cache.Cache[String, Entry[HttpResult]] = Caffeine.newBuilder().maximumSize(10000L).build[String, Entry[HttpResult]]
implicit val httpResultErrorCache: Cache[HttpResult] = CaffeineCache(underlyingCaffeineCache)
Here is the function that I do a recursive operation:
def parseSimpleWithFilter(filter: ParserFilter): Task[Seq[HttpResult]] = {
def parseInner(depth: Int, acc: HttpResult): Task[Seq[HttpResult]] = {
import cats.implicits._
if (depth > 0) {
val batched = acc.elems.collect {
case elem if httpResultErrorCache.get(elem).toOption.exists(_.isEmpty) =>
callURLWithCache(elem).flatMap(newElems => parseInner(depth - 1, newElems))
}.sliding(30).toSeq
.map(chunk => Task.parSequence(chunk))
Task.sequence(batched).map(_.flatten).map(_.flatten)
} else Task.pure(Seq(acc))
}
callURLWithCache(filter.url).map(elem => parseInner(filter.recursionDepth, elem)).flatten
}
It can be seen that I'm checking if the url that I have as my current elem is already in the cache, meaning that I have already tried it and failed, so I would like to avoid doing a HTTP call once again for it.
But what happens is that, the httpResultErrorCache turns up always empty. I'm not sure if the Task chunk is causing this behavior. Any ideas on how to get the cache to work?

scalaj-http - 'execute' method is returninig "stream is closed"

I want to use the scalaj-http library to download a byte content file with 31gb size from a http connection. 'asBytes' is not an option because it retuns a byte array.
I tried to use the 'execute' method returning an input stream, but when I execute the program bellow it returns that the stream is closed. I don't think that I am reading the stream twice.
What I am doing wrong?
val response: HttpResponse[InputStream] = Http(url).postForm(parameters).execute(inputStream => inputStream)
if (response.isError) println(s"Sorry, error found: ${response.code}")
else {
val is: InputStream = response.body
val buffer: Array[Byte] = Array.ofDim[Byte](1024)
val fos = new FileOutputStream("xxx")
var read: Int = 0
while (read >= 0) {
read = is.read(buffer)
if (read > 0) {
fos.write(buffer, 0, read)
}
}
fos.close()
}
You cannot export the inputStream as the stream will be closed at the end of the execute method.
You should use the stream inside the execute, like this :
val response = Http(url).postForm(parameters).execute { is =>
val buffer: Array[Byte] = Array.ofDim[Byte](1024)
val fos = new FileOutputStream("xxx")
var read: Int = 0
while (read >= 0) {
read = is.read(buffer)
if (read > 0) {
fos.write(buffer, 0, read)
}
}
fos.close()
}
if (response.isError) println(s"Sorry, error found: ${response.code}")

Simple Scala Function Not Removing Double Spaces

For some reason when I input a string with double spaces such as " ", the function does not remove them from the string, nor does it remove them when they are generated by two WUB's in a row
For example:
songDecoder("WUBCATWUBWUBBALLWUB") outputs "CAT_ _BALL" (underscores represent spaces)
I could fix this by other means, but since I have no idea why my current code isn't working I figured I should ask to patch my understanding.
def songDecoder(song:String):String = {
val l = song.indexOf("WUB")
if (song.contains(" ")) {
val e = song.indexOf(" ")
songDecoder(song.patch(e,Nil,1))
}
if (l==0) {
val c = song.patch(l,Nil,3)
songDecoder(c)
}
if (l== -1)
song.trim
else {
val c = song.patch(l,Nil,2)
val b = c.patch(l," ",1)
songDecoder(b)
}
}
The reason it doesn't work is because when you call a recursive method it eventually returns with its result. The code that clears out the double-whitespace doesn't save that result.
if (song.contains(" ")) {
val e = song.indexOf(" ")
songDecoder(song.patch(e,Nil,1)) //send patched song to decoder
} //don't save returned string
//continue with unpatched song
The 2nd if block also recurses without saving the result.
if (l==0) {
val c = song.patch(l,Nil,3)
songDecoder(c) //send patched song to decoder
} //don't save returned string
//continue with unpatched song
You can remove both of those if blocks and you'll get the same results from your method. The only code that effects the output is the final if/else and that's because it is at the end of the method's code block. So whatever the if/else produces that's what the method returns.
if (l== -1)
song.trim //return the final result string
else {
val c = song.patch(l,Nil,2) //remove one WUB
val b = c.patch(l," ",1) //replace with space
songDecoder(b) //return whatever the next recursion returns
}
Just as an FYI, here's a different approach.
def songDecoder(song:String):String =
"(WUB)+".r.replaceAllIn(song, " ").trim
How about something like:
song.split(“(WUB)+”).mkString(“ “).trim

Lexical Analyzer not getting the next character

So I am working on a project where we are making a small compiler program but before I can move on to the other parts I am having troubles with getting the lexical analyzer to output anything after '\BEGIN' afterwards I debugged it and it seems the value is stuck in a loop where the condition is saying the next character is always a newline. Is it because I haven't added the pattern matching yet to the defined tokens?
Here is the code
import java.util
//import com.sun.javafx.fxml.expression.Expression.Parser.Token
/*Lexical analyzer will be responsible for the following:
- finds the lexemes
- Checks each given character determining the tokens
* */
class MyLexicalAnalyzer extends LexicalAnalyzer {
//Array full of the keywords
//val SpecialCharacters = List(']', '#', '*', '+', '\\', '[', '(',')', "![", '=')
val TEXT = "[a-z] | _ | 0-9 | [A-Z]:"
private var sourceLine: String = null
private val lexeme: Array[Char] = new Array[Char](999)
private var nextChar: Char = 0
private var lexLength: Int = 0
private var position: Int = 0
private val lexems: util.List[String] = new util.ArrayList[String]
def start(line: String): Unit = {
initializeLexems()
sourceLine = line
position = 0
getChar()
getNextToken()
}
// A helper method to determine if the current character is a space.
private def isSpace(c: Char) = c == ' '
//Defined and intialized tokens
def initializeLexems(): Any = {
lexems.add("\\BEGIN")
lexems.add("\\END")
lexems.add("\\PARAB")
lexems.add("\\DEF[")
lexems.add("\\USE[")
lexems.add("\\PARAE")
lexems.add("\\TITLE[")
lexems.add("]")
lexems.add("[")
lexems.add("\\")
lexems.add("(")
lexems.add(")")
lexems.add("![")
lexems.add("=")
lexems.add("+")
lexems.add("#")
}
//val pattern = new regex("''").r
def getNextToken() ={
lexLength = 0
// Ignore spaces and add the first character to the token
getNonBlank()
addChar()
getChar()
// Continue gathering characters for the token
while ( {
(nextChar != '\n') && (nextChar != ' ')
}) {
addChar()
getChar()
}
// Convert the gathered character array token into a String
val newToken: String = new String(lexeme)
if (lookup(newToken.substring(0, lexLength)))
MyCompiler.setCurrentToken(newToken.substring(0,lexLength))
}
// A helper method to get the next non-blank character.
private def getNonBlank(): Unit = {
while ( {
isSpace(nextChar)
}) getChar()
}
/*
Method of function that adds the current character to the token
after checking to make sure that length of the token isn't too
long, a lexical error in this case.
*/
def addChar(){
if (lexLength <= 998) {
lexeme({
lexLength += 1; lexLength - 1
}) = nextChar
lexeme(lexLength) = 0
}
else
System.out.println("LEXICAL ERROR - The found lexeme is too long!")
if (!isSpace(nextChar))
while ( {
!isSpace(nextChar)
})
getChar()
lexLength = 0
getNonBlank()
addChar()
}
//Reading from the file its obtaining the tokens
def getChar() {
if (position < sourceLine.length)
nextChar = sourceLine.charAt ( {
position += 1;
position - 1
})
else nextChar = '\n'
def lookup(candidateToken: String): Boolean ={
if (!(lexems.contains(candidateToken))) {
System.out.println("LEXICAL ERROR - '" + candidateToken + "' is not recognized.")
return false
}
return true
}
}
else nextChar = '\n'<- this is where the condition goes after rendering the first character '\BEGIN' then just keeps outputting in the debug console as listed below.
This is what the debug console it outputting after '\BEGIN' is read through
Can anyone please let me know why that is? This happens after I keep stepping into it many times as well.
Here is the driver class that uses the lexical analyzer
import scala.io.Source
object MyCompiler {
//check the arguments
//check file extensions
//initialization
//get first token
//call start state
var currentToken : String = ""
def main(args: Array[String]): Unit = {
val filename = args(0)
//check if an input file provided
if(args.length == 0) {
//usage error
println("USAGE ERROR: Must provide an input file. ")
System.exit(0)
}
if(!checkFileExtension(args(0))) {
println("USAGE ERROR: Extension name is invalid make sure its .gtx ")
System.exit(0)
}
val Scanner = new MyLexicalAnalyzer
val Parser = new MySyntaxAnalyzer
//getCurrentToken(Scanner.getNextToken())
//Parser.gittex()
for (line <- Source.fromFile(filename).getLines()){
Scanner.start(line)
println()
}
//.......
//If it gets here, it is compiled
//post processing
}
//checks the file extension if valid and ends with .gtx
def checkFileExtension(filename : String) : Boolean = filename.endsWith(".gtx")
def getCurrentToken() : String = this.currentToken
def setCurrentToken(t : String ) : Unit = this.currentToken = t
}
The code is operating as it is supposed to. The first line contains only the string \BEGIN so the lexical analyser is treating the end of the first line as an '\n' as shown in this method:
def getChar() {
if (position < sourceLine.length)
nextChar = sourceLine.charAt ( {
position += 1;
position - 1
})
else nextChar = '\n'
However, the comment directly above that method does not describe what the method actually does. This could be a hint as to where your confusion lies. If the comment says it should read from the file, but it is not reading from the file, maybe that's what you've forgotten to implement.

BSONDocument.getAs issue

I have 1 problem and 1 question when using BSONDocument getAs.
Whenever I try to access the value l in the format below by calling this:
docFound.getAs[Int]("v.1.0.2013.9.9.l")
it returns None. However if I do:
docFound.getAs[BSONDocument]("v")
it returtns a valid BSONDocument for the whole v section. What is wrong in my first call? Does reactivemongo support path traversal?
BSONDocument: {
v: {
1.0: {
2013: {
9: {
9: {
l: BSONInteger(0),
s: BSONInteger(8)
}
}
}
}
}
}
The second question is:
I find a document in DB with the following filter:
BSONDocument(
"_id" -> 0,
"v.1.0.2013.9.9.l" -> 1)
But it seems like instead of extracting just these values "_id" & "l" it extracts the whole document. When I do BSONDocument.pretty(foundDoc) I see the whole document, not just "l" value that I have requested. Please clarify if it is even worth specifying fields I am interested in if it always downloads the whole document.
Thanks.
It seems like according to the sources it is not supported in reactivemongo. So I have created a quick helper:
def getAsByPath[T](path: String, doc: BSONDocument)
(implicit reader: BSONReader[_ <: BSONValue, T]): Option[T] = {
val pathChunks = path.split('.')
var pathIndex = 0
var curDoc: Option[BSONDocument] = Some(doc)
var currentChunk = ""
while(pathIndex != pathChunks.size) {
currentChunk += pathChunks(pathIndex)
// If this is the last chunk it must be a value
// and if previous Doc is valid let's get it
if (pathIndex == pathChunks.size - 1 && curDoc != None)
return curDoc.get.getAs[T](currentChunk)
val tmpDoc = curDoc.get.getAs[BSONDocument](currentChunk)
if (tmpDoc != None) {
currentChunk = ""
curDoc = tmpDoc
} else {
// We need to support this as sometimes doc ID
// contain dots, for example "1.0"
currentChunk += "."
}
pathIndex += 1
}
None
}
However my second question is still valid. If someone knows please let me know.