Alfresco has a MultilingualContentService but unfortunately it is not implemented in the Share UI.
So, how to handle mutilingual content in Share?
(for each document, several files in different languages)
Is there some solution ready?
If I have no choice but to develop, how would you do it?
Wrap it in an object that's accessible from your webscripts. Here's an example which already does it:
package com.someco.web.jscript;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.processor.BaseProcessorExtension;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Locale;
public final class MultilingualScript extends BaseProcessorExtension
{
private static final Log logger = LogFactory.getLog(MultilingualScript.class);
private MultilingualContentService multilingualContentService;
private ServiceRegistry serviceRegistry;
public MultilingualScript()
{
if (logger.isDebugEnabled()) {
logger.debug("MultilingualScript Constructor Called");
}
}
//path = path of the original document
//language = required language
//returns the noderef for the translation content for the given language
public ScriptNode multilingualContent(String path, String language, ScriptNode companyHome) {
if (logger.isDebugEnabled()) {
logger.debug("MultilingualScript - parameters - " + path + " , " + language);
}
NodeRef nodeRef = new ScriptNode(companyHome.getNodeRef(), serviceRegistry)
.childByNamePath(path).getNodeRef();
nodeRef = multilingualContentService.getTranslationForLocale(nodeRef, new Locale(language) );
return new ScriptNode(nodeRef, serviceRegistry);
}
public MultilingualContentService getMultilingualContentService() {
return multilingualContentService;
}
public void setMultilingualContentService(
MultilingualContentService multilingualContentService) {
this.multilingualContentService = multilingualContentService;
}
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
public void setServiceRegistry(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
}
The Spring bean:
<bean id="multilingualScript" parent="baseJavaScriptExtension" class="com.someco.web.jscript.MultilingualScript">
<property name="extensionName">
<value>multilingual</value>
</property>
<property name="serviceRegistry">
<ref bean="ServiceRegistry" />
</property>
<property name="multilingualContentService">
<ref bean="MultilingualContentService" />
</property>
</bean>
And finally, use it like this:
var multilingualArticle = multilingual.multilingualContent("/myarticle", "es", companyhome);
I guess showing the actual content shouldn't be to hard, because every content has his own uuid.
The difficulty will be in creating a UI to upload a different language.
The first thing I would do is analyze how the action 'upload new version' works.
So what we need is a custom action to upload a different language file and a popup to select which language that is. So the 'upload new version' does almost exactly the same, you can browse to a file and fill in versioning comment.
I don't know if there are webscripts available in Explorer to store the multilingual content, if not you should develop those.
Secondly is to create a webscript to return you all the multilingual files (same as above, probably won't exist)
Then define a block, like the workflows or version block, so links will appear of the files.
Related
I'm facing a problem which I cannot seem to resolve.
I have an entity which has a property (specifically a string) with a value of 'In magazijn':
package com.Code.Pakket.management.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.repository.Modifying;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
//Men maakt een JPA entity class zodat hibernate met onze data kan werken.
#Entity
public class Pakketje {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int code;
private String status ="In magazijn";
public Pakketje() {
}
I would like this string to change when a button click occurs in the react application. The specific object from which the value should be changed is already existing inside of the database, and only the value "In magazijn" should be changed to "Onderweg". This value should change inside of the database.
I have tried the following inside of the service class:
#Override
public String StatusOnderweg(Pakketje pakketje) {
return pakketjeRepository.save(pakketje.setStatus("Onderweg"));
}
So "Pakketje pakketje" is the object of which the string should be changed. I thought about saving the specific object once more to the database (even tough the object already exists) and save it with another string.
My Repository:
package com.Code.Pakket.management.repository;
import com.Code.Pakket.management.model.Pakketje;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
//https://www.javadevjournal.com/spring-boot/spring-boot-with-hibernate/ -- Punt5.
#Repository
public interface PakketjeRepository extends JpaRepository<Pakketje,Integer> {
}
I just don't have an idea how to make this code with a repository, service and controller structure... Any advice?
Thanks in advance.
Update: Link to repo is moved to answer because repo is now updated with code from answer below.
Problem description
Current code is working, but it is using gcloud beta emulators pubsub from google/cloud-sdk for integration tests.
Integration tests are slow due to the size of the google/cloud-sdk image
pubsub emulator has to run on a fixed port, there seems to be no way to tell Micronaut which port the emulator is running on
I'll need to set the following environment variable in maven-surefire-plugin.
<environmentVariables>
<PUBSUB_EMULATOR_HOST>localhost:8085</PUBSUB_EMULATOR_HOST>
</environmentVariables>
How this can be done in Spring Boot
According to Test Containers | Gcloud Module, the correct way of implementing integration tests with PubSubEmulatorContainer in Spring Boot is like this:
https://github.com/saturnism/testcontainers-gcloud-examples/blob/main/springboot/pubsub-example/src/test/java/com/example/springboot/pubsub/PubSubIntegrationTests.java
This will bring up the container on a random port, and that is possible because of DynamicPropertyRegistry in Spring. It seems that Micronaut is missing this possibility.
Doc: https://www.testcontainers.org/modules/gcloud/
I'm looking for a working example of a JUnit5 or Spock integration test implemented in Micronaut 3.x that is using PubSubEmulatorContainer like described in the above doc.
Related doc: https://micronaut-projects.github.io/micronaut-gcp/latest/guide/#emulator
There are some comments on GitHub around configuring TransportChannelProvider. I'm able to inject an instance and inspect it, but I still haven't found out exactly what to do.
These are the closest leads so far:
https://github.com/micronaut-projects/micronaut-gcp/issues/257
https://github.com/micronaut-projects/micronaut-gcp/pull/259
TL;DR
We'll need to start the testcontainer first, get emulator host address and then call ApplicationContext.run like this:
applicationContext = ApplicationContext.run(
["pubsub.emulator.host": emulatorHost])
Small Github repo with example code: https://github.com/roar-skinderviken/pubsub-emulator-demo
Long answer with code
I finally managed to make a working solution using Micronaut 3.0.2 and Spock. A related Micronaut PR got me on track, together with this article: Micronaut Testing Best Practices https://objectcomputing.com/files/9815/9259/7089/slide_deck_Micronaut_Testing_Best_Practices_webinar.pdf
First a PubSubEmulator class (Groovy)
package no.myproject.testframework.testcontainers
import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName
class PubSubEmulator {
static PubSubEmulatorContainer pubSubEmulatorContainer
static init() {
if (pubSubEmulatorContainer == null) {
pubSubEmulatorContainer = new PubSubEmulatorContainer(
DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
pubSubEmulatorContainer.start()
}
}
}
Then a fixture for PubSubEmulator (Groovy)
package no.myproject.testframework.testcontainers
trait PubSubEmulatorFixture {
Map<String, Object> getPubSubConfiguration() {
if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
PubSubEmulator.init()
}
[
"pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
]
}
}
Then a specification class (Groovy) that starts the container, creates a topic and a subscription.
The clue here is to pass in pubsub.emulator.host as part of the configuration when calling ApplicationContext.run.
Remaining part of the code is very similar to the Spring Boot example I linked to in my question.
package no.myproject.testframework
import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
abstract class PubSubSpecification extends Specification
implements PubSubEmulatorFixture, EnvironmentFixture {
#AutoCleanup
#Shared
EmbeddedServer embeddedServer
#AutoCleanup
#Shared
ApplicationContext applicationContext
def setupSpec() {
// start the pubsub emulator
def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")
// start a temporary applicationContext in order to read config
// keep any pubsub subscriptions out of context at this stage
applicationContext = ApplicationContext.run()
def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)
def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
.usePlaintext()
.build()
def channelProvider =
FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))
// START creating topic
def topicAdminClient =
TopicAdminClient.create(
TopicAdminSettings.newBuilder()
.setCredentialsProvider(NoCredentialsProvider.create())
.setTransportChannelProvider(channelProvider)
.build())
def topic = TopicName.of(
gcpConfigProperties.getProjectId(),
pubSubConfigProperties.getTopicName())
try {
topicAdminClient.createTopic(topic)
} catch (AlreadyExistsException) {
// this is fine, already created
topicAdminClient.getTopic(topic)
}
// START creating subscription
pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
def subscription =
ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)
def subscriptionAdminClient =
SubscriptionAdminClient.create(
SubscriptionAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(NoCredentialsProvider.create())
.build())
try {
subscriptionAdminClient
.createSubscription(
subscription,
topic,
PushConfig.getDefaultInstance(),
100)
System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
} catch (AlreadyExistsException) {
// this is fine, already created
subscriptionAdminClient.getSubscription(subscription)
}
})
channel.shutdown()
// stop the temporary applicationContext
applicationContext.stop()
// start the actual applicationContext
embeddedServer = ApplicationContext.run(
EmbeddedServer,
[
'spec.name' : "PubSubEmulatorSpec",
"pubsub.emulator.host": emulatorHost
],
environments)
applicationContext = embeddedServer.applicationContext
}
}
Then a factory class (Groovy) for mocking credentials
package no.myproject.pubsub
import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires
import javax.inject.Singleton
#Factory
#Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {
#Singleton
#Replaces(GoogleCredentials)
GoogleCredentials mockCredentials() {
return GoogleCredentials.create(new AccessToken("", new Date()))
}
}
And finally, a Spock test spec.
package no.myproject.pubsub
import no.myproject.testframework.PubSubSpecification
import java.util.stream.IntStream
class PubSubIntegrationSpec extends PubSubSpecification {
def NUMBER_OF_MESSAGES_IN_TEST = 5
def DELAY_IN_MILLISECONDS_PER_MSG = 100
def "when a number of messages is sent, same amount of messages is received"() {
given:
def documentPublisher = applicationContext.getBean(DocumentPublisher)
def listener = applicationContext.getBean(IncomingDocListenerWithAck)
def initialReceiveCount = listener.getReceiveCount()
when:
IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
.forEach(it -> documentPublisher.send("Hello World!"))
// wait a bit in order to let all messages propagate through the queue
Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)
then:
NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
}
}
The chosen answer is a good deal more complicated than necessary, and it also contains numerous typos. A better answer can be found via the Micronaut GCP codebase itself, with the key bit being:
class IntegrationTestSpec extends Specification {
static CONTAINER_PORT = -1
static CredentialsProvider CREDENTIALS_PROVIDER
static TransportChannelProvider TRANSPORT_CHANNEL_PROVIDER
static PubSubResourceAdmin pubSubResourceAdmin
static GenericContainer pubSubContainer = new GenericContainer("google/cloud-sdk:292.0.0")
.withCommand("gcloud", "beta", "emulators", "pubsub", "start", "--project=test-project",
"--host-port=0.0.0.0:8085")
.withExposedPorts(8085)
.waitingFor(new LogMessageWaitStrategy().withRegEx("(?s).*Server started, listening on.*"))
static {
pubSubContainer.start()
CONTAINER_PORT = pubSubContainer.getMappedPort(8085)
CREDENTIALS_PROVIDER = NoCredentialsProvider.create()
def host = "localhost:" + IntegrationTest.CONTAINER_PORT
ManagedChannel channel = ManagedChannelBuilder.forTarget(host).usePlaintext().build()
TRANSPORT_CHANNEL_PROVIDER =
FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))
pubSubResourceAdmin = new PubSubResourceAdmin(TRANSPORT_CHANNEL_PROVIDER, CREDENTIALS_PROVIDER)
}
}
You'd then just extend that class anywhere you wanted to make use of PubSub. The following is slightly cleaner example that I came up with which manages creating a topic as well during test startup:
#Slf4j
abstract class PubSubSpec extends Specification implements TestPropertyProvider {
static final String cloudSdkName = System.getenv('CLOUD_SDK_IMAGE') ?: "gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"
static final DockerImageName cloudSdkImage = DockerImageName.parse(cloudSdkName)
static final PubSubEmulatorContainer pubsubEmulator = new PubSubEmulatorContainer(cloudSdkImage)
static {
pubsubEmulator.start()
ManagedChannel channel = ManagedChannelBuilder.forTarget(pubsubEmulator.getEmulatorEndpoint()).usePlaintext().build()
try {
TransportChannelProvider channelProvider = FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))
CredentialsProvider credentialsProvider = NoCredentialsProvider.create()
TopicAdminClient topicClient = TopicAdminClient.create(
TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
)
TopicName topicName = TopicName.of("project-id", "project-topic")
topicClient.createTopic(topicName)
} finally {
channel.shutdown()
}
}
#Override
Map<String, String> getProperties() {
[
"pubsub.emulator.host": pubsubEmulator.getEmulatorEndpoint()
]
}
}
hey everyone i have an issue with thymeleaf and my static html pages
to be more specific i have a spring mvc web application am using also spring security , well in my login page i want to use thymeleaf so can spring security communicate with client layer in the other side i don't want to include thymeleaf in my all html pages cause am going to use AngularJs
I tried to put the login in templates folder and the other's in the static folder but id doesn't work
this is my thymleaf configuration class
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.thymeleaf.spring3.SpringTemplateEngine;
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
#Configuration
public class ThymeleafConfig {
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/vues/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setOrder(1);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
}
my problem is i don't want Thymeleaf included in my all pages you know XHTML is pretty annoying with closing the html tag
any guide will be thankfull
Well i think you dont have to use the XHTML Syntax if u are not including thymleaf into the specific page.
I'm working on an angular app using play framework for my rest-services. Everything in the public folder is an angular app (stylesheets, javascripts, images and html). I want every request that is not for something in the stylesheets, javascripts, templates or images folder to be routed to the index.html page. This is so that angular routing can take over from there...
As a side note i can mention that I am going to place every restservice under /services/ which links to my own java controllers.
Is it possible in play framework 2.3.4 to define a route that catches all without having to use the matching elements?
This is my route defs so far:
GET / controllers.Assets.at(path="/public", file="index.html")
GET /stylesheets/*file controllers.Assets.at(path="/public/stylesheets", file)
GET /javascripts/*file controllers.Assets.at(path="/public/javascripts", file)
GET /templates/*file controllers.Assets.at(path="/public/templates", file)
GET /images/*file controllers.Assets.at(path="/public/images", file)
#this line fails
GET /* controllers.Assets.at(path="/public", file="index.html")
It's not possible to omit usage of matching elements but you can route a client via controller. The route definition looks like this:
GET /*path controllers.Application.matchAll(path)
And the corresponding controller can be implemented as follows:
public class Application extends Controller {
public static Result matchAll(String path) {
return redirect(controllers.routes.Assets.at("index.html"));
}
}
Update
If you don't want to redirect a client you can return a static resource as a stream. In this case a response MIME type is required.
public class Application extends Controller {
public static Result matchAll(String path) {
return ok(Application.class.getResourceAsStream("/public/index.html")).as("text/html");
}
}
For this task you can use onHandlerNotFound in Global class which will render some page without redirect:
import play.*;
import play.mvc.*;
import play.mvc.Http.*;
import play.libs.F.*;
import static play.mvc.Results.*;
public class Global extends GlobalSettings {
public Promise<Result> onHandlerNotFound(RequestHeader request) {
return Promise.<Result>pure(notFound(
views.html.notFoundPage.render(request.uri())
));
}
}
Answer for scala developers using playframework :)
Similar to above one about creating controller which will accept parameters and then omit them.
Example routing:
GET / controllers.Assets.at(path="/public", file="index.html")
GET /*ignoredPath ui.controller.AssetsWithIgnoredWildcard.at(path="/public", file="index.html", ignoredPath: String)
controller with assets injected by framework:
class AssetsWithIgnoredWildcard #Inject() (assets: Assets) {
def at(
path: String,
file: String,
wildcardValueToIgnore: String,
aggressiveCaching: Boolean = false): Action[AnyContent] = {
assets.at(path, file, aggressiveCaching)
}
}
I would like to externalise my selenium tests setting in order to make them more configurable.
I would like to externalise my testURL and my node URLS.
Here is my code :
public void setup () throws MalformedURLException
{ //the URL of the application to be tested
TestURL = "http://frstmwarwebsrv2.orsyptst.com:9000";
//Hub URL
BaseURL = "http://10.2.128.126";
//Node1 URL
winURL = "http://10.2.128.120:5556/wd/hub";
//Node2 URL
androidURL ="http://10.2.128.120:5555/wd/hub";
At the moment I have added this setup function in every test I would like to have it in an XML file for an example in order to make it configurable, any suggestions?
Thanks
Thanks for your help
Update :
Here is what i did so far :
Added a config.properties file with this content :
# This is my test.properties file
AppURL = http://************
HubURL= http://*****************
WinURL= http://*********/wd/hub
AndroidURL =
iOSURL
And created a classe to read properties :
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
public class ReadPropertiesFile {
public static void main(String[] args) {
try {
File file = new File("config.properties");
FileInputStream fileInput = new FileInputStream(file);
Properties properties = new Properties();
properties.load(fileInput);
fileInput.close();
Enumeration enuKeys = properties.keys();
while (enuKeys.hasMoreElements()) {
String key = (String) enuKeys.nextElement();
String value = properties.getProperty(key);
System.out.println(key + ": " + value);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
when running this i get this error :
java.io.FileNotFoundException: config.properties (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at ReadPropertiesFile.main(ReadPropertiesFile.java:15)
my properties file is under src folder
Two basic ways you could do this are:
Pass in JVM argument and access it using System.getProperty(...)
Externalize your configuration in to properties files, like here
I recently implemented the second one in my Selenium tests and can expand this answer to give more details if you need them.
In my tests, I resolved it that I created Java class called Environment to store information about given Environment:
Few snippets of code:
public enum NameOfEnvironment {
SYSTEMTEST, ACCEPTANCE
}
stores the Name of given Environment :)
public String getBaseUrl() {
switch (actualEnvironment) {
case SYSTEMTEST: {
baseUrl = getPrefix() + "172.23.32.251:9092/pages/index.html";
break;
}
will return me the URL to the environment. And on beginning of the test I have something like this:
public static final Environment USED_ENVIRONMENT = new Environment(Environment.NameOfEnvironment.SYSTEMTEST);
And later on I just call USED_ENVIRONMENT.getBaseUrl() which will return me the link which is being actual for current run
Btw, to fill in the blanks, here is the constructor f the class
public Environment(NameOfEnvironment env) {
this.actualEnvironment = env;
}