1

I have a directory with deep structure (lot of sub-directories and files) that I read from my play application. On my PC I read the directory using -

val directory = Play.getFile("directory")
for(file <- directory.listFiles) {
  val lines = Source.fromFile(file).getLines()
}

This works perfectly on my PC but not on Heroku. On Heroku I get a NPE on line#2 (above code) which means that the directory object is not getting made.

This suggestion of a similar issue suggests that I could put my directory in public and read it as using the Play.resource API. But I DONT want to put my directory in public. And I have a need to list the contents of a directory as it could be changing... how can I do this in Play on Heroku?

Community
  • 1
  • 1
Bharadwaj
  • 1,361
  • 1
  • 9
  • 24
  • Have you found the solution? I think the problem is those resource directories have not been added to the distribution. In order to that you have to explicitly mention the directories to be added in Play framework. – Supun Wijerathne Jun 08 '16 at 04:07
  • Possible duplicate of [Reading from a file in play on Heroku](http://stackoverflow.com/questions/19089412/reading-from-a-file-in-play-on-heroku) – Supun Wijerathne Jun 08 '16 at 10:55
  • @SupunWijerathne that works only for public. my question is specifically for non public – Bharadwaj Jun 12 '16 at 06:34
  • So are you getting 'file not found' error when calling Play.getFile() right? – Supun Wijerathne Jun 12 '16 at 08:04

3 Answers3

1

As this suggests,in order to make Play.getFile("location_from_project_root") (or any other similar one) working in production environment, you have to explicitly ask from play to add the directory where you put the file ,to the dist.

Ex:

You want to access a file Project_Root/resources/mtFile.json, (inside /resources folder you created), you can use Play.getFile("/resources/mtFile.json")method.

But in order to make it works in any production environment, you have to add /resources folder to the dist. Otherwise that file will not be there. In order to do that you have to add these lines into your build.sbt file.

import com.typesafe.sbt.packager.MappingsHelper._
mappings in Universal ++= directory(baseDirectory.value / "resources")

Now, if you take a dist using activator dist command you can see that a directory called /resources has added into the root of the dist. Now Play.getFile("/resources/mtFile.json") should work in production environment.

Community
  • 1
  • 1
Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
0

Play.getFile(relativePath) retrieves a file relative to the current app's root path. Current app's root path may not be same on your PC and Heroku.

One more thing: Your statement that the directory object is not getting made is not true. listFiles operation is throwing NPE in your case.

Try this to get a list of files from your directory:

 val listOfFilesInDirectory: List[java.io.File] = Option(getClass.getResource("/directory")).map(_.toURI).map(new java.io.File(_)).map(_.listFiles).flatten.toList
Sudheer Aedama
  • 2,116
  • 2
  • 21
  • 39
  • this works only when the directory is under *public* and I specify the URL as "public/directory". I *dont* want to put my directory under *public* – Bharadwaj Jan 13 '14 at 07:20
  • 1
    What happens if you specify this directory name as an environment variable so that you can set it differently on Heroku and your PC ? – Sudheer Aedama Jan 13 '14 at 07:23
0

You can put your files under your conf folder, so that the files are not publicly available. Then use :

Play.resource("conf/directory"): Option[URL]

or

Play.resourceAsStream("conf/directory"): Option[InputStream]
ndeverge
  • 21,378
  • 4
  • 56
  • 85
  • I think it comes from the fact that you cannot open a directory as a resource, since the directory is in your classpath. Do you any index file which can contains the list of files to open ? – ndeverge Jan 13 '14 at 15:59
  • That is what I have ended up doing - keep a index file with the directory/file structure. But its not a good solution :( – Bharadwaj Jan 13 '14 at 16:32