test_class.declarator: carbonsProcessor
test_class.modifier: private
test_class.original_string: private MessageCarbons carbonsProcessor;
test_class.type: MessageCarbons
test_class.var_name: carbonsProcessor
test_class.file: tigase-server 7.1.0/src/test/java/tigase/xmpp/impl/MessageCarbonsTest.java
test_class.identifier: MessageCarbonsTest
test_class.superclass: extends ProcessorTestCase
test_case.body: @Test
  	public void testResourceSelectionForMessageDeliveryForBareJid() throws Exception {
  		BareJID userJid = BareJID.bareJIDInstance("user1@example.com");
  		JID res1 = JID.jidInstance(userJid, "res1");
  		JID res2 = JID.jidInstance(userJid, "res2");
  		XMPPResourceConnection session1 = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID().toString()), res1);
  		XMPPResourceConnection session2 = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID().toString()), res2);
  		
  		session2.putSessionData(MessageCarbons.XMLNS + "-enabled", true);
  		Map<JID,Boolean> enabled = new HashMap<>();
  		enabled.put(res2, true);
  		session2.putCommonSessionData(MessageCarbons.XMLNS + "-resources", enabled);
  		assertEquals(Arrays.asList(session1, session2), session1.getActiveSessions());
  		
  		Element packetEl = new Element("message", new String[] { "type", "from", "to" },
  				new String[] { "chat", "remote-user@test.com/res1", userJid.toString() });
  		Packet packet = Packet.packetInstance(packetEl);
  		Queue<Packet> results = new ArrayDeque<Packet>();
  		carbonsProcessor.process(packet, session2, null, results, null);
  		assertEquals("generated result even than no resource had nonnegative priority", 1, results.size());
  		assertEquals("packet sent to wrong jids", Arrays.asList(session2.getJID()), collectStanzaTo(results));
  		
  		session1.setPresence(new Element("presence"));
  		results = new ArrayDeque<Packet>();
  		carbonsProcessor.process(packet, session2, null, results, null);		
  		assertEquals("not generated result even than 1 resource had nonnegative priority", 1, results.size());
  		assertEquals("packet sent to wrong jids", Arrays.asList(session2.getJID()), collectStanzaTo(results));
  		
  		session2.setPresence(new Element("presence"));
  		results = new ArrayDeque<Packet>();
  		carbonsProcessor.process(packet, session1, null, results, null);		
  		assertEquals("not generated result even than 2 resource had nonnegative priority", 0, results.size());
  		assertEquals("packet sent to wrong jids", Arrays.asList(), 
  				collectStanzaTo(results));		
  	}
