I want to bind commands to my toolbars' items. Is it possible?
I have tried this but it's still doesn't work https://stackoverflow.com/a/21936542/6160208
Toolbar.axml
<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:background="#android:color/holo_blue_light"
android:layout_width="match_parent"
android:layout_height="85dp">
<ImageButton
android:src="#drawable/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/searchImageButton"
android:layout_marginLeft="290dp"
local:MvxBind="Click DoSearchCommand"
android:background="#android:color/holo_blue_light" />
MainView.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include
layout="#layout/toolbar" />
</LinearLayout>
MainViewModel.cs
private MvxCommand _searchCommand;
public System.Windows.Input.ICommand SearchCommand
{
get
{
_searchCommand = _searchCommand ?? new MvxCommand(DoSearchCommand);
return _searchCommand;
}
}
private void DoSearchCommand()
{
ShowViewModel<SearchViewModel>();
}
You bind to DoSearchCommand but that is the method. You should bind to SearchCommand
local:MvxBind="Click SearchCommand"
As improvement you could use a IMvxCommand instead of a ICommand too, and add the ShowViewModel as lambda.
private MvxCommand _searchCommand;
public IMvxCommand SearchCommand
{
get
{
_searchCommand = _searchCommand ?? new MvxCommand(() => ShowViewModel<SearchViewModel>());
return _searchCommand;
}
}
Related
The problem is i'm trying to get the current location of the user and the code is not giving any error except that when the code compiles, it should execute onLocationChanged method but it does't executes it.
I have also Set the permissions right in my manifest file, but i don't know why i can't seem to understand what the problem is. Please help.
Map Activity
this is my map activity where i'm trying to set the marker to current location
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Graphics;
using Android.Locations;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Newtonsoft.Json;
namespace RoutineApp
{
[Activity(Label = "GoogleMapDirectionsActivity", MainLauncher = true, ScreenOrientation = ScreenOrientation.Portrait, Theme = "#style/Theme.AppCompat.Light.NoActionBar")]
public class GoogleMapDirectionsActivity : Activity, IOnMapReadyCallback, ILocationListener
{
private GoogleMap gMap;
private MapFragment mapFragment;
private LocationManager locationManager;
string locationProvider;
private MarkerOptions markerOptions;
private Marker marker;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.googlemapdirections);
mapFragment = (MapFragment)FragmentManager.FindFragmentById(Resource.Id.DirectionMap);
mapFragment.GetMapAsync(this);
goBtn = FindViewById<Button>(Resource.Id.GoBtn);
//user location
IntializeLocationManager();
}
private void IntializeLocationManager()
{
locationManager = (LocationManager)GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
};
IList<string> acceptableLocationProviders = locationManager.GetProviders(criteriaForLocationService, true);
if (acceptableLocationProviders.Any())
{
locationProvider = acceptableLocationProviders.First();
}
else
{
locationProvider = string.Empty;
}
//Log.Debug(TAG, "Using " + locationProvider + ".");
}
public void OnMapReady(GoogleMap googleMap)
{
gMap = googleMap;
//mDirectionMap.TrafficEnabled = true;
gMap.UiSettings.CompassEnabled = true;
gMap.UiSettings.MyLocationButtonEnabled = true;
gMap.UiSettings.ZoomControlsEnabled = true;
OnLocationChanged(locationManager.GetLastKnownLocation(locationProvider));
}
protected override void OnResume()
{
base.OnResume();
locationManager.RequestLocationUpdates(locationProvider, 400, 0, this);
}
protected override void OnPause()
{
base.OnPause();
locationManager.RemoveUpdates(this);
}
public void OnLocationChanged(Location location)
{
if (marker != null)
{
marker.Remove();
}
LatLng latLng = new LatLng(location.Latitude, location.Longitude);
markerOptions = new MarkerOptions()
.SetPosition(latLng)
.SetTitle("My Current Position");
marker = gMap.AddMarker(markerOptions);
CameraUpdate camera = CameraUpdateFactory.NewLatLngZoom(latLng, 19);
gMap.MoveCamera(camera);
}
public void OnProviderDisabled(string provider)
{
//throw new NotImplementedException();
}
public void OnProviderEnabled(string provider)
{
//throw new NotImplementedException();
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
//throw new NotImplementedException();
}
}
Xml Map activity
xml for my map activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="100"
android:background="#android:color/holo_blue_dark">
<EditText
android:id="#+id/SourceTxtBox"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/edit_text_style"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
android:hint="Enter Starting Point"
android:layout_weight="7"
android:textColorHint="#a3a3a3"
android:textColor="#000" />
<EditText
android:id="#+id/DestinationTxtBox"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/edit_text_style"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
android:hint="Enter Destination"
android:layout_weight="7"
android:textColorHint="#a3a3a3"
android:textColor="#000" />
<fragment
android:id="#+id/DirectionMap"
android:layout_height="0dp"
android:layout_width="match_parent"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_weight="80" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6"
android:weightSum="10">
<Button
android:id="#+id/GoBtn"
android:text="Go"
android:textSize="10dp"
android:textStyle="bold"
android:layout_height="wrap_content"
android:layout_width="20dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.company.RoutineApp" android:versionCode="1" android:versionName="1">
<uses-sdk android:minSdkVersion="15" />
<!-- Google Maps for Android v2 requires OpenGL ES v2 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- We need to be able to download map tiles and access Google Play Services-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Allow the application to access Google web-based services. -->
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<!-- Google Maps for Android v2 will cache map tiles on external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to receive remote notifications from Google Play Services -->
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
<uses-permission android:name="com.company.RoutineApp.permission.MAPS_RECEIVE" />
<permission android:name="com.company.RoutineApp.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
<!-- These are optional, but recommended. They will allow Maps to use the My Location provider. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>-->
<application android:label="#string/app_name" android:icon="#drawable/Icon" android:theme="#style/Theme.MyTheme">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyAGQlTIquLL5yyIr47pI_AA9g1CI-Whh0o" />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
</application>
</manifest>
This is the screen shot of my application
I am trying to configure the ack & nack channel and am getting the error like
"Only one confirm call back channel can be configured at a time"
Below are the things which I tried:
1. confirm-correlation-expression="#root" //no result found
2. Changed the amqp template like below
<rabbit:connection-factory id="connectionFactory" host="localhost" publisher-confirms="true" publisher-returns="true" />
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" mandatory="true" /> <!-- for nacks -->
<rabbit:admin connection-factory="connectionFactory" />
/>
The error was not there but the ack channel is not getting invoked.
Can anyone help me on this?
Here the MQ config
<rabbit:template id="nonTransactionalRabbitTemplate"
connection-factory="nonTransactionalConnectionFactory"
mandatory="true"
channel-transacted="false"
confirm-callback="confirmCallback"
return-call`enter code here`back="returnCallback" />
<rabbit:connection-factory id="nonTransactionalConnectionFactory"
connection-factory="rabbitClientConnectionFactory"
publisher-confirms="true"
publisher-returns="true"/>
<rabbit:connection-factory id="nonTransactionalConnectionFactory"
connection-factory="rabbitClientConnectionFactory"
publisher-confirms="true"
publisher-returns="true"/>
<bean id="rabbitClientConnectionFactory" class="com.rabbitmq.client.ConnectionFactory" >
<property name="uri" value="${mq.uri}" />
<property name="requestedHeartbeat" value="30" />
</bean>
Here is my outbound adapter
<int-amqp:outbound-channel-adapter channel="abc"
routing-key="xyz"
amqp-template="amqpTemplate"
confirm-correlation-expression="payload"
confirm-ack-channel="successRespTransformChannel"
confirm-nack-channel="failureRespTransformChannel"
return-channel="failureRespTransformChannel"
mapped-request-headers="*"
Here is my service activator
<chain input-channel="successRespTransformChannel">
<int:header-enricher>
<error-channel ref="failed-publishing" />
</int:header-enricher>
<service-activator id="successResp" expression="#abc.addRequestTracking(payload.id,'success')"/>
</chain>
When using the template in the adapter, you must NOT set your own callbacks
confirm-callback="confirmCallback"
return-callback="returnCallback" />
The adapter sets itself as the callback for both confirms and returns. This fails since you have already set the callbacks.
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" mandatory="true" /> <!-- for nacks -->
mandatory enables returns, not nacks.
EDIT
I have no idea what you are doing wrong. I just wrote a quick test case...
#SpringBootApplication
#ImportResource("context.xml")
public class So36546646Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(So36546646Application.class, args);
ctx.getBean("out", MessageChannel.class).send(new GenericMessage<>("foo"));
boolean received = ctx.getBean(MyService.class).latch.await(10, TimeUnit.SECONDS);
if (!received) {
System.err.println("Did not receive ack");
}
ctx.getBean(RabbitAdmin.class).deleteQueue(ctx.getBean(Queue.class).getName());
ctx.close();
}
public static class MyService {
private final CountDownLatch latch = new CountDownLatch(1);
public void handle(Message<?> ack) {
System.out.println("ack:" + ack);
latch.countDown();
}
}
}
and
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/amqp http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<rabbit:connection-factory id="cf" publisher-confirms="true" publisher-returns="true" host="localhost" />
<rabbit:template id="t" connection-factory="cf" mandatory="true" />
<rabbit:admin connection-factory="cf" />
<rabbit:queue id="anon" />
<int:channel id="out" />
<int-amqp:outbound-channel-adapter
channel="out"
amqp-template="t"
routing-key="#{anon.name}"
confirm-correlation-expression="payload"
confirm-ack-channel="acks"
confirm-nack-channel="acks"
return-channel="returns" />
<int:service-activator input-channel="acks" ref="service" />
<bean id="service" class="com.example.So36546646Application$MyService" />
<int:channel id="returns">
<int:queue />
</int:channel>
</beans>
and it worked fine:
ack:GenericMessage [payload=foo, headers={amqp_publishConfirm=true, id=5eed89bf-11b6-76a5-34ed-0091c6bac2c8, timestamp=1460464254229}]
I have App.config file in C# application.
I want to partially replace all Keys matching ".UAT" with ".PROD" using xdt tranform.
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="MyParam1.UAT" value="param1"/>
<add key="MyParam2.UAT" value="param2"/>
<add key="MyParam2.UAT" value="param3"/>
</appSettings>
</configuration>
Here is the output I want
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="MyParam1.PROD" value="param1"/>
<add key="MyParam2.PROD" value="param2"/>
<add key="MyParam2.PROD" value="param3"/>
</appSettings>
</configuration>
So far I've tried this using CustomTransform but it replaces only one element instead of all element. How can i get this to replace all elements
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add xdt:Locator="Condition(contains(#key, '.UAT'))" xdt:Transform="AttributeRegexReplace(Attribute='key', Pattern='.UAT',Replacement='.PROD')" />
</appSettings>
</configuration>
I found the answer here where I had to replace the Apply method with this method that iterates over all attributes
protected override void Apply()
{
foreach (XmlNode target in this.TargetNodes)
{
foreach (XmlAttribute att in target.Attributes)
{
if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0)
{ // get current value, perform the Regex
att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement);
}
}
}
}
I have the following binding on a MvxListView
<Mvx.MvxListView
android:id="#+id/listGroups"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_below="#+id/layoutGroupPadder"
android:dividerHeight="7dp"
android:divider="#drawable/list_divider"
local:MvxItemTemplate="#layout/list_group"
local:MvxBind="ItemsSource AvailableGroups; ItemClick GroupSelectedCommand" />
The MvxItemTemplate is as follows
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/xxxx.xxxx"
android:orientation="horizontal"
android:background="#color/white"
android:layout_width="fill_parent"
android:layout_height="63dp">
<TextView
android:id="#+id/groupsGroupName"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/verydarknavy"
local:MvxBind="Text Name" />
<RelativeLayout
android:id="#+id/layoutGroupGroupCount"
android:orientation="horizontal"
android:layout_width="90dp"
android:layout_height="fill_parent"
android:layout_centerInParent="true">
<TextView
android:id="#+id/groupsSubGroupCount"
android:layout_width="50dp"
android:layout_height="fill_parent"
android:textSize="16dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/hblue"
android:layout_toLeftOf="#+id/imageArrowGrp"
local:MvxBind="Text SubGroupCount" />
<ImageView
android:src="#drawable/YellowArrowRight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="7dp"
android:layout_alignParentRight="true"
android:id="#+id/imageArrowGrp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/layoutGroupItemCount"
android:orientation="horizontal"
android:layout_width="90dp"
android:layout_height="fill_parent"
android:layout_marginRight="14dp"
android:layout_alignParentRight="true"
android:fitsSystemWindows="false">
<TextView
android:id="#+id/groupsVehicleCount"
android:layout_width="50dp"
android:layout_height="fill_parent"
android:textSize="16dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/hblue"
android:layout_toLeftOf="#+id/imageArrowItem"
local:MvxBind="Text VehicleCount" />
<ImageView
android:src="#drawable/YellowArrowRight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_margin="7dp"
android:id="#+id/imageArrowItem" />
</RelativeLayout>
</RelativeLayout>
When the ItemClick happens the GroupSelectedCommand fires correctly :)
However I want to fire 2 different commands depending where within the item the user touches. I need to distinguish which of the TexViews have been touched (SubGroupCount or VehicleCount)
I tried changing the binding in the MvxListView to be
local:MvxBind="ItemsSource AvailableGroups" />
and changed the binding with the MvxItemTemplate to be
local:MvxBind="Text SubGroupCount; ItemClick GroupSelectedCommand " />
and
local:MvxBind="Text VehicleCount; ItemClick ItemSelectedCommand " />
and I created the necessary handling for the command ItemSelectedCommand.
Unfortunately it didn't fire either command.
Is it possible to fire separate commands from one template, and if so how do I bind them to different controls within the MvxItemTemplate?
To accomplish this you need to have two separate commands that are bound to the view inside the row.
Add this to both of the relative layouts that you want to have separate clicks:
local:MvxBind="Click OpenFirstCommand"
Now you need to have access to the viewmodel the list is bound to instead of the Viewmodel of the row itself. There are multiple approaches you can take there to fix that.
Wrap the RowViewmodel into a Wrapper Item. For more detail see this: Binding button click in ListView template MvvMCross
Use a value converter to wrap the Row into a wrapper item. More info on that one: How to binding list item to whether it is contained in another collection
I would personally go for the converter, because it keeps your code more clean. The converter could look like:
public class ListWrapperValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IEnumerable items = value as IEnumerable;
IList<CellWrapperViewModel<Item>> cellWrapperItems = items.OfType<Item>().Select(x => new CellWrapperViewModel<Item>(x, (BaseViewModel)parameter)).ToList();
ObservableCollection<CellWrapperViewModel<Item>> itemsList = new ObservableCollection<CellWrapperViewModel<Item>> (cellWrapperItems);
// If the old collection was observable, forward the triggers, happening on the old one to the new collection.
if (value as ObservableCollection<Item> != null) {
ObservableCollection<Item> documents = value as ObservableCollection<Item>;
documents.CollectionChanged += (object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) => {
switch (e.Action) {
default:
itemsList.SwitchTo (documents.Select (x => new CellWrapperViewModel<Item> (x, (BaseViewModel)parameter)).ToList ());
break;
}
};
}
return itemsList;
}
}
The Wrapper would be:
public class CellWrapperViewModel<T>
{
public T Item { get; set; }
public BaseViewModel ViewModel { get; set; }
public CellWrapperViewModel(T item, BaseViewModel viewModel)
{
Item = item;
ViewModel = viewModel;
}
}
Your MvxListView binding would then be:
local:MvxBind="ItemsSource ListWrapper(Items, .)"
Your converter for the commands inside the row:
public class OpenFirstCommandValueConverter : MvxValueConverter<CellWrapperViewModel<Item>, MvxCommand>
{
protected override MvxCommand Convert(CellWrapperViewModel<Item> value, Type targetType, object parameter, CultureInfo culture)
{
BaseViewModel viewModel = value.ViewModel;
Item item = value.Item;
return new MvxCommand(() => { viewModel.OptionCommand.Execute((Item)item); });
}
}
If you've done that the binding for the layouts would change to something like this:
local:MvxBind="Click OpenFirstCommand(.)"
local:MvxBind="Click OpenSecondCommand(.)"
More information on this issue is also on the mvvmcross GitHub: https://github.com/MvvmCross/MvvmCross/issues/35
I am using log4j and spring-security in application, and the logger should write logs with username in every message. I am very new to all of this, can somebody help with advice or links? Maybe there is some standart ways of solving this?
Thank you.
EDIT
Using spring framework 3.1
My spring-security.xml is:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/favicon.ico" security="none" />
<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_ADMIN"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="detect_me" password="1111" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
And log4j.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%c] - %m%n" />
</layout>
</appender>
<appender name="R" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="/logs/urlbuilderweb.log"/>
<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p %t %c - %m%n" />
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<param name="BufferSize" value="10000"/>
<appender-ref ref="R"/>
</appender>
<logger name="org.springframework">
<level value="WARN"/>
</logger>
<logger name="org.directwebremoting">
<level value="WARN"/>
</logger>
<logger name="org.apache.http">
<level value="WARN"/>
</logger>
<logger name="org.hibernate">
<level value="WARN"/>
</logger>
<root>
<level value="INFO" />
<appender-ref ref="ASYNC"/>
</root>
</log4j:configuration>
You can use NDC feature.
Set up some filter / interceptor (depends on what presentation technology you use). Add nested diagnostic context (filter example):
public class LogDiagnosticContextFilter implements javax.servlet.Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// do nothing
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
SecurityContext context = SecurityContextHolder.getContext();
if (context != null) {
Authentication authentication = context.getAuthentication();
if (authentication != null) {
NDC.push("Username=" + authentication.getName());
}
}
chain.doFilter(request, response);
NDC.pop();
}
#Override
public void destroy() {
// do nothing
}
}
Ensure that filter executed after Spring Security filter chain (web.xml):
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>logDiagnosticContextFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
Add x to each interested log4j pattern:
%x %d %p %t %c - %m%n
Later when you call
LOGGER.info("some text");
anywhere in you code you will see
Username=corresponding_login some text
in your log