How to reference custom Java class in Fusion Solr Javascript Index Stage? - solr

In Fusion's Javascript Indexing Stage, we can import Java classes and run them in the javascript such as this :
var imports = new JavaImporter(java.lang.String);
with (imports) {
var name = new String("foo"); ...
}
If we have customized complex Java classes, how to include the compile jar with Fusion so that the class can be imported in Javascript Indexing Stages for use?
And where can we store configuration values for the Javascript Indexing Stage to look up and how to retrieve them?
I'm thinking of something like this:
var imports = new JavaImporter(mycompany.com.custompkg.SomeParser);
with (imports) {
var some_config = ResourceManager.GetString("key");
var sp = new SomeParser(some_config); ...
}
Regards,
Kelvin

Starting in Fusion 4.x The API and Connectors started using a common location for jars i.e. apps/libs . This is a reasonable place to put custom jars but the services must be told about the new jars as well. That's done in two places
/jetty/connectors-classic/webapps/connectors-extra-classpath.txt
./jetty/api/webapps/api-extra-classpath.txt
Also, index documents can get processed by the api service so even if the jar is only used for indexing, register with both classpaths. Finally, bounce the services.

Put the Java class file, as a jar file, in $FUSION_HOME/apps/jetty/api/webapps/api/WEB-INF/lib/.
I used this to access my custom class.
var SomeParser = Java.type('mycompany.com.custompkg.SomeParser');

Related

Check if event is coming from a model inside a plugin?

I need all models inside a custom CakePHP plugin to use a database prefix. I'm trying to use an event, as suggested by #lorenzo.
EventManager::instance()->on('Model.initialize', function ($event) {
$instance = $event->subject();
$instance->table('prefix_' . $instance->table());
});
I'm getting several callbacks from my plugin model as well as DebugKit models, and potentially it could be other models in the application.
Is there a way to tell if a given $event is coming from within a plugin?
I have checked $event->getSubject() and it contains the corresponding Table class. The only feasible way I could come up with is to check some properties for the plugin name.
$event->getSubject()->getRegistryAlias() is ExamplePlugin.Posts
$event->getSubject()->getEntityClass() is ExamplePlugin\Model\Entity\Post
I could check if either starts with ExamplePlugin. Is there a better way?
The fact that basically any PHP namespace can be a plugin means you could do something like that:
EventManager::instance()->on('Model.initialize', function (\Cake\Event\EventInterface $event) {
/** #var \Cake\ORM\Table $object */
$object = $event->getSubject();
$tableClassName = get_class($object);
$isApp = str_starts_with($tableClassName, 'App');
});
Because your main app's namespace will always begin with App
This of course wouldn't distinguish between your private plugins which are located in plugins and plugins which are installed via composer and therefore live in the vendor directory.
But you could introduce a name prefix to all your private plugins so you can easily distinguish them from any other plugins.

Spring + Angular + JAR Build with Command Line Parameter

