IndexOutOfBoundsException after filtering adapter - xamarin.android

I have an autocomplete control that'll be drawing from an api to build the autocomplete dropdown list. I have everything wired up but I get this error while typing:
03-26 13:41:40.546 E/AndroidRuntime(31931): java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
03-26 13:41:40.546 E/AndroidRuntime(31931): at java.util.ArrayList.get(ArrayList.java:437)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:385)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.AutoCompleteTextView.buildImeCompletions(AutoCompleteTextView.java:1243)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1203)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.AutoCompleteTextView.updateDropDownForFilter(AutoCompleteTextView.java:1086)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.AutoCompleteTextView.onFilterComplete(AutoCompleteTextView.java:1068)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:285)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.os.Handler.dispatchMessage(Handler.java:106)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.os.Looper.loop(Looper.java:164)
03-26 13:41:40.546 E/AndroidRuntime(31931): at android.app.ActivityThread.main(ActivityThread.java:6494)
03-26 13:41:40.546 E/AndroidRuntime(31931): at java.lang.reflect.Method.invoke(Native Method)>
03-26 13:41:40.546 E/AndroidRuntime(31931): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
03-26 13:41:40.546 E/AndroidRuntime(31931): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
My Adapter Class
public class UserFilterAdapter : ArrayAdapter<UserAutoComplete>, IFilterable
{
private readonly Context _context;
private readonly int _textViewResourceId;
private readonly Filter _filter;
private List<UserAutoComplete> _userAutoComplete;
public override int Count => _userAutoComplete?.Count ?? 0;
public override Filter Filter => _filter;
public DirectoryOrgUnitFilterAdapter(List<UserAutoComplete> userAutoComplete, Context context, int textViewResourceId) : base(context, textViewResourceId)
{
_context = context;
_filter = new UserAutoCompleteFilter(this);
_textViewResourceId = textViewResourceId;
_userAutoComplete = userAutoComplete;
}
public void RefreshAdapter(List<UserAutoComplete> userAutoComplete)
{
_userAutoComplete = userAutoComplete;
NotifyDataSetChanged();
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
var inflater = (LayoutInflater) _context.GetSystemService(Context.LayoutInflaterService);
convertView = inflater.Inflate(_textViewResourceId, parent, false);
}
var itemName = convertView.FindViewById<TextView>(Resource.Id.user_autocomplete_item_name);
var itemType = convertView.FindViewById<TextView>(Resource.Id.user_autocomplete_item_type);
var item = GetItem(position);
itemName.Text = item.UserName;
itemType.Text = item.Email;
return convertView;
}
}
My Filter Class
public class UserAutoCompleteFilter : Filter
{
private readonly UserFilterAdapter _adapter;
public UserAutoCompleteFilter(UserFilterAdapter adapter)
{
_adapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
var results = new FilterResults();
if (string.IsNullOrEmpty(constraint?.ToString()))
{
return results;
}
var searchFor = constraint.ToString();
if (searchFor.Length < 3)
{
return results;
}
var matches = ApiService.GetUsers(searchFor).ConfigureAwait(false).GetAwaiter().GetResult();
results.Values = FromArray(matches.Select(r => r.ToJavaObject()).ToArray());
results.Count = matches.ToList().Count;
constraint.Dispose();
return results;
}
protected override void PublishResults(ICharSequence constraint, FilterResults results)
{
if (results?.Values == null)
{
return;
}
using (var values = results.Values)
{
_adapter.RefreshAdapter(values.ToArray<Object>().Select(a => a.ToNetObject<UserAutoComplete>()).ToList());
}
constraint.Dispose();
results.Dispose();
}
}
I debugged through the logic and the filtering is getting hit and returning data, so I'm lost on where it's losing the data and throwing an out of bounds exception.
I've followed this tutorial on getting filtering to work in C# and then this tutorial on applying it to an autocomplete textview control.

I finally got it working. The key problem was that my adapter was using ArrayAdapter instead of BaseAdapter.
once I switched that out, it works as intended, not sure why I can't use ArrayAdapter but I'm thrilled that my autocomplete control is finally working.

Related

Xamarin Android: How to swipe left recyclerview items

