I'm a newbie developing a liferay 6.1 portlet. I want a static url and static content in the page where my portlet will be. What methods are recommended and available for distributing the portlet and page to different environments?
I want all environments to match as exactly as possible and I prefer to have everything automated, so I would like the page creation automatic too.
You could use the resources importer, a documentation for that can be found in the Liferay Developer Network: Creating plugins to share structures, templates and more.
Or you create a LAR file by exporting your pages - again described in the Liferay Developer Network: Export/Import.
You can import a LAR file from the UI or with the following code:
public void importPages() {
// Define the settings for import - here some examples:
final Map<String, String[]> params = new HashMap<>();
addParam(params, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES, true);
addParam(params, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES_ALL, true);
addParam(params, PortletDataHandlerKeys.PORTLET_CONFIGURATION, true);
addParam(params, PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL, true);
addParam(params, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS, true);
addParam(params, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS_ALL, true);
addParam(params, PortletDataHandlerKeys.PORTLET_DATA, true);
addParam(params, PortletDataHandlerKeys.PORTLET_DATA_ALL, true);
addParam(params, PortletDataHandlerKeys.PORTLET_SETUP, true);
addParam(params, PortletDataHandlerKeys.PORTLET_SETUP_ALL, true);
addParam(params, PortletDataHandlerKeys.PORTLET_DATA_CONTROL_DEFAULT, true);
addParam(params, PortletDataHandlerKeys.THEME_REFERENCE, true);
addParam(params, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS, true);
addParam(params, PortletDataHandlerKeys.LOGO, true);
addParam(params, PortletDataHandlerKeys.CATEGORIES, true);
addParam(params, PortletDataHandlerKeys.RATINGS, true);
addParam(params, PortletDataHandlerKeys.COMMENTS, true);
addParam(params, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS, true);
addParam(params, PortletDataHandlerKeys.DELETIONS, true);
addParam(params, PortletDataHandlerKeys.DELETE_PORTLET_DATA, true);
addParam(params, PortletDataHandlerKeys.USER_ID_STRATEGY, UserIdStrategy.CURRENT_USER_ID);
addParam(params, PortletDataHandlerKeys.DATA_STRATEGY, PortletDataHandlerKeys.DATA_STRATEGY_MIRROR);
addParam(params, PortletDataHandlerKeys.PERMISSIONS, true);
// Import with the current user into the current site (= group)
ThemeDisplay themeDisplay = (ThemeDisplay) getPortletRequest().getAttribute(WebKeys.THEME_DISPLAY)
LayoutLocalServiceUtil.importLayouts(themeDisplay.getUserId(), themeDisplay.getHostGroupId(), false, params, inputStreamOfMyLARFile);
}
// Helper method
private static void addParam(final Map<String, String[]> params, final String key, final Object value) {
params.put(key, new String[] { value.toString() });
}
Related
Whenever Image is uploaded to the Stock item page, I have to resize the image to thump size and upload the copy of the same.
How do I override the upload function to add my logic?
The upload function is HandleUpload of the PXImageUploader control in PX.Web.UI.
You can try to overwrite that function and then replace the control on the page with yours.
Another way will be to handle the resizing inside the InventoryItemMaint graph.
You can check the ImageUrl field update and do the resize there. Any time you upload a new picture the URL is basically updated. Please don't use the example below in production as it was never fully tested.
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class InventoryItemMaintExt : PXGraphExtension<InventoryItemMaint>
{
public PXSelect<UploadFileRevision> uploadFileRevisions;
protected virtual void InventoryItem_ImageUrl_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e, PXFieldUpdated baseMethod)
{
baseMethod?.Invoke(sender, e);
if(e.Row is InventoryItem row)
{
if ((string)e.OldValue != row.ImageUrl) //ADD conditions so that this doesn't work any time user change the image if there are multiple attached
{
UpdateImageFileRevisionToResizedImage(sender, row);
}
}
}
private void UpdateImageFileRevisionToResizedImage(PXCache sender, InventoryItem row)
{
var fileNotes = PXNoteAttribute.GetFileNotes(sender, row);
UploadFileRevision uploadedFile = GetFile(sender.Graph, fileNotes, row.ImageUrl);
if (uploadedFile != null)
{
var data = ResizeImage(uploadedFile.Data);
uploadedFile.Data = data;
uploadFileRevisions.Update(uploadedFile);
}
}
//WARNING: DON'T USE THIS METHOD IN PRODUCTION.
// USE ANY OTHER RECOMMENDED METHOD TO RESIZE IMAGES
private static byte[] ResizeImage(byte[] data)
{
System.IO.MemoryStream myMemStream = new System.IO.MemoryStream(data);
System.Drawing.Image fullsizeImage = System.Drawing.Image.FromStream(myMemStream);
System.Drawing.Image newImage = fullsizeImage.GetThumbnailImage(200, 200, null, IntPtr.Zero);
System.IO.MemoryStream myResult = new System.IO.MemoryStream();
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Jpeg); //Or whatever format you want.
return myResult.ToArray(); //Returns a new byte array.
}
private static UploadFileRevision GetFile(PXGraph graph, Guid[] fileIds,string fileUrl)
{
return (UploadFileRevision)PXSelectBase<UploadFileRevision,
PXSelectJoin< UploadFileRevision,
InnerJoin <UploadFile,
On<UploadFile.fileID, Equal<UploadFileRevision.fileID>,
And<UploadFile.lastRevisionID, Equal<UploadFileRevision.fileRevisionID>>>>,
Where<UploadFile.fileID, In<Required<UploadFile.fileID>>,
And<UploadFile.name,Equal<Required<UploadFile.name>>>>>.Config>.Select(graph, new object[]
{
fileIds,
fileUrl
});
}
}
I have looked in so many places on a lead on how or if it is possible to view images uploaded to cloudinary, by a specific tag through Android studio app i am trying to build.
I was able to implement the upload option by user, with adding a tag to the images, and public id, also retrieving these information, but i cant find anything on how to view these images, for example i want the app to be able to view all images with a specific tag ( username ) to the user that uploaded the pictures, and could delete them ? and also view other images uploaded by other user with no other permission.
Is it possible and how !?
I ended up with this code, and i encountered a problem;
#Override
public void onClick(View v) {
new JsonTask().execute("http://res.cloudinary.com/cloudNAme/video/list/xxxxxxxxxxxxxxxxxxx.json");
// uploadExtract();
}
});
public class JsonTask extends AsyncTask<String ,String,String> {
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
In the log i get the following;
03-28 12:36:14.726 20333-21459/net.we4x4.we4x4 W/System.err: java.io.FileNotFoundException: http://res.cloudinary.com/we4x4/video/list/3c42f867-8c3a-423b-89e8-3fb777ab76f8.json
i am not sure if my understanding is correct of the method or i am doing something wrong ? since in the Admin API Docs. or cloudinary the syntax for the HTML request and also in the suggested page by Nadav:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
this should've returned a JSON ?
The following feature allows you to retrieve a JSON formatted list of resources that which share a common tag:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
Note that image removal will coerce you to use server-side code (e.g. JAVA), since deleting via Cloudinary requires a signature that is based on your API_SECRET.
I'm writing a java program to access hadoop jobhistory service to retrieve some information.
I'm using HTTPClient to make the HttpGet call. I need to login from a keytab file (I have the file on my ~/.ssh/ folder) instead of type in user name and password.
My question is: How to login from keytab in HTTPClient?
Here is how I set up my HTTPClient
System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
System.setProperty("java.security.krb5.realm", prop.getProperty("krb5.realm"));
System.setProperty("java.security.krb5.kdc", prop.getProperty("krb5.kdc"));
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(100);
//TODO login from keytab ?
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("DUMMY", null));
Lookup<AuthSchemeProvider> authRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.build();
httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider)
.setDefaultAuthSchemeRegistry(authRegistry)
.setConnectionManager(cm)
.build();
HttpResponse response = httpClient.execute(request);
One interesting is this code can run successfully in my IntelliJ. But After I build and run it from command line, it will show up the info to ask me for username and password.
I'm new to authentication, hope somebody can help. Thanks a lot.
HttpClientBuilder builder = HttpClientBuilder.create();
Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();
builder.setDefaultAuthSchemeRegistry(authSchemeRegistry);
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(null, -1, null), new Credentials() {
#Override
public Principal getUserPrincipal() {
return null;
}
#Override
public String getPassword() {
return null;
}
});
builder.setDefaultCredentialsProvider(credentialsProvider);
final HttpClient httpClient = builder.build();
final Subject subj = new Subject();
Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> options = new HashMap<>();
options.put("doNotPrompt", "true");
options.put("storeKey", "true");
options.put("useKeyTab", "true");
options.put("useTicketCache", "true");
options.put("keyTab", keytabFilePath); //Path to keytab file
options.put("principal", principal); //Principal name
options.put("debug", "true");
krb5.initialize(subj, null, null, options);
krb5.login();
krb5.commit();
HttpResponse response = Subject.doAs(subj, new PrivilegedExceptionAction<HttpResponse>() {
#Override
public HttpResponse run() throws Exception {
return httpClient.execute(request);
}
});
I developed RssFeed Application using LWUIT j2me(java) for 2 xml files, now I want to show those 2 xml files on LWUIT Tabs.
That means, when my application runs, default tab will be displayed (on that tab my first Rss xml file Titles should be displayed), and when the user click on tab2 my second Rss xml titles should be displayed.
I am able to display the same titles of one rss files on both the tabs, how to control my flow to achieve my task?
Here my code:
public class XMLMidlet extends MIDlet implements ActionListener {
public XMLMidlet() {
Display.init(this);
news = new Vector();
m_backCommand = new Command("Back");
cmdExit = new Command("EXIT");
cmdDetails = new Command("Details");
}
public void startApp() {
//RssFeed URL's
String urls[] = {"http://topnews-23.rss",
"http://topstory-12.rss"};
for(int i=0;i<urls.length;i++){
ParseThread myThread = new ParseThread(this,urls[i]);
//this will start the second thread
myThread.getXMLFeed(urls[i]);
}
}
//method called by the parsing thread
public void addNews(News newsItem,String url) {
try{
news.addElement(newsItem);
form1 = new Form();
myNewsList = new List(newsVector);
newsList =new List(newsVector);
myNewsList.setRenderer(new NewsListCellRenderer());
newsList.setRenderer(new NewsListCellRenderer());
tabs=new Tabs(Component.TOP);
tabs.addTab("TopNews", myNewsList);
tabs.addTab("Topstory",newsList);
form1.addComponent(tabs);
form1.show();
}
catch(Exception e){
e.printStackTrace();
}
}
You should move below code
myNewsList = new List(newsVector);
newsList =new List(newsVector);
myNewsList.setRenderer(new NewsListCellRenderer());
newsList.setRenderer(new NewsListCellRenderer());
tabs=new Tabs(Component.TOP);
form1 = new Form();
tabs=new Tabs(Component.TOP);
tabs.addTab("TopNews", myNewsList);
tabs.addTab("Topstory",newsList);
from addNews method to constructor XMLMidlet. addNews method should use url parameter to differ for which list the newsItem is directed.
Update
Below is how I think you should implement addNews method:
public void addNews(News newsItem, String url) {
if (url.endsWith("topnews-20.rss")) {
myNewsList.addElement(newsItem);
} else if (url.endsWith("topstory-25.rss")) {
newsList.addElement(newsItem);
}
}
serRenderer does not need to be called from addNews and form1.show() should be moved to startApp.
This is a bit of a two part question.
I am using Tim Tripcony's Fancy XPage Typeahead script in a number of applications to return a typeahead list based on a number of different views in a specific database.
Can the server side javascript listed in that blog be transformed into a java class to return the same results that can be picked up by the native typeahead functions in XPages.
Can that class be part of an extension library that is deployed to all servers so it is available to all applications for immediate use and if so how would it be called from the XPage.
Yes, I can't think of an example of any SSJS that cannot be converted to Java, Here is Tim Tripcony's SSJS ported to Java.
import java.util.HashMap;
import java.util.Map;
import lotus.domino.*;
import com.ibm.domino.xsp.module.nsf.NotesContext;
public class TypeAhead {
public static String directoryTypeAhead(String searchValue) {
String returnList = "";
try {
Database directory = NotesContext.getCurrent().getCurrentSession().getDatabase("", "names.nsf");
View allUsers = directory.getView("($Users)");
Map<String, HashMap<String, String>> matches = new HashMap<String, HashMap<String, String>>();
Map<String, String> individualMatches = new HashMap<String, String>();
Map<String, Boolean> includeForm = new HashMap<String, Boolean>();
includeForm.put("Person", Boolean.TRUE);
includeForm.put("Group", Boolean.TRUE);
ViewEntryCollection matchingEntries = allUsers.getAllEntriesByKey(searchValue, false);
ViewEntry entry = matchingEntries.getFirstEntry();
int resultCount = 0;
while (entry != null) {
Document matchDoc = entry.getDocument();
String matchType = matchDoc.getItemValueString("Form");
if ((Boolean)includeForm.get(matchType)) {
String fullName = matchDoc.getItemValue("FullName").elementAt(0).toString();
if (matches.get(fullName) == null) {
resultCount++;
Name matchName = NotesContext.getCurrent().getCurrentSession().createName(fullName);
individualMatches = new HashMap<String, String>();
individualMatches.put("cn", matchName.getCommon());
individualMatches.put("photo", matchDoc.getItemValueString("photoUrl"));
individualMatches.put("job", matchDoc.getItemValueString("jobTitle"));
individualMatches.put("email", matchDoc.getItemValueString("internetAddress"));
matches.put(fullName, (HashMap<String, String>) individualMatches);
}
}
if (resultCount > 9) {
entry = null;
}
else {
entry = matchingEntries.getNextEntry(entry);
}
}
returnList = "<ul>";
for (Map<String, String> match : matches.values()) {
String matchDetails = "<li><table><tr><td><img class=\"avatar\" src=\"" + match.get("photo") + "\"/></td><td valign=\"top\"><p><strong>" + match.get("cn") + "</strong></p><p><span class=\"informal\">" + match.get("job") + "<br/>" + match.get("email") + "</span></p></td></tr></table></li>";
returnList += matchDetails;
}
returnList += "</ul>";
} catch(Exception e) {
System.out.println(e);
}
return returnList;
}
}
As far as creating it in an extension library all you really have to do to get what I think you want is put it in a plugin Jar and create a feature and update site then you can use the new 8.5.3 functionality to replicate it out to all of your servers.
You might use this code by doing the following inside of your xpage:
<xp:inputText id="inputText1" value="#{viewScope.someVar}">
<xp:typeAhead mode="partial" minChars="1" valueMarkup="true"
var="searchValue"
valueList="#{javascript:return com.tobysamples.demo.TypeAhead.directoryTypeAhead(searchValue);}">
</xp:typeAhead></xp:inputText>
I think it is not that hard to convert the SSJS to Java. With a managed bean you can immediately access the java method by the field.
And should be a nice enhancement to the Extension Library, so everyone can benefit this cool typeahead