I am building a UI into a JAR for Spring Server. I have a bunch of Angular JS pages. I want to pass in a command line argument to my jar that tells it where the API server is like so:
java -jar application.jar --api=http://ip:9000
So my application.properties file has:
url=${api:http://localhost:9000}
The way I am currently doing is it just having a hardocoded js config file and on each of my .html pages:
<script src="../js/appName/config.angular.js"></script>
Which contains:
var configData = {
url:"http://localhost:9000"
};
And called in each file:
$scope.apiUrl = configData.url;
How do I tap into the applications.properties file that I can override with my JAR command line parameter during runtime vs. the way it has been coded now.
When you pass a value from command line and the same property name is present in properties file then spring boot overrides the value from command line. So to achieve what you want do something like this
In application.properties
#this is default value
app.url=localhost:8080
Create a class to map the properties value or you can use existing class or something else based on your project structure.
#Component
public class Sample {
#Value("${app.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Now when your execute a jar with argument --app.url="someserver:9090" the value will be overriden and you can use this value anywhere.
Note it will also work if you try to access the properties value directly in jsp using expression.
Try it, it works. I have used the same thing in my latest project which is a composite microservices and each component need each others url.
[Edit]
Reference : http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Am I getting it right: The client part is delivered by the application? So the part of the last sentence 'during runtime' has more the meaning of 'bootstrap/initial loading', right? One (old school) approach is to provide the entry html (e.g. index.html) through the application (a simple template engine) and provide the needed information with a setter in a JS config object:
// pseudo js code with thymeleaf
<script th:inline="javascript">
/*<![CDATA[*/
myConfig.url = [[${#httpServletRequest.remoteHost}]];
/*]]>*/
</script>
This is just a sample that will only set the remote host name but I think you get the idea.
Side note: I still don't really get why do you have to set this. If the application contains the client code, why do you work with absolute URLs for remote calls? (Disclaimer: I have only experience in Angular(2) and not with AngularJS)

AngularJS application with different customizations

I got a "framework" created by us using AngularJS. It allows to build questionnaire system and it has many different parameters that control the behavior of framework.
Using this framework we've created 2 projects: projectA and projectB. The difference between these projects are the settings and assets (css, img, ...)
Both projects are stored on the same branch in git and only config file defines the project customization.
I can't think of the best way how these 2 projects can be easily deployed separately from the same code source using Gulp or something other.
Here are some ideas I got for the moment:
1. Have both settings files and images (e.g. logo_A.png and logo_B.png) in the code and choose appropriate during build using Gulp
2. Create folder customizations that will have 2 subfolders A and B with corresponding settings and assets
3. Create separate repository for each project installation scripts (not the code) and these scripts will do all the work
What is the best way in this case?
Finally, the easieast and most understandible solution was to create additional custom folder.
Assets
In addition to normal application files I got now custom folder with 2 subfolders: A and B each of them containing assets (css, img) that correspond only to concrete project.
In gulp I've used yargs module which allows to pass parameters. After reading project name from input I can looks inside custom folder to see if there are resources interesting for me (I've just added custom folder into the resources paths).
var customPath = './custom/' + app.name;
exports.paths = {
web: {
//Resources
styles: ['./app/**/*.css', './app/**/*.scss', customPath + '/**/*.css', customPath + '/**/*.scss'],
...
And the call to build task now looks like this: gulp build --name A.
Configuration
One more thing was done for configuration file of AngularJS that contains constants. I've used gulp-ng-config plugin which allows to build AngularJS configuration (constants) file on fly. In my flow, first I check if custom configuration file exists inside custom folder I use it, if no I'm using default one from application.
var getAppScripts = function() {
return $.eventStream.merge(
gulp.src(config.paths.web.scripts)
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish'))
//.pipe($.eslint())
.pipe($.eslint.format()),
getAppConfig())
.pipe($.angularFilesort());
};
var getAppConfig = function() {
var configFile = config.paths.web.custom + "/app.config.yaml";
if (fs.existsSync(configFile)) {
return gulp.src(configFile)
.pipe($.ngConfig(config.app.name, {
parser: 'yml',
createModule: false
}));
}
else {
return gulp.src(config.paths.web.config);
}
}

Parsing Swagger JSON data and storing it in .net class

I want to parse Swagger data from the JSON I get from {service}/swagger/docs/v1 into dynamically generated .NET class.
The problem I am facing is that different APIs can have different number of parameters and operations. How do I dynamically parse Swagger JSON data for different services?
My end result should be list of all APIs and it's operations in a variable on which I can perform search easily.
Did you ever find an answer for this? Today I wanted to do the same thing, so I used the AutoRest open source project from MSFT, https://github.com/Azure/autorest. While it looks like it's designed for generating client code (code to consume the API documented by your swagger document), at some point on the way producing this code it had to of done exactly what you asked in your question - parse the Swagger file and understand the operations, inputs and outputs the API supports.
In fact we can get at this information - AutoRest publically exposes this information.
So use nuget to install AutoRest. Then add a reference to AutoRest.core and AutoRest.Model.Swagger. So far I've just simply gone for:
using Microsoft.Rest.Generator;
using Microsoft.Rest.Generator.Utilities;
using System.IO;
...
var settings = new Settings();
settings.Modeler = "Swagger";
var mfs = new MemoryFileSystem();
mfs.WriteFile("AutoRest.json", File.ReadAllText("AutoRest.json"));
mfs.WriteFile("Swagger.json", File.ReadAllText("Swagger.json"));
settings.FileSystem = mfs;
var b = System.IO.File.Exists("AutoRest.json");
settings.Input = "Swagger.json";
Modeler modeler = Microsoft.Rest.Generator.Extensibility.ExtensionsLoader.GetModeler(settings);
Microsoft.Rest.Generator.ClientModel.ServiceClient serviceClient;
try
{
serviceClient = modeler.Build();
}
catch (Exception exception)
{
throw new Exception(String.Format("Something nasty hit the fan: {0}", exception.Message));
}
The swagger document you want to parse is called Swagger.json and is in your bin directory. The AutoRest.json file you can grab from their GitHub (https://github.com/Azure/autorest/tree/master/AutoRest/AutoRest.Core.Tests/Resource). I'm not 100% sure how it's used, but it seems it's needed to inform the tool about what is supports. Both JSON files need to be in your bin.
The serviceClient object is what you want. It will contain information about the methods, model types, method groups
Let me know if this works. You can try it with their resource files. I used their ExtensionLoaderTests for reference when I was playing around(https://github.com/Azure/autorest/blob/master/AutoRest/AutoRest.Core.Tests/ExtensionsLoaderTests.cs).
(Also thank you to the Denis, an author of AutoRest)
If still a question you can use Swagger Parser library:
https://github.com/swagger-api/swagger-parser
as simple as:
// parse a swagger description from the petstore and get the result
SwaggerParseResult result = new OpenAPIParser().readLocation("https://petstore3.swagger.io/api/v3/openapi.json", null, null);

post_import_function in App Engine bulkuploader yaml

I am trying to use post_import_function while uploading data using bulkloader.yaml. As per this link, Using post_import_function in App Engine bulkuploader yaml , I am using type google.appengine.api.datastore.Entity for entity operations. As in the link, this is a subclass of 'dict'. However I am not sure how do I apply methods to this entity.
My code looks like (I am using Geomodel):
def post_import_restaurants(input_dict, instance, bulkload_state_copy):
lat = instance['lat']
lng = instance['lng']
latlng = "%s,%s" % (lat,lng)
instance['location'] = db.GeoPt(latlng)
instance.update_location()
return instance
instance.update_location(), is where I am having issues. And I am not sure how to write this statement.
You can't add methods to an Entity. Just inline the code, or write it as a separate function that you pass the entity to.

Resources