Hello everyone my name is Taniguchi:
I have a recyclerview and i wish to swipe to Delete in xamarin android but i only find articles in java
does anyone knows how to do it in C# ?
The java article teaching how to swipe to delete.
https://medium.com/#zackcosborn/step-by-step-recyclerview-swipe-to-delete-and-undo-7bbae1fce27e
my recylerview adapter:
public class RecyclerAdapter : RecyclerView.Adapter, View.IOnClickListener, View.IOnLongClickListener
{
private View view;
private Boolean isSelected = false;
public Boolean IsSelected()
{
return isSelected;
}
public void setSelected(Boolean selected)
{
isSelected = selected;
}
public static RecyclerView.Adapter mAdapter;
public static bool isActionMode = true;
private int viewType;
private ViewGroup parent;
public static bool unselect = false;
private Activity mActivity;
private MyActionMode mActionMode;
private RecyclerView.ViewHolder holder;
private List<time_entry> mTime_Entries;
private Context context;
private View p;
private ActionMode mode;
public static bool count = false;
public static int CountAuxiliar = 0;
private MyActionMode myActionMode;
public event EventHandler<int> ItemClick;
public RecyclerAdapter(List<time_entry> time_entries, Context context)
{
mTime_Entries = time_entries;
this.context = context;
}
public RecyclerAdapter(List<time_entry> time_entries, Activity activity)
{
mTime_Entries = time_entries;
mActivity = activity;
}
public RecyclerAdapter(List<time_entry> time_entries, MyActionMode myActionMode)
{
mTime_Entries = time_entries;
this.myActionMode = myActionMode;
}
public class MyView : RecyclerView.ViewHolder
{
public View mMainView {get; set;}
public TextView mName {get; set;}
public TextView mSubject {get; set;}
public TextView mMessage {get; set;}
public MyView(View view) : base(view)
{
mMainView = view;
}
}
public override int ItemCount
{
get { return mTime_Entries.Count; }
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.From(parent.Context);
View row = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.row, parent, false);
RecyclerViewHolder vh = new RecyclerViewHolder(row);
return vh;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
RecyclerViewHolder myHolder = holder as RecyclerViewHolder;
myHolder.cbx.Visibility = mTime_Entries[position].IsSelected() ? ViewStates.Visible : ViewStates.Gone;
myHolder.cbx.Checked = mTime_Entries[position].IsSelected();
myHolder.mProject_Task.Text = mTime_Entries[position].projectTask;
myHolder.mDate.Text = mTime_Entries[position].date;
myHolder.mDescription.Text = mTime_Entries[position].description;
myHolder.ItemView.SetBackgroundColor(mTime_Entries[position].IsSelected() ? Color.LightBlue : Color.Transparent);
myHolder.ItemView.Tag = position;
myHolder.ItemView.SetOnClickListener(this);
myHolder.ItemView.SetOnLongClickListener(this);
}
void View.IOnClickListener.OnClick(View v)
{
if (CountAuxiliar > 0)
{
int position = (int)v.Tag;
mTime_Entries[position].setSelected(!mTime_Entries[position].IsSelected());
v.SetBackgroundColor(mTime_Entries[position].IsSelected() ? Color.LightBlue : Color.Transparent);
v.FindViewById(Resource.Id.checkBox1).Visibility = mTime_Entries[position].IsSelected() ? ViewStates.Visible : ViewStates.Invisible;
if (mTime_Entries[position].IsSelected())
{
CountAuxiliar++;
}
else
{
CountAuxiliar--;
}
//mode.Title = CountAuxiliar.ToString() + " " + "Selecionados";
MainActivity.title.Text = CountAuxiliar.ToString() + " " + "Selecionados";
Toast.MakeText(v.Context, "Click : " + CountAuxiliar + "---" + position, ToastLength.Short).Show();
}
if (CountAuxiliar < 1 && count == true)
{
count = false;
MainActivity.toolbar2.Visibility = ViewStates.Gone;
MainActivity.bottomnavigationview1.Visibility = ViewStates.Gone;
MainActivity.floatinactionbutton1.Visibility = ViewStates.Visible;
}
}
public void removeSelection()
{
if (mTime_Entries != null)
{
foreach (time_entry email in mTime_Entries)
{
email.setSelected(false);
}
}
NotifyDataSetChanged();
CountAuxiliar = 0;
count = false;
MainActivity.bottomnavigationview1.Visibility = ViewStates.Gone;
MainActivity.floatinactionbutton1.Visibility = ViewStates.Visible;
}
public void checkall()
{
if (mTime_Entries != null)
{
foreach (time_entry email in mTime_Entries)
{
email.setSelected(true);
}
}
NotifyDataSetChanged();
MainActivity.bottomnavigationview1.Visibility = ViewStates.Visible;
}
public bool OnLongClick(View v)
{
if (CountAuxiliar < 1)
{
CountAuxiliar = 1;
count = true;
int position = (int)v.Tag;
mTime_Entries[position].setSelected(!mTime_Entries[position].IsSelected());
v.SetBackgroundColor(mTime_Entries[position].IsSelected() ? Color.LightBlue : Color.Transparent);
MainActivity.bottomnavigationview1.Visibility = ViewStates.Visible;
MainActivity.floatinactionbutton1.Visibility = ViewStates.Gone;
v.FindViewById(Resource.Id.checkBox1).Visibility = mTime_Entries[position].IsSelected() ? ViewStates.Visible : ViewStates.Invisible;
MainActivity.title.Text = CountAuxiliar.ToString() + " " + "Selecionado";
MainActivity.toolbar2.Visibility = ViewStates.Visible;
count = true;
Toast.MakeText(v.Context, "Long Click : " + mTime_Entries[position].IsSelected() + "---" + position, ToastLength.Short).Show();
}
return true;
}
}
You can custom a SwipeToDeleteCallback inherited from ItemTouchHelper.SimpleCallback to realize it , here is an article for reference .
SwipeToDeleteCallback class:
public class SwipeToDeleteCallback : ItemTouchHelper.SimpleCallback
{
private Context context;
private PhotoAlbumAdapter madapter;
private Android.Graphics.Drawables.Drawable deleteIcon;
private int intrinsicWidth;
private int intrinsicHeight;
private Android.Graphics.Drawables.ColorDrawable background;
private Color backgroundColor;
private Paint clearPaint;
public SwipeToDeleteCallback(int dragDirs, int swipeDirs, Context context) : base(dragDirs, swipeDirs )
{
this.context = context;
deleteIcon = ContextCompat.GetDrawable(context, Resource.Drawable.alter_delete);
intrinsicWidth = deleteIcon.IntrinsicWidth;
intrinsicHeight = deleteIcon.IntrinsicHeight;
background = new Android.Graphics.Drawables.ColorDrawable();
backgroundColor = Color.ParseColor("#f44336");
clearPaint = new Paint();
clearPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
}
public SwipeToDeleteCallback(int dragDirs, int swipeDirs, Context context, PhotoAlbumAdapter mRecyclerView) : this(dragDirs, swipeDirs, context)
{
this.context = context;
this.madapter = mRecyclerView;
deleteIcon = ContextCompat.GetDrawable(context, Resource.Drawable.delete);
intrinsicWidth = deleteIcon.IntrinsicWidth;
intrinsicHeight = deleteIcon.IntrinsicHeight;
background = new Android.Graphics.Drawables.ColorDrawable();
backgroundColor = Color.ParseColor("#f44336");
clearPaint = new Paint();
clearPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
}
public override int GetMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
{
if(viewHolder.AdapterPosition == 10)
{
return 0;
}
return base.GetMovementFlags(recyclerView, viewHolder);
}
public override void OnChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, bool isCurrentlyActive)
{
base.OnChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
public override bool OnMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
{
//throw new NotImplementedException();
return false;
}
public override void OnChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, bool isCurrentlyActive)
{
var itemView = viewHolder.ItemView;
var itemHeight = itemView.Bottom - itemView.Top;
var isCanceled = dX == 0f && !isCurrentlyActive;
if (isCanceled)
{
clearCanvas(c, itemView.Right + dX, (float)itemView.Top, (float)itemView.Right, (float)itemView.Bottom);
base.OnChildDrawOver(c, recyclerView
, viewHolder, dX, dY, actionState, isCurrentlyActive);
return;
}
background.Color = backgroundColor;
background.SetBounds(itemView.Right + (int)dX, itemView.Top, itemView.Right, itemView.Bottom);
background.Draw(c);
var deleteIconTop = itemView.Top + (itemHeight - intrinsicHeight) / 2;
var deleteIconMargin = (itemHeight - intrinsicHeight) / 2;
var deleteIconLeft = itemView.Right - deleteIconMargin - intrinsicWidth;
var deleteIconRight = itemView.Right - deleteIconMargin;
var deleteIconBottom = deleteIconTop + intrinsicHeight;
deleteIcon.SetBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom);
deleteIcon.Draw(c);
base.OnChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
private void clearCanvas(Canvas c, float v, float top, float right, float bottom)
{
c.DrawRect(v, top, right, bottom, clearPaint);
}
public override void OnSwiped(RecyclerView.ViewHolder viewHolder, int direction)
{
//Invoke Removing Item method from adapter
this.madapter.RemoveItem(viewHolder.AdapterPosition);
}
public override void ClearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
{
base.ClearView(recyclerView, viewHolder);
}
}
Then in Activity can use it as follow:
var swipeHandler = new SwipeToDeleteCallback(0, ItemTouchHelper.Left, this, mAdapter);
var itemTouchHelper = new ItemTouchHelper(swipeHandler);
itemTouchHelper.AttachToRecyclerView(mRecyclerView);
Not forgetting to add Remove method in Adapter :
public void RemoveItem (int position)
{
ArrayList al = new ArrayList(mPhotoAlbum.mPhotos);
al.RemoveAt(position);
mPhotoAlbum.mPhotos = (Photo[])al.ToArray(typeof(Photo));
NotifyDataSetChanged();
NotifyItemChanged(position);
}
Maybe from code not understanding totally , I refer to this sample to realize it . And the modified sample will share here . The effect is as follow:
===================================Update====================================
From shared project , there are two places need to modify.
First is RemoveItem method in RecyclerAdapter class.Because my project use Object[] to set source for RecycleView , need to write code to convert to be a ArrayList .However ,the source (mTime_Entries) of your project is also a List[] , so not need to convert it. Modify as follow in your project:
public void RemoveItem(int position)
{
mTime_Entries.RemoveAt(position);
NotifyDataSetChanged();
NotifyItemChanged(position);
}
Second is OnSwiped method in SwipeToDeleteCallback class.Before this , you also need to modify the constructor of SwipeToDeleteCallback. The Adapter is not correct here.
private RecyclerAdapter mdapter;
public SwipeToDeleteCallback(int dragDirs, int swipeDirs, Context context, PhotoAlbumAdapter mRecyclerView) : this(dragDirs, swipeDirs, context)
{
this.context = context;
this.madapter = mRecyclerView;
deleteIcon = ContextCompat.GetDrawable(context, Resource.Drawable.delete);
intrinsicWidth = deleteIcon.IntrinsicWidth;
intrinsicHeight = deleteIcon.IntrinsicHeight;
background = new Android.Graphics.Drawables.ColorDrawable();
backgroundColor = Color.ParseColor("#f44336");
clearPaint = new Paint();
clearPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
}
You should keep them(Adapter) be the same between MainActity and here.
Then OnSwiped can be written with one line code as follow:
public override void OnSwiped(RecyclerView.ViewHolder viewHolder, int direction)
{
//Invoke Removing Item method from
this.mdapter.RemoveItem(viewHolder.AdapterPosition);
}

