How to read resource file in Play Framework >2.6? - playframework-2.6

All the answers to this problem relate to pre-2.6 play framework. Now, it seems that I need to inject an Environment into my Application, but even then, I get nothing.
I want to read in files from conf/i18n in my application root directory. I'm doing the following:
#Singleton
class Application #Inject() (configuration: play.api.Configuration, assets: AssetsFinder, env: play.api.Environment) extends InjectedController {
var root = System.getProperty("user.dir")
var folder = new File(root + "/conf/i18n");
var listOfFiles = folder.listFiles();
val i18n = for {
file <- listOfFiles
filename = file.getName if filename.endsWith(".json")
content = env.resourceAsStream("/conf/i18n/" + filename) match {
case Some(stream) => Source.fromInputStream(stream).getLines.mkString
case None => ""
}
} yield Map(filename.dropRight(".json".length) -> Json.parse(content))
}
but the result of resourceAsStream is always None.
It works if I do it this way:
val i18n = for {
file <- listOfFiles
filename = file.getName if filename.endsWith(".json")
content = Source.fromFile(folder + "/" + filename)("UTF-8").getLines.mkString
} yield Map(filename.dropRight(".json".length) -> Json.parse(content))
Any ideas?

Related

Saxon CS: transform.doTransform cannot find out file from first transformation on windows machine but can on mac