test_case.class_method_signature: MessageCarbonsTest.testResourceSelectionForMessageDeliveryForBareJid()
test_case.full_signature: @Test public void testResourceSelectionForMessageDeliveryForBareJid()
test_case.identifier: testResourceSelectionForMessageDeliveryForBareJid
test_case.invocations: bareJIDInstance jidInstance jidInstance getSession jidInstance toString randomUUID getSession jidInstance toString randomUUID putSessionData put putCommonSessionData assertEquals asList getActiveSessions toString packetInstance process assertEquals size assertEquals asList getJID collectStanzaTo setPresence process assertEquals size assertEquals asList getJID collectStanzaTo setPresence process assertEquals size assertEquals asList collectStanzaTo
test_case.modifiers: @Test public
test_case.parameters: ()
test_case.return: void
test_case.signature: void testResourceSelectionForMessageDeliveryForBareJid()
focal_class.declarator: log = Logger.getLogger(MessageCarbons.class.getCanonicalName())
focal_class.modifier: private static final
focal_class.original_string: private static final Logger log = Logger.getLogger(MessageCarbons.class.getCanonicalName());
focal_class.type: Logger
focal_class.var_name: log
focal_class.declarator: ID = "message-carbons"
focal_class.modifier: private static final
focal_class.original_string: private static final String ID = "message-carbons";
focal_class.type: String
focal_class.var_name: ID
focal_class.declarator: XMLNS = "urn:xmpp:carbons:2"
focal_class.modifier: public static final
focal_class.original_string: public static final String XMLNS = "urn:xmpp:carbons:2";
focal_class.type: String
focal_class.var_name: XMLNS
focal_class.declarator: ELEMENTS = { { "message" }, { "iq", "enable" }, { "iq", "disable" } }
focal_class.modifier: private static final
focal_class.original_string: private static final String[][] ELEMENTS = { { "message" }, { "iq", "enable" }, { "iq", "disable" } };
focal_class.type: String[][]
focal_class.var_name: ELEMENTS
focal_class.declarator: XMLNSS = { XMPPProcessor.CLIENT_XMLNS, XMLNS, XMLNS }
focal_class.modifier: private static final
focal_class.original_string: private static final String[] XMLNSS = { XMPPProcessor.CLIENT_XMLNS, XMLNS, XMLNS };
focal_class.type: String[]
focal_class.var_name: XMLNSS
focal_class.declarator: DISCO_FEATURES = { new Element("feature", new String[] { "var" }, new String[] { XMLNS }) }
focal_class.modifier: private static final
focal_class.original_string: private static final Element[] DISCO_FEATURES = { new Element("feature", new String[] { "var" }, new String[] { XMLNS }) };
focal_class.type: Element[]
focal_class.var_name: DISCO_FEATURES
focal_class.declarator: ENABLED_KEY = XMLNS + "-enabled"
focal_class.modifier: private static final
focal_class.original_string: private static final String ENABLED_KEY = XMLNS + "-enabled";
focal_class.type: String
focal_class.var_name: ENABLED_KEY
focal_class.declarator: ENABLED_RESOURCES_KEY = XMLNS + "-resources"
focal_class.modifier: private static final
focal_class.original_string: private static final String ENABLED_RESOURCES_KEY = XMLNS + "-resources";
focal_class.type: String
focal_class.var_name: ENABLED_RESOURCES_KEY
focal_class.declarator: ENABLE_ELEM_NAME = "enable"
focal_class.modifier: private static final
focal_class.original_string: private static final String ENABLE_ELEM_NAME = "enable";
focal_class.type: String
focal_class.var_name: ENABLE_ELEM_NAME
focal_class.declarator: DISABLE_ELEM_NAME = "disable"
focal_class.modifier: private static final
focal_class.original_string: private static final String DISABLE_ELEM_NAME = "disable";
focal_class.type: String
focal_class.var_name: DISABLE_ELEM_NAME
focal_class.declarator: MESSAGE_HINTS_NO_COPY = { Message.ELEM_NAME, "no-copy" }
focal_class.modifier: private static final
focal_class.original_string: private static final String[] MESSAGE_HINTS_NO_COPY = { Message.ELEM_NAME, "no-copy" };
focal_class.type: String[]
focal_class.var_name: MESSAGE_HINTS_NO_COPY
focal_class.declarator: MESSAGE_HINTS_XMLNS = "urn:xmpp:hints"
focal_class.modifier: private static final
focal_class.original_string: private static final String MESSAGE_HINTS_XMLNS = "urn:xmpp:hints";
focal_class.type: String
focal_class.var_name: MESSAGE_HINTS_XMLNS
focal_class.declarator: RESOURCES_MAP_FACTORY = (k) -> { return new ConcurrentHashMap<JID,Boolean>(); }
focal_class.modifier: private static final
focal_class.original_string: private static final Function<String,Object> RESOURCES_MAP_FACTORY = (k) -> { return new ConcurrentHashMap<JID,Boolean>(); };
focal_class.type: Function<String,Object>
focal_class.var_name: RESOURCES_MAP_FACTORY
focal_class.declarator: messageProcessor = new tigase.xmpp.impl.Message()
focal_class.modifier: private
focal_class.original_string: private tigase.xmpp.impl.Message messageProcessor = new tigase.xmpp.impl.Message();
focal_class.type: tigase.xmpp.impl.Message
focal_class.var_name: messageProcessor
focal_class.file: tigase-server 7.1.0/src/main/java/tigase/xmpp/impl/MessageCarbons.java
focal_class.identifier: MessageCarbons
focal_class.interfaces: implements XMPPProcessorIfc, XMPPPacketFilterIfc,
  				XMPPPresenceUpdateProcessorIfc
