I used the code below to get the list of culture type, is there a way on how to get just the country name?
Thank you
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
sb.Append(ci.DisplayName);
sb.AppendLine();
}
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
Sample Output:
Spanish (Puerto Rico)
Spanish (United States)
You can use the Name property of the CultureInfo to construct a RegionInfo. You can then use the DisplayName property.
Try:
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
var ri = new RegionInfo(ci.Name);
Console.WriteLine(ri.DisplayName);
}
Well, this regular expression seems to do the job in most cases:
var regex = new System.Text.RegularExpressions.Regex(#"([\w+\s*\.*]+\))");
foreach (var item in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
var match = regex.Match(item.DisplayName);
string countryName = match.Value.Length == 0 ? "NA" : match.Value.Substring(0, match.Value.Length - 1);
Console.WriteLine(countryName);
}
// Build your normal dictionary as container
Dictionary<string, string> countryNames = new Dictionary<string, string>();
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
RegionInfo ri = new RegionInfo(ci.Name);
// Check if the ISO language code is already in your collection
// Because you don't want double entries in a country box because we had to use the culture info
if (!countryNames.ContainsKey(ri.TwoLetterISORegionName))
{
countryNames.Add(ri.TwoLetterISORegionName.ToUpper(), ri.EnglishName);
}
}
// Code for dictionary to dropdownlist transform can be written with your personal preference for symantics
SelectList countryDropdown = new SelectList(countryNames.OrderBy(o => o.Value), "Key", "Value");
Or ready for use without comments:
Dictionary<string, string> countryNames = new Dictionary<string, string>();
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
RegionInfo ri = new RegionInfo(ci.Name);
if (!countryNames.ContainsKey(ri.TwoLetterISORegionName)) countryNames.Add(ri.TwoLetterISORegionName.ToUpper(), ri.EnglishName);
}
SelectList countryDropdown = new SelectList(countryNames.OrderBy(o => o.Value), "Key", "Value");
this would be what you are looking for:
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
sb.Append(ci.EnglishName);
sb.AppendLine();
}
You will need to use following namespaces
using System.Configuration;
using System.Globalization;
/// <summary>
/// populate country name
/// </summary>
/// <param name="dropDown"></param>
public static void GetCountryNames(DropDownList dropDown)
{
Hashtable h = new Hashtable();
Dictionary<string, string> objDic = new Dictionary<string, string>();
foreach (CultureInfo ObjCultureInfo in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
RegionInfo objRegionInfo = new RegionInfo(ObjCultureInfo.Name);
if (!objDic.ContainsKey(objRegionInfo.EnglishName))
{
objDic.Add(objRegionInfo.EnglishName, objRegionInfo.TwoLetterISORegionName.ToLower());
}
}
SortedList<string, string> sortedList = new SortedList<string, string>(objDic);
foreach (KeyValuePair<string, string> val in sortedList)
{
dropDown.Items.Add(new ListItem(val.Key, val.Key));
}
dropDown.Items.Insert(0, new ListItem("Select", "Select"));
dropDown.Items.Insert(1, new ListItem("Other Country", "Other"));
}
You can use my nuget package Nager.Country. There is a lot of additional information available for each country. For more information please visit the Github project
PM> install-package Nager.Country
ICountryProvider countryProvider = new CountryProvider();
foreach (var countryCode in (Alpha2Code[])Enum.GetValues(typeof(Alpha2Code)))
{
var countryInfo = countryProvider.GetCountry(countryCode);
Console.WriteLine(countryInfo.CommonName);
}
Related
Is it possible to use a foreach loop in a BLC to iterate through the fields of a PXResultSet to get the FieldNames?
Is this doable? I can't seem to find a good way.
Thanks...
The PXResultset records are selected from a view. You can get the field names from the View.
Here's a full example:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
// Get field list from data view
var dataView = new PXSelect<SOOrder>(Base);
string fieldNames = string.Join(",", GetFieldNames(dataView.View, Base.Caches));
// You don't need result set to get field names
PXResultset<SOOrder> resultSet = dataView.Select();
throw new PXException(fieldNames);
}
public string[] GetFieldNames(PXView view, PXCacheCollection caches)
{
var list = new List<string>();
var set = new HashSet<string>();
foreach (Type t in view.GetItemTypes())
{
if (list.Count == 0)
{
list.AddRange(caches[t].Fields);
set.AddRange(list);
}
else
{
foreach (string field in caches[t].Fields)
{
string s = String.Format("{0}__{1}", t.Name, field);
if (set.Add(s))
{
list.Add(s);
}
}
}
}
return list.ToArray();
}
}
When run, this example will show the fields names used in the data view in Sales Order screen SO301000 as an exception.
Field names are contained in Cache object. If you really need to get field names from PXResultset you need to iterate the cache types in the result set.
Example for first DacType (0) of result set:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
var dataView = new PXSelect<SOOrder>(Base);
PXResultset<SOOrder> resultSet = dataView.Select();
foreach (PXResult result in resultSet)
{
Type dacType = result.GetItemType(0);
foreach (var field in Base.Caches[dacType].Fields)
PXTrace.WriteInformation(field);
}
}
}
I'm would like to use MOXy to marshal / unmarshal object from existing classes.
I would like to know if there is a mean to generate XML binding files (cause I don't want to use annotations) from my classes.
Or do we have to do it all with our little hands :) ?
By default JAXB/MOXy doesn't require any metadata to be specified (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html). You only need to specify the metadata where you want to override the default behaviour.
I'm guessing your real question is what is the easiest way to create the MOXy external mapping document. I do the following with Eclipse, there are probably similar steps for your favourite IDE:
Get the XML Schema for MOXy's mapping document
<EclipseLink_Home>/xsds/eclipselink_oxm_2_5.xsd
Register the XML Schema with your IDE
Eclipse | Preferences | XML | XML Catalog | Add
Create and XML document in the IDE and specify the following as the root element.
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"/>
Use the auto-complete functionality offered by your IDE to construct the XML document.
Another option is to generate jaxb classes and from those read the bindings (annotations) producing an external mapping (after which you can remove the annotations). PoC code:
public class MoxyBindingGenerator {
private static final String PACKAGE = "com.company.binding.jaxbclasses";
private static ObjectFactory xmlBindingsFactory = new ObjectFactory();
public static void main(String[] args) throws Exception {
Collection<TypeInfo> typeInfos = readAnnotations();
XmlBindings xmlBindings = xmlBindingsFactory.createXmlBindings();
xmlBindings.setPackageName(PACKAGE);
JavaTypes javaTypes = xmlBindingsFactory.createXmlBindingsJavaTypes();
xmlBindings.setJavaTypes(javaTypes);
List<JavaType> javaTypesList = javaTypes.getJavaType();
XmlEnums xmlEnums = xmlBindingsFactory.createXmlBindingsXmlEnums();
xmlBindings.setXmlEnums(xmlEnums);
List<XmlEnum> xmlEnumsList = xmlEnums.getXmlEnum();
typeInfos.stream().forEach(typeInfo -> {
if (!typeInfo.isEnumerationType()) {
fillJavaTypes(javaTypesList, typeInfo);
}
else {
fillEnumTypes(xmlEnumsList, typeInfo);
}
});
saveToFile(xmlBindings);
}
private static Collection<TypeInfo> readAnnotations() throws JAXBException, Exception {
JAXBContext jaxbContext = (JAXBContext) javax.xml.bind.JAXBContext.newInstance(PACKAGE);
Object contextState = getPrivateField(jaxbContext, "contextState");
Generator generator = (Generator) getPrivateField(contextState, "generator");
AnnotationsProcessor annotationsProcessor = generator.getAnnotationsProcessor();
Collection<TypeInfo> typeInfos = annotationsProcessor.getTypeInfo().values();
return typeInfos;
}
private static void fillEnumTypes(List<XmlEnum> xmlEnumsList, TypeInfo typeInfo) {
EnumTypeInfo et = (EnumTypeInfo) typeInfo;
XmlEnum xmlEnum = xmlBindingsFactory.createXmlEnum();
xmlEnum.setJavaEnum(et.getJavaClassName());
List<String> xmlEnumNames = et.getFieldNames();
List<Object> xmlEnumValues = et.getXmlEnumValues();
for (int i = 0; i < xmlEnumNames.size(); i++) {
String xmlEnumName = xmlEnumNames.get(i);
Object xmlEnumObject = xmlEnumValues.get(i);
XmlEnumValue xmlEnumValue = xmlBindingsFactory.createXmlEnumValue();
xmlEnumValue.setJavaEnumValue(xmlEnumName);
xmlEnumValue.setValue(xmlEnumObject.toString());
xmlEnum.getXmlEnumValue().add(xmlEnumValue);
}
xmlEnumsList.add(xmlEnum);
}
private static void fillJavaTypes(List<JavaType> javaTypesList, TypeInfo typeInfo) {
JavaType javaType = xmlBindingsFactory.createJavaType();
javaType.setName(typeInfo.getJavaClassName());
fillXmlType(javaType, typeInfo);
if (typeInfo.getXmlRootElement() != null) {
XmlRootElement xmlRootElement = typeInfo.getXmlRootElement();
xmlRootElement.setNamespace(null);
javaType.setXmlRootElement(xmlRootElement);
}
JavaAttributes javaAttributes = xmlBindingsFactory.createJavaTypeJavaAttributes();
javaType.setJavaAttributes(javaAttributes);
List<JAXBElement<? extends JavaAttribute>> javaAttributeList = javaAttributes.getJavaAttribute();
typeInfo.getNonTransientPropertiesInPropOrder().stream().forEach(field -> {
fillFields(javaAttributeList, field);
});
javaTypesList.add(javaType);
}
private static void fillFields(List<JAXBElement<? extends JavaAttribute>> javaAttributeList, Property field) {
if (field.getXmlElements() != null && field.getXmlElements().getXmlElement().size() > 0) {
XmlElements xmlElements = xmlBindingsFactory.createXmlElements();
xmlElements.setJavaAttribute(field.getPropertyName());
List<XmlElement> elements = field.getXmlElements().getXmlElement();
elements.stream().forEach(e -> {
e.setDefaultValue(null);
e.setNamespace(null);
xmlElements.getXmlElement().add(e);
});
JAXBElement<XmlElements> value = xmlBindingsFactory.createXmlElements(xmlElements);
javaAttributeList.add(value);
}
else if (!field.isAttribute()) {
XmlElement value = xmlBindingsFactory.createXmlElement();
value.setJavaAttribute(field.getPropertyName());
value.setName(field.getSchemaName().getLocalPart());
if (field.isNillable())
value.setNillable(field.isNillable());
if (field.isRequired())
value.setRequired(field.isRequired());
javaAttributeList.add(xmlBindingsFactory.createXmlElement(value));
}
else {
XmlAttribute value = xmlBindingsFactory.createXmlAttribute();
value.setJavaAttribute(field.getPropertyName());
value.setName(field.getSchemaName().getLocalPart());
javaAttributeList.add(xmlBindingsFactory.createXmlAttribute(value));
}
}
private static void saveToFile(XmlBindings xmlBindings)
throws JAXBException, PropertyException, FileNotFoundException, IOException {
JAXBContext xmlModelJaxbContext =
(JAXBContext) javax.xml.bind.JAXBContext.newInstance("org.eclipse.persistence.jaxb.xmlmodel");
JAXBMarshaller marshaller = xmlModelJaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
FileOutputStream fos = new FileOutputStream(new File(System.getProperty("user.home"), "binding-imspoor-oxm.xml"));
marshaller.marshal(xmlBindings, fos);
fos.close();
}
private static void fillXmlType(JavaType javaType, TypeInfo typeInfo) {
XmlType orgXmlType = typeInfo.getXmlType();
if (orgXmlType != null) {
boolean add = false;
XmlType xmlType = xmlBindingsFactory.createXmlType();
if (!StringUtils.isEmpty(orgXmlType.getName())) {
xmlType.setName(orgXmlType.getName());
add = true;
}
if (orgXmlType.getPropOrder() != null && orgXmlType.getPropOrder().size() > 1) {
xmlType.getPropOrder().addAll(orgXmlType.getPropOrder());
add = true;
}
if (add)
javaType.setXmlType(xmlType);
}
}
private static Object getPrivateField(Object obj, String fieldName) throws Exception {
Field declaredField = obj.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField.get(obj);
}
}
I've just included Lucene search into my first application (ASP.NET MVC 5) but I'm having some issues indexing my database initially and in figuring out what the correct overall application architecture should be.
My current setup is:
Azure scheduler that calls into my web API to request indexing of all categories, and then separately all items. Another scheduler that runs once every 3 months or so to call Optimize (db won't change that often). The API grabs all entities from the DB and adds a new CloudQueueMessage to a CloudQueueClient.
A running WebJob pulls from the queue and calls back into my web API with an ID. The API grabs the item and adds or removes it from the Lucene index accordingly using the AzureDirectory project (https://azuredirectory.codeplex.com/). This all functions as expected, and if I manually post ID's to my API method, everything is great. When it runs through the WebJob, somehow my index becomes corrupt and any call, even to get the number of indexed items, returns a 404 not found looking for a file that doesn't exist in my directory (typically something like _1a.cfs).
I'm thinking it's some sort of a locking issue or that my objects aren't being disposed of properly, but I can't see where I'm going wrong and I'm not sure this is the best way to structure the application and the workflow. Latter half of the code pasted below, any help would be hugely appreciated!
WebJob:
public class Program
{
static void Main()
{
JobHost host = new JobHost();
host.RunAndBlock();
}
public static void IndexItemOrCategory([QueueTrigger("searchindexrequest")] string id)
{
string baseUri = ConfigurationSettings.AppSettings["BaseUri"];
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUri);
string response = client.GetStringAsync("api/search/indexitem/" + id).Result;
Console.Out.WriteLine(response);
}
}
}
API:
public HttpResponseMessage IndexItem(string id)
{
try
{
var item = db.Items.Find(dbId);
if (item != null && item.Active && !string.IsNullOrWhiteSpace(item.Name))
LuceneSearch.AddUpdateLuceneIndex(item);
else
{
LuceneSearch.RemoveLuceneIndexRecord<Item>(dbId);
removed = true;
}
}
catch (Exception exc)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exc);
}
return Request.CreateResponse(HttpStatusCode.OK, id + (removed ? " removed " : " indexed ") + "successfully.");
}
public class LuceneSearch
{
private static CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureConnection"].ToString());
private static AzureDirectory azureDirectory = new AzureDirectory(storageAccount, "lucene-search", new RAMDirectory());
public static void AddUpdateLuceneIndex(Item item)
{
AddToLuceneIndex(item);
}
private static void AddToLuceneIndex(Item toIndex)
{
using (StandardAnalyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30))
{
using (IndexWriter writer = new IndexWriter(azureDirectory, analyzer, new IndexWriter.MaxFieldLength(IndexWriter.DEFAULT_MAX_FIELD_LENGTH)))
{
string Id = "Item" + toIndex.ItemID.ToString();
//Remove any existing index entry
var searchQuery = new TermQuery(new Term("Id", Id));
writer.DeleteDocuments(searchQuery);
string name = string.IsNullOrWhiteSpace(toIndex.CommonName) ? toIndex.Name : toIndex.Name + ", " + toIndex.CommonName;
if (!string.IsNullOrWhiteSpace(name))
{
//Create new entry
Document doc = new Document();
doc.Add(new Field("Id", Id, Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("Name", toIndex.Name, Field.Store.YES, Field.Index.ANALYZED));
if (!string.IsNullOrWhiteSpace(toIndex.Description1))
doc.Add(new Field("Description", toIndex.Description1, Field.Store.YES, Field.Index.ANALYZED));
doc.Add(new Field("CategoryName", toIndex.Category.Name, Field.Store.YES, Field.Index.ANALYZED));
doc.Add(new Field("SeoUrl", toIndex.SeoUrl, Field.Store.YES, Field.Index.NOT_ANALYZED));
if (!string.IsNullOrWhiteSpace(toIndex.Image1))
doc.Add(new Field("Image", toIndex.Image1, Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("CategorySeoUrl", toIndex.Category.SeoUrl, Field.Store.YES, Field.Index.NOT_ANALYZED));
writer.AddDocument(doc);
}
writer.Dispose();
}
}
}
...
}
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
Using the following block of code, the listItem.Update fails with a NullReferenceException:
SPWeb web = null;
SPList list = null;
SPListItem listItem = null;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(this.SiteUrl))
{
web = site.OpenWeb();
list = web.Lists[this.ListName];
listItem = list.Items.Add();
listItem["Background"] = "foo";
}
}
);
listItem.Update();
}
catch
{
}
finally
{
web.Dispose();
}
If I move the listItem.Update() method inside of the anonymous delegate, I get "Operation is not valid due to the current state of the object."
Yes, I've combed through SO and have tried many permutations without success.
Any ideas?
Update:
After the first comment, I tried to remove the anonymous delegate from the code to see if it fared any better:
// store the selected item to pass between methods
public T SelectedItem { get; set; }
// set the selected item and call the delegate method
public virtual void Save(T item)
{
SelectedItem = item;
try
{
SPSecurity.RunWithElevatedPrivileges(SaveSelectedItem);
}
catch
{
}
}
public virtual void SaveSelectedItem()
{
if (SelectedItem != null)
{
using (SPSite site = new SPSite(this.SiteUrl))
{
using(SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[this.ListName];
SPListItem listItem = list.Items.Add();
//UpdateListItem(listItem, SelectedItem);
listItem["Background"] = "foo";
listItem.Update();
}
}
}
}
And this still fails "Operation is not valid due to the current state of the object." In both code samples, it looks like site.Impersonating is false. I am using Windows Auth, and Impersonation in the web.config. This is running from the ASP.Net Development server.
I found an example from this site (blackninjasoftware). I create a reference to the site, grab its SystemAccount token and then create another reference to the site, using the admin token. It seemed a little hackish to me at first - but hey - I have a deadline.
Final working method body now looks like:
SPListItem new_item = null;
SPSite initialSite = new SPSite(this.SiteUrl);
using (var site = new SPSite(this.SiteUrl, initialSite.SystemAccount.UserToken))
{
// This code runs under the security context of the SHAREPOINT\system
// for all objects accessed through the "site" reference. Note that it's a
// different reference than SPContext.Current.Site.
using (var elevatedWeb = site.OpenWeb())
{
elevatedWeb.AllowUnsafeUpdates = true;
SPList list = elevatedWeb.Lists[this.ListName];
new_item = list.Items.Add();
UpdateListItem(new_item, item);
if (new_item != null)
{
new_item.Update();
}
}
}
initialSite.Dispose();