I am creating an azure function application to validate xml files using a zip folder of schematron files.
I have run into a compatibility issue with how the URI's for the files are being created between mac and windows.
The files are downloaded from a zip on azure blob storage and then extracted to the functions local storage.
When the a colleague runs the transform method of the saxon cs api on a windows machine the method is able to run the first transformation and produce the stage 1.out file, however on the second transformation the transform method throws an exception stating that it cannot find the file even though it is present on the temp directory.
On mac the URI is /var/folders/6_/3x594vpn6z1fjclc0vx4v89m0000gn/T and on windows it is trying to find it at file:///C:/Users/44741/AppData/Local/Temp/ but the library is unable to find the file on the windows machine even if it is moved out of temp storage.
Unable to retrieve URI file:///C:/Users/44741/Desktop/files/stage1.out
The file is present at this location but for some reason the library cannot pick it up on the windows machine but it works fine on my mac. I am using Path.Combine to build the URI.
Has anyone else ran into this issue before?
The code being used for the transformations is below.
{
try
{
var transform = new Transform();
transform.doTransform(GetTransformArguments(arguments[Constants.InStage1File],
arguments[Constants.SourceDir] + "/" + schematronFile, arguments[Constants.Stage1Out]));
transform.doTransform(GetTransformArguments(arguments[Constants.InStage2File], arguments[Constants.Stage1Out],
arguments[Constants.Stage2Out]));
transform.doTransform(GetFinalTransformArguments(arguments[Constants.InStage3File], arguments[Constants.Stage2Out],
arguments[Constants.Stage3Out]));
Log.Information("Stage 3 out file written to : " + arguments[Constants.Stage3Out]);;
return true;
}
catch (FileNotFoundException ex)
{
Log.Warning("Cannot find files" + ex);
return false;
}
}
private static string[] GetTransformArguments(string xslFile, string inputFile, string outputFile)
{
return new[]
{
"-xsl:" + xslFile,
"-s:" + inputFile,
"-o:" + outputFile
};
}
private static string[] GetFinalTransformArguments(string xslFile, string inputFile, string outputFile)
{
return new[]
{
"-xsl:" + xslFile,
"-s:" + inputFile,
"-o:" + outputFile,
"allow-foreign=true",
"generate-fired-rule=true"
};
}```
So assuming the intermediary results are not needed as files but you just want the result (I assume that is the Schematron schema compiled to XSLT) you could try to run XSLT 3.0 using the API of SaxonCS (using Saxon.Api) by compiling and chaining your three stylesheets with e.g.
using Saxon.Api;
string isoSchematronDir = #"C:\SomePath\SomeDir\iso-schematron-xslt2";
string[] isoSchematronXslts = { "iso_dsdl_include.xsl", "iso_abstract_expand.xsl", "iso_svrl_for_xslt2.xsl" };
Processor processor = new(true);
var xsltCompiler = processor.NewXsltCompiler();
var baseUri = new Uri(Path.Combine(isoSchematronDir, isoSchematronXslts[2]));
xsltCompiler.BaseUri = baseUri;
var isoSchematronStages = isoSchematronXslts.Select(xslt => xsltCompiler.Compile(new Uri(baseUri, xslt)).Load30()).ToList();
isoSchematronStages[2].SetStylesheetParameters(new Dictionary<QName, XdmValue>() { { new QName("allow-foreign"), new XdmAtomicValue(true) } });
using (var schematronIs = File.OpenRead("price.sch"))
{
using (var compiledOs = File.OpenWrite("price.sch.xsl"))
{
isoSchematronStages[0].ApplyTemplates(
schematronIs,
isoSchematronStages[1].AsDocumentDestination(
isoSchematronStages[2].AsDocumentDestination(processor.NewSerializer(compiledOs)
)
);
}
}
If you only need the compiled Schematron to apply it further to validate an XML instance document against that Schematron you could even store the Schematron as an XdmDestination whose XdmNode you feed to XsltCompiler e.g.
using Saxon.Api;
string isoSchematronDir = #"C:\SomePath\SomeDir\iso-schematron-xslt2";
string[] isoSchematronXslts = { "iso_dsdl_include.xsl", "iso_abstract_expand.xsl", "iso_svrl_for_xslt2.xsl" };
Processor processor = new(true);
var xsltCompiler = processor.NewXsltCompiler();
var baseUri = new Uri(Path.Combine(isoSchematronDir, isoSchematronXslts[2]));
xsltCompiler.BaseUri = baseUri;
var isoSchematronStages = isoSchematronXslts.Select(xslt => xsltCompiler.Compile(new Uri(baseUri, xslt)).Load30()).ToList();
isoSchematronStages[2].SetStylesheetParameters(new Dictionary<QName, XdmValue>() { { new QName("allow-foreign"), new XdmAtomicValue(true) } });
var compiledSchematronXslt = new XdmDestination();
using (var schematronIs = File.OpenRead("price.sch"))
{
isoSchematronStages[0].ApplyTemplates(
schematronIs,
isoSchematronStages[1].AsDocumentDestination(
isoSchematronStages[2].AsDocumentDestination(compiledSchematronXslt)
)
);
}
var schematronValidator = xsltCompiler.Compile(compiledSchematronXslt.XdmNode).Load30();
using (var sampleIs = File.OpenRead("books.xml"))
{
schematronValidator.ApplyTemplates(sampleIs, processor.NewSerializer(Console.Out));
}
The last example writes the XSLT/Schematron validation SVRL output to the console but could of course also write it to a file.

What is the correct way to obtain the Resource folder path from the running iOS / macOS app instance (Xamarin Forms)

I am having difficulties copying some files from my application Resources folder:
var myDocuments = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Library");
// Confirm these paths are OK for iOS too
var root = Path.Combine(myDocuments, "VisitsRota.MacOS");
var styles = Path.Combine(root, "Styles");
var stylesheet = Path.Combine(styles, "ElderlyInfirm-Schedule-v1.css");
var db = Path.Combine(root, "ElderlyInfirmRotaData.xml");
var defaultroot = Path.Combine( ".", "Resources");
// Main folder
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
// Database
if (!File.Exists(db))
{
var defaultdb = Path.Combine(defaultroot, "ElderlyInfirmRotaData.xml");
File.Copy(defaultdb, db);
}
// Styles folder
if (!Directory.Exists(styles))
{
Directory.CreateDirectory(styles);
}
// Stylesheet
if (!File.Exists(stylesheet))
{
var defaultstylesheet = Path.Combine(defaultroot, "Styles", "ElderlyInfirm-Schedule-v1.css");
File.Copy(defaultstylesheet, stylesheet);
}
The problem is determining the application folders Resources folder, At the moment I get this exception:
What is the correct way to get to the Resources folder (for either iOS or macOS)?
In the IDE I only see just the one Resource folder:
Both of my resources have a Build Action set to Content.
Thank you for pointing me in the right direction to resolve this.
I tried using the result from:
public static string GetExecutingDirectoryName()
{
var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase);
return new FileInfo(location.AbsolutePath).Directory.FullName;
}
It was completely wrong.
I am running the app in the Debugger in VS for Mac (macOS build).
I assume that using the Resource folder for these files was OK. Unless there is a better way to do this?
It was much easier to use BundleResource:
var myDocuments = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Library");
// Create the folders first
// Main folder
var root = Path.Combine(myDocuments, "VisitsRota.MacOS");
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
// Styles folder
var styles = Path.Combine(root, "Styles");
if (!Directory.Exists(styles))
{
Directory.CreateDirectory(styles);
}
// Now copy the files
// Database
var db = Path.Combine(root, "ElderlyInfirmRotaData.xml");
var defaultdb = NSBundle.MainBundle.PathForResource("ElderlyInfirmRotaData", ofType: "xml");
if (!File.Exists(db))
{
File.Copy(defaultdb, db);
}
// Stylesheet
var stylesheet = Path.Combine(styles, "ElderlyInfirm-Schedule-v1.css");
var defaultstylesheet = NSBundle.MainBundle.PathForResource("ElderlyInfirm-Schedule-v1", ofType: "css");
if (!File.Exists(stylesheet))
{
File.Copy(defaultstylesheet, stylesheet);
}

read data from a csv file using asp net mvc

I try to read data from csv file but a i get this error :
System.NotSupportedException: Le format du chemin d'accès donné n'est pas pris en charge.
and the error source is:
System.IO.StreamReader file = new System.IO.StreamReader(root + #"C:\Users\user PC\Desktop\données financiere finale\Classeur1.csv");
this is my code
public ActionResult Index()
{
var collection1 = db.GetCollection<Devise>("Devise");
var devises2 = new Devise();
collection1.InsertOneAsync(devises2);
var root = AppDomain.CurrentDomain.BaseDirectory;
System.IO.StreamReader file = new System.IO.StreamReader(root + #"C:\Users\user PC\Desktop\données financiere finale\Classeur1.csv");
string fileLines;
{
while ((fileLines = file.ReadLine()) != null)
{
string[] elements;
elements = fileLines.Split(new char[] { ' ' });
for (int x = 0; x < elements.Length; x++)
{
devises2.parité = "EUR/USD";
devises2.date_observation = elements[0];
devises2.low = float.Parse(elements[3], CultureInfo.InvariantCulture.NumberFormat);
devises2.high = float.Parse(elements[2], CultureInfo.InvariantCulture.NumberFormat);
collection1.InsertOneAsync(devises2);
}
}
}
return View(devises2);
}
Your file path is invalid; the current directory is being concatenated with an absolute path (that starts with a drive specifier).
var root = AppDomain.CurrentDomain.BaseDirectory;
Followed by...
root + #"C:\Users\user PC\Desktop\données financiere finale\Classeur1.csv");
You need to decide whether you want to use a path that is relative to the current directory, or one that you specify using an absolute path.

Where's located the declaration of messageSource in Grails?

Background
We have some legacy internationalization for field labels that are stored in the database, so I tried to make a "merged" messageSource. If the code exists in database, return, if not, use PluginAwareResourceBundleMessageSource to look in the i18n.
Problem
For some reason the cachedMergedPluginProperties is caching the wrong file for the locale. For example, if I search for en_US, I receive pt_BR messages (the key of the Map is en_US, but the properties are pt_BR).
I declared my messageSource as follows:
messageSource(DatabaseMessageSource) {
messageBundleMessageSource = { org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource m ->
basenames = "WEB-INF/grails-app/i18n/messages"
}
}
The inner bean is beacause of Grails won't let me have two beans of type MessageSource.
Am I declaring PluginAwareResourceBundleMessageSource different from the default of Grails? In which file of Grails I can see this bean declaration?
I found the declaration inside I18nGrailsPlugin, and it's a bit more detailed then mine:
String baseDir = "grails-app/i18n"
String version = GrailsUtil.getGrailsVersion()
String watchedResources = "file:./${baseDir}/**/*.properties".toString()
...
Set baseNames = []
def messageResources
if (application.warDeployed) {
messageResources = parentCtx?.getResources("**/WEB-INF/${baseDir}/**/*.properties")?.toList()
}
else {
messageResources = plugin.watchedResources
}
if (messageResources) {
for (resource in messageResources) {
// Extract the file path of the file's parent directory
// that comes after "grails-app/i18n".
String path
if (resource instanceof ContextResource) {
path = StringUtils.substringAfter(resource.pathWithinContext, baseDir)
}
else {
path = StringUtils.substringAfter(resource.path, baseDir)
}
// look for an underscore in the file name (not the full path)
String fileName = resource.filename
int firstUnderscore = fileName.indexOf('_')
if (firstUnderscore > 0) {
// grab everyting up to but not including
// the first underscore in the file name
int numberOfCharsToRemove = fileName.length() - firstUnderscore
int lastCharacterToRetain = -1 * (numberOfCharsToRemove + 1)
path = path[0..lastCharacterToRetain]
}
else {
// Lop off the extension - the "basenames" property in the
// message source cannot have entries with an extension.
path -= ".properties"
}
baseNames << "WEB-INF/" + baseDir + path
}
}
LOG.debug "Creating messageSource with basenames: $baseNames"
messageSource(PluginAwareResourceBundleMessageSource) {
basenames = baseNames.toArray()
fallbackToSystemLocale = false
pluginManager = manager
if (Environment.current.isReloadEnabled() || GrailsConfigUtils.isConfigTrue(application, GroovyPagesTemplateEngine.CONFIG_PROPERTY_GSP_ENABLE_RELOAD)) {
def cacheSecondsSetting = application?.flatConfig?.get('grails.i18n.cache.seconds')
if (cacheSecondsSetting != null) {
cacheSeconds = cacheSecondsSetting as Integer
} else {
cacheSeconds = 5
}
}
}
Since Grails don't let you have two beans of type MessageSource I had to copy this code and adapt to mine "merged" messageSource.

ASP.NET MVC Open a .xls file

I have to create a .xls file from the data displayed in a table in my page. This happens when the user clicks 'export' button. I have the following code for it and it is created okay. Now, I want to open this file in the same click. How should I open it for user to see it?
string filePath = "C:/Upload/Stats_" + viewModel.SelectedTest.ToString() + ".xls";
//write the header
using (var pw = new StreamWriter(filePath, true))
{
pw.WriteLine(String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", "Month", "Total Users", "K",
"T", "G", "Detail", "GS",
"BI", "GHF","A"));
//write to the file
for (int i = 0; i < 12; i++)
{
pw.WriteLine(
String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", viewModel.Months[i],
viewModel.M[i], viewModel.MKau[i],
viewModel.MTech[i], viewModel.MGew[i],
viewModel.MDet[i], viewModel.MGes[i],
viewModel.MBea[i], viewModel.MGesHf[i],viewModel.MAug[i]));
pw.Flush();
}
pw.Close();
}
Here I would like to open it.
I had the same 'requirement' to be able to export to xls, and instead I gave the client an export to csv, which will open in excel if you are on a machine with excel installed but is also available to other systems. I achieved it like this.
Create an extension method that supports .AsCsv, which was taken largely from Mike Hadlow's implementation
public static class EnumerableExtensions
{
public static string AsCsv<T>(this IEnumerable<T> items) where T : class
{
var csvBuilder = new StringBuilder();
var properties = typeof(T).GetProperties();
foreach (T item in items)
{
string line = string.Join(",", properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray());
csvBuilder.AppendLine(line);
}
return csvBuilder.ToString();
}
private static string ToCsvValue<T>(this T item)
{
if (item is string)
{
return string.Format("\"{0}\"", item.ToString().Replace("\"", "\\\""));
}
double dummy;
if (double.TryParse(item.ToString(), out dummy))
{
return string.Format("{0}", item.ToString());
}
return string.Format("\"{0}\"", item.ToString());
}
}
Then you would need set your controller method to return a FileContentResult and have some logic like this within the controller method:
var outputModel = viewModel.ToList().Select(model => new
{
Months = model.Months
M = model.M[i],
MKau= model.MKau,
MTech = model.MTech,
MGew = model.MGew,
MDet = model.MDet,
MGes = model.MGes,
MBea= model.MBea,
MGesHf= model.MGesHf
});
string csv = "\"Month\",\"Total Users\",\"K\",\"T\",\"G\",\"Detail\",\"GS\",\"BI\",\"GHF\",\"A\""
+ System.Environment.NewLine
+ outputModel.AsCsv();
string fileName = "Stats_" + viewModel.SelectedTest.ToString() + ".csv"
return this.File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", fileName);

Resources