In the encoding process I encountered one of the following exceptions:
09-12 14:12:36.327 10764-10764/cn.com.luckytry.interview E/ActivityThread: Failed to find provider info for cn.com.luckytry.interview.service
09-12 14:12:36.327 10764-10764/cn.com.luckytry.interview E/ContentResolver: query() unstableProvider is null
I am registering and declaring the permissions code in the AndroidManifest file AndroidManifest as follows:
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#mipmap/logo"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name=".service.InterViewPathProvider"
android:authorities="cn.com.luckytry.interview.service"
android:permission="cn.com.service.InterViewPathProvider"
android:enabled="true"
android:exported="true"
android:process=":Provider">
</provider>
...
</application>
<permission
android:name="cn.com.service.InterViewPathProvider"
android:protectionLevel="normal" />
Customize the ContentProvider:
public class InterViewPathProvider extends ContentProvider {
public static final String AUTHORITY = "cn.com.luckytry.interview.service";
public static final Uri PATH_CONTENT_URI = Uri.parse("content://"
+ AUTHORITY + "/path");
public static final int PATH_URI_CODE = 0;
private static final UriMatcher sUriMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(AUTHORITY, "path", PATH_URI_CODE);
}
private Context mContext;
private SQLiteDatabase mDb;
#Override
public boolean onCreate() {
mContext = getContext();
mDb =new DbOpenHelper(mContext).getReadableDatabase();
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection, #Nullable String[] selectionArgs, #Nullable String sortOrder) {
String table = getTableName(uri);
if (table == null) {
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
LUtil.e("query");//日志没有输出
return mDb.query(table, projection, selection, selectionArgs, null, null, sortOrder, null);
}
...
private String getTableName(Uri uri) {
LUtil.e("getTableName");
String tableName = null;
switch (sUriMatcher.match(uri)) {
case PATH_URI_CODE:
tableName = "interpath.db";
break;
default:break;
}
return tableName;
}
}
Services Use:
/**
* 解析查询结果
* #param id
* #return
*/
private String getQueryResult(int id) {
Uri userUri = InterViewPathProvider.PATH_CONTENT_URI;
// Cursor cursor = db.query("news", null, "commentcount>?", new String[]{"0"}, null, null, null);
String result = null;
Cursor pathCursor = getContentResolver().query(userUri, null, "beanId=?", new String[]{id+""}, null);
if(pathCursor!=null){
while (pathCursor.moveToNext()) {
result = pathCursor.getString(1);
}
pathCursor.close();
}
return result;
}
Related
I am trying to authorize URLs to users with authority like ADMIN/LEAD/AGENT.
UsernamePasswordAuthenticationToken takes two arguments but I would like to pass 3 args userid , password as null and role of userid.
I have application-users.txt
{
"users": ["userid1","userid2","userid3","userid4"],
"agents": ["userid1"],
"leads": ["userid2"],
"admins": ["userid4"]
}
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
#EnableWebSecurity
#ConditionalOnWebApplication
#ConfigurationPropertiesScan("com.spectrum.sci.config")
#EnableConfigurationProperties(ApplicationClients.class)
#RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
private static final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
#Autowired
OrderDetailsUsers orderDetailsUsers;
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/order/greet").hasAnyAuthority("admins","leads")
.antMatchers("/order").hasRole("agents")
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
log.info("Importing {} clients: " , applicationClients.getClients().toString());
AuthenticationManager authenticationManager = null;
KeyValues kvAgents = orderDetailsUsers.applicatonUsers.getAgents();
String keyAgent = kvAgents.getKey();
String[] valueAgents = kvAgents.getValues();
for (int i = 0; i < valueAgents.length ; i++) {
Authentication authentication =
new UsernamePasswordAuthenticationToken(keyAgent, null, valueAgents[i]);
SecurityContextHolder.getContext().setAuthentication(authentication);
authenticationManager.authenticate(authentication);
manager.setAuthenticationManager(authenticationManager);
}
return manager;
}
}
#Component
public class OrderDetailsUsers {
private static final Logger log = LoggerFactory.getLogger(OrderDetailsUsers.class);
private ResourceLoader resourceLoader;
//#Autowired
ApplicationUsers applicatonUsers = new ApplicationUsers();
public OrderDetailsUsers(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
#PostConstruct
public void init() {
try {
log.info("Trying to load users...");
Resource resource = resourceLoader.getResource("classpath:application-users.txt");
InputStream inputStream = resource.getInputStream();
log.info("inputStream = " + inputStream.toString());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
StringBuilder stringBuilder = new StringBuilder();
String str;
while ( (str = bufferedReader.readLine()) != null) {
stringBuilder.append(str);
}
log.info("stringBuilder = " + stringBuilder.toString());
JsonObject jsonObject = new JsonParser().parse(stringBuilder.toString()).getAsJsonObject();
JsonArray users = jsonObject.get("users").getAsJsonArray();
log.info("users = " + users.toString());
String[] strUsersArray = toStringArray(users);
KeyValues kvUsers = new KeyValues();
kvUsers.setKey("users");
kvUsers.setValues(strUsersArray);
applicatonUsers.setUsers(kvUsers);
log.info("final users = " + applicatonUsers.getUsers().toString());
JsonArray agents = jsonObject.get("agents").getAsJsonArray();
log.info("agents = " + agents.toString());
String[] strAgentsArray = toStringArray(agents);
KeyValues kvAgents = new KeyValues();
kvAgents.setKey("agents");
kvAgents.setValues(strAgentsArray);
applicatonUsers.setAgents(kvAgents);
log.info("final Agents = " + applicatonUsers.getAgents().toString());
JsonArray leads = jsonObject.get("leads").getAsJsonArray();
log.info("leads = " + leads.toString());
String[] strLeadsArray = toStringArray(leads);
KeyValues kvLeads = new KeyValues();
kvLeads.setKey("leads");
kvLeads.setValues(strLeadsArray);
applicatonUsers.setLeads(kvLeads);
log.info("final leads = " + applicatonUsers.getLeads().toString());
JsonArray admins = jsonObject.get("admins").getAsJsonArray();
log.info("admins = " + admins.toString());
String[] strAdminsArray = toStringArray(admins);
KeyValues kvAdmins = new KeyValues();
kvAdmins.setKey("admins");
kvAdmins.setValues(strAdminsArray);
applicatonUsers.setAdmins(kvAdmins);
log.info("final admins = " + applicatonUsers.getAdmins().toString());
} catch(IOException | NullPointerException e) {
log.error("Failing to load users..." , e);
}
}
public static String[] toStringArray(JsonArray jsonArray) {
if (jsonArray == null)
return null;
String[] strArray = new String[jsonArray.size()];
for ( int i =0; i < strArray.length ; i++) {
strArray[i] = jsonArray.get(i).getAsString();
}
return strArray;
}
}
#Getter
#Setter
#ToString
public class ApplicationUsers {
private KeyValues users;
private KeyValues agents;
private KeyValues leads;
private KeyValues admins;
}
#Getter
#Setter
#ToString
public class KeyValues {
private String key;
private String[] values;
}
UsernamePasswordAuthenticationToken is asking for two arguments userid and password. But, I would like to pass userid, password as null, role of userid.
The purpose of InMemoryUserDetailsManager is just to represent user information in memory, it's userdetails service which is used by authentication provider. Ex:
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
List<UserDetails> listOfUserDetails = new ArrayList<>();
listOfUserDetails.add(User.withUsername("userName").password(passwordEncoder().encode("pass"))
.roles("ADMIN", "LEAD","AGENT").build());
return new InMemoryUserDetailsManager(listOfUserDetails);
}
I do not think it is a good place to have authentication manipulations in InMemoryUserDetailsManager bean(It has different purpose).
Then register inMemoryUserDetailsManager bean to authenticationManagerBuilder:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(inMemoryUserDetailsManager());
}
As for UsernamePasswordAuthenticationToken, authentication provider after successful credential validation should return UsernamePasswordAuthenticationToken object built by 3 argument constructor as it sets authenticated flag to true.
I changed inMemoryUserDetailsManager() method and added passwordEncoder() method.
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
KeyValues kvAgents = orderDetailsUsers.applicatonUsers.getAgents();
String keyAgent = kvAgents.getKey();
String[] valueAgents = kvAgents.getValues();
for (int i = 0; i < valueAgents.length ; i++) {
manager.createUser(User.withUsername(valueAgents[i])
.password(passwordEncoder().encode(""))
.roles(keyAgent)
.build());
}
KeyValues kvAdmins = orderDetailsUsers.applicatonUsers.getAdmins();
String keyAdmin = kvAdmins.getKey();
String[] valueAdmins = kvAdmins.getValues();
for (int i = 0; i < valueAdmins.length ; i++) {
manager.createUser(User.withUsername(valueAdmins[i])
.password(passwordEncoder().encode(""))
.roles(keyAdmin)
.build());
}
KeyValues kvLeads = orderDetailsUsers.applicatonUsers.getLeads();
String keyLead = kvLeads.getKey();
String[] valueLeads = kvLeads.getValues();
for (int i = 0; i < valueLeads.length ; i++) {
manager.createUser(User.withUsername(valueLeads[i])
.password(passwordEncoder().encode(""))
.roles(keyLead)
.build());
}
return manager;
}
private PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
I have a requirement to use same variable of a request scoped backing bean which is a List datatype for h:selectOneListbox and h:selectManyListbox. I get "ip: Validation Error: Value is not valid" error with h:selectOneListbox even after using a converter. Can some one help me resolving this ?
In page1.xhtml I've given it as:
<h:selectManyListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectManyListbox>
In page2.xhtml I've given it as:
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
<f:converter converterId="ipAddressConverter"></f:converter>
</h:selectOneListbox>
My Input bean, a request scoped managed bean looks like this:
#ManagedBean
#RequestScoped
public class InputTablePlot implements Serializable{
private static final long serialVersionUID = 1L;
#ManagedProperty("#{database}")
private Database database;
private Connection connection;
private StringBuilder query;
private PreparedStatement pst_query;
private ResultSet rs;
private List<Long> ipAddress;
private Map<String, Long> ipAddrMenu;
public InputBean()
{
ipAddrMenu = new LinkedHashMap<String, Long>();
}
#PostConstruct
public void init()
{
ipAddrMenu.clear();
try
{
connection = database.getDbConnection();
query = new StringBuilder();
query.append("SELECT distinct source AS ipaddr FROM addrtable ORDER BY source");
pst_query = connection.prepareStatement(query.toString());
rs = pst_query.executeQuery();
while (rs.next())
{
ipAddrMenu.put(ipLongToString(rs.getLong("ipaddr")), rs.getLong("ipaddr")); // Adding
// sources
}
rs.close();
pst_query.close();
connection.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public List<Long> getIpAddress()
{
System.out.println("In Getter" + ipAddress);
return ipAddress;
}
public void setIpAddress(List<Long> ipAddress)
{
System.out.println("In Setter");
System.out.println(ipAddress);
this.ipAddress = ipAddress;
}
public Map<String, Long> getIpAddressList()
{
return ipAddrMenu;
}
public void setIpAddressList(Map<String, Long> ipAddressList)
{
this.ipAddrMenu = ipAddressList;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((connection == null) ? 0 : connection.hashCode());
result = prime * result + ((database == null) ? 0 : database.hashCode());
result = prime * result + ((ipAddrMenu == null) ? 0 : ipAddrMenu.hashCode());
result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InputBean other = (InputBean) obj;
if (connection == null)
{
if (other.connection != null)
return false;
}
else if (!connection.equals(other.connection))
return false;
if (database == null)
{
if (other.database != null)
return false;
}
else if (!m_database.equals(other.database))
return false;
if (ipAddrMenu == null)
{
if (other.ipAddrMenu != null)
return false;
}
else if (!ipAddrMenu.equals(other.ipAddrMenu))
return false;
if (ipAddress == null)
{
if (other.ipAddress != null)
return false;
}
else if (!ipAddress.equals(other.ipAddress))
return false;
return true;
}
}
Converter code:
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
public class IpAddressConverter implements Converter
{
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2)
{
List<Long> ipAddr = new ArrayList<Long>();
try{
ipAddr.add(Long.valueOf(arg2));
}catch(NumberFormatException e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
for(int i=0; i< ipAddr.size(); i++){
System.out.println("ipAddr >>> "+ipAddr);
}
return ipAddr;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2)
{
String val = null;
try{
Long ip = (Long) arg2;
val = ip.toString();
}catch(Exception e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
System.out.println("value >>> "+val);
return val;
}
}
It failed because List<Long> as returned by the converter doesn't match the individual Long item of the available items while JSF is validating the submitted (and converted!) value against the list of available items (as part of safeguard against tampered/spoofed HTTP requests wherein attacker manipulated the selected item value). The converter is supposed to return a Long. All with all, such a converter is simply insuitable for usage in an UISelectOne component.
You'd better bind the value straight to a single property. If you insist in using a List property, then just prepare it with a single empty item and specify the list item index in the value.
private List<Long> ipAddress = new ArrayList<>(1);
with
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress[0]}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectOneListbox>
See also:
Validation Error: Value is not valid
I am using persistent stores to store data in a Blackberry application. I am trying to store phone number in persistent objects, but after storing, it gives null value.
here i am posting my code:
public static Vector push_data;
public static PersistentObject push_store = null;
public static final long KEY = 0x9df9f961bc333daL;
boolean isNumberVerified;
// PasswordEditField password;
static String verifiedPhoneNumber = "number";
public static String phoneNumber;
static String Number = "number";
public Third() {
super(Field.USE_ALL_HEIGHT | Field.FIELD_HCENTER);
System.out.println("******************** Into SplashScreen");
try {
bitmap = Bitmap.getBitmapResource("im.png");
BitmapField bmpField = new BitmapField(bitmap);
HorizontalFieldManager hfm = new HorizontalFieldManager();
hfm.add(bmpField);`
........
public void fieldChanged(Field field, int context) {
if (field == btnNext) {
final String msg = Util.getRandomNumber();
checkIsVerified(Number, msg);
}
}
private void checkIsVerified(final String Number, final String msg) {
Dialog.alert("Verifying " + Number);
if (verifiedPhoneNumber == Number) {
isNumberVerified = true;
Dialog.alert("isverified " + Number);
push_store = PersistentStore.getPersistentObject( KEY );
push_data = (Vector) push_store.getContents();
if( push_data == null ) {
push_data = new Vector();
push_data.addElement("number");
push_store.setContents( push_data );
push_store.commit();
Dialog.alert("isverified " + push_data);
UiApplication.getUiApplication().pushScreen(new spinner());
} else {
isNumberVerified = false;
UiApplication.getUiApplication().pushScreen(new Sms());
}
}
Try this -
public static String push_data="";
public static PersistentObject push_store;
public static final long KEY = 0x9df9f961bc33352L;
//For get contents
push_store = PersistentStore.getPersistentObject( KEY );
push_data = (String) push_store.getContents();
//For set contents
push_data=Number;
push_store.setContents( push_data );
push_store.commit();
I am working with JSF 2 and Hibernate. I have XHTML page where bean is get from database and inserted into page. When I change the values of bean and submit for savign I am getting only the last value. What I making wrong?
Here is my XHTML page form code:
<h:form id="edit-slide-form">
<h:panelGrid columns="2">
<h:outputText value="#{msgs.slideTitle}" styleClass="label"/>
<h:inputText id="title" value="#{sliderAction.newSlide.title}" name="#{sliderAction.slide.title}" required="true"/>
<p></p><h:message for="title" errorClass="error"/>
<h:outputText value="#{msgs.description}" styleClass="label"/>
<h:inputTextarea id="description" value="#{sliderAction.newSlide.description}" name="#{sliderAction.slide.description}" required="true"/>
<p></p><h:message for="description" errorClass="error"/>
<p></p>
<h:commandButton value="#{msgs.save}" action="#{sliderAction.saveChanges}" styleClass="button"/>
<h:message for="edit-slide-form"/>
</h:panelGrid>
</h:form>
When I submit this form I can get only last value (e.g id="description").
SliderAction.class
#Named
#SessionScoped
public class SliderAction implements Serializable {
private static final long serialVersionUID = 1L;
private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("iaau");
private EntityManager entityManager;
private int id;
private Integer coordinates[] = new Integer[4];
private Image image = new Image();
private Slide slide = new Slide();
private Slide newSlide = new Slide();
private List<Slide> slides = new ArrayList<Slide>();
private UploadedFile uploadedFile;
private boolean uploaded;
public String uploadSlideImage() {
ImageAction imageAction = new ImageAction();
if( uploaded ) {
imageAction.delete( image.getUniqueName(), image.getThumb() );
for( int i = 0; i < coordinates.length; i++ ) {
coordinates[i] = null;
}
}
imageAction.upload(uploadedFile, false);
setImage( imageAction.getImage() );
uploaded = true;
return null;
}
public String cropAndSave(){
ImageAction imageAction = new ImageAction();
imageAction.cropSlide( image, coordinates, 928, 318 );
newSlide = new Slide();
newSlide.setImage( image );
startTransaction();
entityManager.persist(image);
entityManager.persist(newSlide);
endTransaction();
closeTransaction();
uploaded = false;
setId(newSlide.getId());
return "edit";
}
public String saveChanges() {
startTransaction();
entityManager.merge(newSlide);
endTransaction();
closeTransaction();
return "list";
}
public void deleteSlide() {
startTransaction();
slide = (Slide)entityManager.find(Slide.class, id);
entityManager.remove(slide);
endTransaction();
closeTransaction();
ImageAction imageAtion = new ImageAction();
imageAtion.delete(slide.getImage().getUniqueName(), slide.getImage().getThumb());
}
public Slide getSlide() {
startTransaction();
slide = entityManager.find(Slide.class, id);
endTransaction();
closeTransaction();
return slide;
}
public void setSlide(Slide slide) {
this.slide = slide;
}
public Slide getNewSlide() {
startTransaction();
newSlide = entityManager.find(Slide.class, id);
endTransaction();
closeTransaction();
return newSlide;
}
public void setNewSlide(Slide newSlide) {
this.newSlide = newSlide;
}
#SuppressWarnings("unchecked")
public List<Slide> getSlides() {
startTransaction();
slides = entityManager.createQuery("from Slide").getResultList();
endTransaction();
closeTransaction();
return slides;
}
/*Declaration of EntityManager and other getter and setter methods*/
}
Slide.class
#Entity
public class Slide extends AbstractEntity<Integer>{
private static final long serialVersionUID = 1L;
private String title;
private String description;
private Image image;
private String link;
private Page page;
private boolean showOnFeed;
private boolean approved;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#OneToOne
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
#OneToOne
public Page getPage() {
return page;
}
public void setPage(Page page) {
this.page = page;
}
#Column(name="show_on_feed")
public boolean isShowOnFeed() {
return showOnFeed;
}
public void setShowOnFeed(boolean showOnFeed) {
this.showOnFeed = showOnFeed;
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
}
Also I have notices this warning message:
[org.hibernate.ejb.internal.EntityManagerFactoryRegistry] (http-localhost-127.0.0.1-8080-1) HHH000436: Entity manager factory name (iaau) is already registered. If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'
can this cause such problems
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.