Listview Filter with SearchView Using Base Adapter in Xamarin android Error

I am try to filter listview with searchview using Base Adapter in in xamarin Android, My listView Bind in sql server using restfull web service i am stuck in PublishResults which is given an error
Here Is My Code:-
GetHospNames.cs
public class GetHospNames
{
public string HospID { get; set; }
public string HospName { get; set; }
public GetHospNames(string HospID, string HospName)
{
this.HospID = HospID;
this.HospName = HospName;
//this.HospLogo = HospLogo;
}
}
ContListViewHospNameClass.cs
using System.Collections.Generic;
using Android.App;
using Android.Views;
using Android.Widget;
using System;
using Android.Graphics;
using Android.Graphics.Drawables;
using System.IO;
using Android.Content;
using Java.Lang;
using Android.Text;
using Java.Util;
using Oject = Java.Lang.Object;
namespace HSAPP
{
public class ContListViewHospNameClass : BaseAdapter<GetHospNames>, IFilterable
{
public List<GetHospNames> objList;
Activity objActivity;
List<GetHospNames> filterList;
public ContListViewHospNameClass(Activity objMyAct, List<GetHospNames> objMyList) : base()
{
this.objActivity = objMyAct;
objList = objMyList;
this.filterList = objList;
Filter = new CustomFilter(this);
}
public override GetHospNames this[int position]
{
get
{
return objList[position];
}
}
public override int Count
{
get
{
return objList.Count;
}
}
public Filter Filter { get; set; }
public override void NotifyDataSetChanged()
{
base.NotifyDataSetChanged();
}
//This is Inner Class
public class CustomFilter : Filter
{
ContListViewHospNameClass CustomAdapter;
public CustomFilter(ContListViewHospNameClass adapter) : base()
{
this.CustomAdapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
FilterResults result = new FilterResults();
if (constraint != null && constraint.Length() > 0)
{
//Contraint To Upper
List<GetHospNames> filter = new List<GetHospNames>();
foreach (GetHospNames name in CustomAdapter.objList)
{
if (name.HospName.ToUpper().Contains(constraint.ToString().ToUpper()))
{
filter.Add(name);
}
}
Oject[] Name;
Name = new Oject[filter.Count];
for (int i = 0; i < filter.Count; i++)
{
Name[i] = filter[i].HospName.ToString();
}
result.Count = filter.Count;
result.Values = Name;
}
return result;
}
protected override void PublishResults(ICharSequence constraint, Filter.FilterResults result)
{
List<GetHospNames> filteredList = new List<GetHospNames>();
for (int i = 0; i < ((Oject[])result.Values).Length; i++)
{
filteredList.Add((Oject[])result.Values[i]);//Here Is An Error *****Cannot apply indexing with [] to an expression of type 'Object'****
}
CustomAdapter.objList = filteredList;
CustomAdapter.NotifyDataSetChanged();
}
}
public override long GetItemId(int position)
{
return position;
}
public Bitmap getBitmap(byte[] getByte)
{
if (getByte.Length != 0)
{
return BitmapFactory.DecodeByteArray(getByte, 0, getByte.Length);
}
else
{
return null;
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = objList[position];
if (convertView == null)
{
convertView = objActivity.LayoutInflater.Inflate(Resource.Layout.ContListViewHospName, null);
}
convertView.FindViewById<TextView>(Resource.Id.tvHospID).Text = item.HospID;
convertView.FindViewById<TextView>(Resource.Id.tvHospName).Text = item.HospName;
return convertView;
}
}
public static class ObjectTypeHelper
{
public static T Cast<T>(this Java.Lang.Object obj) where T : class
{
var propertyInfo = obj.GetType().GetProperty("Instance");
return propertyInfo == null ? null : propertyInfo.GetValue(obj, null) as T;
}
}
}
This is my MainActivity Code
private void BindControl_BindHospCompleted(object sender, BindControl.BindHospCompletedEventArgs e)
{
jsonValue = e.Result.ToString();
try
{
if (jsonValue == null)
{
Toast.MakeText(this, "No Data For Bind", ToastLength.Long).Show();
return;
}
JArrayValue = JArray.Parse(jsonValue);
list = new List<GetHospNames>();
int count = 0;
while (count < JArrayValue.Count)
{
GetHospNames getHospName = new GetHospNames(JArrayValue[count]["HospID"].ToString(), JArrayValue[count]["HospName"].ToString());
list.Add(getHospName);
count++;
}
if (count == 0)
{
Toast.MakeText(this, "No List Of Hospitals", ToastLength.Long).Show();
}
adapter = new ContListViewHospNameClass(this, list);
listView.Adapter = adapter;
search.QueryTextChange += (s, e) =>
{
adapter.Filter.InvokeFilter(e.NewText);
};
listView.ItemClick += ListView_ItemClick;
pBar.Dismiss();
}
catch (Java.Lang.Exception ex)
{
pBar.Dismiss();
//Toast.MakeText(this, ex.ToString(), ToastLength.Long).Show();
Finish();
Intent intent = new Intent(this, typeof(ChkIntConnActivity));
StartActivity(intent);
}
}
Please Help...Thank You

Serilog stops logging events

I have created a Serilog sink that talks to a web service which persists log messages to a database. It works most of the time. Even in cases where there is an exception calling the web service it will log to the Selflog file. However, However, periodically it simply stops logging either to our custom web service or to the self log file and after it stops logging it never begins logging anywhere else. This is being executed in a windows service and I have to stop and restart the windows service before it begins logging again. A typical exception that i might get from the web service call is: "Task was cancelled". This would be caused because the webservice does not respond within the configured timeout period. As I said normally it will properly write the events to the selflog file. Only periodically will it just stop logging everywhere. I should also say that the volume of logs being generated is very high.
This is a dnx project and here is a portion of the project.json file:
"dependencies": {
"Newtonsoft.Json": "8.0.2",
"Serilog.Sinks.PeriodicBatching": "2.0.0",
"Serilog": "2.0.0-beta-465",
"Serilog.Extensions.Logging": "1.0.0-rc1-final-10092",
"JA.AppCentral.Logging.Contracts": "0.1.0-alpha1-*",
"FluentAssertions": "4.2.2",
"Microsoft.Extensions.Configuration": "1.0.0-rc1-final",
"Microsoft.AspNet.WebApi.Client": "4.0.30506"
}
I have included relevant portions of the sink class. It inherits from periodic batching sink.
The code used to configure the Selflog follows:
FileStream fs = new FileStream(selfLogFilePath, fileMode, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
Serilog.Debugging.SelfLog.Out = TextWriter.Synchronized(sw);
Here is the sink code:enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using System.Net.Http;
using Serilog.Core;
using Serilog.Events;
using System.Net.Http.Headers;
using System.IO;
using Serilog.Formatting.Json;
using Serilog.Debugging;
using Newtonsoft.Json;
using JA.AppCentral.Logging.Contracts;
using Microsoft.Extensions.Configuration;
using Serilog.Sinks.PeriodicBatching;
using System.Diagnostics;
using System.Threading;
namespace JA.AppCentral.Logging
{
public class AppCentralSink: Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink
{
readonly HttpClient _httpClient;
LoggingLevelSwitch _levelControlSwitch;
const string BulkAddUri = "api/appLogging/bulkAdd";
private Uri _baseUri;
private string _baseUriPath;
readonly long? _eventBodyLimitBytes = 1000000;
static readonly TimeSpan RequiredLevelCheckInterval = TimeSpan.FromSeconds(10);
private TimeSpan _timeout = TimeSpan.FromMinutes(1);
private bool _saveMessageTemplate;
private int eventsCount;
private LoggingRepositoryServiceResponse _logServiceResponse;
private int _totalInsertedRecords;
public event EventHandler<ResponseEventArgs> ResponseReceived = delegate { };
DateTime _nextRequiredLevelCheckUtc = DateTime.Now.Add(RequiredLevelCheckInterval);
private int osId;
private string server;
private string username;
private int threadId;
private string appcode;
/// <summary>
/// Overloaded constructor, to pass AppSettings via IConfiguration , instead of separate parameters
/// </summary>
/// <param name="config"></param>
public AppCentralSink(IConfiguration config)
: base(Convert.ToInt32(GetConfigParams(config)["BatchSizeLimit"]),
TimeSpan.FromSeconds(Convert.ToDouble(GetConfigParams(config)["BatchEmitIntervalSeconds"])))
{
Dictionary<string, string> appSettingDict = GetConfigParams(config);
long tempLongVal;
long? eventBodyLimitBytes = long.TryParse(appSettingDict["EventBodyMaxSizeBytes"], out tempLongVal) ? tempLongVal : (long?)null;
if (eventBodyLimitBytes != null)
_eventBodyLimitBytes = eventBodyLimitBytes;
bool saveMessageTemplate = Convert.ToBoolean(appSettingDict["LogMessageTemplate"]);
if (saveMessageTemplate != false)
_saveMessageTemplate = saveMessageTemplate;
string serverUrl = appSettingDict["Url"];
//baseUri = "http://localhost:49774/";
if (!serverUrl.EndsWith("/"))
serverUrl += "/";
_baseUriPath = serverUrl;
_baseUri = new Uri(serverUrl);
TimeSpan timeout = TimeSpan.FromSeconds(Convert.ToDouble(appSettingDict["WebRequestTimeoutSeconds"]));
if (timeout != default(TimeSpan))
_timeout = timeout;
//Default Authentication via http client handler
HttpClientHandler handler = new HttpClientHandler()
{
PreAuthenticate = true,
UseDefaultCredentials = true
};
_httpClient = new HttpClient(handler);
_httpClient.BaseAddress = _baseUri;
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.Timeout = _timeout;
//Init Context properties
OsId = Process.GetCurrentProcess().Id;
Server = Environment.MachineName;
Username = Environment.UserName;
ThreadId = Thread.CurrentThread.ManagedThreadId;
Appcode = config["JA:AppCatalog:AppCode"];
}
private static Dictionary<string,string> GetConfigParams(IConfiguration config)
{
Dictionary<string, string> appSettings = new Dictionary<string, string>();
var SerilogSection = config.GetSection("AppCentralLogging");
appSettings.Add("Url", SerilogSection["Url"]);
appSettings.Add("BatchSizeLimit", SerilogSection["BatchSizeLimit"]);
appSettings.Add("BatchEmitIntervalSeconds", SerilogSection["BatchEmitIntervalSeconds"]);
appSettings.Add("EventBodyMaxSizeBytes", SerilogSection["EventBodyMaxSizeBytes"]);
appSettings.Add("LogMessageTemplate", SerilogSection["LogMessageTemplate"]);
appSettings.Add("WebRequestTimeoutSeconds", SerilogSection["WebRequestTimeoutSeconds"]);
appSettings.Add("SelfLogFileLocationAndPrefix", config["Serilog:SelfLogFileLocationAndPrefix"]);
return appSettings;
}
// The sink must emit at least one event on startup, and the server be
// configured to set a specific level, before background level checks will be performed.
protected override void OnEmptyBatch()
{
if (_levelControlSwitch != null &&
_nextRequiredLevelCheckUtc < DateTime.Now)
{
EmitBatch(Enumerable.Empty<LogEvent>());
}
}
protected override async Task EmitBatchAsync(IEnumerable<LogEvent> events)
{
_nextRequiredLevelCheckUtc = DateTime.Now.Add(RequiredLevelCheckInterval);
var formatter = new JsonFormatter();
List<LogEntry> logEntriesList = new List<LogEntry>();
try
{
foreach (var logEvent in events)
{
EventsCount++;
LogEntry jaLogEvent = ConvertToLogEntry(logEvent);
if (_eventBodyLimitBytes.HasValue)
{
var scratch = new StringWriter();
formatter.Format(logEvent, scratch);
var buffered = scratch.ToString();
if (Encoding.UTF8.GetByteCount(buffered) > _eventBodyLimitBytes.Value)
{
SelfLog.WriteLine("Event JSON representation exceeds the byte size limit of {0} set for this sink and will be dropped; data: {1}", _eventBodyLimitBytes, buffered);
}
else
{
logEntriesList.Add(jaLogEvent);
}
}
else
{
logEntriesList.Add(jaLogEvent);
}
}
var result = await _httpClient.PostAsJsonAsync(BulkAddUri, logEntriesList);
if (!result.IsSuccessStatusCode)
{
try
{
var error = await result.Content.ReadAsStringAsync();
var responseExcep = new Exception(error);
throw responseExcep;
}
catch (Exception e)
{
SelfLog.WriteLine("FailedEvents: " + GetEventsAsString(events));
throw new Exception("Error calling Logging Web Service: status code: " + result.StatusCode +
" reason: " + result.ReasonPhrase + " excep: " + e.ToString());
}
}
_logServiceResponse = await result.Content.ReadAsAsync<LoggingRepositoryServiceResponse>();
if (_logServiceResponse.ResponseException != null)
{
SelfLog.WriteLine("FailedEvents: " + GetEventsAsString(events));
SelfLog.WriteLine(_logServiceResponse.ResponseMessage);
throw new Exception("Error calling Logging Web Service: " +
_logServiceResponse.ResponseMessage);
}
_totalInsertedRecords = _totalInsertedRecords + _logServiceResponse.NumRecordsInserted;
ResponseReceived(this, new ResponseEventArgs(result));
}
catch (Exception e)
{
SelfLog.WriteLine("Error processing log batch, excep: " + e.ToString());
SelfLogEvents(events);
throw;
}
}
private void SelfLogEvents(IEnumerable<LogEvent> events)
{
SelfLog.WriteLine("Failed to write following log events:");
foreach (var e in events)
{
SelfLog.WriteLine($" Event: " + e.RenderMessage());
}
}
private string GetEventsAsString(IEnumerable<LogEvent> events)
{
string eventsResult = string.Empty;
foreach(LogEvent le in events)
{
eventsResult += "[" + le.RenderMessage() + "]";
}
return eventsResult;
}
private LogEntry ConvertToLogEntry(LogEvent logEvent)
{
string propertiesString = JsonConvert.SerializeObject(logEvent.Properties);
string messageTemplate = _saveMessageTemplate == true ? logEvent.MessageTemplate.Text : string.Empty;
//Append Exception to the message if it's not null
string logEventMessage = logEvent.RenderMessage();
if (logEvent.Exception != null)
{
logEventMessage = logEventMessage + " Exception: " + logEvent.Exception.ToString();
}
LogEntry logEntry = new LogEntry("AppCode", "Action", logEvent.Level.ToString(), messageTemplate,
logEventMessage, propertiesString,
logEvent.Timestamp);
//Append additional properties
if (String.IsNullOrEmpty(Appcode))
{
logEntry.AppCode = logEvent.Properties.Keys.Contains("appcode") ? logEvent.Properties["appcode"].ToString().Replace("\"", "") : string.Empty;
logEntry.OsPId = logEvent.Properties.Keys.Contains("os_pid") ? logEvent.Properties["os_pid"].ToString().Replace("\"", "") : string.Empty;
logEntry.ThreadId = logEvent.Properties.Keys.Contains("thread_id") ? logEvent.Properties["thread_id"].ToString().Replace("\"", "") : string.Empty;
logEntry.Server = logEvent.Properties.Keys.Contains("server") ? logEvent.Properties["server"].ToString().Replace("\"", "") : string.Empty;
logEntry.Username = logEvent.Properties.Keys.Contains("username") ? logEvent.Properties["username"].ToString().Replace("\"", "") : string.Empty;
}
else
{
logEntry.AppCode = Appcode;
logEntry.OsPId = OsId.ToString();
logEntry.ThreadId = ThreadId.ToString();
logEntry.Server = Server;
logEntry.Username = Username;
}
logEntry.SessionId = logEvent.Properties.Keys.Contains("session_id") ? logEvent.Properties["session_id"].ToString().Replace("\"", "") : string.Empty;
logEntry.Action = logEvent.Properties.Keys.Contains("action") ? logEvent.Properties["action"].ToString().Replace("\"", "") : string.Empty;
//Append SourceContext
//Append SourceContext
LogEventPropertyValue propertyValue;
if (logEvent.Properties.TryGetValue("SourceContext", out propertyValue))
{
logEntry.SourceContext = propertyValue.ToString().Trim(new[] { '"' });
}
return logEntry;
}
public int EventsCount
{
get
{
return eventsCount;
}
set
{
eventsCount = value;
}
}
public LoggingRepositoryServiceResponse LogServiceResponse
{
get
{
return _logServiceResponse;
}
set
{
_logServiceResponse = value;
}
}
public int TotalInsertedRecords
{
get
{
return _totalInsertedRecords;
}
set
{
_totalInsertedRecords = value;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_httpClient.Dispose();
}
public HttpClient HttpClient
{
get { return _httpClient; }
}
}
public class ResponseEventArgs : EventArgs
{
public ResponseEventArgs(HttpResponseMessage response)
{
Response = response;
}
public HttpResponseMessage Response { get; }
}
}

System.ArgumentException: Keyword not supported "pwd"

I am developing a unity project which requires a MySQL connection.
My connection works fine in Unity and Android builds, but when I build the whole project into iOS platform, I had an error (I have localized this through a reporter plugin)
First an exception:
System.ArgumentException: Keyword not supported. Parameter name: pwd at MySql.Data.MSqlClient.MySqlConnectionStringBuilder.ValidateKeyword (System.String keyword) [0x000000] in <filename unknown>:0
Later an error:
NullReferenceException: A null value was found where an object instance was required.
HandlerMySQL.Conectar ()
The code is the following
using System.Collections.Generic;
using System.Security.Cryptography;
using MySql.Data;
using MySql.Data.MySqlClient;
public class HandlerMySQL{
public string host, database, user, password;
public bool pooling = true;
private string connectionString;
private static MySqlConnection con = null;
private MySqlCommand cmd = null;
private MySqlDataReader rdr = null;
private MD5 _md5Hash;
public HandlerMySQL(string h,string db, string u, string pw)
{
host = h;
database = db;
user = u;
password = pw;
}
public void Conectar()
{
connectionString = "Server=" + host + ";Database=" + database + ";Uid=" + user + ";Pwd=" + password + ";Pooling=";
if (pooling)
{
connectionString += "true;";
}
else
{
connectionString += "false;";
}
try
{
con = new MySqlConnection(connectionString);
con.Open();
Debug.Log("MySQL State: " + con.State);
}
catch(Exception e)
{
Debug.Log(e);
Debug.Log("MySQL State: " + con.State);
}
}
void OnApplicationQuit()
{
if (con != null)
{
if (con.State.ToString() != "Close")
{
con.Close();
Debug.Log("MySQL Connection closed");
}
con.Dispose();
}
}
public bool GetIsConnected()
{
if (con.State.ToString() == "Open")
{
return true;
}
else
{
return false;
}
}
public bool CreateData(string dnow, string dstart,int dend)
{
DataMySql data = new DataMySql(dnow, dstart, dend);
if (DataToolsMySql.Agregar(data, con) > 0)
{
Debug.Log("Se agrego correctamente");
return true;
}
else
{
Debug.Log("ERROR!!! No se agrego");
return false;
}
}
}

java.lang.StackOverFlow in Primefaces's treeTable

I use this code:
JSF:
<p:treeTable id="treeSkill" value="#{skillManager.rootSkill}"
var="skill" selectionMode="single" widgetVar="skillsTreeTable"
style="border: 0;">
<p:ajax event="expand"
listener="#{skillManager.expandNodeListener}" />
<p:column> ..... </p:column>
<p/treeTable>
SkillManager:
#Named
#SessionScoped
public class SkillManager implements Serializable {
private static final long serialVersionUID = 1L;
private TreeNode rootSkill;
public SkillManager() {
initSkillTree();
}
public void expandNodeListener(NodeExpandEvent nee) {
TreeNode treeNode = nee.getTreeNode();
if (treeNode instanceof FetchChildren)
((FetchChildren) treeNode).fetchChildren();
if (treeNode instanceof LazySkillTreeNode)
((LazySkillTreeNode) treeNode).fetchSubchildren();
}
private void initSkillTree() {
rootSkill = new DefaultTreeNode("Root", null);
Skill realRootSkill = HrDaoFactory.getInstance().getSkillDAO().getRootSkill();
TreeNode realRootNode = new LazySkillTreeNode(realRootSkill, rootSkill);
for (Skill skill : realRootSkill.getChildrensSkills()) {
LazySkillTreeNode node = new LazySkillTreeNode(skill, realRootNode);
node.fetchChildren();
}
RequestContext.getCurrentInstance().update("woCatalogTabView:skillTreeForm");
}
}
LazySkillTreeNode:
public class LazySkillTreeNode extends LazyTreeNode implements FetchChildren {
private static final long serialVersionUID = 8856168173751148652L;
private boolean childrenFetched;
public LazySkillTreeNode(Object data, TreeNode parent) {
super(data, parent);
}
#Override
public void fetchChildren() {
if (childrenFetched)
return;
for (Skill skill : ((Skill) super.getData()).getChildrensSkills())
new LazySkillTreeNode(skill, this);
childrenFetched = true;
}
}
LazyTreeNode:
public abstract class LazyTreeNode extends DefaultTreeNode {
private static final long serialVersionUID = 8839307424434170537L;
private boolean subChildrenFetched;
public LazyTreeNode(Object data, TreeNode parent) {
super(data, parent);
}
public void fetchSubchildren() {
if (subChildrenFetched || isLeaf())
return;
List<TreeNode> treeNodeList = getChildren();
for (TreeNode node : treeNodeList) {
if (node instanceof FetchChildren)
((FetchChildren) node).fetchChildren();
}
subChildrenFetched = true;
}
}
Everything works fine, but if add/delete elements (after all this operations we call method initSkillTree() for rebuild tree) a lot of times, or if 2 or more users start to do it, we beginning to recieve in response from server this string:
<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class java.lang.StackOverflowError</error-name><error-message><![CDATA[]]></error-message></error></partial-response>
Other problem that i don't have any information about error. No information in log files. In server.log nothing to.
We use: JSF (Mojarra 2.14), Primefaces 3.41, JBOSS 7.
And in the end error was in Controller class where method:
public void addOrUpdateSkill(Skill skill) {
Session session = null;
try {
session = HibernateUtil.getCurrentSession();
session.beginTransaction();
session.saveOrUpdate(skill);
session.getTransaction().commit();
evictAllSkillsFromSession();
} catch (Throwable e) {
logger.fatal(skill, e);
if (session.getTransaction() != null && session.getTransaction().isActive())
session.getTransaction().rollback();
throw new RuntimeException(e);
}
}
and stack trace was appeared in the row "logger.fatal(skill, e);"
you must pass the error message by first argument instead of Entity object.
Error appear because of it's toString() method implementation of Skill class:
#Entity
#Table(name = "SKILLS", schema = AppData.HR_SCHEMA)
public class Skill implements Serializable {
private static final long serialVersionUID = -2728239519286686549L;
#Id
#SequenceGenerator(name = "SKILLS_ID_GENERATOR", sequenceName = AppData.HR_SCHEMA + ".SKILLS_ID_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SKILLS_ID_GENERATOR")
private BigDecimal id;
#Column(name = "NAME_ENG")
private String nameEng;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updatedAt;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UPDATED_BY", referencedColumnName = "USER_ID")
private User updatedBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARENT_ID")
private Skill parentSkill;
#OneToMany(mappedBy = "parentSkill", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Skill> childrensSkills;
#Column(name = "DESCRIPTION")
private String description;
#OneToMany(orphanRemoval = true, mappedBy = "skill")
private List<SkillJoinedAction> skillJoinedActions;
#OneToMany(orphanRemoval = true, mappedBy = "skill")
private List<SkillJoinedEmployee> skillJoinedEmployees;
public Skill() {
}
public Skill(String nameEng, User updateBy, String description) {
this.nameEng = nameEng;
this.updatedBy = updateBy;
this.updatedAt = new Date();
this.setDescription(description);
}
public BigDecimal getId() {
return id;
}
public void setId(BigDecimal id) {
this.id = id;
}
public String getNameEng() {
return this.nameEng;
}
public void setNameEng(String nameEng) {
this.nameEng = nameEng;
}
public Date getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public User getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(User updatedBy) {
this.updatedBy = updatedBy;
}
public List<Skill> getChildrensSkills() {
return childrensSkills;
}
public void setChildrensSkills(List<Skill> childrensSkills) {
this.childrensSkills = childrensSkills;
}
public Skill getParentSkill() {
return parentSkill;
}
public void setParentSkill(Skill parentSkill) {
this.parentSkill = parentSkill;
}
#Override
public String toString() {
return "Skill [id=" + id + ", nameEng=" + nameEng + ", updatedAt=" + updatedAt + ", updatedBy=" + updatedBy + ", parentSkill="
+ parentSkill + ", childrensSkills=" + childrensSkills + "]";
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<SkillJoinedAction> getSkillJoinedActions() {
return skillJoinedActions;
}
public void setSkillJoinedActions(List<SkillJoinedAction> skillJoinedActions) {
this.skillJoinedActions = skillJoinedActions;
}
public List<SkillJoinedEmployee> getSkillJoinedEmployees() {
return skillJoinedEmployees;
}
public void setSkillJoinedEmployees(List<SkillJoinedEmployee> skillJoinedEmployees) {
this.skillJoinedEmployees = skillJoinedEmployees;
}
}
as you can see in method:
#Override
public String toString() {
return "Skill [id=" + id + ", nameEng=" + nameEng + ", updatedAt=" + updatedAt + ", updatedBy=" + updatedBy + ", parentSkill="
+ parentSkill + ", childrensSkills=" + childrensSkills + "]";
}
was called method toString() on parentSkill who in his turn call toString() on childrensSkills... infinite recursion.

Resources