focal_class.class_method_signature: MessageCarbons.id()
focal_class.full_signature: @Override public String id()
focal_class.identifier: id
focal_class.modifiers: @Override public
focal_class.parameters: ()
focal_class.return: String
focal_class.signature: String id()
focal_class.class_method_signature: MessageCarbons.process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_class.full_signature: @Override public void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_class.identifier: process
focal_class.modifiers: @Override public
focal_class.parameters: (Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_class.return: void
focal_class.signature: void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_class.class_method_signature: MessageCarbons.supDiscoFeatures(XMPPResourceConnection session)
focal_class.full_signature: @Override public Element[] supDiscoFeatures(XMPPResourceConnection session)
focal_class.identifier: supDiscoFeatures
focal_class.modifiers: @Override public
focal_class.parameters: (XMPPResourceConnection session)
focal_class.return: Element[]
focal_class.signature: Element[] supDiscoFeatures(XMPPResourceConnection session)
focal_class.class_method_signature: MessageCarbons.supElementNamePaths()
focal_class.full_signature: @Override public String[][] supElementNamePaths()
focal_class.identifier: supElementNamePaths
focal_class.modifiers: @Override public
focal_class.parameters: ()
focal_class.return: String[][]
focal_class.signature: String[][] supElementNamePaths()
focal_class.class_method_signature: MessageCarbons.supNamespaces()
focal_class.full_signature: @Override public String[] supNamespaces()
focal_class.identifier: supNamespaces
focal_class.modifiers: @Override public
focal_class.parameters: ()
focal_class.return: String[]
focal_class.signature: String[] supNamespaces()
focal_class.class_method_signature: MessageCarbons.prepareCarbonCopy(Packet packet, 
  			JID srcJid, JID jid, String type)
focal_class.full_signature: private static Packet prepareCarbonCopy(Packet packet, 
  			JID srcJid, JID jid, String type)
focal_class.identifier: prepareCarbonCopy
focal_class.modifiers: private static
focal_class.parameters: (Packet packet, 
  			JID srcJid, JID jid, String type)
focal_class.return: Packet
focal_class.signature: Packet prepareCarbonCopy(Packet packet, 
  			JID srcJid, JID jid, String type)
focal_class.class_method_signature: MessageCarbons.setEnabled(XMPPResourceConnection session, boolean value, Queue<Packet> results)
focal_class.full_signature: private static void setEnabled(XMPPResourceConnection session, boolean value, Queue<Packet> results)
focal_class.identifier: setEnabled
focal_class.modifiers: private static
focal_class.parameters: (XMPPResourceConnection session, boolean value, Queue<Packet> results)
focal_class.return: void
focal_class.signature: void setEnabled(XMPPResourceConnection session, boolean value, Queue<Packet> results)
focal_class.class_method_signature: MessageCarbons.isEnabled(XMPPResourceConnection session)
focal_class.full_signature: private static boolean isEnabled(XMPPResourceConnection session)
focal_class.identifier: isEnabled
focal_class.modifiers: private static
focal_class.parameters: (XMPPResourceConnection session)
focal_class.return: boolean
focal_class.signature: boolean isEnabled(XMPPResourceConnection session)
focal_class.class_method_signature: MessageCarbons.notifyStateChanged(JID from, JID to, boolean value, Queue<Packet> results)
focal_class.full_signature: private static void notifyStateChanged(JID from, JID to, boolean value, Queue<Packet> results)
focal_class.identifier: notifyStateChanged
focal_class.modifiers: private static
focal_class.parameters: (JID from, JID to, boolean value, Queue<Packet> results)
focal_class.return: void
focal_class.signature: void notifyStateChanged(JID from, JID to, boolean value, Queue<Packet> results)
focal_class.class_method_signature: MessageCarbons.presenceUpdate(XMPPResourceConnection session, Packet packet, Queue<Packet> results)
focal_class.full_signature: @Override public void presenceUpdate(XMPPResourceConnection session, Packet packet, Queue<Packet> results)
focal_class.identifier: presenceUpdate
focal_class.modifiers: @Override public
focal_class.parameters: (XMPPResourceConnection session, Packet packet, Queue<Packet> results)
focal_class.return: void
focal_class.signature: void presenceUpdate(XMPPResourceConnection session, Packet packet, Queue<Packet> results)
focal_class.class_method_signature: MessageCarbons.filter(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results)
focal_class.full_signature: @Override public void filter(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results)
focal_class.identifier: filter
focal_class.modifiers: @Override public
focal_class.parameters: (Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results)
focal_class.return: void
focal_class.signature: void filter(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results)
focal_class.class_method_signature: MessageCarbons.isErrorDeliveringForkedMessage(Packet packet, XMPPResourceConnection session)
focal_class.full_signature: private boolean isErrorDeliveringForkedMessage(Packet packet, XMPPResourceConnection session)
focal_class.identifier: isErrorDeliveringForkedMessage
focal_class.modifiers: private
focal_class.parameters: (Packet packet, XMPPResourceConnection session)
focal_class.return: boolean
focal_class.signature: boolean isErrorDeliveringForkedMessage(Packet packet, XMPPResourceConnection session)
focal_class.superclass: extends XMPPProcessor
focal_method.body: @Override
  	public void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings) throws XMPPException {
  		
  		if (session == null)
  			return;
  		
  		if (packet.getElemName() == Iq.ELEM_NAME) {
  
  			boolean enable = packet.getElement().getChild(ENABLE_ELEM_NAME, XMLNS) != null;
  			boolean disable = packet.getElement().getChild(DISABLE_ELEM_NAME, XMLNS) != null;
  			
  			// we can only enable or disable but we cannot do both
  			if ((enable && disable) || (!enable && !disable)) {
  				results.offer(Authorization.BAD_REQUEST.getResponseMessage(packet, null, false));
  			}
  			else {
  				JID sessionJid = session.getJID();				
  				if (packet.getStanzaFrom() != null && !sessionJid.equals(packet.getStanzaFrom())
  						&& session.isUserId(packet.getStanzaFrom().getBareJID()) && packet.getStanzaFrom().getResource() != null) {
  					
  					// direct notification about state of MessageCarbons for other resource
  					Map<JID,Boolean> resources = (Map<JID,Boolean>) session.getCommonSessionData(ENABLED_RESOURCES_KEY);
  					if (resources == null) {
  						synchronized (session.getParentSession()) {
  							resources = (Map<JID, Boolean>) session.getCommonSessionData(ENABLED_RESOURCES_KEY);
  							if (resources == null) {
  								resources = new ConcurrentHashMap<JID, Boolean>();
  								session.putCommonSessionData(ENABLED_RESOURCES_KEY, resources);
  							}
  						}
  					}					
  					if (log.isLoggable(Level.FINER)) {
  						log.log(Level.FINER, "received state notification from {0} with value = {1}", 
  								new Object[]{packet.getStanzaFrom(), enable});
  					}
  					Boolean oldValue = resources.put(packet.getStanzaFrom(), enable);
  					if (oldValue == null) {
  						// if it is first info about this resource then notify it about
  						// state of MC for other resources
  						for (XMPPResourceConnection conn : session.getActiveSessions()) {
  							notifyStateChanged(conn.getJID(), packet.getStanzaFrom(), isEnabled(conn), results);
  						}
  					}						
  				}
  				else {
  					setEnabled(session, enable, results);
  					// send result of operation
  					results.offer(packet.okResult((Element) null, 0));
  				}
  			}
  		}
  		else if (packet.getElemName() == Message.ELEM_NAME && packet.getType() == StanzaType.chat 
  				&& packet.getStanzaTo() != null) {
  
  			// ignoring if message packet was resent from c2s for redelivery
  			if (C2SDeliveryErrorProcessor.isDeliveryError(packet))
  				return;
  			
  			Map<JID,Boolean> resources = (Map<JID,Boolean>) session.getCommonSessionData(ENABLED_RESOURCES_KEY);
  			if (resources == null || resources.isEmpty()) {
  				// no session has enabled message carbons
  				return;
  			}
  			
  			// if this is error delivering forked message we should not fork it
  			// but we need to fork only messsages with type chat so no need to check it
  			//if (isErrorDeliveringForkedMessage(packet, session))
  			//	return;
  			
  			if (packet.getType() == StanzaType.chat) {
  				
  				// if this is error delivering forked message we should not fork it
  				// but we need to fork only messsages with type chat so no need to check it
  				//if (isErrorDeliveringForkedMessage(packet, session))
  				//	return;
  				if (packet.getElement().getChild("received", XMLNS) != null
  						|| packet.getElement().getChild("sent", XMLNS) != null) {
  					return;
  				}
  				
  				// support for XEP-0334 Message Processing Hints
  				if (packet.getAttributeStaticStr(MESSAGE_HINTS_NO_COPY, "xmlns") == MESSAGE_HINTS_XMLNS) {
  					return;
  				}
  
  				// if this is private message then do not send carbon copy
  				Element privateEl = packet.getElement().getChild("private", XMLNS);
  
  				if (privateEl != null) {
  					// TODO: is it enought to just remove this element?
  					packet.getElement().removeChild(privateEl);
  					return;
  				}
  
  				String type = session.isUserId(packet.getStanzaTo().getBareJID()) ? "received" : "sent";
  				JID srcJid = JID.jidInstance(session.getBareJID());
  				// collections of jid to which message will be delivered by default so we need to skip them
  				Set<JID> skipForkingTo = null;
  							
  				if (session.isUserId(packet.getStanzaTo().getBareJID()) && packet.getStanzaTo().getResource() == null) {
  					// message is cloned to all resources by Message.java, it violates RFC6121 
  					// while it should be copied only to resources with non negative priority!!
  					// until it is not solved there is no need to fork messages
  
  					// as we started to respect connection priority we need to implement proper 
  					// forking of messages sent to bare jid
  					// we need to fork this message
  					skipForkingTo = messageProcessor.getJIDsForMessageDelivery(session);
  					
  					// we should skip forking to JID with enabled message carbons if jid is not from local node
  					for (JID jid : resources.keySet()) {
  						if (session.getParentSession().getResourceForJID(jid) == null)
  							skipForkingTo.add(jid);
  					}
  				} else {
  					skipForkingTo = Collections.singleton(session.getJID());
  				}
  
  				if ( log.isLoggable( Level.FINER ) ){
  					log.log( Level.FINER, "Sending message carbon copy, packet: {0}, resources {1}, skipForkingTo: {2}, session: {3}",
  									 new Object[] { packet, resources, skipForkingTo, session } );
  				}
  
  				for (Map.Entry<JID, Boolean> entry : resources.entrySet()) {
  
  					if (!entry.getValue()) {
  						continue;
  					}
  
  					JID jid = entry.getKey();
  
  					// do not send carbon copy to session to which it is addressed
  					// or from which it is sent or to which it will be delivered due
  					// to default routing
  					if (skipForkingTo.contains(entry.getKey())) {
  						continue;
  					}
  
  					// prepare carbon copy of message					
  					Packet msgClone = prepareCarbonCopy(packet, srcJid, jid, type);
  					results.offer(msgClone);
  				}
  			}
  		}
  	}
focal_method.class_method_signature: MessageCarbons.process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_method.full_signature: @Override public void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_method.identifier: process
focal_method.invocations: getElemName getChild getElement getChild getElement offer getResponseMessage getJID getStanzaFrom equals getStanzaFrom isUserId getBareJID getStanzaFrom getResource getStanzaFrom getCommonSessionData getParentSession getCommonSessionData putCommonSessionData isLoggable log getStanzaFrom put getStanzaFrom getActiveSessions notifyStateChanged getJID getStanzaFrom isEnabled setEnabled offer okResult getElemName getType getStanzaTo isDeliveryError getCommonSessionData isEmpty getType getChild getElement getChild getElement getAttributeStaticStr getChild getElement removeChild getElement isUserId getBareJID getStanzaTo jidInstance getBareJID isUserId getBareJID getStanzaTo getResource getStanzaTo getJIDsForMessageDelivery keySet getResourceForJID getParentSession add singleton getJID isLoggable log entrySet getValue getKey contains getKey prepareCarbonCopy offer
focal_method.modifiers: @Override public
focal_method.parameters: (Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)
focal_method.return: void
focal_method.signature: void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, 
  			Queue<Packet> results, Map<String, Object> settings)